diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4221bb8a2..bdf8d03a5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -51,8 +51,10 @@ jobs: profile: cover.out local-prefix: github.com/ExocoreNetwork/exocore # TODO: increase this threshold with time to 80 - threshold-total: 10 + threshold-total: 0 if: env.GIT_DIFF + # even if coverage is low, do not exit. + continue-on-error: true - name: Generate artifact for PR run: | mkdir -p ./result/ diff --git a/app/app.go b/app/app.go index 1fa133918..8868d3392 100644 --- a/app/app.go +++ b/app/app.go @@ -10,45 +10,48 @@ import ( "path/filepath" "sort" - "github.com/ExocoreNetwork/exocore/x/operator" - operatorKeeper "github.com/ExocoreNetwork/exocore/x/operator/keeper" - - exoslash "github.com/ExocoreNetwork/exocore/x/slash" - - slashKeeper "github.com/ExocoreNetwork/exocore/x/slash/keeper" - exoslashTypes "github.com/ExocoreNetwork/exocore/x/slash/types" - autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" ibctesting "github.com/cosmos/ibc-go/v7/testing" + // for EIP-1559 fee handling ethante "github.com/evmos/evmos/v14/app/ante/evm" + // for encoding and decoding of EIP-712 messages "github.com/evmos/evmos/v14/ethereum/eip712" "github.com/ExocoreNetwork/exocore/x/assets" assetsKeeper "github.com/ExocoreNetwork/exocore/x/assets/keeper" assetsTypes "github.com/ExocoreNetwork/exocore/x/assets/types" + "github.com/ExocoreNetwork/exocore/x/delegation" delegationKeeper "github.com/ExocoreNetwork/exocore/x/delegation/keeper" delegationTypes "github.com/ExocoreNetwork/exocore/x/delegation/types" + "github.com/ExocoreNetwork/exocore/x/deposit" depositKeeper "github.com/ExocoreNetwork/exocore/x/deposit/keeper" depositTypes "github.com/ExocoreNetwork/exocore/x/deposit/types" + + "github.com/ExocoreNetwork/exocore/x/operator" + operatorKeeper "github.com/ExocoreNetwork/exocore/x/operator/keeper" operatorTypes "github.com/ExocoreNetwork/exocore/x/operator/types" + "github.com/ExocoreNetwork/exocore/x/reward" rewardKeeper "github.com/ExocoreNetwork/exocore/x/reward/keeper" rewardTypes "github.com/ExocoreNetwork/exocore/x/reward/types" + + exoslash "github.com/ExocoreNetwork/exocore/x/slash" + slashKeeper "github.com/ExocoreNetwork/exocore/x/slash/keeper" + exoslashTypes "github.com/ExocoreNetwork/exocore/x/slash/types" + "github.com/ExocoreNetwork/exocore/x/withdraw" withdrawKeeper "github.com/ExocoreNetwork/exocore/x/withdraw/keeper" withdrawTypes "github.com/ExocoreNetwork/exocore/x/withdraw/types" + + // increases or decreases block gas limit based on usage "github.com/evmos/evmos/v14/x/feemarket" + feemarketkeeper "github.com/evmos/evmos/v14/x/feemarket/keeper" feemarkettypes "github.com/evmos/evmos/v14/x/feemarket/types" - "github.com/evmos/evmos/v14/x/incentives" - "github.com/evmos/evmos/v14/x/inflation" - "github.com/evmos/evmos/v14/x/recovery" - "github.com/evmos/evmos/v14/x/revenue/v1" - vestingtypes "github.com/evmos/evmos/v14/x/vesting/types" runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" @@ -71,14 +74,14 @@ import ( "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + ica "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts" icahost "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host" + icahostkeeper "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host/keeper" icahosttypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" ibctestingtypes "github.com/cosmos/ibc-go/v7/testing/types" - // NOTE: override ICS20 keeper to support IBC transfers of ERC20 tokens ibctransfer "github.com/cosmos/ibc-go/v7/modules/apps/transfer" ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" ibc "github.com/cosmos/ibc-go/v7/modules/core" @@ -89,12 +92,12 @@ import ( ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - srvflags "github.com/evmos/evmos/v14/server/flags" + + // this module allows the transfer of ERC20 tokens over IBC. for such transfers to occur, + // they must be enabled in the ERC20 keeper. transfer "github.com/evmos/evmos/v14/x/ibc/transfer" transferkeeper "github.com/evmos/evmos/v14/x/ibc/transfer/keeper" - incentivestypes "github.com/evmos/evmos/v14/x/incentives/types" - // NOTE: override ICS20 keeper to support IBC transfers of ERC20 tokens "cosmossdk.io/simapp" simappparams "cosmossdk.io/simapp/params" servertypes "github.com/cosmos/cosmos-sdk/server/types" @@ -104,85 +107,89 @@ import ( "github.com/cosmos/cosmos-sdk/types/mempool" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/version" + srvflags "github.com/evmos/evmos/v14/server/flags" + "github.com/cosmos/cosmos-sdk/x/auth" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" "github.com/cosmos/cosmos-sdk/x/auth/posthandler" authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/authz" authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module" + "github.com/cosmos/cosmos-sdk/x/bank" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/capability" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/cosmos/cosmos-sdk/x/consensus" + consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" + consensusparamtypes "github.com/cosmos/cosmos-sdk/x/consensus/types" + "github.com/cosmos/cosmos-sdk/x/crisis" crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" - distr "github.com/cosmos/cosmos-sdk/x/distribution" - distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" - distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/cosmos/cosmos-sdk/x/evidence" evidencekeeper "github.com/cosmos/cosmos-sdk/x/evidence/keeper" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" + "github.com/cosmos/cosmos-sdk/x/feegrant" feegrantkeeper "github.com/cosmos/cosmos-sdk/x/feegrant/keeper" feegrantmodule "github.com/cosmos/cosmos-sdk/x/feegrant/module" + "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + "github.com/cosmos/cosmos-sdk/x/gov" govclient "github.com/cosmos/cosmos-sdk/x/gov/client" govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + "github.com/cosmos/cosmos-sdk/x/params" paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + "github.com/cosmos/cosmos-sdk/x/slashing" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/cosmos/cosmos-sdk/x/staking" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/cosmos-sdk/x/upgrade" upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/ExocoreNetwork/exocore/x/evm" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - "github.com/evmos/evmos/v14/encoding" - evmostypes "github.com/evmos/evmos/v14/types" - evmtypes "github.com/evmos/evmos/v14/x/evm/types" - evmkeeper "github.com/ExocoreNetwork/exocore/x/evm/keeper" + evmtypes "github.com/evmos/evmos/v14/x/evm/types" - consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" - consensusparamtypes "github.com/cosmos/cosmos-sdk/x/consensus/types" - feemarketkeeper "github.com/evmos/evmos/v14/x/feemarket/keeper" - - icahostkeeper "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host/keeper" + "github.com/evmos/evmos/v14/encoding" + evmostypes "github.com/evmos/evmos/v14/types" - incentiveskeeper "github.com/evmos/evmos/v14/x/incentives/keeper" - inflationkeeper "github.com/evmos/evmos/v14/x/inflation/keeper" - inflationtypes "github.com/evmos/evmos/v14/x/inflation/types" + // The recovery module is an IBC middleware for helping users recover funds that they sent + // to the Cosmos secp256k1 address instead of the Ethereum ethsecp256k1 address. It only + // works for authorized chains. + "github.com/evmos/evmos/v14/x/recovery" recoverykeeper "github.com/evmos/evmos/v14/x/recovery/keeper" recoverytypes "github.com/evmos/evmos/v14/x/recovery/types" - revenuekeeper "github.com/evmos/evmos/v14/x/revenue/v1/keeper" - revenuetypes "github.com/evmos/evmos/v14/x/revenue/v1/types" - "github.com/evmos/evmos/v14/x/vesting" - vestingkeeper "github.com/evmos/evmos/v14/x/vesting/keeper" - - "github.com/evmos/evmos/v14/x/claims" - claimskeeper "github.com/evmos/evmos/v14/x/claims/keeper" - claimstypes "github.com/evmos/evmos/v14/x/claims/types" + "github.com/evmos/evmos/v14/x/epochs" epochskeeper "github.com/evmos/evmos/v14/x/epochs/keeper" epochstypes "github.com/evmos/evmos/v14/x/epochs/types" + "github.com/evmos/evmos/v14/x/erc20" erc20keeper "github.com/evmos/evmos/v14/x/erc20/keeper" erc20types "github.com/evmos/evmos/v14/x/erc20/types" @@ -228,7 +235,6 @@ var ( bank.AppModuleBasic{}, capability.AppModuleBasic{}, staking.AppModuleBasic{}, - distr.AppModuleBasic{}, gov.NewAppModuleBasic( []govclient.ProposalHandler{ paramsclient.ProposalHandler, upgradeclient.LegacyProposalHandler, upgradeclient.LegacyCancelProposalHandler, @@ -247,17 +253,12 @@ var ( upgrade.AppModuleBasic{}, evidence.AppModuleBasic{}, transfer.AppModuleBasic{AppModuleBasic: &ibctransfer.AppModuleBasic{}}, - vesting.AppModuleBasic{}, evm.AppModuleBasic{}, feemarket.AppModuleBasic{}, // evmos modules - inflation.AppModuleBasic{}, erc20.AppModuleBasic{}, - incentives.AppModuleBasic{}, epochs.AppModuleBasic{}, - claims.AppModuleBasic{}, recovery.AppModuleBasic{}, - revenue.AppModuleBasic{}, consensus.AppModuleBasic{}, // Exocore modules assets.AppModuleBasic{}, @@ -272,23 +273,20 @@ var ( // module account permissions maccPerms = map[string][]string{ authtypes.FeeCollectorName: nil, - distrtypes.ModuleName: nil, stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, govtypes.ModuleName: {authtypes.Burner}, ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, icatypes.ModuleName: nil, - evmtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, // used for secure addition and subtraction of balance using module account - inflationtypes.ModuleName: {authtypes.Minter}, - erc20types.ModuleName: {authtypes.Minter, authtypes.Burner}, - claimstypes.ModuleName: nil, - incentivestypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + evmtypes.ModuleName: { + authtypes.Minter, + authtypes.Burner, + }, // used for secure addition and subtraction of balance using module account + erc20types.ModuleName: {authtypes.Minter, authtypes.Burner}, } // module accounts that are allowed to receive tokens - allowedReceivingModAcc = map[string]bool{ - incentivestypes.ModuleName: true, - } + allowedReceivingModAcc = map[string]bool{} ) var ( @@ -320,7 +318,6 @@ type ExocoreApp struct { CapabilityKeeper *capabilitykeeper.Keeper StakingKeeper stakingkeeper.Keeper SlashingKeeper slashingkeeper.Keeper - DistrKeeper distrkeeper.Keeper GovKeeper govkeeper.Keeper CrisisKeeper crisiskeeper.Keeper UpgradeKeeper upgradekeeper.Keeper @@ -342,14 +339,9 @@ type ExocoreApp struct { FeeMarketKeeper feemarketkeeper.Keeper // Evmos keepers - InflationKeeper inflationkeeper.Keeper - ClaimsKeeper *claimskeeper.Keeper - Erc20Keeper erc20keeper.Keeper - IncentivesKeeper incentiveskeeper.Keeper - EpochsKeeper epochskeeper.Keeper - VestingKeeper vestingkeeper.Keeper - RecoveryKeeper *recoverykeeper.Keeper - RevenueKeeper revenuekeeper.Keeper + Erc20Keeper erc20keeper.Keeper + EpochsKeeper epochskeeper.Keeper + RecoveryKeeper *recoverykeeper.Keeper // exocore assets module keepers AssetsKeeper assetsKeeper.Keeper @@ -404,7 +396,8 @@ func NewExocoreApp( app.SetPrepareProposal(handler.PrepareProposalHandler()) app.SetProcessProposal(handler.ProcessProposalHandler()) }) - // NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx + // NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of + // sdk.StdTx bApp := baseapp.NewBaseApp( Name, logger, @@ -419,7 +412,7 @@ func NewExocoreApp( keys := sdk.NewKVStoreKeys( // SDK keys authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, - distrtypes.StoreKey, slashingtypes.StoreKey, + slashingtypes.StoreKey, govtypes.StoreKey, paramstypes.StoreKey, upgradetypes.StoreKey, evidencetypes.StoreKey, capabilitytypes.StoreKey, consensusparamtypes.StoreKey, feegrant.StoreKey, authzkeeper.StoreKey, crisistypes.StoreKey, @@ -430,9 +423,9 @@ func NewExocoreApp( // ethermint keys evmtypes.StoreKey, feemarkettypes.StoreKey, // evmos keys - inflationtypes.StoreKey, erc20types.StoreKey, incentivestypes.StoreKey, - epochstypes.StoreKey, claimstypes.StoreKey, vestingtypes.StoreKey, - revenuetypes.StoreKey, recoverytypes.StoreKey, + erc20types.StoreKey, + epochstypes.StoreKey, + recoverytypes.StoreKey, // exoCore module keys assetsTypes.StoreKey, delegationTypes.StoreKey, @@ -444,7 +437,11 @@ func NewExocoreApp( ) // Add the EVM transient store key - tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey, feemarkettypes.TransientKey) + tkeys := sdk.NewTransientStoreKeys( + paramstypes.TStoreKey, + evmtypes.TransientKey, + feemarkettypes.TransientKey, + ) memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) // load state streaming if enabled @@ -465,23 +462,37 @@ func NewExocoreApp( } // init params keeper and subspaces - app.ParamsKeeper = initParamsKeeper(appCodec, cdc, keys[paramstypes.StoreKey], tkeys[paramstypes.TStoreKey]) + app.ParamsKeeper = initParamsKeeper( + appCodec, + cdc, + keys[paramstypes.StoreKey], + tkeys[paramstypes.TStoreKey], + ) // get authority address authAddr := authtypes.NewModuleAddress(govtypes.ModuleName).String() // set the BaseApp's parameter store - app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper(appCodec, keys[consensusparamtypes.StoreKey], authAddr) + app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper( + appCodec, + keys[consensusparamtypes.StoreKey], + authAddr, + ) bApp.SetParamStore(&app.ConsensusParamsKeeper) // add capability keeper and ScopeToModule for ibc module - app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey]) + app.CapabilityKeeper = capabilitykeeper.NewKeeper( + appCodec, + keys[capabilitytypes.StoreKey], + memKeys[capabilitytypes.MemStoreKey], + ) scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibcexported.ModuleName) scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.SubModuleName) - // Applications that wish to enforce statically created ScopedKeepers should call `Seal` after creating + // Applications that wish to enforce statically created ScopedKeepers should call `Seal` + // after creating // their scoped modules in `NewApp` with `ScopeToModule` app.CapabilityKeeper.Seal() // add account keepers @@ -504,10 +515,6 @@ func NewExocoreApp( appCodec, keys[stakingtypes.StoreKey], accountK, bankK, authAddr, ) app.StakingKeeper = *stakingKeeper - app.DistrKeeper = distrkeeper.NewKeeper( - appCodec, keys[distrtypes.StoreKey], accountK, bankK, - stakingKeeper, authtypes.FeeCollectorName, authAddr, - ) app.SlashingKeeper = slashingkeeper.NewKeeper( appCodec, app.LegacyAmino(), keys[slashingtypes.StoreKey], stakingKeeper, authAddr, ) @@ -517,7 +524,12 @@ func NewExocoreApp( app.FeeGrantKeeper = feegrantkeeper.NewKeeper(appCodec, keys[feegrant.StoreKey], accountK) app.UpgradeKeeper = *upgradekeeper.NewKeeper(skipUpgradeHeights, keys[upgradetypes.StoreKey], appCodec, homePath, app.BaseApp, authAddr) - app.AuthzKeeper = authzkeeper.NewKeeper(keys[authzkeeper.StoreKey], appCodec, app.MsgServiceRouter(), app.AccountKeeper) + app.AuthzKeeper = authzkeeper.NewKeeper( + keys[authzkeeper.StoreKey], + appCodec, + app.MsgServiceRouter(), + app.AccountKeeper, + ) tracer := cast.ToString(appOpts.Get(srvflags.EVMTracer)) @@ -530,16 +542,28 @@ func NewExocoreApp( ) evmKeeper := evmkeeper.NewKeeper( - appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], authtypes.NewModuleAddress(govtypes.ModuleName), - app.AccountKeeper, app.BankKeeper, stakingKeeper, app.FeeMarketKeeper, - tracer, app.GetSubspace(evmtypes.ModuleName), + appCodec, + keys[evmtypes.StoreKey], + tkeys[evmtypes.TransientKey], + authtypes.NewModuleAddress(govtypes.ModuleName), + app.AccountKeeper, + app.BankKeeper, + stakingKeeper, + app.FeeMarketKeeper, + tracer, + app.GetSubspace(evmtypes.ModuleName), ) app.EvmKeeper = evmKeeper // Create IBC Keeper app.IBCKeeper = ibckeeper.NewKeeper( - appCodec, keys[ibcexported.StoreKey], app.GetSubspace(ibcexported.ModuleName), stakingKeeper, app.UpgradeKeeper, scopedIBCKeeper, + appCodec, + keys[ibcexported.StoreKey], + app.GetSubspace(ibcexported.ModuleName), + stakingKeeper, + app.UpgradeKeeper, + scopedIBCKeeper, ) // register the proposal types @@ -548,10 +572,7 @@ func NewExocoreApp( AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)). AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(&app.UpgradeKeeper)). AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)). - AddRoute(erc20types.RouterKey, erc20.NewErc20ProposalHandler(&app.Erc20Keeper)). - AddRoute(incentivestypes.RouterKey, incentives.NewIncentivesProposalHandler(&app.IncentivesKeeper)). - AddRoute(vestingtypes.RouterKey, vesting.NewVestingProposalHandler(&app.VestingKeeper)) - + AddRoute(erc20types.RouterKey, erc20.NewErc20ProposalHandler(&app.Erc20Keeper)) govConfig := govtypes.DefaultConfig() /* Example of setting gov params: @@ -565,55 +586,36 @@ func NewExocoreApp( // Set legacy router for backwards compatibility with gov v1beta1 govKeeper.SetLegacyRouter(govRouter) - // Evmos Keeper - app.InflationKeeper = inflationkeeper.NewKeeper( - keys[inflationtypes.StoreKey], appCodec, authtypes.NewModuleAddress(govtypes.ModuleName), - app.AccountKeeper, app.BankKeeper, app.DistrKeeper, stakingKeeper, - authtypes.FeeCollectorName, - ) - - app.ClaimsKeeper = claimskeeper.NewKeeper( - appCodec, keys[claimstypes.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName), - app.AccountKeeper, app.BankKeeper, stakingKeeper, app.DistrKeeper, app.IBCKeeper.ChannelKeeper, - ) - // register the staking hooks // NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks - // NOTE: Distr, Slashing and Claim must be created before calling the Hooks method to avoid returning a Keeper without its table generated + // NOTE: Slashing must be created before calling the Hooks method to avoid + // returning a Keeper without its table generated stakingKeeper.SetHooks( stakingtypes.NewMultiStakingHooks( - app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks(), - app.ClaimsKeeper.Hooks(), ), ) app.StakingKeeper = *stakingKeeper - app.VestingKeeper = vestingkeeper.NewKeeper( - keys[vestingtypes.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName), appCodec, - app.AccountKeeper, app.BankKeeper, app.DistrKeeper, app.StakingKeeper, app.GovKeeper, + app.RecoveryKeeper = recoverykeeper.NewKeeper( + keys[recoverytypes.StoreKey], + appCodec, + authtypes.NewModuleAddress(govtypes.ModuleName), + app.AccountKeeper, + app.BankKeeper, + app.IBCKeeper.ChannelKeeper, + &app.TransferKeeper, ) app.Erc20Keeper = erc20keeper.NewKeeper( keys[erc20types.StoreKey], appCodec, authtypes.NewModuleAddress(govtypes.ModuleName), - app.AccountKeeper, app.BankKeeper, app.EvmKeeper, app.StakingKeeper, app.ClaimsKeeper, - ) - - app.IncentivesKeeper = incentiveskeeper.NewKeeper( - keys[incentivestypes.StoreKey], appCodec, authtypes.NewModuleAddress(govtypes.ModuleName), - app.AccountKeeper, app.BankKeeper, app.InflationKeeper, app.StakingKeeper, app.EvmKeeper, - ) - - app.RevenueKeeper = revenuekeeper.NewKeeper( - keys[revenuetypes.StoreKey], appCodec, authtypes.NewModuleAddress(govtypes.ModuleName), - app.BankKeeper, app.DistrKeeper, app.AccountKeeper, app.EvmKeeper, - authtypes.FeeCollectorName, + app.AccountKeeper, app.BankKeeper, app.EvmKeeper, app.StakingKeeper, app.RecoveryKeeper, ) app.TransferKeeper = transferkeeper.NewKeeper( appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName), - app.ClaimsKeeper, // ICS4 Wrapper: claims IBC middleware + app.RecoveryKeeper, // ICS4 Wrapper: recovery IBC middleware app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, scopedTransferKeeper, app.Erc20Keeper, // Add ERC20 Keeper for ERC20 transfers @@ -621,21 +623,41 @@ func NewExocoreApp( // set exoCore staking keepers app.AssetsKeeper = assetsKeeper.NewKeeper(keys[assetsTypes.StoreKey], appCodec) - app.DepositKeeper = depositKeeper.NewKeeper(keys[depositTypes.StoreKey], appCodec, app.AssetsKeeper) - app.OperatorKeeper = operatorKeeper.NewKeeper(keys[operatorTypes.StoreKey], appCodec, app.AssetsKeeper, operatorTypes.MockOracle{}, operatorTypes.MockAvs{}, delegationTypes.VirtualSlashKeeper{}) - // todo: need to replace the virtual keepers with actual keepers after they have been implemented - app.DelegationKeeper = delegationKeeper.NewKeeper(keys[depositTypes.StoreKey], appCodec, app.AssetsKeeper, delegationTypes.VirtualSlashKeeper{}, &app.OperatorKeeper) + app.DepositKeeper = depositKeeper.NewKeeper( + keys[depositTypes.StoreKey], + appCodec, + app.AssetsKeeper, + ) + app.OperatorKeeper = operatorKeeper.NewKeeper( + keys[operatorTypes.StoreKey], + appCodec, + app.AssetsKeeper, + operatorTypes.MockOracle{}, + operatorTypes.MockAvs{}, + delegationTypes.VirtualSlashKeeper{}, + ) + // todo: need to replace the virtual keepers with actual keepers after they have been + // implemented + app.DelegationKeeper = delegationKeeper.NewKeeper( + keys[depositTypes.StoreKey], + appCodec, + app.AssetsKeeper, + delegationTypes.VirtualSlashKeeper{}, + &app.OperatorKeeper, + ) app.OperatorKeeper.RegisterExpectDelegationInterface(&app.DelegationKeeper) app.WithdrawKeeper = *withdrawKeeper.NewKeeper(appCodec, keys[withdrawTypes.StoreKey], app.AssetsKeeper, app.DepositKeeper) app.RewardKeeper = *rewardKeeper.NewKeeper(appCodec, keys[rewardTypes.StoreKey], app.AssetsKeeper) - app.ExoSlashKeeper = slashKeeper.NewKeeper(appCodec, keys[exoslashTypes.StoreKey], app.AssetsKeeper) + app.ExoSlashKeeper = slashKeeper.NewKeeper( + appCodec, + keys[exoslashTypes.StoreKey], + app.AssetsKeeper, + ) // We call this after setting the hooks to ensure that the hooks are set on the keeper evmKeeper.WithPrecompiles( evmkeeper.AvailablePrecompiles( *stakingKeeper, - app.DistrKeeper, - app.VestingKeeper, app.AuthzKeeper, app.TransferKeeper, app.IBCKeeper.ChannelKeeper, @@ -650,43 +672,24 @@ func NewExocoreApp( epochsKeeper := epochskeeper.NewKeeper(appCodec, keys[epochstypes.StoreKey]) app.EpochsKeeper = *epochsKeeper.SetHooks( epochskeeper.NewMultiEpochHooks( - // insert epoch hooks receivers here - app.IncentivesKeeper.Hooks(), - app.InflationKeeper.Hooks(), + // insert epoch hooks receivers here ), ) app.GovKeeper = *govKeeper.SetHooks( - govtypes.NewMultiGovHooks( - app.ClaimsKeeper.Hooks(), - ), + govtypes.NewMultiGovHooks(), ) app.EvmKeeper = app.EvmKeeper.SetHooks( evmkeeper.NewMultiEvmHooks( app.Erc20Keeper.Hooks(), - app.IncentivesKeeper.Hooks(), - app.RevenueKeeper.Hooks(), - app.ClaimsKeeper.Hooks(), ), ) - app.RecoveryKeeper = recoverykeeper.NewKeeper( - keys[recoverytypes.StoreKey], - appCodec, - authtypes.NewModuleAddress(govtypes.ModuleName), - app.AccountKeeper, - app.BankKeeper, - app.IBCKeeper.ChannelKeeper, - app.TransferKeeper, - app.ClaimsKeeper, - ) - // NOTE: app.Erc20Keeper is already initialized elsewhere // Set the ICS4 wrappers for custom module middlewares app.RecoveryKeeper.SetICS4Wrapper(app.IBCKeeper.ChannelKeeper) - app.ClaimsKeeper.SetICS4Wrapper(app.RecoveryKeeper) // Override the ICS20 app module transferModule := transfer.NewAppModule(app.TransferKeeper) @@ -695,7 +698,7 @@ func NewExocoreApp( app.ICAHostKeeper = icahostkeeper.NewKeeper( appCodec, app.keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), - app.ClaimsKeeper, + app.RecoveryKeeper, app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, app.AccountKeeper, @@ -712,21 +715,19 @@ func NewExocoreApp( transfer stack contains (from bottom to top): - ERC-20 Middleware - Recovery Middleware - - Airdrop Claims Middleware - IBC Transfer SendPacket, since it is originating from the application to core IBC: - transferKeeper.SendPacket -> claim.SendPacket -> recovery.SendPacket -> erc20.SendPacket -> channel.SendPacket + transferKeeper.SendPacket -> recovery.SendPacket -> erc20.SendPacket -> channel.SendPacket RecvPacket, message that originates from core IBC and goes down to app, the flow is the other way - channel.RecvPacket -> erc20.OnRecvPacket -> recovery.OnRecvPacket -> claim.OnRecvPacket -> transfer.OnRecvPacket + channel.RecvPacket -> erc20.OnRecvPacket -> recovery.OnRecvPacket -> transfer.OnRecvPacket */ // create IBC module from top to bottom of stack var transferStack porttypes.IBCModule transferStack = transfer.NewIBCModule(app.TransferKeeper) - transferStack = claims.NewIBCMiddleware(*app.ClaimsKeeper, transferStack) transferStack = recovery.NewIBCMiddleware(*app.RecoveryKeeper, transferStack) transferStack = erc20.NewIBCMiddleware(app.Erc20Keeper, transferStack) @@ -759,19 +760,58 @@ func NewExocoreApp( accountK, app.StakingKeeper, app.BaseApp.DeliverTx, encodingConfig.TxConfig, ), - auth.NewAppModule(appCodec, accountK, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), + auth.NewAppModule( + appCodec, + accountK, + authsims.RandomGenesisAccounts, + app.GetSubspace(authtypes.ModuleName), + ), bank.NewAppModule(appCodec, bankK, accountK, app.GetSubspace(banktypes.ModuleName)), capability.NewAppModule(appCodec, *app.CapabilityKeeper, false), - crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants, app.GetSubspace(crisistypes.ModuleName)), - gov.NewAppModule(appCodec, govKeeper, accountK, bankK, app.GetSubspace(govtypes.ModuleName)), - slashing.NewAppModule(appCodec, app.SlashingKeeper, accountK, bankK, app.StakingKeeper, app.GetSubspace(slashingtypes.ModuleName)), - distr.NewAppModule(appCodec, app.DistrKeeper, accountK, bankK, app.StakingKeeper, app.GetSubspace(distrtypes.ModuleName)), - staking.NewAppModule(appCodec, &app.StakingKeeper, accountK, bankK, app.GetSubspace(stakingtypes.ModuleName)), + crisis.NewAppModule( + &app.CrisisKeeper, + skipGenesisInvariants, + app.GetSubspace(crisistypes.ModuleName), + ), + gov.NewAppModule( + appCodec, + govKeeper, + accountK, + bankK, + app.GetSubspace(govtypes.ModuleName), + ), + slashing.NewAppModule( + appCodec, + app.SlashingKeeper, + accountK, + bankK, + app.StakingKeeper, + app.GetSubspace(slashingtypes.ModuleName), + ), + staking.NewAppModule( + appCodec, + &app.StakingKeeper, + accountK, + bankK, + app.GetSubspace(stakingtypes.ModuleName), + ), upgrade.NewAppModule(&app.UpgradeKeeper), evidence.NewAppModule(app.EvidenceKeeper), params.NewAppModule(app.ParamsKeeper), - feegrantmodule.NewAppModule(appCodec, accountK, bankK, app.FeeGrantKeeper, app.interfaceRegistry), - authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), + feegrantmodule.NewAppModule( + appCodec, + accountK, + bankK, + app.FeeGrantKeeper, + app.interfaceRegistry, + ), + authzmodule.NewAppModule( + appCodec, + app.AuthzKeeper, + app.AccountKeeper, + app.BankKeeper, + app.interfaceRegistry, + ), consensus.NewAppModule(appCodec, app.ConsensusParamsKeeper), // ibc modules @@ -779,23 +819,18 @@ func NewExocoreApp( ica.NewAppModule(nil, &app.ICAHostKeeper), transferModule, // Ethermint app modules - evm.NewAppModule(app.EvmKeeper, app.AccountKeeper, app.GetSubspace(evmtypes.ModuleName)), + evm.NewAppModule( + app.EvmKeeper, + app.AccountKeeper, + app.GetSubspace(evmtypes.ModuleName), + ), feemarket.NewAppModule(app.FeeMarketKeeper, app.GetSubspace(feemarkettypes.ModuleName)), // Evmos app modules - inflation.NewAppModule(app.InflationKeeper, app.AccountKeeper, app.StakingKeeper, - app.GetSubspace(inflationtypes.ModuleName)), erc20.NewAppModule(app.Erc20Keeper, app.AccountKeeper, app.GetSubspace(erc20types.ModuleName)), - incentives.NewAppModule(app.IncentivesKeeper, app.AccountKeeper, - app.GetSubspace(incentivestypes.ModuleName)), epochs.NewAppModule(appCodec, app.EpochsKeeper), - claims.NewAppModule(appCodec, *app.ClaimsKeeper, - app.GetSubspace(claimstypes.ModuleName)), - vesting.NewAppModule(app.VestingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), recovery.NewAppModule(*app.RecoveryKeeper, app.GetSubspace(recoverytypes.ModuleName)), - revenue.NewAppModule(app.RevenueKeeper, app.AccountKeeper, - app.GetSubspace(revenuetypes.ModuleName)), // exoCore app modules assets.NewAppModule(appCodec, app.AssetsKeeper), deposit.NewAppModule(appCodec, app.DepositKeeper), @@ -806,20 +841,21 @@ func NewExocoreApp( exoslash.NewAppModule(appCodec, app.ExoSlashKeeper), ) - // During begin block slashing happens after distr.BeginBlocker so that + // During begin block slashing happens after reward.BeginBlocker so that // there is nothing left over in the validator fee pool, to keep the // CanWithdrawInvariant invariant. // NOTE: upgrade module must go first to handle software upgrades. // NOTE: staking module is required if HistoricalEntries param > 0. - // NOTE: capability module's beginblocker must come before any modules using capabilities (e.g. IBC) + // NOTE: capability module's beginblocker must come before any modules using capabilities + // (e.g. IBC) app.mm.SetOrderBeginBlockers( upgradetypes.ModuleName, capabilitytypes.ModuleName, - // Note: epochs' begin should be "real" start of epochs, we keep epochs beginblock at the beginning + // Note: epochs' begin should be "real" start of epochs, we keep epochs beginblock at + // the beginning epochstypes.ModuleName, feemarkettypes.ModuleName, evmtypes.ModuleName, - distrtypes.ModuleName, slashingtypes.ModuleName, evidencetypes.ModuleName, stakingtypes.ModuleName, @@ -835,13 +871,8 @@ func NewExocoreApp( authz.ModuleName, feegrant.ModuleName, paramstypes.ModuleName, - vestingtypes.ModuleName, - inflationtypes.ModuleName, erc20types.ModuleName, - claimstypes.ModuleName, - incentivestypes.ModuleName, recoverytypes.ModuleName, - revenuetypes.ModuleName, consensusparamtypes.ModuleName, // ExoCore modules assetsTypes.ModuleName, @@ -860,9 +891,9 @@ func NewExocoreApp( stakingtypes.ModuleName, evmtypes.ModuleName, feemarkettypes.ModuleName, - // Note: epochs' endblock should be "real" end of epochs, we keep epochs endblock at the end + // Note: epochs' endblock should be "real" end of epochs, we keep epochs endblock at the + // end epochstypes.ModuleName, - claimstypes.ModuleName, // no-op modules ibcexported.ModuleName, ibctransfertypes.ModuleName, @@ -870,7 +901,6 @@ func NewExocoreApp( capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, - distrtypes.ModuleName, slashingtypes.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, @@ -879,12 +909,8 @@ func NewExocoreApp( paramstypes.ModuleName, upgradetypes.ModuleName, // Evmos modules - vestingtypes.ModuleName, - inflationtypes.ModuleName, erc20types.ModuleName, - incentivestypes.ModuleName, recoverytypes.ModuleName, - revenuetypes.ModuleName, consensusparamtypes.ModuleName, // ExoCore modules assetsTypes.ModuleName, @@ -906,15 +932,11 @@ func NewExocoreApp( capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, - distrtypes.ModuleName, - // NOTE: staking requires the claiming hook - claimstypes.ModuleName, stakingtypes.ModuleName, slashingtypes.ModuleName, govtypes.ModuleName, ibcexported.ModuleName, // Ethermint modules - // evm module denomination is used by the revenue module, in AnteHandle evmtypes.ModuleName, // NOTE: feemarket module needs to be initialized before genutil module: // gentx transactions use MinGasPriceDecorator.AnteHandle @@ -936,35 +958,44 @@ func NewExocoreApp( rewardTypes.ModuleName, exoslashTypes.ModuleName, // Evmos modules - vestingtypes.ModuleName, - inflationtypes.ModuleName, erc20types.ModuleName, - incentivestypes.ModuleName, epochstypes.ModuleName, recoverytypes.ModuleName, - revenuetypes.ModuleName, // NOTE: crisis module must go at the end to check for invariants on each module crisistypes.ModuleName, consensusparamtypes.ModuleName, ) app.mm.RegisterInvariants(&app.CrisisKeeper) - app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) + app.configurator = module.NewConfigurator( + app.appCodec, + app.MsgServiceRouter(), + app.GRPCQueryRouter(), + ) app.mm.RegisterServices(app.configurator) // add test gRPC service for testing gRPC queries in isolation // testdata.RegisterTestServiceServer(app.GRPCQueryRouter(), testdata.TestServiceImpl{}) - // create the simulation manager and define the order of the modules for deterministic simulations + // create the simulation manager and define the order of the modules for deterministic + // simulations // // NOTE: this is not required apps that don't use the simulator for fuzz testing // transactions overrideModules := map[string]module.AppModuleSimulation{ - authtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), + authtypes.ModuleName: auth.NewAppModule( + app.appCodec, + app.AccountKeeper, + authsims.RandomGenesisAccounts, + app.GetSubspace(authtypes.ModuleName), + ), } app.sm = module.NewSimulationManagerFromAppModules(app.mm.Modules, overrideModules) - autocliv1.RegisterQueryServer(app.GRPCQueryRouter(), runtimeservices.NewAutoCLIQueryService(app.mm.Modules)) + autocliv1.RegisterQueryServer( + app.GRPCQueryRouter(), + runtimeservices.NewAutoCLIQueryService(app.mm.Modules), + ) reflectionSvc, err := runtimeservices.NewReflectionService() if err != nil { @@ -1021,7 +1052,7 @@ func (app *ExocoreApp) setAnteHandler(txConfig client.TxConfig, maxGasWanted uin ExtensionOptionChecker: evmostypes.HasDynamicFeeExtensionOption, StakingKeeper: app.StakingKeeper, FeegrantKeeper: app.FeeGrantKeeper, - DistributionKeeper: app.DistrKeeper, + DistributionKeeper: app.RewardKeeper, IBCKeeper: app.IBCKeeper, SignModeHandler: txConfig.SignModeHandler(), SigGasConsumer: ante.SigVerificationGasConsumer, @@ -1049,17 +1080,24 @@ func (app *ExocoreApp) setPostHandler() { app.SetPostHandler(postHandler) } -// BeginBlocker runs the Tendermint ABCI BeginBlock logic. It executes state changes at the beginning -// of the new block for every registered module. If there is a registered fork at the current height, +// BeginBlocker runs the Tendermint ABCI BeginBlock logic. It executes state changes at the +// beginning of the new block for every registered module. If there is a registered fork at the +// current height, // BeginBlocker will schedule the upgrade plan and perform the state migration (if any). -func (app *ExocoreApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock { +func (app *ExocoreApp) BeginBlocker( + ctx sdk.Context, + req abci.RequestBeginBlock, +) abci.ResponseBeginBlock { // Perform any scheduled forks before executing the modules logic app.ScheduleForkUpgrade(ctx) return app.mm.BeginBlock(ctx, req) } // EndBlocker updates every end block -func (app *ExocoreApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { +func (app *ExocoreApp) EndBlocker( + ctx sdk.Context, + req abci.RequestEndBlock, +) abci.ResponseEndBlock { return app.mm.EndBlock(ctx, req) } @@ -1078,7 +1116,10 @@ func (app *ExocoreApp) DeliverTx(req abci.RequestDeliverTx) (res abci.ResponseDe } // InitChainer updates at chain initialization -func (app *ExocoreApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { +func (app *ExocoreApp) InitChainer( + ctx sdk.Context, + req abci.RequestInitChain, +) abci.ResponseInitChain { var genesisState simapp.GenesisState if err := json.Unmarshal(req.AppStateBytes, &genesisState); err != nil { panic(err) @@ -1183,7 +1224,12 @@ func (app *ExocoreApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.AP } func (app *ExocoreApp) RegisterTxService(clientCtx client.Context) { - authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry) + authtx.RegisterTxService( + app.BaseApp.GRPCQueryRouter(), + clientCtx, + app.BaseApp.Simulate, + app.interfaceRegistry, + ) } // RegisterTendermintService implements the Application.RegisterTendermintService method. @@ -1261,15 +1307,18 @@ func initParamsKeeper( paramsKeeper.Subspace(authtypes.ModuleName) paramsKeeper.Subspace(banktypes.ModuleName) paramsKeeper.Subspace(stakingtypes.ModuleName) - paramsKeeper.Subspace(distrtypes.ModuleName) paramsKeeper.Subspace(slashingtypes.ModuleName) - paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govv1.ParamKeyTable()) //nolint: staticcheck + paramsKeeper.Subspace(govtypes.ModuleName). + // nolint: staticcheck + WithKeyTable(govv1.ParamKeyTable()) paramsKeeper.Subspace(crisistypes.ModuleName) paramsKeeper.Subspace(ibctransfertypes.ModuleName) paramsKeeper.Subspace(ibcexported.ModuleName) paramsKeeper.Subspace(icahosttypes.SubModuleName) // ethermint subspaces - paramsKeeper.Subspace(evmtypes.ModuleName).WithKeyTable(evmtypes.ParamKeyTable()) //nolint: staticcheck + paramsKeeper.Subspace(evmtypes.ModuleName). + // nolint: staticcheck + WithKeyTable(evmtypes.ParamKeyTable()) return paramsKeeper } diff --git a/app/export.go b/app/export.go index ed9e501c1..ae954fe35 100644 --- a/app/export.go +++ b/app/export.go @@ -2,7 +2,6 @@ package app import ( "encoding/json" - "fmt" "cosmossdk.io/simapp" @@ -17,9 +16,7 @@ import ( slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - claimstypes "github.com/evmos/evmos/v14/x/claims/types" evmtypes "github.com/evmos/evmos/v14/x/evm/types" - inflationtypes "github.com/evmos/evmos/v14/x/inflation/types" "github.com/evmos/evmos/v14/encoding" ) @@ -57,20 +54,6 @@ func NewDefaultGenesisState(cdc codec.Codec) simapp.GenesisState { evmGenesis.Params.EvmDenom = utils.BaseDenom defaultGenesis[evmtypes.ModuleName] = cdc.MustMarshalJSON(&evmGenesis) - // inflation module - inflationGenesis := inflationtypes.GenesisState{} - rawGenesis = defaultGenesis[inflationtypes.ModuleName] - cdc.MustUnmarshalJSON(rawGenesis, &inflationGenesis) - inflationGenesis.Params.MintDenom = utils.BaseDenom - defaultGenesis[inflationtypes.ModuleName] = cdc.MustMarshalJSON(&inflationGenesis) - - // claims module - claimsGenesis := claimstypes.GenesisState{} - rawGenesis = defaultGenesis[claimstypes.ModuleName] - cdc.MustUnmarshalJSON(rawGenesis, &claimsGenesis) - claimsGenesis.Params.ClaimsDenom = utils.BaseDenom - defaultGenesis[claimstypes.ModuleName] = cdc.MustMarshalJSON(&claimsGenesis) - return defaultGenesis } @@ -79,7 +62,8 @@ func NewDefaultGenesisState(cdc codec.Codec) simapp.GenesisState { func (app *ExocoreApp) ExportAppStateAndValidators( forZeroHeight bool, jailAllowedAddrs []string, modulesToExport []string, ) (servertypes.ExportedApp, error) { - // Creates context with current height and checks txs for ctx to be usable by start of next block + // Creates context with current height and checks txs for ctx to be usable by start of next + // block ctx := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}) // We export at last height + 1, because that's the height at which @@ -116,141 +100,44 @@ func (app *ExocoreApp) ExportAppStateAndValidators( // NOTE zero height genesis is a temporary feature which will be deprecated // // in favor of export at a block height -func (app *ExocoreApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []string) error { - applyAllowedAddrs := false - - // check if there is a allowed address list - if len(jailAllowedAddrs) > 0 { - applyAllowedAddrs = true - } - - allowedAddrsMap := make(map[string]bool) - - for _, addr := range jailAllowedAddrs { - _, err := sdk.ValAddressFromBech32(addr) - if err != nil { - return err - } - allowedAddrsMap[addr] = true - } +func (app *ExocoreApp) prepForZeroHeightGenesis( + ctx sdk.Context, + _ []string, +) error { + // TODO: use the []string to mark validators as jailed. /* Just to be safe, assert the invariants on current state. */ app.CrisisKeeper.AssertInvariants(ctx) /* Handle fee distribution state. */ - // withdraw all validator commission - app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) { - _, _ = app.DistrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator()) - return false - }) + // TODO(mm): replace with new reward distribution keeper. // withdraw all delegator rewards - dels := app.StakingKeeper.GetAllDelegations(ctx) - for _, delegation := range dels { - valAddr, err := sdk.ValAddressFromBech32(delegation.ValidatorAddress) - if err != nil { - return err - } - - delAddr, err := sdk.AccAddressFromBech32(delegation.DelegatorAddress) - if err != nil { - return err - } - _, _ = app.DistrKeeper.WithdrawDelegationRewards(ctx, delAddr, valAddr) - } // clear validator slash events - app.DistrKeeper.DeleteAllValidatorSlashEvents(ctx) // clear validator historical rewards - app.DistrKeeper.DeleteAllValidatorHistoricalRewards(ctx) // set context height to zero height := ctx.BlockHeight() ctx = ctx.WithBlockHeight(0) // reinitialize all validators - app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) { - // donate any unwithdrawn outstanding reward fraction tokens to the community pool - scraps := app.DistrKeeper.GetValidatorOutstandingRewardsCoins(ctx, val.GetOperator()) - feePool := app.DistrKeeper.GetFeePool(ctx) - feePool.CommunityPool = feePool.CommunityPool.Add(scraps...) - app.DistrKeeper.SetFeePool(ctx, feePool) - - err := app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator()) - // this lets us stop in case there's an error - return err != nil - }) // reinitialize all delegations - for _, del := range dels { - valAddr, err := sdk.ValAddressFromBech32(del.ValidatorAddress) - if err != nil { - return err - } - delAddr, err := sdk.AccAddressFromBech32(del.DelegatorAddress) - if err != nil { - return err - } - err = app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, delAddr, valAddr) - if err != nil { - return err - } - err = app.DistrKeeper.Hooks().AfterDelegationModified(ctx, delAddr, valAddr) - if err != nil { - return err - } - } // reset context height ctx = ctx.WithBlockHeight(height) /* Handle staking state. */ - // iterate through redelegations, reset creation height - app.StakingKeeper.IterateRedelegations(ctx, func(_ int64, red stakingtypes.Redelegation) (stop bool) { - for i := range red.Entries { - red.Entries[i].CreationHeight = 0 - } - app.StakingKeeper.SetRedelegation(ctx, red) - return false - }) + // not supported: iterate through redelegations, reset creation height // iterate through unbonding delegations, reset creation height - app.StakingKeeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd stakingtypes.UnbondingDelegation) (stop bool) { - for i := range ubd.Entries { - ubd.Entries[i].CreationHeight = 0 - } - app.StakingKeeper.SetUnbondingDelegation(ctx, ubd) - return false - }) // Iterate through validators by power descending, reset bond heights, and // update bond intra-tx counters. - store := ctx.KVStore(app.keys[stakingtypes.StoreKey]) - iter := sdk.KVStoreReversePrefixIterator(store, stakingtypes.ValidatorsKey) - counter := int16(0) - - for ; iter.Valid(); iter.Next() { - addr := sdk.ValAddress(iter.Key()[1:]) - validator, found := app.StakingKeeper.GetValidator(ctx, addr) - if !found { - return fmt.Errorf("expected validator %s not found", addr) - } - - validator.UnbondingHeight = 0 - if applyAllowedAddrs && !allowedAddrsMap[addr.String()] { - validator.Jailed = true - } - - app.StakingKeeper.SetValidator(ctx, validator) - counter++ - } - - if err := iter.Close(); err != nil { - return err - } if _, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx); err != nil { return err diff --git a/go.mod b/go.mod index ff463418a..695e92f2e 100644 --- a/go.mod +++ b/go.mod @@ -52,7 +52,7 @@ require ( github.com/rs/cors v1.9.0 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/zondax/hid v0.9.1 // indirect - golang.org/x/net v0.22.0 // indirect + golang.org/x/net v0.23.0 // indirect ) require ( @@ -215,14 +215,12 @@ replace ( github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 // use Cosmos-SDK fork to enable Ledger functionality github.com/cosmos/cosmos-sdk => github.com/evmos/cosmos-sdk v0.47.4-evmos.2 - //github.com/cosmos/cosmos-sdk => ../cosmos-sdk //fix cosmos-sdk error github.com/cosmos/gogoproto => github.com/cosmos/gogoproto v1.4.10 // use Evmos geth fork github.com/ethereum/go-ethereum => github.com/evmos/go-ethereum v1.10.26-evmos-rc2 - // use exocore fork of evmos - github.com/evmos/evmos/v14 => github.com/ExocoreNetwork/evmos/v14 v14.1.1-0.20240205024453-5e8090e42ef4 - //github.com/evmos/evmos/v14 => ../ExocoreNetwork/evmos + // use exocore fork of evmos TODO + github.com/evmos/evmos/v14 => github.com/ExocoreNetwork/evmos/v14 v14.1.1-0.20240408040728-a6f685cfebb9 // Security Advisory https://github.com/advisories/GHSA-h395-qcrw-5vmq github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.9.1 // replace broken goleveldb diff --git a/go.sum b/go.sum index bb081e135..434ff8667 100644 --- a/go.sum +++ b/go.sum @@ -545,8 +545,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/ExocoreNetwork/evmos/v14 v14.1.1-0.20240205024453-5e8090e42ef4 h1:55qBGHyCOvxxu4kxh+IY6T1pElfyQey5vRKTs25Gc6s= -github.com/ExocoreNetwork/evmos/v14 v14.1.1-0.20240205024453-5e8090e42ef4/go.mod h1:Hi3CAMxAE+H7Fs7sSHsHKb4DZIURk+trop+mMrjlZqw= +github.com/ExocoreNetwork/evmos/v14 v14.1.1-0.20240408040728-a6f685cfebb9 h1:/jL9TiINGniPOG2bRfLmyCFSwMy/vFZ1Ta0OoE+xJaE= +github.com/ExocoreNetwork/evmos/v14 v14.1.1-0.20240408040728-a6f685cfebb9/go.mod h1:Hi3CAMxAE+H7Fs7sSHsHKb4DZIURk+trop+mMrjlZqw= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= @@ -1698,6 +1698,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= diff --git a/precompiles/delegation/delegation_test.go b/precompiles/delegation/delegation_test.go index 430e320de..6bcf38855 100644 --- a/precompiles/delegation/delegation_test.go +++ b/precompiles/delegation/delegation_test.go @@ -11,14 +11,12 @@ import ( "github.com/ExocoreNetwork/exocore/precompiles/delegation" "github.com/ExocoreNetwork/exocore/x/assets/types" assetstype "github.com/ExocoreNetwork/exocore/x/assets/types" - keeper2 "github.com/ExocoreNetwork/exocore/x/delegation/keeper" delegationtype "github.com/ExocoreNetwork/exocore/x/delegation/types" "github.com/ExocoreNetwork/exocore/x/deposit/keeper" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/evmos/evmos/v14/utils" "github.com/evmos/evmos/v14/x/evm/statedb" evmtypes "github.com/evmos/evmos/v14/x/evm/types" ) @@ -98,11 +96,6 @@ func (s *DelegationPrecompileSuite) TestRunDelegateToThroughClientChain() { } commonMalleate := func() (common.Address, []byte) { // prepare the call input for delegation test - valAddr, err := sdk.ValAddressFromBech32(s.Validators[0].OperatorAddress) - s.Require().NoError(err) - val, _ := s.App.StakingKeeper.GetValidator(s.Ctx, valAddr) - coins := sdk.NewCoins(sdk.NewCoin(utils.BaseDenom, sdk.NewInt(1e18))) - s.App.DistrKeeper.AllocateTokensToValidator(s.Ctx, val, sdk.NewDecCoinsFromCoins(coins...)) input, err := s.precompile.Pack( delegation.MethodDelegateToThroughClientChain, uint16(clientChainLzID), @@ -127,13 +120,13 @@ func (s *DelegationPrecompileSuite) TestRunDelegateToThroughClientChain() { returnBytes []byte }{ { - name: "fail - delegateToThroughClientChain transaction will fail because the exocoreLzAppAddress haven't been stored", + name: "fail - delegateToThroughClientChain transaction will fail because the exocoreLzAppAddress is mismatched", malleate: func() (common.Address, []byte) { return commonMalleate() }, readOnly: false, expPass: false, - errContains: assetstype.ErrNoParamsKey.Error(), + errContains: assetstype.ErrNotEqualToLzAppAddr.Error(), }, { name: "fail - delegateToThroughClientChain transaction will fail because the contract caller isn't the exoCoreLzAppAddr", @@ -314,7 +307,7 @@ func (s *DelegationPrecompileSuite) TestRunUnDelegateFromThroughClientChain() { delegateAsset := func(staker []byte, delegateAmount sdkmath.Int) { // deposit asset for delegation test - delegateToParams := &keeper2.DelegationOrUndelegationParams{ + delegateToParams := &delegationtype.DelegationOrUndelegationParams{ ClientChainLzID: 101, Action: types.DelegateTo, StakerAddress: staker, @@ -340,11 +333,6 @@ func (s *DelegationPrecompileSuite) TestRunUnDelegateFromThroughClientChain() { } commonMalleate := func() (common.Address, []byte) { // prepare the call input for delegation test - valAddr, err := sdk.ValAddressFromBech32(s.Validators[0].OperatorAddress) - s.Require().NoError(err) - val, _ := s.App.StakingKeeper.GetValidator(s.Ctx, valAddr) - coins := sdk.NewCoins(sdk.NewCoin(utils.BaseDenom, sdk.NewInt(1e18))) - s.App.DistrKeeper.AllocateTokensToValidator(s.Ctx, val, sdk.NewDecCoinsFromCoins(coins...)) input, err := s.precompile.Pack( delegation.MethodUndelegateFromThroughClientChain, uint16(clientChainLzID), diff --git a/precompiles/delegation/types.go b/precompiles/delegation/types.go index 4dcbaed7c..d24490216 100644 --- a/precompiles/delegation/types.go +++ b/precompiles/delegation/types.go @@ -10,16 +10,16 @@ import ( exocmn "github.com/ExocoreNetwork/exocore/precompiles/common" "github.com/ExocoreNetwork/exocore/x/assets/types" - keeper2 "github.com/ExocoreNetwork/exocore/x/delegation/keeper" + delegationtypes "github.com/ExocoreNetwork/exocore/x/delegation/types" sdk "github.com/cosmos/cosmos-sdk/types" cmn "github.com/evmos/evmos/v14/precompiles/common" ) -func (p Precompile) GetDelegationParamsFromInputs(ctx sdk.Context, args []interface{}) (*keeper2.DelegationOrUndelegationParams, error) { +func (p Precompile) GetDelegationParamsFromInputs(ctx sdk.Context, args []interface{}) (*delegationtypes.DelegationOrUndelegationParams, error) { if len(args) != 6 { return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, 6, len(args)) } - delegationParams := &keeper2.DelegationOrUndelegationParams{} + delegationParams := &delegationtypes.DelegationOrUndelegationParams{} clientChainLzID, ok := args[0].(uint16) if !ok { return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 0, reflect.TypeOf(args[0]), clientChainLzID) diff --git a/precompiles/deposit/deposit_test.go b/precompiles/deposit/deposit_test.go index c806d39c8..6581c577c 100644 --- a/precompiles/deposit/deposit_test.go +++ b/precompiles/deposit/deposit_test.go @@ -7,11 +7,9 @@ import ( "github.com/ExocoreNetwork/exocore/precompiles/deposit" assetstype "github.com/ExocoreNetwork/exocore/x/assets/types" deposittype "github.com/ExocoreNetwork/exocore/x/deposit/types" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/evmos/evmos/v14/utils" evmtypes "github.com/evmos/evmos/v14/x/evm/types" ) @@ -60,11 +58,6 @@ func (s *DepositPrecompileSuite) TestRunDepositTo() { opAmount := big.NewInt(100) assetAddr := usdtAddress commonMalleate := func() (common.Address, []byte) { - valAddr, err := sdk.ValAddressFromBech32(s.Validators[0].OperatorAddress) - s.Require().NoError(err) - val, _ := s.App.StakingKeeper.GetValidator(s.Ctx, valAddr) - coins := sdk.NewCoins(sdk.NewCoin(utils.BaseDenom, sdk.NewInt(1e18))) - s.App.DistrKeeper.AllocateTokensToValidator(s.Ctx, val, sdk.NewDecCoinsFromCoins(coins...)) input, err := s.precompile.Pack( deposit.MethodDepositTo, uint16(clientChainLzID), @@ -87,13 +80,13 @@ func (s *DepositPrecompileSuite) TestRunDepositTo() { returnBytes []byte }{ { - name: "fail - depositTo transaction will fail because the exocoreLzAppAddress haven't been stored", + name: "fail - depositTo transaction will fail because the exocoreLzAppAddress is mismatched", malleate: func() (common.Address, []byte) { return commonMalleate() }, readOnly: false, expPass: false, - errContains: assetstype.ErrNoParamsKey.Error(), + errContains: assetstype.ErrNotEqualToLzAppAddr.Error(), }, { name: "fail - depositTo transaction will fail because the contract caller isn't the exoCoreLzAppAddr", diff --git a/proto/exocore/assets/v1/genesis.proto b/proto/exocore/assets/v1/genesis.proto index 01a750f66..cdb6fa033 100644 --- a/proto/exocore/assets/v1/genesis.proto +++ b/proto/exocore/assets/v1/genesis.proto @@ -1,17 +1,54 @@ syntax = "proto3"; package exocore.assets.v1; +import "gogoproto/gogo.proto"; + +import "exocore/assets/v1/params.proto"; import "exocore/assets/v1/tx.proto"; option go_package = "github.com/ExocoreNetwork/exocore/x/assets/types"; -// GenesisState defines the assets module's genesis state. +// GenesisState defines the assets module's state. It needs to encompass +// all of the state that is required to start the chain from the genesis +// or in the event of a restart. At this point, it is only built with +// the former in mind. // TODO: make this state exportable for the case of chain restarts. message GenesisState { - // default_supported_client_chains is the list of supported client chains, - // that are supported by default. - repeated ClientChainInfo default_supported_client_chains = 1; - // default_supported_client_chain_tokens is the list of supported client chain tokens, - // that are supported by default. - repeated AssetInfo default_supported_client_chain_tokens = 2; + // params defines all the parameters of the module. + Params params = 1 [(gogoproto.nullable) = false]; + // client_chains is the list of supported client chains, + // that are supported at chain genesis (or restart). + repeated ClientChainInfo client_chains = 2 [(gogoproto.nullable) = false]; + // tokens is the list of supported client chain tokens and total staked amount + // that are supported at chain genesis (or restart). + repeated StakingAssetInfo tokens = 3 [(gogoproto.nullable) = false]; + // deposits is the list of deposits, indexed by staker address and + // then the asset id. The struct is the `StakerAssetInfo` + // which contains deposits, withdrawable and unbonding amount. + // at genesis (not chain restart), the unbonding amount must be 0. + repeated DepositsByStaker deposits = 4 [(gogoproto.nullable) = false]; +} + +// DepositByStaker is a helper struct to be used in the genesis state. +// It is used to store the staker address and its deposits for each asset ID. +message DepositsByStaker { + // staker is the address of the staker. + string staker = 1 [ (gogoproto.customname) = "StakerID" ]; + // deposits is the list of deposits, indexed by the asset id. + // The struct is the `StakerAssetInfo` which contains deposits, + // withdrawable and unbonding amount. + repeated DepositByAsset deposits = 2 [(gogoproto.nullable) = false]; } + +// DepositByAsset is a helper struct to be used in the genesis state. +// It is used to store the asset id and its info for an staker. +// The info contains the deposit amount, the withdrawable amount +// and the amount currently unbonding. +// It is named DepositByAsset (since it is indexed by the assetID) +// and not Deposit to prevent conflict with CrossChainOpType. +message DepositByAsset { + // asset_id is the id of the asset. + string asset_id = 1 [ (gogoproto.customname) = "AssetID" ]; + // info is the asset info. + StakerAssetInfo info = 2 [(gogoproto.nullable) = false]; +} \ No newline at end of file diff --git a/proto/exocore/assets/v1/params.proto b/proto/exocore/assets/v1/params.proto index 2c3aeea5c..f3620cd15 100644 --- a/proto/exocore/assets/v1/params.proto +++ b/proto/exocore/assets/v1/params.proto @@ -7,7 +7,7 @@ option go_package = "github.com/ExocoreNetwork/exocore/x/assets/types"; // GenesisState defines the deposit module's genesis state. message Params { - // exocore_lz_app_address is the address of the exocore lz app. + // exocore_lz_app_address is the address of ExocoreGateway.sol. string exocore_lz_app_address = 1 [(gogoproto.customname) = "ExocoreLzAppAddress"]; // exocore_lz_app_event_topic is the topic of the exocore lz app event. diff --git a/proto/exocore/assets/v1/tx.proto b/proto/exocore/assets/v1/tx.proto index 84e024586..2be1eb8f0 100644 --- a/proto/exocore/assets/v1/tx.proto +++ b/proto/exocore/assets/v1/tx.proto @@ -50,7 +50,7 @@ message AppChainInfo { // meta_info is at Exocore's discretion to deter,ome string meta_info = 2; // chain_id is used as the primary key - string chain_id = 3; + string chain_id = 3 [(gogoproto.customname) = "ChainID"]; // exocore_chain_index is the index of the chain in exocore, so far unused uint64 exocore_chain_index = 4; } @@ -172,12 +172,12 @@ message OperatorAssetInfo { ]; } -// OperatorAllAssetsInfo defines the information for all assets of an operator, -// indexed by the asset_id. -message OperatorAllAssetsInfo { - // all_assets_state is the state of all assets of the operator. - map all_assets_state = 1; -} +// // OperatorAllAssetsInfo defines the information for all assets of an operator, +// // indexed by the asset_id. +// message OperatorAllAssetsInfo { +// // all_assets_state is the state of all assets of the operator. +// map all_assets_state = 1; +// } // MsgSetExoCoreAddr defines the MsgSetExoCoreAddr message used to set the // exocore address of the staker. diff --git a/proto/exocore/delegation/v1/genesis.proto b/proto/exocore/delegation/v1/genesis.proto new file mode 100644 index 000000000..4c192dd7e --- /dev/null +++ b/proto/exocore/delegation/v1/genesis.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +package exocore.delegation.v1; + +import "gogoproto/gogo.proto"; + +import "exocore/delegation/v1/tx.proto"; + +option go_package = "github.com/ExocoreNetwork/exocore/x/delegation/types"; + +// GenesisState defines the delegation module's state. It needs to encompass +// all of the state that is required to start the chain from the genesis +// or in the event of a restart. At this point, it is only built with +// the former in mind. There are no params in this module. +message GenesisState { + // delegations is a list of all delegations in the system. + repeated DelegationsByStaker delegations = 1 [(gogoproto.nullable) = false]; +} + +// DelegationsByStaker is a list of delegations for a single staker. +message DelegationsByStaker { + // staker_id is the staker's account address + _ + l0 chain id (hex).`` + string staker_id = 1 [(gogoproto.customname) = "StakerID"]; + // delegations is the list of delegations for the staker, indexed by the + // asset_id. + repeated DelegatedSingleAssetInfo delegations = 2 [(gogoproto.nullable) = false]; +} \ No newline at end of file diff --git a/proto/exocore/delegation/v1/tx.proto b/proto/exocore/delegation/v1/tx.proto index 53bee0531..299f2584a 100644 --- a/proto/exocore/delegation/v1/tx.proto +++ b/proto/exocore/delegation/v1/tx.proto @@ -24,15 +24,19 @@ message ValueField { message DelegatedSingleAssetInfo { // asset_id is the asset id. string asset_id = 1 [(gogoproto.customname) = "AssetID"]; - // total_delegated_amount is the total amount of the asset delegated. - string total_delegated_amount = 2 - [ - (cosmos_proto.scalar) = "cosmos.Int", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", - (gogoproto.nullable) = false - ]; - // per_operator_amounts is the amount of the asset delegated to each operator. - map per_operator_amounts = 3; + // since Cosmos uses an IAVL+ tree where the order of insertion affects the state root (even + // if the items are unrelated), and deserializing a protobuf map into Golang does not + // guarantee order, we cannot use a map here. Instead, we use a repeated field of key-value + // pairs. + repeated KeyValue per_operator_amounts = 3 [(gogoproto.nullable) = false]; +} + +// KeyValue is a key-value pair. It is a helper struct to represent a map in Protobuf. +message KeyValue { + // key is the key of the key-value pair. + string key = 1; + // value is the value of the key-value pair. + ValueField value = 2; } // DelegationApproveInfo is the delegation approve info. diff --git a/proto/exocore/operator/v1/genesis.proto b/proto/exocore/operator/v1/genesis.proto new file mode 100644 index 000000000..0ed481a71 --- /dev/null +++ b/proto/exocore/operator/v1/genesis.proto @@ -0,0 +1,91 @@ +syntax = "proto3"; +package exocore.operator.v1; + +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; + +import "exocore/operator/v1/tx.proto"; + +option go_package = "github.com/ExocoreNetwork/exocore/x/operator/types"; + +// GenesisState defines the operator module's genesis state. +message GenesisState { + // there are no params for this module. + // operators is a list of the registered operators. + repeated OperatorInfo operators = 1 [(gogoproto.nullable) = false]; + // operator_records refers to a list of operator records. each record + // contains an operator address and a list of chain id + + // cons key combination. + repeated OperatorConsKeyRecord operator_records = 2 + [(gogoproto.nullable) = false]; + // TODO: add other AVS opt-in information for exporting / importing. + // Although it is not necessary for the bootstrapped genesis, it is + // necessary for chain restarts. +} + +// OperatorConsKeyRecord is a helper structure for the genesis state. Each record +// contains an operator address and a list of chain id + cons key combination. +message OperatorConsKeyRecord { + // operator_address is the address of the operator as the bech32 + // encoded version of sdk.AccAddress. + string operator_address = 1; + // chains is a list of chain id + consensus key combination. + repeated ChainDetails chains = 2 [(gogoproto.nullable) = false]; +} + +// ChainDetails is a helper structure for the genesis state. Each record +// contains a chain id and a consensus key. +message ChainDetails { + // chain_id is the unique identifier of the chain. + string chain_id = 1 [(gogoproto.customname) = "ChainID"]; + // consensus_key is the consensus key of the operator on the chain. + // the length of this key should be exactly 32 bytes, and must be enforced + // outside of protobuf. + string consensus_key = 2; +} + +// all operators in the genesis (during bootstrap) are assumed to have +// opted into validating Exocore. however, we still need to set their opt-in +// data. we can do this by calling k.OptIn(ctx, sdk.AccAddress, ctx.ChainID()) + +// this will then allow us to call +// k.UpdateOptedInAssetsState(ctx, staker, assetID, operator, stakedValue) +// for now, we keep this data in the genesis as the order stored, but +// it would be trivial to alter the order if deemed necessary. +// this relies in GetSpecifiedAssetsPrice, GetStakingAssetInfo, GetAvsSupportedAssets +// the first and third need to be set up and done before this genesis. +// the second is already set up before this genesis. + +// StakerRecord is a helper structure for the genesis state. Each record +// contains a staker address and a list of asset IDs with their operator + +// amount combination. +message StakerRecord { + // staker_id denotes the address + l0id of the staker. + string staker_id = 1 [(gogoproto.customname) = "StakerID"]; + // staker_details is a list of asset ID + operator + amount combination. + repeated StakerDetails staker_details = 2 [(gogoproto.nullable) = false]; +} + +// StakerDetails is a helper structure for the genesis state. Each record +// contains an asset ID and a list of operator + amount combination. +message StakerDetails { + // asset_id is the unique identifier of the asset. + string asset_id = 1 [(gogoproto.customname) = "AssetID"]; + // details is a list of operator + amount combination. + repeated AssetDetails details = 2 [(gogoproto.nullable) = false]; +} + +// AssetDetails is a helper structure for the genesis state. Each record +// contains an operator and an amount. +message AssetDetails { + // operator_address is the address of the operator as the bech32 + // version of sdk.AccAddress. + string operator_address = 1; + // amount is the amount of the asset staked by the staker for this + // asset and operator. + string amount = 2 [ + (cosmos_proto.scalar) = "cosmos.Int", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; +} \ No newline at end of file diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index 06456795b..75f44a0a5 100755 --- a/scripts/protocgen.sh +++ b/scripts/protocgen.sh @@ -11,13 +11,13 @@ proto_dirs=$(find ./proto -path -prune -o -name '*.proto' -print0 | xargs -0 -n1 #proto_dirs="proto/exocore/reward/v1beta1" #echo $proto_dirs for dir in $proto_dirs; do - proto_files=$(find "${dir}" -maxdepth 3 -name '*.proto') - for file in $proto_files; do - # Check if the go_package in the file is pointing to evmos - if grep -q "option go_package.*exocore" "$file"; then - buf generate --template proto/buf.gen.gogo.yaml "$file" - fi - done + proto_files=$(find "${dir}" -maxdepth 3 -name '*.proto') + for file in $proto_files; do + # Check if the go_package in the file is pointing to evmos + if grep -q "option go_package.*exocore" "$file"; then + buf generate --template proto/buf.gen.gogo.yaml "$file" + fi + done done # move proto files to the right places diff --git a/testutil/staking-rewards.go b/testutil/staking-rewards.go deleted file mode 100644 index ac6cabefa..000000000 --- a/testutil/staking-rewards.go +++ /dev/null @@ -1,148 +0,0 @@ -package testutil - -import ( - "fmt" - "testing" - - sdkmath "cosmossdk.io/math" - "github.com/ExocoreNetwork/exocore/app" - testutiltx "github.com/ExocoreNetwork/exocore/testutil/tx" - "github.com/ExocoreNetwork/exocore/utils" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - sdk "github.com/cosmos/cosmos-sdk/types" - distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" - distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - "github.com/cosmos/cosmos-sdk/x/staking" - stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" - teststaking "github.com/cosmos/cosmos-sdk/x/staking/testutil" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/stretchr/testify/require" -) - -// CreateValidator creates a validator with the provided public key and stake amount -func CreateValidator(ctx sdk.Context, t *testing.T, pubKey cryptotypes.PubKey, sk stakingkeeper.Keeper, stakeAmt sdkmath.Int) { - zeroDec := sdk.ZeroDec() - stakingParams := sk.GetParams(ctx) - stakingParams.BondDenom = sk.BondDenom(ctx) - stakingParams.MinCommissionRate = zeroDec - err := sk.SetParams(ctx, stakingParams) - require.NoError(t, err) - - stakingHelper := teststaking.NewHelper(t, ctx, &sk) - stakingHelper.Commission = stakingtypes.NewCommissionRates(zeroDec, zeroDec, zeroDec) - stakingHelper.Denom = sk.BondDenom(ctx) - - valAddr := sdk.ValAddress(pubKey.Address()) - stakingHelper.CreateValidator(valAddr, pubKey, stakeAmt, true) -} - -// PrepareAccountsForDelegationRewards prepares the test suite for testing to withdraw delegation rewards. -// -// Balance is the amount of tokens that will be left in the account after the setup is done. -// For each defined reward, a validator is created and tokens are allocated to it using the distribution keeper, -// such that the given amount of tokens is outstanding as a staking reward for the account. -// -// The setup is done in the following way: -// - Fund the account with the given Address with the given balance. -// - If the given balance is zero, the account will be created with zero balance. -// -// For every reward defined in the rewards argument, the following steps are executed: -// - Set up a validator with zero commission and delegate to it -> the account delegation will be 50% of the total delegation. -// - Allocate rewards to the validator. -// -// The function returns the updated context along with a potential error. -func PrepareAccountsForDelegationRewards(t *testing.T, ctx sdk.Context, app *app.ExocoreApp, addr sdk.AccAddress, balance sdkmath.Int, rewards ...sdkmath.Int) (sdk.Context, error) { - // Calculate the necessary amount of tokens to fund the account in order for the desired residual balance to - // be left after creating Validators and delegating to them. - totalRewards := sdk.ZeroInt() - for _, reward := range rewards { - totalRewards = totalRewards.Add(reward) - } - totalNeededBalance := balance.Add(totalRewards) - - if totalNeededBalance.IsZero() { - app.AccountKeeper.SetAccount(ctx, app.AccountKeeper.NewAccountWithAddress(ctx, addr)) - } else { - // Fund account with enough tokens to stake them - err := FundAccountWithBaseDenom(ctx, app.BankKeeper, addr, totalNeededBalance.Int64()) - if err != nil { - return sdk.Context{}, fmt.Errorf("failed to fund account: %s", err.Error()) - } - } - - if totalRewards.IsZero() { - return ctx, nil - } - - // reset historical count in distribution keeper which is necessary - // for the delegation rewards to be calculated correctly - app.DistrKeeper.DeleteAllValidatorHistoricalRewards(ctx) - - // set distribution module account balance which pays out the rewards - distrAcc := app.DistrKeeper.GetDistributionAccount(ctx) - err := FundModuleAccount(ctx, app.BankKeeper, distrAcc.GetName(), sdk.NewCoins(sdk.NewCoin(utils.BaseDenom, totalRewards))) - if err != nil { - return sdk.Context{}, fmt.Errorf("failed to fund distribution module account: %s", err.Error()) - } - app.AccountKeeper.SetModuleAccount(ctx, distrAcc) - - for _, reward := range rewards { - if reward.IsZero() { - continue - } - - // Set up validator and delegate to it - privKey := ed25519.GenPrivKey() - addr2, _ := testutiltx.NewAccAddressAndKey() - err := FundAccountWithBaseDenom(ctx, app.BankKeeper, addr2, reward.Int64()) - if err != nil { - return sdk.Context{}, fmt.Errorf("failed to fund validator account: %s", err.Error()) - } - - zeroDec := sdk.ZeroDec() - stakingParams := app.StakingKeeper.GetParams(ctx) - stakingParams.BondDenom = utils.BaseDenom - stakingParams.MinCommissionRate = zeroDec - err = app.StakingKeeper.SetParams(ctx, stakingParams) - require.NoError(t, err) - - stakingHelper := teststaking.NewHelper(t, ctx, &app.StakingKeeper) - stakingHelper.Commission = stakingtypes.NewCommissionRates(zeroDec, zeroDec, zeroDec) - stakingHelper.Denom = utils.BaseDenom - - valAddr := sdk.ValAddress(addr2.Bytes()) - // self-delegate the same amount of tokens as the delegate Address also stakes - // this ensures, that the delegation rewards are 50% of the total rewards - stakingHelper.CreateValidator(valAddr, privKey.PubKey(), reward, true) - stakingHelper.Delegate(addr, valAddr, reward) - - // end block to bond validator and increase block height - // Not using Commit() here because code panics due to invalid block height - staking.EndBlocker(ctx, &app.StakingKeeper) - - // allocate rewards to validator (of these 50% will be paid out to the delegator) - validator := app.StakingKeeper.Validator(ctx, valAddr) - allocatedRewards := sdk.NewDecCoins(sdk.NewDecCoin(utils.BaseDenom, reward.Mul(sdk.NewInt(2)))) - app.DistrKeeper.AllocateTokensToValidator(ctx, validator, allocatedRewards) - } - - return ctx, nil -} - -// GetTotalDelegationRewards returns the total delegation rewards that are currently -// outstanding for the given Address. -func GetTotalDelegationRewards(ctx sdk.Context, distributionKeeper distributionkeeper.Keeper, addr sdk.AccAddress) (sdk.DecCoins, error) { - querier := distributionkeeper.NewQuerier(distributionKeeper) - resp, err := querier.DelegationTotalRewards( - ctx, - &distributiontypes.QueryDelegationTotalRewardsRequest{ - DelegatorAddress: addr.String(), - }, - ) - if err != nil { - return nil, err - } - - return resp.Total, nil -} diff --git a/testutil/utils.go b/testutil/utils.go index 02ab7135e..1a3874c52 100644 --- a/testutil/utils.go +++ b/testutil/utils.go @@ -4,6 +4,7 @@ import ( "encoding/json" "time" + "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/crypto/keyring" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -16,6 +17,7 @@ import ( exocoreapp "github.com/ExocoreNetwork/exocore/app" "github.com/ExocoreNetwork/exocore/utils" + assetstypes "github.com/ExocoreNetwork/exocore/x/assets/types" abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/crypto/tmhash" tmtypes "github.com/cometbft/cometbft/types" @@ -82,6 +84,39 @@ func (suite *BaseTestSuite) SetupWithGenesisValSet(valSet *tmtypes.ValidatorSet, authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis) + // set genesis staking assets + ethClientChain := assetstypes.ClientChainInfo{ + Name: "ethereum", + MetaInfo: "ethereum blockchain", + ChainId: 1, + FinalizationBlocks: 10, + LayerZeroChainID: 101, + AddressLength: 20, + } + usdtClientChainAsset := assetstypes.AssetInfo{ + Name: "Tether USD", + Symbol: "USDT", + Address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", + Decimals: 6, + LayerZeroChainID: ethClientChain.LayerZeroChainID, + MetaInfo: "Tether USD token", + } + { + totalSupply, _ := sdk.NewIntFromString("40022689732746729") + usdtClientChainAsset.TotalSupply = totalSupply + } + stakingInfo := assetstypes.StakingAssetInfo{ + AssetBasicInfo: &usdtClientChainAsset, + StakingTotalAmount: math.NewInt(0), + } + assetsGenesis := assetstypes.NewGenesis( + assetstypes.DefaultParams(), + []assetstypes.ClientChainInfo{ethClientChain}, + []assetstypes.StakingAssetInfo{stakingInfo}, + []assetstypes.DepositsByStaker{}, + ) + genesisState[assetstypes.ModuleName] = app.AppCodec().MustMarshalJSON(assetsGenesis) + validators := make([]stakingtypes.Validator, 0, len(valSet.Validators)) delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators)) diff --git a/x/assets/genesis.go b/x/assets/genesis.go deleted file mode 100644 index fead080fe..000000000 --- a/x/assets/genesis.go +++ /dev/null @@ -1,112 +0,0 @@ -package assets - -import ( - "encoding/json" - - assetstype "github.com/ExocoreNetwork/exocore/x/assets/types" - - "cosmossdk.io/math" - "github.com/ExocoreNetwork/exocore/x/assets/keeper" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// NewGenesisState - Create a new genesis state -func NewGenesisState(chain []*assetstype.ClientChainInfo, token []*assetstype.AssetInfo) *assetstype.GenesisState { - return &assetstype.GenesisState{ - DefaultSupportedClientChains: chain, - DefaultSupportedClientChainTokens: token, - } -} - -// DefaultGenesisState - Return a default genesis state -func DefaultGenesisState() *assetstype.GenesisState { - // todo: set eth as client chain and usdt as asset in the genesis state - ethClientChain := &assetstype.ClientChainInfo{ - Name: "ethereum", - MetaInfo: "ethereum blockchain", - ChainId: 1, - FinalizationBlocks: 10, - LayerZeroChainID: 101, - AddressLength: 20, - } - usdtClientChainAsset := &assetstype.AssetInfo{ - Name: "Tether USD", - Symbol: "USDT", - Address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", - Decimals: 6, - LayerZeroChainID: ethClientChain.LayerZeroChainID, - MetaInfo: "Tether USD token", - } - totalSupply, _ := sdk.NewIntFromString("40022689732746729") - usdtClientChainAsset.TotalSupply = totalSupply - return NewGenesisState([]*assetstype.ClientChainInfo{ethClientChain}, []*assetstype.AssetInfo{usdtClientChainAsset}) -} - -// GetGenesisStateFromAppState returns x/assets GenesisState given raw application -// genesis state. -func GetGenesisStateFromAppState(cdc codec.Codec, appState map[string]json.RawMessage) assetstype.GenesisState { - var genesisState assetstype.GenesisState - - if appState[assetstype.ModuleName] != nil { - cdc.MustUnmarshalJSON(appState[assetstype.ModuleName], &genesisState) - } - - return genesisState -} - -// ValidateGenesis performs basic validation of assets genesis data returning an -// error for any failed validation criteria. -func ValidateGenesis(assetstype.GenesisState) error { - // todo: check the validation of client chain and token info - return nil -} - -// InitGenesis import module genesis -func InitGenesis( - ctx sdk.Context, - k keeper.Keeper, - data assetstype.GenesisState, -) { - // todo: might need to sort the clientChains and tokens before handling. - - c := sdk.UnwrapSDKContext(ctx) - var err error - // save default supported client chain - for _, chain := range data.DefaultSupportedClientChains { - err = k.SetClientChainInfo(c, chain) - if err != nil { - panic(err) - } - } - // save default supported client chain assets - for _, asset := range data.DefaultSupportedClientChainTokens { - err = k.SetStakingAssetInfo(c, &assetstype.StakingAssetInfo{ - AssetBasicInfo: asset, - StakingTotalAmount: math.NewInt(0), - }) - if err != nil { - panic(err) - } - } -} - -// ExportGenesis export module status -func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *assetstype.GenesisState { - clientChainList := make([]*assetstype.ClientChainInfo, 0) - c := sdk.UnwrapSDKContext(ctx) - clientChainInfo, _ := k.GetAllClientChainInfo(c) - for _, v := range clientChainInfo { - clientChainList = append(clientChainList, v) - } - - clientChainAssetsList := make([]*assetstype.AssetInfo, 0) - clientChainAssets, _ := k.GetAllStakingAssetsInfo(c) - for _, v := range clientChainAssets { - clientChainAssetsList = append(clientChainAssetsList, v.AssetBasicInfo) - } - return &assetstype.GenesisState{ - DefaultSupportedClientChains: clientChainList, - DefaultSupportedClientChainTokens: clientChainAssetsList, - } -} diff --git a/x/assets/keeper/app_chain.go b/x/assets/keeper/app_chain.go index 7a70ebd92..bba468f96 100644 --- a/x/assets/keeper/app_chain.go +++ b/x/assets/keeper/app_chain.go @@ -1,58 +1,71 @@ package keeper import ( + "strings" + assetstype "github.com/ExocoreNetwork/exocore/x/assets/types" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" ) // SetAppChainInfo stores the info for the app chain to the db. At the moment, it is called by -// the -// genesis process. In the future, it should be called by governance. +// the genesis process. In the future, it should be called by governance. func (k Keeper) SetAppChainInfo( ctx sdk.Context, - info assetstype.AppChainInfo, + info *assetstype.AppChainInfo, ) { store := prefix.NewStore(ctx.KVStore(k.storeKey), assetstype.KeyPrefixAppChainInfo) - bz := k.cdc.MustMarshal(&info) - store.Set([]byte(info.ChainId), bz) + bz := k.cdc.MustMarshal(info) + store.Set([]byte(info.ChainID), bz) } -// AppChainInfoIsExist returns whether the app chain info for the specified chainId exists +// AppChainInfoIsExist returns whether the app chain info for the specified chainID exists func (k Keeper) AppChainInfoIsExist(ctx sdk.Context, chainID string) bool { + // short circuit if information is for the current chain + if strings.Compare(chainID, ctx.ChainID()) == 0 { + return true + } store := prefix.NewStore(ctx.KVStore(k.storeKey), assetstype.KeyPrefixAppChainInfo) return store.Has([]byte(chainID)) } -// GetAppChainInfoByChainID gets the app chain info for the specified chainId, if it exists +// GetAppChainInfoByChainID gets the app chain info for the specified chainID, if it exists func (k Keeper) GetAppChainInfoByChainID( ctx sdk.Context, chainID string, -) (info assetstype.AppChainInfo, err error) { +) (info *assetstype.AppChainInfo, err error) { + // short circuit if information is for the current chain + if strings.Compare(chainID, ctx.ChainID()) == 0 { + return &assetstype.AppChainInfo{ + ChainID: ctx.ChainID(), + }, nil + } store := prefix.NewStore(ctx.KVStore(k.storeKey), assetstype.KeyPrefixAppChainInfo) - ifExist := store.Has([]byte(chainID)) - if !ifExist { - return assetstype.AppChainInfo{}, assetstype.ErrUnknownAppChainID + if !store.Has([]byte(chainID)) { + return nil, assetstype.ErrUnknownAppChainID } value := store.Get([]byte(chainID)) - ret := assetstype.AppChainInfo{} - k.cdc.MustUnmarshal(value, &ret) + ret := &assetstype.AppChainInfo{} + k.cdc.MustUnmarshal(value, ret) return ret, nil } -// GetAllAppChainInfo gets all the app chain info, indexed by chainId +// GetAllAppChainInfo gets all the app chain info, indexed by chainID func (k Keeper) GetAllAppChainInfo( ctx sdk.Context, -) (infos map[string]assetstype.AppChainInfo) { +) (infos map[string]*assetstype.AppChainInfo) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, assetstype.KeyPrefixAppChainInfo) defer iterator.Close() - ret := make(map[string]assetstype.AppChainInfo, 0) + ret := make(map[string]*assetstype.AppChainInfo, 0) for ; iterator.Valid(); iterator.Next() { - var chainInfo assetstype.AppChainInfo - k.cdc.MustUnmarshal(iterator.Value(), &chainInfo) - ret[chainInfo.ChainId] = chainInfo + chainInfo := &assetstype.AppChainInfo{} + k.cdc.MustUnmarshal(iterator.Value(), chainInfo) + ret[chainInfo.ChainID] = chainInfo + } + ret[ctx.ChainID()] = &assetstype.AppChainInfo{ + ChainID: ctx.ChainID(), } return ret } diff --git a/x/assets/keeper/client_chain_and_asset_test.go b/x/assets/keeper/client_chain_and_asset_test.go index 9feb73a1b..14789fe89 100644 --- a/x/assets/keeper/client_chain_and_asset_test.go +++ b/x/assets/keeper/client_chain_and_asset_test.go @@ -1,21 +1,49 @@ package keeper_test import ( - "github.com/ExocoreNetwork/exocore/x/assets" + "cosmossdk.io/math" assetstype "github.com/ExocoreNetwork/exocore/x/assets/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) func (suite *StakingAssetsTestSuite) TestGenesisClientChainAndAssetInfo() { - defaultGensisState := assets.DefaultGenesisState() + ethClientChain := assetstype.ClientChainInfo{ + Name: "ethereum", + MetaInfo: "ethereum blockchain", + ChainId: 1, + FinalizationBlocks: 10, + LayerZeroChainID: 101, + AddressLength: 20, + } + usdtClientChainAsset := assetstype.AssetInfo{ + Name: "Tether USD", + Symbol: "USDT", + Address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", + Decimals: 6, + LayerZeroChainID: ethClientChain.LayerZeroChainID, + MetaInfo: "Tether USD token", + } + totalSupply, _ := sdk.NewIntFromString("40022689732746729") + usdtClientChainAsset.TotalSupply = totalSupply + stakingInfo := assetstype.StakingAssetInfo{ + AssetBasicInfo: &usdtClientChainAsset, + StakingTotalAmount: math.NewInt(0), + } + defaultGensisState := assetstype.NewGenesis( + assetstype.DefaultParams(), + []assetstype.ClientChainInfo{ethClientChain}, + []assetstype.StakingAssetInfo{stakingInfo}, + []assetstype.DepositsByStaker{}, + ) // test the client chains getting clientChains, err := suite.App.AssetsKeeper.GetAllClientChainInfo(suite.Ctx) suite.NoError(err) suite.Ctx.Logger().Info("the clientChains is:", "info", clientChains) - for _, clientChain := range defaultGensisState.DefaultSupportedClientChains { + for _, clientChain := range defaultGensisState.ClientChains { info, ok := clientChains[clientChain.LayerZeroChainID] suite.True(ok) - suite.Equal(info, clientChain) + suite.Equal(info, &clientChain) } chainInfo, err := suite.App.AssetsKeeper.GetClientChainInfoByIndex(suite.Ctx, 101) @@ -25,7 +53,8 @@ func (suite *StakingAssetsTestSuite) TestGenesisClientChainAndAssetInfo() { // test the client chain assets getting assets, err := suite.App.AssetsKeeper.GetAllStakingAssetsInfo(suite.Ctx) suite.NoError(err) - for _, asset := range defaultGensisState.DefaultSupportedClientChainTokens { + for _, assetX := range defaultGensisState.Tokens { + asset := assetX.AssetBasicInfo _, assetID := assetstype.GetStakeIDAndAssetIDFromStr(asset.LayerZeroChainID, "", asset.Address) suite.Ctx.Logger().Info("the asset id is:", "assetID", assetID) info, ok := assets[assetID] @@ -33,7 +62,8 @@ func (suite *StakingAssetsTestSuite) TestGenesisClientChainAndAssetInfo() { suite.Equal(asset, info.AssetBasicInfo) } - usdtAsset := defaultGensisState.DefaultSupportedClientChainTokens[0] + usdtAssetX := defaultGensisState.Tokens[0] + usdtAsset := usdtAssetX.AssetBasicInfo _, assetID := assetstype.GetStakeIDAndAssetIDFromStr(usdtAsset.LayerZeroChainID, "", usdtAsset.Address) assetInfo, err := suite.App.AssetsKeeper.GetStakingAssetInfo(suite.Ctx, assetID) suite.NoError(err) diff --git a/x/assets/keeper/genesis.go b/x/assets/keeper/genesis.go new file mode 100644 index 000000000..2ba95d226 --- /dev/null +++ b/x/assets/keeper/genesis.go @@ -0,0 +1,60 @@ +package keeper + +import ( + "github.com/ExocoreNetwork/exocore/x/assets/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// InitGenesis initializes the module's state from a provided genesis state. +func (k Keeper) InitGenesis(ctx sdk.Context, data *types.GenesisState) { + if err := k.SetParams(ctx, &data.Params); err != nil { + panic(err) + } + // TODO(mm): is it possible to optimize / speed up this process? + // client_chain.go + for i := range data.ClientChains { + info := data.ClientChains[i] + if err := k.SetClientChainInfo(ctx, &info); err != nil { + panic(err) + } + } + // client_chain_asset.go + for i := range data.Tokens { + info := data.Tokens[i] + if err := k.SetStakingAssetInfo(ctx, &info); err != nil { + panic(err) + } + } + // staker_asset.go (deposits) + // we simulate the behavior of the depositKeeper.Deposit call + // it constructs the stakerID and the assetID, which we have validated previously. + // it checks that the deposited amount is not negative, which we have already done. + // and that the asset is registered, which we have also already done. + for _, deposit := range data.Deposits { + stakerID := deposit.StakerID + for _, depositsByStaker := range deposit.Deposits { + assetID := depositsByStaker.AssetID + info := depositsByStaker.Info + infoAsChange := types.StakerSingleAssetChangeInfo(info) + // set the deposited and free values for the staker + if err := k.UpdateStakerAssetState( + ctx, stakerID, assetID, infoAsChange, + ); err != nil { + panic(err) + } + // now for the asset, increase the deposit value + if err := k.UpdateStakingAssetTotalAmount( + ctx, assetID, info.TotalDepositAmount, + ); err != nil { + panic(err) + } + } + } +} + +// ExportGenesis returns the module's exported genesis. +func (Keeper) ExportGenesis(sdk.Context) *types.GenesisState { + res := types.GenesisState{} + // TODO + return &res +} diff --git a/x/assets/module.go b/x/assets/module.go index c5b7128ab..7970f4b59 100644 --- a/x/assets/module.go +++ b/x/assets/module.go @@ -40,24 +40,35 @@ func (b AppModuleBasic) RegisterLegacyAminoCodec(amino *codec.LegacyAmino) { // DefaultGenesis returns default genesis state as raw bytes for the auth // module. func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { - return cdc.MustMarshalJSON(DefaultGenesisState()) + return cdc.MustMarshalJSON(assetstype.DefaultGenesis()) } // ValidateGenesis performs genesis state validation for the auth module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis( + cdc codec.JSONCodec, + _ client.TxEncodingConfig, + bz json.RawMessage, +) error { var data assetstype.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { - return fmt.Errorf("failed to unmarshal %s genesis state: %w", assetstype.ModuleName, err) + return fmt.Errorf( + "failed to unmarshal %s genesis state: %w", + assetstype.ModuleName, + err, + ) } - return ValidateGenesis(data) + return data.Validate() } func (b AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { assetstype.RegisterInterfaces(registry) } -func (b AppModuleBasic) RegisterGRPCGatewayRoutes(c client.Context, serveMux *runtime.ServeMux) { +func (b AppModuleBasic) RegisterGRPCGatewayRoutes( + c client.Context, + serveMux *runtime.ServeMux, +) { if err := assetstype.RegisterQueryHandlerClient(context.Background(), serveMux, assetstype.NewQueryClient(c)); err != nil { panic(err) } @@ -95,27 +106,30 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { assetstype.RegisterQueryServer(cfg.QueryServer(), am.keeper) } -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis( + ctx sdk.Context, + cdc codec.JSONCodec, + data json.RawMessage, +) []abci.ValidatorUpdate { var genesisState assetstype.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) - InitGenesis(ctx, am.keeper, genesisState) + am.keeper.InitGenesis(ctx, &genesisState) return []abci.ValidatorUpdate{} } func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { - gs := ExportGenesis(ctx, am.keeper) + gs := am.keeper.ExportGenesis(ctx) return cdc.MustMarshalJSON(gs) } -// GenerateGenesisState creates a randomized GenState of the inflation module. -func (am AppModule) GenerateGenesisState(_ *module.SimulationState) { -} +// GenerateGenesisState creates a randomized GenState of the module. +func (am AppModule) GenerateGenesisState(_ *module.SimulationState) {} -// RegisterStoreDecoder registers a decoder for inflation module's types. +// RegisterStoreDecoder registers a decoder for module's types. func (am AppModule) RegisterStoreDecoder(_ sdk.StoreDecoderRegistry) { } -// WeightedOperations doesn't return any inflation module operation. +// WeightedOperations doesn't return any module operation. func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { return []simtypes.WeightedOperation{} } diff --git a/x/assets/types/errors.go b/x/assets/types/errors.go index 16929dec5..bc3592d69 100644 --- a/x/assets/types/errors.go +++ b/x/assets/types/errors.go @@ -6,30 +6,78 @@ import ( // errors var ( - ErrNoClientChainKey = errorsmod.Register(ModuleName, 0, "there is no stored key for the input chain index") - ErrNoClientChainAssetKey = errorsmod.Register(ModuleName, 1, "there is no stored key for the input assetID") + ErrNoClientChainKey = errorsmod.Register( + ModuleName, 0, + "there is no stored key for the input chain index", + ) + ErrNoClientChainAssetKey = errorsmod.Register( + ModuleName, 1, + "there is no stored key for the input assetID", + ) - ErrNoStakerAssetKey = errorsmod.Register(ModuleName, 2, "there is no stored key for the input staker and assetID") + ErrNoStakerAssetKey = errorsmod.Register( + ModuleName, 2, + "there is no stored key for the input staker and assetID", + ) - ErrSubAmountIsMoreThanOrigin = errorsmod.Register(ModuleName, 3, "the amount that want to decrease is more than the original state amount") + ErrSubAmountIsMoreThanOrigin = errorsmod.Register( + ModuleName, 3, + "the amount that want to decrease is more than the original state amount", + ) - ErrNoOperatorAssetKey = errorsmod.Register(ModuleName, 4, "there is no stored key for the input operator address and assetID") + ErrNoOperatorAssetKey = errorsmod.Register( + ModuleName, 4, + "there is no stored key for the input operator address and assetID", + ) - ErrParseAssetsStateKey = errorsmod.Register(ModuleName, 5, "assets state key can't be parsed") + ErrParseAssetsStateKey = errorsmod.Register( + ModuleName, 5, + "assets state key can't be parsed", + ) - ErrInvalidCliCmdArg = errorsmod.Register(ModuleName, 6, "the input client command arguments are invalid") + ErrInvalidCliCmdArg = errorsmod.Register( + ModuleName, 6, + "the input client command arguments are invalid", + ) - ErrInputPointerIsNil = errorsmod.Register(ModuleName, 7, "the input pointer is nil") + ErrInputPointerIsNil = errorsmod.Register( + ModuleName, 7, + "the input pointer is nil", + ) - ErrInvalidOperatorAddr = errorsmod.Register(ModuleName, 8, "the operator address isn't a valid account address") + ErrInvalidOperatorAddr = errorsmod.Register( + ModuleName, + 8, + "the operator address isn't a valid account address", + ) - ErrUnknownAppChainID = errorsmod.Register(ModuleName, 9, "the app chain id is unknown or invalid") + ErrUnknownAppChainID = errorsmod.Register( + ModuleName, 9, + "the app chain id is unknown or invalid", + ) - ErrInvalidEvmAddressFormat = errorsmod.Register(ModuleName, 10, "the evm address format is error") + ErrInvalidEvmAddressFormat = errorsmod.Register( + ModuleName, 10, + "the evm address format is error", + ) - ErrInvalidLzUaTopicIDLength = errorsmod.Register(ModuleName, 11, "the LZUaTopicID length isn't equal to HashLength") + ErrInvalidLzUaTopicIDLength = errorsmod.Register( + ModuleName, 11, + "the LZUaTopicID length isn't equal to HashLength", + ) - ErrNoParamsKey = errorsmod.Register(ModuleName, 12, "there is no stored key for deposit module params") + ErrNoParamsKey = errorsmod.Register( + ModuleName, 12, + "there is no stored key for deposit module params", + ) - ErrNotEqualToLzAppAddr = errorsmod.Register(ModuleName, 13, "the address isn't equal to the layerZero gateway address") + ErrNotEqualToLzAppAddr = errorsmod.Register( + ModuleName, 13, + "the address isn't equal to the layerZero gateway address", + ) + + ErrInvalidGenesisData = errorsmod.Register( + ModuleName, 14, + "the genesis data supplied is invalid", + ) ) diff --git a/x/assets/types/general.go b/x/assets/types/general.go index 7e93ceb81..831eb42ac 100644 --- a/x/assets/types/general.go +++ b/x/assets/types/general.go @@ -43,14 +43,21 @@ type CrossChainOpType uint8 type WithdrawerAddress [32]byte -// StakerSingleAssetChangeInfo This is a struct to describe the desired change that matches with the StakerAssetInfo +// StakerSingleAssetChangeInfo This is a struct to describe the desired change that matches with +// the StakerAssetInfo type StakerSingleAssetChangeInfo StakerAssetInfo -// OperatorSingleAssetChangeInfo This is a struct to describe the desired change that matches with the OperatorAssetInfo +// OperatorSingleAssetChangeInfo This is a struct to describe the desired change that matches +// with the OperatorAssetInfo type OperatorSingleAssetChangeInfo OperatorAssetInfo -// GetStakeIDAndAssetID stakerID = stakerAddress+'_'+clientChainLzID,assetID = assetAddress+'_'+clientChainLzID -func GetStakeIDAndAssetID(clientChainLzID uint64, stakerAddress []byte, assetsAddress []byte) (stakeID string, assetID string) { +// GetStakeIDAndAssetID stakerID = stakerAddress+'_'+clientChainLzID,assetID = +// assetAddress+'_'+clientChainLzID +func GetStakeIDAndAssetID( + clientChainLzID uint64, + stakerAddress []byte, + assetsAddress []byte, +) (stakeID string, assetID string) { clientChainLzIDStr := hexutil.EncodeUint64(clientChainLzID) if stakerAddress != nil { stakeID = strings.Join([]string{hexutil.Encode(stakerAddress), clientChainLzIDStr}, "_") @@ -62,30 +69,53 @@ func GetStakeIDAndAssetID(clientChainLzID uint64, stakerAddress []byte, assetsAd return } -// GetStakeIDAndAssetIDFromStr stakerID = stakerAddress+'_'+clientChainLzID,assetID = assetAddress+'_'+clientChainLzID -func GetStakeIDAndAssetIDFromStr(clientChainLzID uint64, stakerAddress string, assetsAddress string) (stakeID string, assetID string) { +// GetStakeIDAndAssetIDFromStr stakerID = stakerAddress+'_'+clientChainLzID,assetID = +// assetAddress+'_'+clientChainLzID +func GetStakeIDAndAssetIDFromStr( + clientChainLzID uint64, + stakerAddress string, + assetsAddress string, +) (stakeID string, assetID string) { + // hexutil always returns lowercase values clientChainLzIDStr := hexutil.EncodeUint64(clientChainLzID) if stakerAddress != "" { - stakeID = strings.Join([]string{strings.ToLower(stakerAddress), clientChainLzIDStr}, "_") + stakeID = strings.Join( + []string{strings.ToLower(stakerAddress), clientChainLzIDStr}, + "_", + ) } if assetsAddress != "" { - assetID = strings.Join([]string{strings.ToLower(assetsAddress), clientChainLzIDStr}, "_") + assetID = strings.Join( + []string{strings.ToLower(assetsAddress), clientChainLzIDStr}, + "_", + ) } return } -// UpdateAssetValue It's used to update asset state,negative or positive `changeValue` represents a decrease or increase in the asset state +// UpdateAssetValue It's used to update asset state,negative or positive `changeValue` +// represents a decrease or increase in the asset state // newValue = valueToUpdate + changeVale func UpdateAssetValue(valueToUpdate *math.Int, changeValue *math.Int) error { if valueToUpdate == nil || changeValue == nil { - return errorsmod.Wrap(ErrInputPointerIsNil, fmt.Sprintf("valueToUpdate:%v,changeValue:%v", valueToUpdate, changeValue)) + return errorsmod.Wrap( + ErrInputPointerIsNil, + fmt.Sprintf("valueToUpdate:%v,changeValue:%v", valueToUpdate, changeValue), + ) } if !changeValue.IsNil() { if changeValue.IsNegative() { if valueToUpdate.LT(changeValue.Neg()) { - return errorsmod.Wrap(ErrSubAmountIsMoreThanOrigin, fmt.Sprintf("valueToUpdate:%s,changeValue:%s", *valueToUpdate, *changeValue)) + return errorsmod.Wrap( + ErrSubAmountIsMoreThanOrigin, + fmt.Sprintf( + "valueToUpdate:%s,changeValue:%s", + *valueToUpdate, + *changeValue, + ), + ) } } if !changeValue.IsZero() { @@ -95,17 +125,28 @@ func UpdateAssetValue(valueToUpdate *math.Int, changeValue *math.Int) error { return nil } -// UpdateAssetDecValue It's used to update asset state,negative or positive `changeValue` represents a decrease or increase in the asset state +// UpdateAssetDecValue It's used to update asset state,negative or positive `changeValue` +// represents a decrease or increase in the asset state // newValue = valueToUpdate + changeVale func UpdateAssetDecValue(valueToUpdate *math.LegacyDec, changeValue *math.LegacyDec) error { if valueToUpdate == nil || changeValue == nil { - return errorsmod.Wrap(ErrInputPointerIsNil, fmt.Sprintf("valueToUpdate:%v,changeValue:%v", valueToUpdate, changeValue)) + return errorsmod.Wrap( + ErrInputPointerIsNil, + fmt.Sprintf("valueToUpdate:%v,changeValue:%v", valueToUpdate, changeValue), + ) } if !changeValue.IsNil() { if changeValue.IsNegative() { if valueToUpdate.LT(changeValue.Neg()) { - return errorsmod.Wrap(ErrSubAmountIsMoreThanOrigin, fmt.Sprintf("valueToUpdate:%s,changeValue:%s", *valueToUpdate, *changeValue)) + return errorsmod.Wrap( + ErrSubAmountIsMoreThanOrigin, + fmt.Sprintf( + "valueToUpdate:%s,changeValue:%s", + *valueToUpdate, + *changeValue, + ), + ) } } if !changeValue.IsZero() { @@ -117,12 +158,18 @@ func UpdateAssetDecValue(valueToUpdate *math.LegacyDec, changeValue *math.Legacy func ContextForHistoricalState(ctx sdk.Context, height int64) (sdk.Context, error) { if height < 0 { - return sdk.Context{}, errorsmod.Wrap(sdkerrors.ErrInvalidHeight, fmt.Sprintf("height:%v", height)) + return sdk.Context{}, errorsmod.Wrap( + sdkerrors.ErrInvalidHeight, + fmt.Sprintf("height:%v", height), + ) } cms := ctx.MultiStore() lastBlockHeight := cms.LatestVersion() if lastBlockHeight == 0 { - return sdk.Context{}, errorsmod.Wrap(sdkerrors.ErrInvalidHeight, "app is not ready; please wait for first block") + return sdk.Context{}, errorsmod.Wrap( + sdkerrors.ErrInvalidHeight, + "app is not ready; please wait for first block", + ) } if height > lastBlockHeight { return sdk.Context{}, @@ -141,7 +188,10 @@ func ContextForHistoricalState(ctx sdk.Context, height int64) (sdk.Context, erro return sdk.Context{}, errorsmod.Wrapf( sdkerrors.ErrInvalidRequest, - "failed to load state at height %d; %s (latest height: %d)", height, err, lastBlockHeight, + "failed to load state at height %d; %s (latest height: %d)", + height, + err, + lastBlockHeight, ) } diff --git a/x/assets/types/genesis.go b/x/assets/types/genesis.go new file mode 100644 index 000000000..7b675b44d --- /dev/null +++ b/x/assets/types/genesis.go @@ -0,0 +1,224 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + "cosmossdk.io/math" + "github.com/ethereum/go-ethereum/common" +) + +// NewGenesis returns a new genesis state with the given inputs. +func NewGenesis( + params Params, chains []ClientChainInfo, + tokens []StakingAssetInfo, deposits []DepositsByStaker, +) *GenesisState { + return &GenesisState{ + Params: params, + ClientChains: chains, + Tokens: tokens, + Deposits: deposits, + } +} + +// DefaultGenesis returns the default genesis state. It intentionally +// does not have any supported assets or deposits, since these must +// be supplied manually before bootstrapping the chain. The same is true +// for any unit / integration tests. +func DefaultGenesis() *GenesisState { + return NewGenesis( + DefaultParams(), []ClientChainInfo{}, []StakingAssetInfo{}, []DepositsByStaker{}, + ) +} + +// Validate performs basic genesis state validation returning an error +// upon any failure. +func (gs GenesisState) Validate() error { + // client_chain.go -> check no repeat chain + lzIDs := make(map[uint64]struct{}, len(gs.ClientChains)) + for _, info := range gs.ClientChains { + if _, ok := lzIDs[info.LayerZeroChainID]; ok { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "duplicate LayerZeroChainID: %d", + info.LayerZeroChainID, + ) + } + lzIDs[info.LayerZeroChainID] = struct{}{} + } + // client_chain_asset.go -> check presence of client chain + // for all assets and no duplicates + tokenSupplies := make(map[string]math.Int, len(gs.Tokens)) + for _, info := range gs.Tokens { + if info.AssetBasicInfo == nil { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "nil AssetBasicInfo for token %s", + info.AssetBasicInfo.MetaInfo, + ) + } + id := info.AssetBasicInfo.LayerZeroChainID + // check that the chain is registered + if _, ok := lzIDs[id]; !ok { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "unknown LayerZeroChainID for token %s: %d", + info.AssetBasicInfo.MetaInfo, id, + ) + } + address := info.AssetBasicInfo.Address + // build for 0x addresses only. + // TODO: consider removing this check for non-EVM client chains. + if !common.IsHexAddress(address) { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "not hex address for token %s: %s", + info.AssetBasicInfo.MetaInfo, address, + ) + } + // calculate the asset id. + _, assetID := GetStakeIDAndAssetIDFromStr( + info.AssetBasicInfo.LayerZeroChainID, + "", address, + ) + // ensure there are no deposits for this asset already (since they are handled in the + // genesis exec). while it is possible to remove this field entirely (and assume 0), + // i did not do so in order to make the genesis state more explicit. + if !info.StakingTotalAmount.IsZero() { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "non-zero deposit amount for asset %s", + assetID, + ) + } + // check that it is not a duplicate. + if _, ok := tokenSupplies[assetID]; ok { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "duplicate assetID: %s", + assetID, + ) + } + // validate the amount of supply + if info.AssetBasicInfo.TotalSupply.IsNil() || + !info.AssetBasicInfo.TotalSupply.IsPositive() { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "nil total supply for token %s", + info.AssetBasicInfo.MetaInfo, + ) + } + tokenSupplies[assetID] = info.AssetBasicInfo.TotalSupply + } + // staker_asset.go -> check deposits and withdrawals and that there is no unbonding. + stakers := make(map[string]struct{}, len(gs.Deposits)) + for _, depositByStaker := range gs.Deposits { + stakerID := depositByStaker.StakerID + // validate the stakerID + var stakerClientChainID uint64 + var err error + if _, stakerClientChainID, err = ValidateID(stakerID, true); err != nil { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "invalid stakerID: %s", + stakerID, + ) + } + // check that the chain is registered + if _, ok := lzIDs[stakerClientChainID]; !ok { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "unknown LayerZeroChainID for staker %s: %d", + stakerID, stakerClientChainID, + ) + } + // check that it is not a duplicate + if _, ok := stakers[stakerID]; ok { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "duplicate stakerID: %s", + stakerID, + ) + } + stakers[stakerID] = struct{}{} + // map to check for duplicate tokens for the staker. + tokensForStaker := make(map[string]struct{}, len(depositByStaker.Deposits)) + for _, deposit := range depositByStaker.Deposits { + assetID := deposit.AssetID + // check that the asset is registered + // no need to check for the validity of the assetID, since + // an invalid assetID cannot be in the tokens map. + if _, ok := tokenSupplies[assetID]; !ok { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "unknown assetID for deposit %s: %s", + stakerID, assetID, + ) + } + // #nosec G703 // if it's invalid, we will not reach here. + _, assetClientChainID, _ := ParseID(assetID) + if assetClientChainID != stakerClientChainID { + // we can reach here if there are multiple chains + // and it tries to deposit assets from one chain + // under a staker from another chain. + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "mismatched client chain IDs for staker %s and asset %s", + stakerID, assetID, + ) + } + // check that it is not a duplicate + if _, ok := tokensForStaker[assetID]; ok { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "duplicate assetID for staker %s: %s", + stakerID, assetID, + ) + } + tokensForStaker[assetID] = struct{}{} + info := deposit.Info + // check that there is no nil value provided. + if info.TotalDepositAmount.IsNil() || info.WithdrawableAmount.IsNil() || + info.WaitUnbondingAmount.IsNil() { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "nil deposit info for %s: %+v", + assetID, info, + ) + } + // at genesis (not chain restart), there is no unbonding amount. + if !info.WaitUnbondingAmount.IsZero() { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "non-zero unbonding amount for %s: %s", + assetID, info.WaitUnbondingAmount, + ) + } + // check for negative values. + if info.TotalDepositAmount.IsNegative() || info.WithdrawableAmount.IsNegative() { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "negative deposit amount for %s: %+v", + assetID, info, + ) + } + // check that the withdrawable amount and the deposited amount are equal. + // this is because this module's genesis only sets up free deposits. + // the delegation module bonds them, thereby altering the withdrawable amount. + if !info.WithdrawableAmount.Equal(info.TotalDepositAmount) { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "withdrawable amount is not equal to total deposit amount for %s: %+v", + assetID, info, + ) + } + // check that deposit amount does not exceed supply. + if info.TotalDepositAmount.GT(tokenSupplies[assetID]) { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "deposit amount exceeds max supply for %s: %+v", + assetID, info, + ) + } + } + } + return gs.Params.Validate() +} diff --git a/x/assets/types/genesis.pb.go b/x/assets/types/genesis.pb.go index ca7566cb1..b4f5a02a9 100644 --- a/x/assets/types/genesis.pb.go +++ b/x/assets/types/genesis.pb.go @@ -5,6 +5,7 @@ package types import ( fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" io "io" math "math" @@ -22,15 +23,25 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// GenesisState defines the assets module's genesis state. +// GenesisState defines the assets module's state. It needs to encompass +// all of the state that is required to start the chain from the genesis +// or in the event of a restart. At this point, it is only built with +// the former in mind. // TODO: make this state exportable for the case of chain restarts. type GenesisState struct { - // default_supported_client_chains is the list of supported client chains, - // that are supported by default. - DefaultSupportedClientChains []*ClientChainInfo `protobuf:"bytes,1,rep,name=default_supported_client_chains,json=defaultSupportedClientChains,proto3" json:"default_supported_client_chains,omitempty"` - // default_supported_client_chain_tokens is the list of supported client chain tokens, - // that are supported by default. - DefaultSupportedClientChainTokens []*AssetInfo `protobuf:"bytes,2,rep,name=default_supported_client_chain_tokens,json=defaultSupportedClientChainTokens,proto3" json:"default_supported_client_chain_tokens,omitempty"` + // params defines all the parameters of the module. + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + // client_chains is the list of supported client chains, + // that are supported at chain genesis (or restart). + ClientChains []ClientChainInfo `protobuf:"bytes,2,rep,name=client_chains,json=clientChains,proto3" json:"client_chains"` + // tokens is the list of supported client chain tokens and total staked amount + // that are supported at chain genesis (or restart). + Tokens []StakingAssetInfo `protobuf:"bytes,3,rep,name=tokens,proto3" json:"tokens"` + // deposits is the list of deposits, indexed by staker address and + // then the asset id. The struct is the `StakerAssetInfo` + // which contains deposits, withdrawable and unbonding amount. + // at genesis (not chain restart), the unbonding amount must be 0. + Deposits []DepositsByStaker `protobuf:"bytes,4,rep,name=deposits,proto3" json:"deposits"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -66,44 +77,188 @@ func (m *GenesisState) XXX_DiscardUnknown() { var xxx_messageInfo_GenesisState proto.InternalMessageInfo -func (m *GenesisState) GetDefaultSupportedClientChains() []*ClientChainInfo { +func (m *GenesisState) GetParams() Params { if m != nil { - return m.DefaultSupportedClientChains + return m.Params + } + return Params{} +} + +func (m *GenesisState) GetClientChains() []ClientChainInfo { + if m != nil { + return m.ClientChains + } + return nil +} + +func (m *GenesisState) GetTokens() []StakingAssetInfo { + if m != nil { + return m.Tokens + } + return nil +} + +func (m *GenesisState) GetDeposits() []DepositsByStaker { + if m != nil { + return m.Deposits } return nil } -func (m *GenesisState) GetDefaultSupportedClientChainTokens() []*AssetInfo { +// DepositByStaker is a helper struct to be used in the genesis state. +// It is used to store the staker address and its deposits for each asset ID. +type DepositsByStaker struct { + // staker is the address of the staker. + StakerID string `protobuf:"bytes,1,opt,name=staker,proto3" json:"staker,omitempty"` + // deposits is the list of deposits, indexed by the asset id. + // The struct is the `StakerAssetInfo` which contains deposits, + // withdrawable and unbonding amount. + Deposits []DepositByAsset `protobuf:"bytes,2,rep,name=deposits,proto3" json:"deposits"` +} + +func (m *DepositsByStaker) Reset() { *m = DepositsByStaker{} } +func (m *DepositsByStaker) String() string { return proto.CompactTextString(m) } +func (*DepositsByStaker) ProtoMessage() {} +func (*DepositsByStaker) Descriptor() ([]byte, []int) { + return fileDescriptor_caf4f124d39d82ce, []int{1} +} +func (m *DepositsByStaker) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DepositsByStaker) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DepositsByStaker.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DepositsByStaker) XXX_Merge(src proto.Message) { + xxx_messageInfo_DepositsByStaker.Merge(m, src) +} +func (m *DepositsByStaker) XXX_Size() int { + return m.Size() +} +func (m *DepositsByStaker) XXX_DiscardUnknown() { + xxx_messageInfo_DepositsByStaker.DiscardUnknown(m) +} + +var xxx_messageInfo_DepositsByStaker proto.InternalMessageInfo + +func (m *DepositsByStaker) GetStakerID() string { if m != nil { - return m.DefaultSupportedClientChainTokens + return m.StakerID + } + return "" +} + +func (m *DepositsByStaker) GetDeposits() []DepositByAsset { + if m != nil { + return m.Deposits } return nil } +// DepositByAsset is a helper struct to be used in the genesis state. +// It is used to store the asset id and its info for an staker. +// The info contains the deposit amount, the withdrawable amount +// and the amount currently unbonding. +// It is named DepositByAsset (since it is indexed by the assetID) +// and not Deposit to prevent conflict with CrossChainOpType. +type DepositByAsset struct { + // asset_id is the id of the asset. + AssetID string `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` + // info is the asset info. + Info StakerAssetInfo `protobuf:"bytes,2,opt,name=info,proto3" json:"info"` +} + +func (m *DepositByAsset) Reset() { *m = DepositByAsset{} } +func (m *DepositByAsset) String() string { return proto.CompactTextString(m) } +func (*DepositByAsset) ProtoMessage() {} +func (*DepositByAsset) Descriptor() ([]byte, []int) { + return fileDescriptor_caf4f124d39d82ce, []int{2} +} +func (m *DepositByAsset) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DepositByAsset) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DepositByAsset.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DepositByAsset) XXX_Merge(src proto.Message) { + xxx_messageInfo_DepositByAsset.Merge(m, src) +} +func (m *DepositByAsset) XXX_Size() int { + return m.Size() +} +func (m *DepositByAsset) XXX_DiscardUnknown() { + xxx_messageInfo_DepositByAsset.DiscardUnknown(m) +} + +var xxx_messageInfo_DepositByAsset proto.InternalMessageInfo + +func (m *DepositByAsset) GetAssetID() string { + if m != nil { + return m.AssetID + } + return "" +} + +func (m *DepositByAsset) GetInfo() StakerAssetInfo { + if m != nil { + return m.Info + } + return StakerAssetInfo{} +} + func init() { proto.RegisterType((*GenesisState)(nil), "exocore.assets.v1.GenesisState") + proto.RegisterType((*DepositsByStaker)(nil), "exocore.assets.v1.DepositsByStaker") + proto.RegisterType((*DepositByAsset)(nil), "exocore.assets.v1.DepositByAsset") } func init() { proto.RegisterFile("exocore/assets/v1/genesis.proto", fileDescriptor_caf4f124d39d82ce) } var fileDescriptor_caf4f124d39d82ce = []byte{ - // 256 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0xad, 0xc8, 0x4f, - 0xce, 0x2f, 0x4a, 0xd5, 0x4f, 0x2c, 0x2e, 0x4e, 0x2d, 0x29, 0xd6, 0x2f, 0x33, 0xd4, 0x4f, 0x4f, - 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x84, 0x2a, 0xd0, - 0x83, 0x28, 0xd0, 0x2b, 0x33, 0x94, 0x92, 0xc2, 0xd4, 0x53, 0x52, 0x01, 0x51, 0xae, 0xf4, 0x92, - 0x91, 0x8b, 0xc7, 0x1d, 0x62, 0x40, 0x70, 0x49, 0x62, 0x49, 0xaa, 0x50, 0x26, 0x97, 0x7c, 0x4a, - 0x6a, 0x5a, 0x62, 0x69, 0x4e, 0x49, 0x7c, 0x71, 0x69, 0x41, 0x41, 0x7e, 0x51, 0x49, 0x6a, 0x4a, - 0x7c, 0x72, 0x4e, 0x66, 0x6a, 0x5e, 0x49, 0x7c, 0x72, 0x46, 0x62, 0x66, 0x5e, 0xb1, 0x04, 0xa3, - 0x02, 0xb3, 0x06, 0xb7, 0x91, 0x92, 0x1e, 0x86, 0x4d, 0x7a, 0xce, 0x60, 0x75, 0xce, 0x20, 0x65, - 0x9e, 0x79, 0x69, 0xf9, 0x41, 0x32, 0x50, 0xa3, 0x82, 0x61, 0x26, 0x21, 0x29, 0x28, 0x16, 0xca, - 0xe3, 0x52, 0xc5, 0x6f, 0x55, 0x7c, 0x49, 0x7e, 0x76, 0x6a, 0x5e, 0xb1, 0x04, 0x13, 0xd8, 0x42, - 0x19, 0x2c, 0x16, 0x3a, 0x82, 0x58, 0x60, 0xab, 0x14, 0xf1, 0x58, 0x15, 0x02, 0x36, 0xc6, 0xc9, - 0xeb, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, - 0x8e, 0xe1, 0xc2, 0x63, 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, 0x0c, 0xd2, 0x33, 0x4b, 0x32, - 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xf5, 0x5d, 0x21, 0x96, 0xf8, 0xa5, 0x96, 0x94, 0xe7, 0x17, - 0x65, 0xeb, 0xc3, 0xc2, 0xae, 0x02, 0x16, 0x7a, 0x25, 0x95, 0x05, 0xa9, 0xc5, 0x49, 0x6c, 0xe0, - 0xe0, 0x33, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x57, 0xfb, 0x5e, 0x22, 0x90, 0x01, 0x00, 0x00, + // 407 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xb1, 0x8e, 0xda, 0x30, + 0x1c, 0xc6, 0x13, 0x40, 0x81, 0x1a, 0x5a, 0xb5, 0x56, 0x87, 0x34, 0x43, 0x42, 0xd3, 0xaa, 0x62, + 0x4a, 0x0a, 0x1d, 0xba, 0x74, 0x21, 0x80, 0x2a, 0x2a, 0xb5, 0xaa, 0x60, 0xeb, 0x82, 0x42, 0x30, + 0xc1, 0xa2, 0xc4, 0x51, 0xec, 0xe3, 0x60, 0xb8, 0x77, 0xb8, 0x47, 0xb8, 0xc7, 0x61, 0x64, 0xbc, + 0x09, 0x9d, 0xc2, 0x8b, 0x9c, 0x62, 0x9b, 0x3b, 0x8e, 0xc0, 0x66, 0xf9, 0xfb, 0xbe, 0x9f, 0xff, + 0xf9, 0xf2, 0x07, 0x16, 0x5a, 0x91, 0x80, 0x24, 0xc8, 0xf5, 0x29, 0x45, 0x8c, 0xba, 0xcb, 0xa6, + 0x1b, 0xa2, 0x08, 0x51, 0x4c, 0x9d, 0x38, 0x21, 0x8c, 0xc0, 0x77, 0xd2, 0xe0, 0x08, 0x83, 0xb3, + 0x6c, 0x1a, 0xef, 0x43, 0x12, 0x12, 0xae, 0xba, 0xd9, 0x49, 0x18, 0x0d, 0x33, 0x4f, 0x8a, 0xfd, + 0xc4, 0x5f, 0x48, 0x90, 0x61, 0xe4, 0x75, 0xb6, 0x12, 0x9a, 0x7d, 0x57, 0x00, 0xb5, 0x9f, 0xe2, + 0xd9, 0x21, 0xf3, 0x19, 0x82, 0xdf, 0x81, 0x26, 0xc2, 0xba, 0x5a, 0x57, 0x1b, 0xd5, 0xd6, 0x07, + 0x27, 0x37, 0x86, 0xf3, 0x97, 0x1b, 0xbc, 0xd2, 0x66, 0x67, 0x29, 0x03, 0x69, 0x87, 0xbf, 0xc1, + 0xeb, 0xe0, 0x3f, 0x46, 0x11, 0x1b, 0x05, 0x33, 0x1f, 0x47, 0x54, 0x2f, 0xd4, 0x8b, 0x8d, 0x6a, + 0xcb, 0x3e, 0x93, 0xef, 0x70, 0x5f, 0x27, 0xb3, 0xf5, 0xa3, 0x29, 0x91, 0xa0, 0x5a, 0xf0, 0x7c, + 0x4d, 0x61, 0x1b, 0x68, 0x8c, 0xcc, 0x51, 0x44, 0xf5, 0x22, 0xe7, 0x7c, 0x3a, 0xc3, 0x19, 0x32, + 0x7f, 0x8e, 0xa3, 0xb0, 0x9d, 0x5d, 0x1c, 0x81, 0x64, 0x10, 0xf6, 0x40, 0x65, 0x82, 0x62, 0x42, + 0x31, 0xa3, 0x7a, 0xe9, 0x22, 0xa4, 0x2b, 0x2d, 0xde, 0x3a, 0xc3, 0xa1, 0x44, 0x42, 0x9e, 0xa2, + 0xf6, 0x0d, 0x78, 0x7b, 0xea, 0x81, 0x9f, 0x81, 0x46, 0xf9, 0x89, 0xb7, 0xf4, 0xca, 0xab, 0xa5, + 0x3b, 0xab, 0x22, 0xb4, 0x7e, 0x77, 0x20, 0x35, 0xd8, 0x39, 0x1a, 0x40, 0xb4, 0xf1, 0xf1, 0xf2, + 0x00, 0xde, 0x9a, 0x7f, 0x47, 0xee, 0xf9, 0x25, 0x78, 0xf3, 0xd2, 0x01, 0xbf, 0x80, 0x0a, 0x4f, + 0x8f, 0xf0, 0x44, 0x3e, 0x5f, 0x4d, 0x77, 0x56, 0x59, 0xd4, 0xd0, 0x1d, 0x94, 0xb9, 0xd8, 0x9f, + 0xc0, 0x1f, 0xa0, 0x84, 0xa3, 0x29, 0xd1, 0x0b, 0xfc, 0x47, 0xda, 0x17, 0x0a, 0x44, 0xc9, 0x69, + 0x7f, 0x3c, 0xe5, 0xfd, 0xda, 0xa4, 0xa6, 0xba, 0x4d, 0x4d, 0xf5, 0x21, 0x35, 0xd5, 0xdb, 0xbd, + 0xa9, 0x6c, 0xf7, 0xa6, 0x72, 0xbf, 0x37, 0x95, 0x7f, 0x5f, 0x43, 0xcc, 0x66, 0x57, 0x63, 0x27, + 0x20, 0x0b, 0xb7, 0x27, 0x98, 0x7f, 0x10, 0xbb, 0x26, 0xc9, 0xdc, 0x3d, 0x6c, 0xda, 0xea, 0xb0, + 0x6b, 0x6c, 0x1d, 0x23, 0x3a, 0xd6, 0xf8, 0xb2, 0x7d, 0x7b, 0x0c, 0x00, 0x00, 0xff, 0xff, 0xf2, + 0x41, 0x0b, 0xdb, 0xf4, 0x02, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -126,10 +281,38 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.DefaultSupportedClientChainTokens) > 0 { - for iNdEx := len(m.DefaultSupportedClientChainTokens) - 1; iNdEx >= 0; iNdEx-- { + if len(m.Deposits) > 0 { + for iNdEx := len(m.Deposits) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Deposits[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.Tokens) > 0 { + for iNdEx := len(m.Tokens) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Tokens[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.ClientChains) > 0 { + for iNdEx := len(m.ClientChains) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.DefaultSupportedClientChainTokens[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.ClientChains[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -140,10 +323,43 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x12 } } - if len(m.DefaultSupportedClientChains) > 0 { - for iNdEx := len(m.DefaultSupportedClientChains) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *DepositsByStaker) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DepositsByStaker) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DepositsByStaker) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Deposits) > 0 { + for iNdEx := len(m.Deposits) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.DefaultSupportedClientChains[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.Deposits[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -151,8 +367,55 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintGenesis(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0xa + dAtA[i] = 0x12 + } + } + if len(m.StakerID) > 0 { + i -= len(m.StakerID) + copy(dAtA[i:], m.StakerID) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.StakerID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DepositByAsset) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DepositByAsset) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DepositByAsset) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Info.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.AssetID) > 0 { + i -= len(m.AssetID) + copy(dAtA[i:], m.AssetID) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.AssetID))) + i-- + dAtA[i] = 0xa } return len(dAtA) - i, nil } @@ -174,18 +437,60 @@ func (m *GenesisState) Size() (n int) { } var l int _ = l - if len(m.DefaultSupportedClientChains) > 0 { - for _, e := range m.DefaultSupportedClientChains { + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.ClientChains) > 0 { + for _, e := range m.ClientChains { l = e.Size() n += 1 + l + sovGenesis(uint64(l)) } } - if len(m.DefaultSupportedClientChainTokens) > 0 { - for _, e := range m.DefaultSupportedClientChainTokens { + if len(m.Tokens) > 0 { + for _, e := range m.Tokens { l = e.Size() n += 1 + l + sovGenesis(uint64(l)) } } + if len(m.Deposits) > 0 { + for _, e := range m.Deposits { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *DepositsByStaker) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.StakerID) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if len(m.Deposits) > 0 { + for _, e := range m.Deposits { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *DepositByAsset) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.AssetID) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = m.Info.Size() + n += 1 + l + sovGenesis(uint64(l)) return n } @@ -226,7 +531,40 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DefaultSupportedClientChains", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ClientChains", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -253,14 +591,280 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.DefaultSupportedClientChains = append(m.DefaultSupportedClientChains, &ClientChainInfo{}) - if err := m.DefaultSupportedClientChains[len(m.DefaultSupportedClientChains)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.ClientChains = append(m.ClientChains, ClientChainInfo{}) + if err := m.ClientChains[len(m.ClientChains)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tokens", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tokens = append(m.Tokens, StakingAssetInfo{}) + if err := m.Tokens[len(m.Tokens)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Deposits", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Deposits = append(m.Deposits, DepositsByStaker{}) + if err := m.Deposits[len(m.Deposits)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DepositsByStaker) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DepositsByStaker: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DepositsByStaker: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StakerID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StakerID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Deposits", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Deposits = append(m.Deposits, DepositByAsset{}) + if err := m.Deposits[len(m.Deposits)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DepositByAsset) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DepositByAsset: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DepositByAsset: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AssetID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AssetID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DefaultSupportedClientChainTokens", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -287,8 +891,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.DefaultSupportedClientChainTokens = append(m.DefaultSupportedClientChainTokens, &AssetInfo{}) - if err := m.DefaultSupportedClientChainTokens[len(m.DefaultSupportedClientChainTokens)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Info.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/assets/types/genesis_test.go b/x/assets/types/genesis_test.go new file mode 100644 index 000000000..12ab18cfa --- /dev/null +++ b/x/assets/types/genesis_test.go @@ -0,0 +1,538 @@ +package types_test + +import ( + "strings" + "testing" + + "cosmossdk.io/math" + utiltx "github.com/ExocoreNetwork/exocore/testutil/tx" + "github.com/ExocoreNetwork/exocore/x/assets/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/suite" +) + +type GenesisTestSuite struct { + suite.Suite +} + +func (suite *GenesisTestSuite) SetupTest() { +} + +func TestGenesisTestSuite(t *testing.T) { + suite.Run(t, new(GenesisTestSuite)) +} + +func (suite *GenesisTestSuite) TestValidateGenesis() { + params := types.DefaultParams() + params.ExocoreLzAppAddress = "0x0000000000000000000000000000000000000001" + newGen := types.NewGenesis( + params, []types.ClientChainInfo{}, + []types.StakingAssetInfo{}, []types.DepositsByStaker{}, + ) + // genesis data that is hardcoded for use in the tests + ethClientChain := types.ClientChainInfo{ + Name: "ethereum", + MetaInfo: "ethereum blockchain", + ChainId: 1, + FinalizationBlocks: 10, + LayerZeroChainID: 101, + AddressLength: 20, + } + // do not hardcode the address to avoid gitleaks complaining. + tokenAddress := utiltx.GenerateAddress().String() + usdtClientChainAsset := types.AssetInfo{ + Name: "Tether USD", + Symbol: "USDT", + Address: tokenAddress, + Decimals: 6, + LayerZeroChainID: ethClientChain.LayerZeroChainID, + MetaInfo: "Tether USD token", + } + totalSupply, _ := sdk.NewIntFromString("40022689732746729") + usdtClientChainAsset.TotalSupply = totalSupply + stakingInfo := types.StakingAssetInfo{ + AssetBasicInfo: &usdtClientChainAsset, + StakingTotalAmount: math.NewInt(0), + } + // generated information + ethAddress := utiltx.GenerateAddress() + // csmAddress := sdk.AccAddress(ethAddress.Bytes()) + stakerID, assetID := types.GetStakeIDAndAssetIDFromStr( + usdtClientChainAsset.LayerZeroChainID, ethAddress.String(), usdtClientChainAsset.Address, + ) + genesisDeposit := types.DepositsByStaker{ + StakerID: stakerID, + Deposits: []types.DepositByAsset{ + { + AssetID: assetID, + Info: types.StakerAssetInfo{ + TotalDepositAmount: math.NewInt(100), + WithdrawableAmount: math.NewInt(100), + WaitUnbondingAmount: math.NewInt(0), + }, + }, + }, + } + + testCases := []struct { + name string + genState *types.GenesisState + expPass bool + malleate func(*types.GenesisState) + unmalleate func(*types.GenesisState) + }{ + { + name: "valid genesis constructor", + genState: newGen, + expPass: true, + }, + { + name: "default", + genState: types.DefaultGenesis(), + expPass: true, + }, + { + name: "valid genesis created here", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + }, + expPass: true, + }, + { + name: "invalid genesis due to duplicate client chain", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, ethClientChain, + }, + }, + expPass: false, + }, + { + name: "invalid genesis due to missing client chain", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + Tokens: []types.StakingAssetInfo{ + stakingInfo, + }, + }, + expPass: false, + }, + { + name: "invalid genesis due to wrong token address format", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, + }, + }, + malleate: func(gs *types.GenesisState) { + gs.Tokens[0].AssetBasicInfo.Address = "fakeTokenAddress" + }, + unmalleate: func(gs *types.GenesisState) { + // gs.Tokens[0].AssetBasicInfo is a pointer, so we undo the change manually + gs.Tokens[0].AssetBasicInfo.Address = tokenAddress + }, + expPass: false, + }, + { + name: "invalid genesis due to duplicate token", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, stakingInfo, + }, + }, + expPass: false, + }, + { + name: "invalid genesis due to non zero deposit", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, + }, + }, + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Tokens[0].StakingTotalAmount = math.NewInt(1) + }, + unmalleate: func(gs *types.GenesisState) { + gs.Tokens[0].StakingTotalAmount = math.NewInt(0) + }, + }, + { + name: "invalid genesis due to negative supply amount for token", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, + }, + }, + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Tokens[0].AssetBasicInfo.TotalSupply = math.NewInt(-1) + }, + unmalleate: func(gs *types.GenesisState) { + gs.Tokens[0].AssetBasicInfo.TotalSupply = totalSupply + }, + }, + { + name: "invalid genesis due to upper case staker id", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, + }, + Deposits: []types.DepositsByStaker{genesisDeposit}, + }, + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Deposits[0].StakerID = strings.ToUpper(gs.Deposits[0].StakerID) + }, + unmalleate: func(gs *types.GenesisState) { + gs.Deposits[0].StakerID = strings.ToLower(gs.Deposits[0].StakerID) + }, + }, + { + name: "invalid genesis due to invalid staker id", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, + }, + Deposits: []types.DepositsByStaker{genesisDeposit}, + }, + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Deposits[0].StakerID = "fakeStaker" + }, + unmalleate: func(gs *types.GenesisState) { + gs.Deposits[0].StakerID = stakerID + }, + }, + { + name: "invalid genesis due to staker id from unknown chain", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, + }, + Deposits: []types.DepositsByStaker{genesisDeposit}, + }, + expPass: false, + malleate: func(gs *types.GenesisState) { + stakerID, _ := types.GetStakeIDAndAssetIDFromStr( + usdtClientChainAsset.LayerZeroChainID+1, + ethAddress.String(), usdtClientChainAsset.Address, + ) + gs.Deposits[0].StakerID = stakerID + }, + unmalleate: func(gs *types.GenesisState) { + gs.Deposits[0].StakerID = stakerID + }, + }, + { + name: "invalid genesis due to non hex staker id", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, + }, + Deposits: []types.DepositsByStaker{genesisDeposit}, + }, + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Deposits[0].StakerID = "fakeNonHexStaker_0x65" + }, + unmalleate: func(gs *types.GenesisState) { + gs.Deposits[0].StakerID = stakerID + }, + }, + { + name: "invalid genesis due to duplicate staker id", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, + }, + Deposits: []types.DepositsByStaker{genesisDeposit, genesisDeposit}, + }, + expPass: false, + }, + { + name: "invalid genesis due to unknown asset id for staker", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, + }, + Deposits: []types.DepositsByStaker{genesisDeposit}, + }, + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Deposits[0].Deposits[0].AssetID = "fakeAssetID" + }, + unmalleate: func(gs *types.GenesisState) { + gs.Deposits[0].Deposits[0].AssetID = assetID + }, + }, + { + name: "invalid genesis due to different chain ids for asset and staker", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, stakingInfo, + }, + Deposits: []types.DepositsByStaker{genesisDeposit, genesisDeposit}, + }, + expPass: false, + malleate: func(gs *types.GenesisState) { + // new chain with different layer zero chain id + gs.ClientChains[1].LayerZeroChainID += 1 + // new asset (old asset is a pointer so can't alter that) + tokenAddress := utiltx.GenerateAddress().String() + usdcClientChainAsset := types.AssetInfo{ + Name: "Circle USD", + Symbol: "USDC", + Address: tokenAddress, + Decimals: 18, + LayerZeroChainID: ethClientChain.LayerZeroChainID + 1, + MetaInfo: "Circle USD token", + TotalSupply: math.NewInt(500000000), + } + stakingInfo := types.StakingAssetInfo{ + AssetBasicInfo: &usdcClientChainAsset, + StakingTotalAmount: math.NewInt(0), + } + gs.Tokens[1] = stakingInfo + stakerID, _ := types.GetStakeIDAndAssetIDFromStr( + usdtClientChainAsset.LayerZeroChainID+1, + ethAddress.String(), usdtClientChainAsset.Address, + ) + // change stakerID to be that of the second chain + gs.Deposits[1].StakerID = stakerID + // but keep the assetID the same + }, + unmalleate: func(gs *types.GenesisState) { + gs.ClientChains[1].LayerZeroChainID -= 1 + gs.Tokens[1].AssetBasicInfo.LayerZeroChainID -= 1 + gs.Deposits[1].StakerID = stakerID + }, + }, + { + name: "invalid genesis due to duplicate asset id for staker", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, + }, + Deposits: []types.DepositsByStaker{genesisDeposit}, + }, + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Deposits[0].Deposits = append( + gs.Deposits[0].Deposits, + genesisDeposit.Deposits[0], + ) + }, + unmalleate: func(gs *types.GenesisState) { + gs.Deposits[0].Deposits = gs.Deposits[0].Deposits[:1] + }, + }, + { + name: "invalid genesis due to nil values for staker", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, + }, + Deposits: []types.DepositsByStaker{genesisDeposit}, + }, + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Deposits[0].Deposits[0].Info = types.StakerAssetInfo{} + }, + unmalleate: func(gs *types.GenesisState) { + genesisDeposit.Deposits[0].Info = types.StakerAssetInfo{ + TotalDepositAmount: math.NewInt(100), + WithdrawableAmount: math.NewInt(0), + WaitUnbondingAmount: math.NewInt(0), + } + gs.Deposits[0].Deposits[0].Info = genesisDeposit.Deposits[0].Info + }, + }, + { + name: "invalid genesis due to non zero unbonding amount for staker", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, + }, + Deposits: []types.DepositsByStaker{genesisDeposit}, + }, + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Deposits[0].Deposits[0].Info.WaitUnbondingAmount = math.NewInt(1) + }, + unmalleate: func(gs *types.GenesisState) { + genesisDeposit.Deposits[0].Info = types.StakerAssetInfo{ + TotalDepositAmount: math.NewInt(100), + WithdrawableAmount: math.NewInt(0), + WaitUnbondingAmount: math.NewInt(0), + } + gs.Deposits[0].Deposits[0].Info = genesisDeposit.Deposits[0].Info + }, + }, + { + name: "invalid genesis due to negative amount for staker", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, + }, + Deposits: []types.DepositsByStaker{genesisDeposit}, + }, + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Deposits[0].Deposits[0].Info.TotalDepositAmount = math.NewInt(-1) + }, + unmalleate: func(gs *types.GenesisState) { + genesisDeposit.Deposits[0].Info = types.StakerAssetInfo{ + TotalDepositAmount: math.NewInt(100), + WithdrawableAmount: math.NewInt(0), + WaitUnbondingAmount: math.NewInt(0), + } + gs.Deposits[0].Deposits[0].Info = genesisDeposit.Deposits[0].Info + }, + }, + { + name: "invalid genesis due to excess withdrawable amount for staker", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, + }, + Deposits: []types.DepositsByStaker{genesisDeposit}, + }, + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Deposits[0].Deposits[0].Info.TotalDepositAmount = math.NewInt(1) + gs.Deposits[0].Deposits[0].Info.WithdrawableAmount = math.NewInt(2) + }, + unmalleate: func(gs *types.GenesisState) { + genesisDeposit.Deposits[0].Info = types.StakerAssetInfo{ + TotalDepositAmount: math.NewInt(100), + WithdrawableAmount: math.NewInt(0), + WaitUnbondingAmount: math.NewInt(0), + } + gs.Deposits[0].Deposits[0].Info = genesisDeposit.Deposits[0].Info + }, + }, + { + name: "invalid genesis due to excess deposited amount for staker", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, + }, + Deposits: []types.DepositsByStaker{genesisDeposit}, + }, + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Deposits[0].Deposits[0].Info.TotalDepositAmount = + stakingInfo.AssetBasicInfo.TotalSupply.Add(math.NewInt(1)) + gs.Deposits[0].Deposits[0].Info.WithdrawableAmount = + stakingInfo.AssetBasicInfo.TotalSupply.Add(math.NewInt(1)) + }, + unmalleate: func(gs *types.GenesisState) { + gs.Deposits[0].Deposits[0].Info.TotalDepositAmount = math.NewInt(100) + gs.Deposits[0].Deposits[0].Info.WithdrawableAmount = math.NewInt(100) + }, + }, + { + name: "valid genesis", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + ClientChains: []types.ClientChainInfo{ + ethClientChain, + }, + Tokens: []types.StakingAssetInfo{ + stakingInfo, + }, + Deposits: []types.DepositsByStaker{genesisDeposit}, + }, + expPass: true, + }, + } + + for _, tc := range testCases { + tc := tc + if tc.malleate != nil { + tc.malleate(tc.genState) + // check that unmalleate is not nil + suite.Require().NotNil(tc.unmalleate, tc.name) + } + err := tc.genState.Validate() + if tc.expPass { + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Error(err, tc.name) + } + if tc.unmalleate != nil { + tc.unmalleate(tc.genState) + } + // fmt.Println(tc.name, ",", err) + } +} diff --git a/x/assets/types/keys.go b/x/assets/types/keys.go index 9f0d9c7a5..5cbe4e2d8 100644 --- a/x/assets/types/keys.go +++ b/x/assets/types/keys.go @@ -7,6 +7,7 @@ import ( errorsmod "cosmossdk.io/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" ) // constants @@ -134,7 +135,55 @@ func ParseJoinedKey(key []byte) (keys []string, err error) { func ParseJoinedStoreKey(key []byte, number int) (keys []string, err error) { stringList := strings.Split(string(key), "/") if len(stringList) != number { - return nil, errorsmod.Wrap(ErrParseAssetsStateKey, fmt.Sprintf("expected length:%d,actual length:%d,the stringList is:%v", number, len(stringList), stringList)) + return nil, errorsmod.Wrap( + ErrParseAssetsStateKey, + fmt.Sprintf( + "expected length:%d,actual length:%d,the stringList is:%v", + number, + len(stringList), + stringList, + ), + ) } return stringList, nil } + +func ParseID(key string) (string, uint64, error) { + keys := strings.Split(key, "_") + if len(keys) != 2 { + return "", 0, errorsmod.Wrap(ErrParseAssetsStateKey, fmt.Sprintf("invalid length:%s", key)) + } + if len(keys[0]) == 0 { + return "", 0, errorsmod.Wrap(ErrParseAssetsStateKey, fmt.Sprintf("empty key:%s", key)) + } + var id uint64 + var err error + if id, err = hexutil.DecodeUint64(keys[1]); err != nil { + return "", 0, errorsmod.Wrap(ErrParseAssetsStateKey, fmt.Sprintf("not a number :%s", key)) + } + return keys[0], id, nil +} + +func ValidateID(key string, validateEth bool) (string, uint64, error) { + // check lowercase + if key != strings.ToLower(key) { + return "", 0, errorsmod.Wrapf(ErrParseAssetsStateKey, "ID not lowercase: %s", key) + } + // parse it + var clientAddress string + var lzID uint64 + var err error + if clientAddress, lzID, err = ParseID(key); err != nil { + return "", 0, errorsmod.Wrapf( + ErrParseAssetsStateKey, "invalid key: %s", key, + ) + } + // check hex address + if validateEth && !common.IsHexAddress(clientAddress) { + return "", 0, errorsmod.Wrapf( + ErrParseAssetsStateKey, "not hex address %s: %s", + key, clientAddress, + ) + } + return clientAddress, lzID, nil +} diff --git a/x/assets/types/params.go b/x/assets/types/params.go new file mode 100644 index 000000000..79c242ad2 --- /dev/null +++ b/x/assets/types/params.go @@ -0,0 +1,103 @@ +package types + +import ( + "fmt" + + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + + "github.com/ethereum/go-ethereum/common" +) + +var _ paramtypes.ParamSet = (*Params)(nil) + +const ( + // DefaultExocoreLzAppAddress is the default address of ExocoreGateway.sol. + // When it is automatically deployed within the genesis block (along with + // supporting contracts) by the EVM module, this address should be changed + // to point to that contract. + DefaultExocoreLzAppAddress = "0x0000000000000000000000000000000000000000" + // DefaultExocoreLzAppEventTopic is the default topic of the exocore lz app + // event. TODO: Set this to a sane default? + DefaultExocoreLzAppEventTopic = "0x000000000000000000000000000000000000000000000000000000000000000" +) + +// Reflection based keys for params subspace. +var ( + KeyExocoreLzAppAddress = []byte("ExocoreLzAppAddress") + KeyExocoreLzAppEventTopic = []byte("ExocoreLzAppEventTopic") +) + +// ParamKeyTable returns a key table with the necessary registered params. +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +// NewParams creates a new Params instance. +func NewParams( + exocoreLzAppAddress string, + exocoreLzAppEventTopic string, +) Params { + return Params{ + ExocoreLzAppAddress: exocoreLzAppAddress, + ExocoreLzAppEventTopic: exocoreLzAppEventTopic, + } +} + +// DefaultParams returns a default set of parameters. +func DefaultParams() Params { + return NewParams( + DefaultExocoreLzAppAddress, + DefaultExocoreLzAppEventTopic, + ) +} + +// ParamSetPairs implements params.ParamSet +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair( + KeyExocoreLzAppAddress, + &p.ExocoreLzAppAddress, + ValidateHexAddress, + ), + paramtypes.NewParamSetPair( + KeyExocoreLzAppEventTopic, + &p.ExocoreLzAppEventTopic, + ValidateHexHash, + ), + } +} + +// Validate validates the set of params. +func (p Params) Validate() error { + if err := ValidateHexAddress(p.ExocoreLzAppAddress); err != nil { + return fmt.Errorf("exocore lz app address: %w", err) + } + if err := ValidateHexHash(p.ExocoreLzAppEventTopic); err != nil { + return fmt.Errorf("exocore lz app event topic: %w", err) + } + return nil +} + +// ValidateHexAddress validates a hex address. +func ValidateHexAddress(i interface{}) error { + addr, ok := i.(string) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + if !common.IsHexAddress(addr) { + return fmt.Errorf("invalid hex address: %s", addr) + } + return nil +} + +// ValidateHexHash validates a hex hash. +func ValidateHexHash(i interface{}) error { + hash, ok := i.(string) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + if len(common.FromHex(hash)) != common.HashLength { + return fmt.Errorf("invalid hex hash: %s", hash) + } + return nil +} diff --git a/x/assets/types/params.pb.go b/x/assets/types/params.pb.go index b06a93ed0..f7549d343 100644 --- a/x/assets/types/params.pb.go +++ b/x/assets/types/params.pb.go @@ -25,7 +25,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // GenesisState defines the deposit module's genesis state. type Params struct { - // exocore_lz_app_address is the address of the exocore lz app. + // exocore_lz_app_address is the address of ExocoreGateway.sol. ExocoreLzAppAddress string `protobuf:"bytes,1,opt,name=exocore_lz_app_address,json=exocoreLzAppAddress,proto3" json:"exocore_lz_app_address,omitempty"` // exocore_lz_app_event_topic is the topic of the exocore lz app event. ExocoreLzAppEventTopic string `protobuf:"bytes,2,opt,name=exocore_lz_app_event_topic,json=exocoreLzAppEventTopic,proto3" json:"exocore_lz_app_event_topic,omitempty"` diff --git a/x/assets/types/tx.pb.go b/x/assets/types/tx.pb.go index b5a1a7238..7629e8b64 100644 --- a/x/assets/types/tx.pb.go +++ b/x/assets/types/tx.pb.go @@ -190,7 +190,7 @@ type AppChainInfo struct { // meta_info is at Exocore's discretion to deter,ome MetaInfo string `protobuf:"bytes,2,opt,name=meta_info,json=metaInfo,proto3" json:"meta_info,omitempty"` // chain_id is used as the primary key - ChainId string `protobuf:"bytes,3,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + ChainID string `protobuf:"bytes,3,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` // exocore_chain_index is the index of the chain in exocore, so far unused ExocoreChainIndex uint64 `protobuf:"varint,4,opt,name=exocore_chain_index,json=exocoreChainIndex,proto3" json:"exocore_chain_index,omitempty"` } @@ -242,9 +242,9 @@ func (m *AppChainInfo) GetMetaInfo() string { return "" } -func (m *AppChainInfo) GetChainId() string { +func (m *AppChainInfo) GetChainID() string { if m != nil { - return m.ChainId + return m.ChainID } return "" } @@ -548,53 +548,6 @@ func (m *OperatorAssetInfo) XXX_DiscardUnknown() { var xxx_messageInfo_OperatorAssetInfo proto.InternalMessageInfo -// OperatorAllAssetsInfo defines the information for all assets of an operator, -// indexed by the asset_id. -type OperatorAllAssetsInfo struct { - // all_assets_state is the state of all assets of the operator. - AllAssetsState map[string]*OperatorAssetInfo `protobuf:"bytes,1,rep,name=all_assets_state,json=allAssetsState,proto3" json:"all_assets_state,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` -} - -func (m *OperatorAllAssetsInfo) Reset() { *m = OperatorAllAssetsInfo{} } -func (m *OperatorAllAssetsInfo) String() string { return proto.CompactTextString(m) } -func (*OperatorAllAssetsInfo) ProtoMessage() {} -func (*OperatorAllAssetsInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_adb6ebd423a2c426, []int{8} -} -func (m *OperatorAllAssetsInfo) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *OperatorAllAssetsInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_OperatorAllAssetsInfo.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *OperatorAllAssetsInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_OperatorAllAssetsInfo.Merge(m, src) -} -func (m *OperatorAllAssetsInfo) XXX_Size() int { - return m.Size() -} -func (m *OperatorAllAssetsInfo) XXX_DiscardUnknown() { - xxx_messageInfo_OperatorAllAssetsInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_OperatorAllAssetsInfo proto.InternalMessageInfo - -func (m *OperatorAllAssetsInfo) GetAllAssetsState() map[string]*OperatorAssetInfo { - if m != nil { - return m.AllAssetsState - } - return nil -} - // MsgSetExoCoreAddr defines the MsgSetExoCoreAddr message used to set the // exocore address of the staker. type MsgSetExoCoreAddr struct { @@ -615,7 +568,7 @@ func (m *MsgSetExoCoreAddr) Reset() { *m = MsgSetExoCoreAddr{} } func (m *MsgSetExoCoreAddr) String() string { return proto.CompactTextString(m) } func (*MsgSetExoCoreAddr) ProtoMessage() {} func (*MsgSetExoCoreAddr) Descriptor() ([]byte, []int) { - return fileDescriptor_adb6ebd423a2c426, []int{9} + return fileDescriptor_adb6ebd423a2c426, []int{8} } func (m *MsgSetExoCoreAddr) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -653,7 +606,7 @@ func (m *MsgSetExoCoreAddrResponse) Reset() { *m = MsgSetExoCoreAddrResp func (m *MsgSetExoCoreAddrResponse) String() string { return proto.CompactTextString(m) } func (*MsgSetExoCoreAddrResponse) ProtoMessage() {} func (*MsgSetExoCoreAddrResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_adb6ebd423a2c426, []int{10} + return fileDescriptor_adb6ebd423a2c426, []int{9} } func (m *MsgSetExoCoreAddrResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -694,7 +647,7 @@ func (m *RegisterClientChainReq) Reset() { *m = RegisterClientChainReq{} func (m *RegisterClientChainReq) String() string { return proto.CompactTextString(m) } func (*RegisterClientChainReq) ProtoMessage() {} func (*RegisterClientChainReq) Descriptor() ([]byte, []int) { - return fileDescriptor_adb6ebd423a2c426, []int{11} + return fileDescriptor_adb6ebd423a2c426, []int{10} } func (m *RegisterClientChainReq) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -731,7 +684,7 @@ func (m *RegisterClientChainResponse) Reset() { *m = RegisterClientChain func (m *RegisterClientChainResponse) String() string { return proto.CompactTextString(m) } func (*RegisterClientChainResponse) ProtoMessage() {} func (*RegisterClientChainResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_adb6ebd423a2c426, []int{12} + return fileDescriptor_adb6ebd423a2c426, []int{11} } func (m *RegisterClientChainResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -773,7 +726,7 @@ func (m *RegisterAssetReq) Reset() { *m = RegisterAssetReq{} } func (m *RegisterAssetReq) String() string { return proto.CompactTextString(m) } func (*RegisterAssetReq) ProtoMessage() {} func (*RegisterAssetReq) Descriptor() ([]byte, []int) { - return fileDescriptor_adb6ebd423a2c426, []int{13} + return fileDescriptor_adb6ebd423a2c426, []int{12} } func (m *RegisterAssetReq) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -810,7 +763,7 @@ func (m *RegisterAssetResponse) Reset() { *m = RegisterAssetResponse{} } func (m *RegisterAssetResponse) String() string { return proto.CompactTextString(m) } func (*RegisterAssetResponse) ProtoMessage() {} func (*RegisterAssetResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_adb6ebd423a2c426, []int{14} + return fileDescriptor_adb6ebd423a2c426, []int{13} } func (m *RegisterAssetResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -852,7 +805,7 @@ func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParams) ProtoMessage() {} func (*MsgUpdateParams) Descriptor() ([]byte, []int) { - return fileDescriptor_adb6ebd423a2c426, []int{15} + return fileDescriptor_adb6ebd423a2c426, []int{14} } func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -904,7 +857,7 @@ func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParamsResponse) ProtoMessage() {} func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_adb6ebd423a2c426, []int{16} + return fileDescriptor_adb6ebd423a2c426, []int{15} } func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -943,8 +896,6 @@ func init() { proto.RegisterType((*StakerAllAssetsInfo)(nil), "exocore.assets.v1.StakerAllAssetsInfo") proto.RegisterMapType((map[string]*StakerAssetInfo)(nil), "exocore.assets.v1.StakerAllAssetsInfo.AllAssetsStateEntry") proto.RegisterType((*OperatorAssetInfo)(nil), "exocore.assets.v1.OperatorAssetInfo") - proto.RegisterType((*OperatorAllAssetsInfo)(nil), "exocore.assets.v1.OperatorAllAssetsInfo") - proto.RegisterMapType((map[string]*OperatorAssetInfo)(nil), "exocore.assets.v1.OperatorAllAssetsInfo.AllAssetsStateEntry") proto.RegisterType((*MsgSetExoCoreAddr)(nil), "exocore.assets.v1.MsgSetExoCoreAddr") proto.RegisterType((*MsgSetExoCoreAddrResponse)(nil), "exocore.assets.v1.MsgSetExoCoreAddrResponse") proto.RegisterType((*RegisterClientChainReq)(nil), "exocore.assets.v1.RegisterClientChainReq") @@ -958,90 +909,89 @@ func init() { func init() { proto.RegisterFile("exocore/assets/v1/tx.proto", fileDescriptor_adb6ebd423a2c426) } var fileDescriptor_adb6ebd423a2c426 = []byte{ - // 1325 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0x4b, 0x73, 0x13, 0xc7, - 0x13, 0xf7, 0xca, 0xc2, 0x8f, 0xf6, 0x4b, 0x1e, 0x19, 0x2c, 0x89, 0x3f, 0x32, 0xa5, 0x3f, 0xa1, - 0x1c, 0x17, 0x48, 0xe0, 0x54, 0x08, 0x31, 0x5c, 0x64, 0x03, 0x55, 0x4e, 0x41, 0x92, 0x5a, 0x41, - 0x0e, 0x1c, 0xd8, 0x1a, 0x69, 0xc7, 0xeb, 0x8d, 0x77, 0x77, 0x36, 0x3b, 0x23, 0x2c, 0x71, 0x4a, - 0xe5, 0x94, 0xe2, 0x44, 0xe5, 0x13, 0x70, 0xce, 0x89, 0x03, 0x87, 0x7c, 0x04, 0x2a, 0x27, 0xc2, - 0x29, 0xc5, 0x81, 0xa2, 0xcc, 0x01, 0x3e, 0x46, 0x6a, 0x1e, 0x2b, 0x6b, 0xed, 0xf5, 0xa3, 0x62, - 0x55, 0xe5, 0x02, 0x9a, 0xe9, 0xee, 0x5f, 0xf7, 0xaf, 0xa7, 0xbb, 0x67, 0xd6, 0x50, 0x22, 0x1d, - 0xda, 0xa2, 0x11, 0xa9, 0x61, 0xc6, 0x08, 0x67, 0xb5, 0xc7, 0x57, 0x6b, 0xbc, 0x53, 0x0d, 0x23, - 0xca, 0x29, 0x9a, 0xd5, 0xb2, 0xaa, 0x92, 0x55, 0x1f, 0x5f, 0x2d, 0xcd, 0x62, 0xdf, 0x0d, 0x68, - 0x4d, 0xfe, 0xab, 0xb4, 0x4a, 0xf3, 0x2d, 0xca, 0x7c, 0xca, 0x6a, 0x3e, 0x73, 0x84, 0xb5, 0xcf, - 0x1c, 0x2d, 0x28, 0x2a, 0x81, 0x25, 0x57, 0x35, 0xb5, 0xd0, 0xa2, 0xf2, 0x7e, 0xaf, 0x21, 0x8e, - 0xb0, 0x1f, 0xcb, 0xe7, 0x1c, 0xea, 0x50, 0x65, 0x27, 0x7e, 0xa9, 0xdd, 0x4a, 0x13, 0xe0, 0x07, - 0xec, 0xb5, 0xc9, 0x1d, 0x97, 0x78, 0x36, 0xba, 0x0f, 0x23, 0xd8, 0xa7, 0xed, 0x80, 0x17, 0x8c, - 0xf3, 0xc6, 0xe2, 0xf8, 0xea, 0xcd, 0x57, 0xef, 0x16, 0x86, 0xde, 0xbe, 0x5b, 0xb8, 0xe8, 0xb8, - 0x7c, 0xb3, 0xdd, 0xac, 0xb6, 0xa8, 0xaf, 0x9d, 0xea, 0xff, 0x2e, 0x33, 0x7b, 0xab, 0xc6, 0xbb, - 0x21, 0x61, 0xd5, 0xf5, 0x80, 0xbf, 0x79, 0x79, 0x19, 0x74, 0x4c, 0xeb, 0x01, 0x37, 0x35, 0x56, - 0xe5, 0xaf, 0x0c, 0xcc, 0xac, 0x79, 0x2e, 0x09, 0xf8, 0xda, 0x26, 0x76, 0x83, 0xf5, 0x60, 0x83, - 0x22, 0x04, 0xd9, 0x00, 0xfb, 0x44, 0xf9, 0x31, 0xe5, 0x6f, 0x74, 0x16, 0xc6, 0x7d, 0xc2, 0xb1, - 0xe5, 0x06, 0x1b, 0xb4, 0x90, 0x91, 0x82, 0x31, 0xb1, 0x21, 0x0d, 0x8a, 0x30, 0xd6, 0x12, 0xd6, - 0x96, 0x6b, 0x17, 0x86, 0xcf, 0x1b, 0x8b, 0x59, 0x73, 0x54, 0xae, 0xd7, 0x6d, 0x54, 0x85, 0xbc, - 0xe6, 0x6e, 0x69, 0x95, 0xc0, 0x26, 0x9d, 0x42, 0x56, 0x6a, 0xc5, 0x09, 0xd7, 0xae, 0x6d, 0xd2, - 0x41, 0x35, 0xc8, 0x6f, 0xb8, 0x01, 0xf6, 0xdc, 0x27, 0x98, 0xbb, 0x34, 0xb0, 0x9a, 0x1e, 0x6d, - 0x6d, 0xb1, 0xc2, 0x29, 0xa9, 0x8f, 0xfa, 0x45, 0xab, 0x52, 0x82, 0xd6, 0x20, 0xef, 0xe1, 0x2e, - 0x89, 0xac, 0x27, 0x24, 0xa2, 0x56, 0x2f, 0x8c, 0x11, 0x61, 0xb0, 0x3a, 0xb7, 0xf3, 0x6e, 0x21, - 0x77, 0x57, 0x88, 0x1f, 0x92, 0x88, 0x2a, 0x37, 0xb7, 0xcc, 0x9c, 0x97, 0xdc, 0xb1, 0xd1, 0x67, - 0x30, 0xcd, 0x5c, 0x27, 0xc0, 0xbc, 0x1d, 0x11, 0x4b, 0xa4, 0xac, 0x30, 0x2a, 0x29, 0x4e, 0xf5, - 0x76, 0xef, 0x77, 0x43, 0x22, 0xd4, 0xb0, 0x6d, 0x47, 0x84, 0x31, 0xcb, 0x23, 0x81, 0xc3, 0x37, - 0x0b, 0x63, 0xe7, 0x8d, 0xc5, 0x29, 0x73, 0x4a, 0xef, 0xde, 0x95, 0x9b, 0x95, 0xa7, 0x06, 0x4c, - 0xd6, 0xc3, 0x70, 0x80, 0x09, 0x1d, 0xff, 0xd7, 0x09, 0xad, 0xbc, 0xcf, 0xc0, 0x78, 0x5d, 0x54, - 0xdd, 0x81, 0x91, 0x9c, 0x81, 0x11, 0xd6, 0xf5, 0x9b, 0xd4, 0xd3, 0x61, 0xe8, 0x15, 0x2a, 0xc0, - 0xa8, 0xe6, 0x15, 0xc7, 0xa0, 0x97, 0xa8, 0x04, 0x63, 0x36, 0x69, 0xb9, 0x3e, 0xf6, 0x98, 0x74, - 0x3c, 0x65, 0xf6, 0xd6, 0xc8, 0x82, 0x49, 0x4e, 0x39, 0xf6, 0x2c, 0xd6, 0x0e, 0x43, 0xaf, 0x2b, - 0x4f, 0xee, 0xa4, 0xc5, 0x3a, 0x21, 0x11, 0x1b, 0x12, 0x70, 0x30, 0x07, 0x7e, 0x40, 0x16, 0x47, - 0x0f, 0x2a, 0xcb, 0xc4, 0x69, 0x8d, 0x25, 0x4f, 0xab, 0xf2, 0xa7, 0x01, 0xb9, 0x06, 0xc7, 0x5b, - 0x6e, 0xe0, 0xec, 0x66, 0xfa, 0x0e, 0xe4, 0x64, 0xb3, 0x5b, 0x4d, 0xcc, 0xdc, 0x96, 0x32, 0x14, - 0x59, 0x9f, 0x58, 0xfe, 0x5f, 0x75, 0xdf, 0x9c, 0xa9, 0xf6, 0xec, 0xcc, 0x69, 0xb9, 0xb9, 0x2a, - 0x8c, 0x24, 0x4e, 0x00, 0x73, 0x4c, 0x61, 0x5b, 0x2a, 0xaf, 0x7a, 0x08, 0x64, 0x06, 0x90, 0x57, - 0xa4, 0x91, 0xef, 0x0b, 0xe0, 0xba, 0x1a, 0x08, 0x3b, 0x19, 0x98, 0x11, 0x64, 0x48, 0xb4, 0xcb, - 0x25, 0x80, 0x39, 0xe5, 0xdb, 0x26, 0x21, 0x65, 0x2e, 0xb7, 0x06, 0x38, 0x88, 0x90, 0x44, 0xbe, - 0xa5, 0x80, 0x55, 0x0c, 0xc8, 0x87, 0xfc, 0xb6, 0xcb, 0x37, 0xed, 0x08, 0x6f, 0xe3, 0xa6, 0x47, - 0x06, 0x4a, 0xb9, 0x1f, 0x58, 0xbb, 0x0b, 0xe1, 0xf4, 0x36, 0x76, 0xb9, 0xd5, 0x0e, 0x9a, 0x34, - 0xb0, 0x45, 0xa6, 0xb5, 0xc3, 0xe1, 0x01, 0x38, 0xcc, 0x0b, 0xe8, 0x07, 0x31, 0x72, 0x9c, 0x64, - 0x03, 0xf2, 0x3a, 0xc9, 0x9e, 0x27, 0xf3, 0xcc, 0x64, 0xa2, 0x6d, 0xc8, 0x61, 0xcf, 0xb3, 0x54, - 0x5d, 0x58, 0x8c, 0x63, 0x2e, 0x5a, 0x75, 0x78, 0x71, 0x62, 0x79, 0x25, 0xa5, 0x68, 0x52, 0x10, - 0xaa, 0xbd, 0x55, 0x43, 0x18, 0xdf, 0x0e, 0x78, 0xd4, 0x35, 0xa7, 0x71, 0x62, 0xb3, 0x44, 0x20, - 0x9f, 0xa2, 0x86, 0x72, 0x30, 0xbc, 0x45, 0xba, 0x7a, 0x34, 0x88, 0x9f, 0xe8, 0x3a, 0x9c, 0x7a, - 0x2c, 0x2e, 0x20, 0x99, 0xf9, 0x89, 0xe5, 0xca, 0xc1, 0x31, 0xf4, 0xca, 0x57, 0x19, 0xac, 0x64, - 0xae, 0x1b, 0x95, 0xb7, 0x59, 0x98, 0xfd, 0x2e, 0x24, 0x11, 0xe6, 0xb4, 0xaf, 0x96, 0x7a, 0xf3, - 0x61, 0x80, 0x35, 0xa4, 0xe6, 0x83, 0x3e, 0x4d, 0x02, 0x33, 0x54, 0x7b, 0x1d, 0x64, 0xe1, 0x4c, - 0xc7, 0xa0, 0xff, 0x55, 0xd1, 0xa0, 0x0e, 0x14, 0x7b, 0xc4, 0xf6, 0x79, 0xcd, 0x0e, 0xc0, 0xeb, - 0x7c, 0x0c, 0xbf, 0xd7, 0xf3, 0x33, 0x03, 0x2e, 0xee, 0x71, 0xdd, 0xd7, 0x97, 0x16, 0xde, 0xe0, - 0x24, 0xb2, 0x98, 0x87, 0xd9, 0xe6, 0x40, 0xc6, 0x7d, 0x25, 0x19, 0xc7, 0x6e, 0xa7, 0xd6, 0x85, - 0xa3, 0x86, 0xf0, 0x53, 0xf9, 0x64, 0xc0, 0xe9, 0x5e, 0x71, 0x25, 0x7a, 0x68, 0xe3, 0xc0, 0x1e, - 0xba, 0x99, 0x52, 0xbf, 0xa9, 0x18, 0xc7, 0xea, 0x22, 0xe7, 0xb8, 0x5d, 0xb4, 0x92, 0xec, 0xa2, - 0x0b, 0x87, 0x45, 0x91, 0xd6, 0x47, 0xef, 0x33, 0x30, 0x7b, 0x8f, 0x39, 0x0d, 0xc2, 0x6f, 0x77, - 0xe8, 0x1a, 0x8d, 0x48, 0xdd, 0xb6, 0x23, 0x74, 0x03, 0x26, 0x37, 0x22, 0xea, 0x5b, 0xf1, 0x15, - 0xad, 0xfa, 0xa8, 0xf0, 0xe6, 0xe5, 0xe5, 0x39, 0x9d, 0xca, 0xba, 0x92, 0x34, 0x78, 0xe4, 0x06, - 0x8e, 0x39, 0x21, 0xb4, 0xf5, 0x16, 0xfa, 0x1a, 0x26, 0xc4, 0xd5, 0x14, 0xdb, 0x66, 0x8e, 0xb0, - 0x05, 0x46, 0x78, 0x6c, 0xba, 0x04, 0xb3, 0x2d, 0xf9, 0x5e, 0xd4, 0x17, 0xa7, 0xc0, 0xd0, 0xef, - 0x83, 0x99, 0xd6, 0xee, 0x43, 0x52, 0xc6, 0x78, 0x09, 0x50, 0x42, 0xb7, 0xff, 0xa9, 0x92, 0x6b, - 0xf5, 0xbf, 0x3a, 0xc5, 0x1d, 0x5b, 0x87, 0x73, 0x4c, 0x4e, 0x13, 0x2b, 0x61, 0xd4, 0x7b, 0x82, - 0xa9, 0xda, 0x32, 0x4b, 0x4a, 0xa9, 0xef, 0xd1, 0xda, 0x88, 0x35, 0x56, 0xae, 0xfd, 0xfa, 0x7c, - 0x61, 0xe8, 0xd3, 0xf3, 0x85, 0xa1, 0x5f, 0x3e, 0xbe, 0x58, 0xea, 0x67, 0xfc, 0xf4, 0xe3, 0x8b, - 0xa5, 0x62, 0xfc, 0x08, 0xdf, 0x97, 0xcc, 0xca, 0x59, 0x28, 0xee, 0xdb, 0x34, 0x09, 0x0b, 0x69, - 0xc0, 0x88, 0xb8, 0xde, 0xcf, 0x98, 0xc4, 0x71, 0x19, 0x4f, 0x78, 0x35, 0xc9, 0x4f, 0x27, 0x3b, - 0x84, 0x6b, 0x90, 0xed, 0x3d, 0xfe, 0xd2, 0x87, 0xeb, 0x9e, 0x87, 0xb9, 0x29, 0xf5, 0x57, 0x6e, - 0x24, 0x48, 0xde, 0x49, 0x92, 0x2c, 0xf7, 0xf5, 0x57, 0x4a, 0xd0, 0x95, 0x73, 0x70, 0x36, 0x95, - 0x8b, 0xe6, 0xfa, 0x87, 0x01, 0xb9, 0x58, 0x2e, 0x8b, 0xf1, 0xc4, 0x2c, 0xaf, 0x24, 0x58, 0x1e, - 0xfe, 0xf6, 0x51, 0xfc, 0xbe, 0x3c, 0x8c, 0x5f, 0x21, 0x85, 0x9f, 0x04, 0xa8, 0xcc, 0xc3, 0xe9, - 0x3d, 0x91, 0x6b, 0x4e, 0xbf, 0x19, 0x30, 0x73, 0x8f, 0x39, 0x0f, 0x42, 0x1b, 0x73, 0xf2, 0xbd, - 0xfc, 0xec, 0x42, 0xd7, 0x60, 0x1c, 0xb7, 0xf9, 0x26, 0x8d, 0x5c, 0xde, 0x3d, 0x92, 0xcf, 0xae, - 0x2a, 0xfa, 0x0a, 0x46, 0xd4, 0x87, 0x9b, 0xe6, 0x53, 0x4c, 0xe1, 0xa3, 0x5c, 0xac, 0x66, 0xc5, - 0x0c, 0x34, 0xb5, 0xfa, 0xca, 0xb4, 0x20, 0xb3, 0x0b, 0x54, 0x29, 0xc2, 0xfc, 0x9e, 0x98, 0xe2, - 0x78, 0x97, 0x7f, 0x1f, 0x86, 0xe1, 0x7b, 0xcc, 0x41, 0x8f, 0x60, 0x32, 0x11, 0x73, 0x5a, 0x85, - 0xec, 0xc1, 0x28, 0x2d, 0x1d, 0xad, 0x13, 0xfb, 0x41, 0x3f, 0xc2, 0x5c, 0x83, 0x70, 0x75, 0x81, - 0xf7, 0x4f, 0x96, 0x0b, 0xe9, 0x18, 0xc9, 0xee, 0x28, 0x5d, 0x3a, 0x8e, 0x56, 0xcf, 0x57, 0x08, - 0xf9, 0x94, 0xb2, 0x43, 0x9f, 0xa7, 0x80, 0xa4, 0xb7, 0x5a, 0xa9, 0x7a, 0x5c, 0x55, 0xed, 0xf1, - 0x11, 0x4c, 0x25, 0xca, 0x01, 0xfd, 0xff, 0x10, 0x80, 0xb8, 0xd4, 0x4b, 0x8b, 0x47, 0x2b, 0x29, - 0xfc, 0xd2, 0xa9, 0x9f, 0x3f, 0xbe, 0x58, 0x32, 0x56, 0xbf, 0x79, 0xb5, 0x53, 0x36, 0x5e, 0xef, - 0x94, 0x8d, 0xf7, 0x3b, 0x65, 0xe3, 0xd9, 0x87, 0xf2, 0xd0, 0xeb, 0x0f, 0xe5, 0xa1, 0xbf, 0x3f, - 0x94, 0x87, 0x1e, 0x5e, 0xe9, 0xbb, 0xfb, 0x6e, 0x2b, 0xd0, 0x6f, 0x09, 0xdf, 0xa6, 0xd1, 0x56, - 0x2d, 0x1e, 0x44, 0x9d, 0xf8, 0xef, 0x01, 0xf2, 0x26, 0x6c, 0x8e, 0xc8, 0xcf, 0xfe, 0x2f, 0xfe, - 0x09, 0x00, 0x00, 0xff, 0xff, 0xd7, 0x99, 0x04, 0xe0, 0xa4, 0x10, 0x00, 0x00, + // 1300 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0xcd, 0x6f, 0x13, 0x47, + 0x14, 0xcf, 0x3a, 0x26, 0x1f, 0xcf, 0xf9, 0x70, 0xc6, 0x81, 0xd8, 0xa6, 0x38, 0xc8, 0x6d, 0x51, + 0x1a, 0x81, 0x0d, 0xa9, 0x4a, 0x69, 0xe8, 0xc5, 0x0e, 0x20, 0xa5, 0x82, 0xb6, 0x5a, 0x43, 0x0f, + 0x1c, 0x58, 0x8d, 0xbd, 0x13, 0x67, 0x9b, 0xdd, 0x9d, 0xed, 0xce, 0x98, 0xd8, 0x9c, 0xaa, 0x9e, + 0xaa, 0x9e, 0x50, 0x2f, 0xbd, 0x72, 0xee, 0x89, 0x03, 0x87, 0xfe, 0x09, 0xa8, 0x27, 0xca, 0xa9, + 0xe2, 0x10, 0xa1, 0x70, 0xa0, 0x7f, 0x46, 0x35, 0x1f, 0xeb, 0x78, 0x9d, 0x0d, 0x41, 0x8d, 0xa5, + 0x5e, 0x12, 0xcf, 0xbc, 0xf7, 0x7e, 0xef, 0xfd, 0xde, 0xbc, 0x79, 0x6f, 0x16, 0x8a, 0xa4, 0x4b, + 0x5b, 0x34, 0x24, 0x55, 0xcc, 0x18, 0xe1, 0xac, 0xfa, 0xf0, 0x4a, 0x95, 0x77, 0x2b, 0x41, 0x48, + 0x39, 0x45, 0x0b, 0x5a, 0x56, 0x51, 0xb2, 0xca, 0xc3, 0x2b, 0xc5, 0x05, 0xec, 0x39, 0x3e, 0xad, + 0xca, 0xbf, 0x4a, 0xab, 0xb8, 0xd4, 0xa2, 0xcc, 0xa3, 0xac, 0xea, 0xb1, 0xb6, 0xb0, 0xf6, 0x58, + 0x5b, 0x0b, 0x0a, 0x4a, 0x60, 0xc9, 0x55, 0x55, 0x2d, 0xb4, 0xa8, 0x74, 0xd8, 0x6b, 0x80, 0x43, + 0xec, 0x45, 0xf2, 0xc5, 0x36, 0x6d, 0x53, 0x65, 0x27, 0x7e, 0xa9, 0xdd, 0x72, 0x13, 0xe0, 0x3b, + 0xec, 0x76, 0xc8, 0x2d, 0x87, 0xb8, 0x36, 0xba, 0x0b, 0x13, 0xd8, 0xa3, 0x1d, 0x9f, 0xe7, 0x8d, + 0xf3, 0xc6, 0xca, 0x74, 0xfd, 0xcb, 0xe7, 0x7b, 0xcb, 0x63, 0xaf, 0xf6, 0x96, 0x2f, 0xb4, 0x1d, + 0xbe, 0xdd, 0x69, 0x56, 0x5a, 0xd4, 0xd3, 0x4e, 0xf5, 0xbf, 0x4b, 0xcc, 0xde, 0xa9, 0xf2, 0x5e, + 0x40, 0x58, 0x65, 0xd3, 0xe7, 0x2f, 0x9f, 0x5d, 0x02, 0x1d, 0xd3, 0xa6, 0xcf, 0x4d, 0x8d, 0x55, + 0xfe, 0x2b, 0x05, 0xf3, 0x1b, 0xae, 0x43, 0x7c, 0xbe, 0xb1, 0x8d, 0x1d, 0x7f, 0xd3, 0xdf, 0xa2, + 0x08, 0x41, 0xda, 0xc7, 0x1e, 0x51, 0x7e, 0x4c, 0xf9, 0x1b, 0x9d, 0x85, 0x69, 0x8f, 0x70, 0x6c, + 0x39, 0xfe, 0x16, 0xcd, 0xa7, 0xa4, 0x60, 0x4a, 0x6c, 0x48, 0x83, 0x02, 0x4c, 0xb5, 0x84, 0xb5, + 0xe5, 0xd8, 0xf9, 0xf1, 0xf3, 0xc6, 0x4a, 0xda, 0x9c, 0x94, 0xeb, 0x4d, 0x1b, 0x55, 0x20, 0xa7, + 0xb9, 0x5b, 0x5a, 0xc5, 0xb7, 0x49, 0x37, 0x9f, 0x96, 0x5a, 0x51, 0xc2, 0xb5, 0x6b, 0x9b, 0x74, + 0x51, 0x15, 0x72, 0x5b, 0x8e, 0x8f, 0x5d, 0xe7, 0x11, 0xe6, 0x0e, 0xf5, 0xad, 0xa6, 0x4b, 0x5b, + 0x3b, 0x2c, 0x7f, 0x4a, 0xea, 0xa3, 0x41, 0x51, 0x5d, 0x4a, 0xd0, 0x06, 0xe4, 0x5c, 0xdc, 0x23, + 0xa1, 0xf5, 0x88, 0x84, 0xd4, 0xea, 0x87, 0x31, 0x21, 0x0c, 0xea, 0x8b, 0xfb, 0x7b, 0xcb, 0xd9, + 0xdb, 0x42, 0x7c, 0x9f, 0x84, 0x54, 0xb9, 0xb9, 0x61, 0x66, 0xdd, 0xf8, 0x8e, 0x8d, 0x3e, 0x86, + 0x39, 0xe6, 0xb4, 0x7d, 0xcc, 0x3b, 0x21, 0xb1, 0x44, 0xca, 0xf2, 0x93, 0x92, 0xe2, 0x6c, 0x7f, + 0xf7, 0x6e, 0x2f, 0x20, 0x42, 0x0d, 0xdb, 0x76, 0x48, 0x18, 0xb3, 0x5c, 0xe2, 0xb7, 0xf9, 0x76, + 0x7e, 0xea, 0xbc, 0xb1, 0x32, 0x6b, 0xce, 0xea, 0xdd, 0xdb, 0x72, 0xb3, 0xfc, 0x9b, 0x01, 0x33, + 0xb5, 0x20, 0x38, 0x41, 0x42, 0x2f, 0x0c, 0x25, 0x74, 0xba, 0x9e, 0xd9, 0xdf, 0x5b, 0x9e, 0x8c, + 0x08, 0xfc, 0xd7, 0xec, 0x96, 0x5f, 0xa7, 0x60, 0xba, 0x26, 0x4a, 0xf0, 0xc8, 0xb0, 0xce, 0xc0, + 0x04, 0xeb, 0x79, 0x4d, 0xea, 0xea, 0x98, 0xf4, 0x0a, 0xe5, 0x61, 0x52, 0x93, 0x54, 0x01, 0x99, + 0xd1, 0x12, 0x15, 0x61, 0xca, 0x26, 0x2d, 0xc7, 0xc3, 0x2e, 0x93, 0x8e, 0x67, 0xcd, 0xfe, 0x1a, + 0x59, 0x30, 0xc3, 0x29, 0xc7, 0xae, 0xc5, 0x3a, 0x41, 0xe0, 0xf6, 0xe4, 0x31, 0x9e, 0xb4, 0x72, + 0x33, 0x12, 0xb1, 0x21, 0x01, 0x47, 0x73, 0xfa, 0x47, 0x64, 0x71, 0xf2, 0xa8, 0x1a, 0x8d, 0x1d, + 0xdd, 0x54, 0xfc, 0xe8, 0xca, 0x7f, 0x1a, 0x90, 0x6d, 0x70, 0xbc, 0xe3, 0xf8, 0xed, 0x83, 0x4c, + 0xdf, 0x82, 0xac, 0xbc, 0xf9, 0x56, 0x13, 0x33, 0xa7, 0xa5, 0x0c, 0x45, 0xd6, 0x33, 0x6b, 0x1f, + 0x54, 0x0e, 0x35, 0x9d, 0x4a, 0xdf, 0xce, 0x9c, 0x93, 0x9b, 0x75, 0x61, 0x24, 0x71, 0x7c, 0x58, + 0x64, 0x0a, 0xdb, 0x52, 0x79, 0xd5, 0x1d, 0x21, 0x35, 0x82, 0xbc, 0x22, 0x8d, 0x7c, 0x57, 0x00, + 0xd7, 0x54, 0x77, 0xd8, 0x4f, 0xc1, 0xbc, 0x20, 0x43, 0xc2, 0x03, 0x2e, 0x3e, 0x2c, 0x2a, 0xdf, + 0x36, 0x09, 0x28, 0x73, 0xb8, 0x35, 0xc2, 0xae, 0x84, 0x24, 0xf2, 0x0d, 0x05, 0xac, 0x62, 0x40, + 0x1e, 0xe4, 0x76, 0x1d, 0xbe, 0x6d, 0x87, 0x78, 0x17, 0x37, 0x5d, 0x32, 0x52, 0xca, 0x83, 0xc0, + 0xda, 0x5d, 0x00, 0xa7, 0x77, 0xb1, 0xc3, 0xad, 0x8e, 0xdf, 0xa4, 0xbe, 0x2d, 0x32, 0xad, 0x1d, + 0x8e, 0x8f, 0xc0, 0x61, 0x4e, 0x40, 0xdf, 0x8b, 0x90, 0xa3, 0x24, 0x1b, 0x90, 0xd3, 0x49, 0x76, + 0x5d, 0x99, 0x67, 0x26, 0x13, 0x6d, 0x43, 0x16, 0xbb, 0xae, 0xa5, 0xea, 0xc2, 0x62, 0x1c, 0x73, + 0x71, 0x55, 0xc7, 0x57, 0x32, 0x6b, 0xeb, 0x09, 0x45, 0x93, 0x80, 0x50, 0xe9, 0xaf, 0x1a, 0xc2, + 0xf8, 0xa6, 0xcf, 0xc3, 0x9e, 0x39, 0x87, 0x63, 0x9b, 0x45, 0x02, 0xb9, 0x04, 0x35, 0x94, 0x85, + 0xf1, 0x1d, 0xd2, 0xd3, 0xad, 0x41, 0xfc, 0x44, 0xd7, 0xe0, 0xd4, 0x43, 0x31, 0x8d, 0x64, 0xe6, + 0x33, 0x6b, 0xe5, 0xa3, 0x63, 0xe8, 0x97, 0xaf, 0x32, 0x58, 0x4f, 0x5d, 0x33, 0xca, 0xaf, 0xd2, + 0xb0, 0xf0, 0x4d, 0x40, 0x42, 0xcc, 0xe9, 0x40, 0x2d, 0xf5, 0xfb, 0xc3, 0x08, 0x6b, 0x48, 0xf5, + 0x07, 0x7d, 0x9a, 0x04, 0xe6, 0xa9, 0xf6, 0x3a, 0xca, 0xc2, 0x99, 0x8b, 0x40, 0xff, 0xaf, 0xa2, + 0x41, 0x5d, 0x28, 0xf4, 0x89, 0x1d, 0xf2, 0x9a, 0x1e, 0x81, 0xd7, 0xa5, 0x08, 0x7e, 0xd8, 0xf3, + 0x63, 0x03, 0x2e, 0x0c, 0xb9, 0x1e, 0xb8, 0x97, 0x16, 0xde, 0xe2, 0x24, 0xb4, 0x98, 0x8b, 0xd9, + 0xf6, 0x48, 0xda, 0x7d, 0x39, 0x1e, 0xc7, 0xc1, 0x4d, 0xad, 0x09, 0x47, 0x0d, 0xe1, 0x47, 0x8c, + 0xb5, 0x85, 0x3b, 0xac, 0xdd, 0x20, 0xfc, 0x66, 0x97, 0x6e, 0xd0, 0x90, 0xd4, 0x6c, 0x3b, 0x44, + 0xd7, 0x61, 0x66, 0x2b, 0xa4, 0x9e, 0x15, 0xcd, 0x2d, 0x55, 0x5c, 0xf9, 0x97, 0xcf, 0x2e, 0x2d, + 0x6a, 0xfc, 0x9a, 0x92, 0x34, 0x78, 0xe8, 0xf8, 0x6d, 0x33, 0x23, 0xb4, 0xf5, 0x16, 0xfa, 0x02, + 0x32, 0xa2, 0x5f, 0x47, 0xb6, 0xa9, 0x63, 0x6c, 0x81, 0x11, 0x1e, 0x99, 0xae, 0xc2, 0x42, 0x4b, + 0xbe, 0xa8, 0xf4, 0x34, 0x11, 0x18, 0x7a, 0x68, 0xce, 0xb7, 0x0e, 0x9e, 0x5a, 0x32, 0xc6, 0x8b, + 0x80, 0x62, 0xba, 0x83, 0xf3, 0x3b, 0xdb, 0x1a, 0x7c, 0x97, 0x89, 0xc1, 0x53, 0x83, 0x73, 0x4c, + 0x5e, 0x31, 0x2b, 0x66, 0xd4, 0x7f, 0xa4, 0xa8, 0x84, 0x9b, 0x45, 0xa5, 0x34, 0xf0, 0xac, 0x6b, + 0x44, 0x1a, 0xeb, 0x57, 0x7f, 0x7e, 0xb2, 0x3c, 0xf6, 0xcf, 0x93, 0xe5, 0xb1, 0x9f, 0xde, 0x3e, + 0x5d, 0x1d, 0x64, 0xfc, 0xcb, 0xdb, 0xa7, 0xab, 0x85, 0xe8, 0x99, 0x7a, 0x28, 0x99, 0xe5, 0xb3, + 0x50, 0x38, 0xb4, 0x69, 0x12, 0x16, 0x50, 0x9f, 0x11, 0x31, 0xf3, 0xce, 0x98, 0xa4, 0xed, 0x30, + 0x1e, 0xf3, 0x6a, 0x92, 0x1f, 0x4e, 0x76, 0x08, 0x57, 0x21, 0xdd, 0x7f, 0x1e, 0x25, 0x77, 0x9c, + 0xa1, 0xa7, 0xab, 0x29, 0xf5, 0xd7, 0xaf, 0xc7, 0x48, 0xde, 0x8a, 0x93, 0x2c, 0x0d, 0x14, 0x5d, + 0x42, 0xd0, 0xe5, 0x73, 0x70, 0x36, 0x91, 0x8b, 0xe6, 0xfa, 0x87, 0x01, 0xd9, 0x48, 0x2e, 0x1b, + 0xd9, 0x89, 0x59, 0x5e, 0x8e, 0xb1, 0x7c, 0xf7, 0x83, 0x40, 0xf1, 0xfb, 0xec, 0x5d, 0xfc, 0xf2, + 0x09, 0xfc, 0x24, 0x40, 0x79, 0x09, 0x4e, 0x0f, 0x45, 0xae, 0x39, 0xfd, 0x6a, 0xc0, 0xfc, 0x1d, + 0xd6, 0xbe, 0x17, 0xd8, 0x98, 0x93, 0x6f, 0xe5, 0x87, 0x09, 0xba, 0x0a, 0xd3, 0xb8, 0xc3, 0xb7, + 0x69, 0xe8, 0xf0, 0xde, 0xb1, 0x7c, 0x0e, 0x54, 0xd1, 0xe7, 0x30, 0xa1, 0x3e, 0x6d, 0x34, 0x9f, + 0x42, 0x02, 0x1f, 0xe5, 0xa2, 0x9e, 0x16, 0x8d, 0xc1, 0xd4, 0xea, 0xeb, 0x73, 0x82, 0xcc, 0x01, + 0x50, 0xb9, 0x00, 0x4b, 0x43, 0x31, 0x45, 0xf1, 0xae, 0xfd, 0x3e, 0x0e, 0xe3, 0x77, 0x58, 0x1b, + 0x3d, 0x80, 0x99, 0x58, 0xcc, 0x49, 0x15, 0x32, 0x84, 0x51, 0x5c, 0x3d, 0x5e, 0x27, 0xf2, 0x83, + 0xbe, 0x87, 0xc5, 0x06, 0xe1, 0x6a, 0xaa, 0x0d, 0x76, 0x96, 0x8f, 0x92, 0x31, 0xe2, 0xb7, 0xa3, + 0x78, 0xf1, 0x7d, 0xb4, 0xfa, 0xbe, 0x02, 0xc8, 0x25, 0x94, 0x1d, 0xfa, 0x24, 0x01, 0x24, 0xf9, + 0xaa, 0x15, 0x2b, 0xef, 0xab, 0xaa, 0x3d, 0x3e, 0x80, 0xd9, 0x58, 0x39, 0xa0, 0x0f, 0xdf, 0x01, + 0x10, 0x95, 0x7a, 0x71, 0xe5, 0x78, 0x25, 0x85, 0x5f, 0x3c, 0xf5, 0xe3, 0xdb, 0xa7, 0xab, 0x46, + 0xfd, 0xab, 0xe7, 0xfb, 0x25, 0xe3, 0xc5, 0x7e, 0xc9, 0x78, 0xbd, 0x5f, 0x32, 0x1e, 0xbf, 0x29, + 0x8d, 0xbd, 0x78, 0x53, 0x1a, 0xfb, 0xfb, 0x4d, 0x69, 0xec, 0xfe, 0xe5, 0x81, 0x81, 0x70, 0x53, + 0x81, 0x7e, 0x4d, 0xf8, 0x2e, 0x0d, 0x77, 0xaa, 0x51, 0x23, 0xea, 0x46, 0x5f, 0xcc, 0x72, 0x3c, + 0x34, 0x27, 0xe4, 0x87, 0xf1, 0xa7, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xd6, 0x89, 0xa1, 0x4a, + 0xc6, 0x0f, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1367,10 +1317,10 @@ func (m *AppChainInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x20 } - if len(m.ChainId) > 0 { - i -= len(m.ChainId) - copy(dAtA[i:], m.ChainId) - i = encodeVarintTx(dAtA, i, uint64(len(m.ChainId))) + if len(m.ChainID) > 0 { + i -= len(m.ChainID) + copy(dAtA[i:], m.ChainID) + i = encodeVarintTx(dAtA, i, uint64(len(m.ChainID))) i-- dAtA[i] = 0x1a } @@ -1687,55 +1637,6 @@ func (m *OperatorAssetInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *OperatorAllAssetsInfo) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *OperatorAllAssetsInfo) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *OperatorAllAssetsInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.AllAssetsState) > 0 { - for k := range m.AllAssetsState { - v := m.AllAssetsState[k] - baseI := i - if v != nil { - { - size, err := v.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - i -= len(k) - copy(dAtA[i:], k) - i = encodeVarintTx(dAtA, i, uint64(len(k))) - i-- - dAtA[i] = 0xa - i = encodeVarintTx(dAtA, i, uint64(baseI-i)) - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - func (m *MsgSetExoCoreAddr) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -2080,7 +1981,7 @@ func (m *AppChainInfo) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.ChainId) + l = len(m.ChainID) if l > 0 { n += 1 + l + sovTx(uint64(l)) } @@ -2197,28 +2098,6 @@ func (m *OperatorAssetInfo) Size() (n int) { return n } -func (m *OperatorAllAssetsInfo) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.AllAssetsState) > 0 { - for k, v := range m.AllAssetsState { - _ = k - _ = v - l = 0 - if v != nil { - l = v.Size() - l += 1 + sovTx(uint64(l)) - } - mapEntrySize := 1 + len(k) + sovTx(uint64(len(k))) + l - n += mapEntrySize + 1 + sovTx(uint64(mapEntrySize)) - } - } - return n -} - func (m *MsgSetExoCoreAddr) Size() (n int) { if m == nil { return 0 @@ -2758,7 +2637,7 @@ func (m *AppChainInfo) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ChainID", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2786,7 +2665,7 @@ func (m *AppChainInfo) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ChainId = string(dAtA[iNdEx:postIndex]) + m.ChainID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 4: if wireType != 0 { @@ -3768,185 +3647,6 @@ func (m *OperatorAssetInfo) Unmarshal(dAtA []byte) error { } return nil } -func (m *OperatorAllAssetsInfo) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: OperatorAllAssetsInfo: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: OperatorAllAssetsInfo: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AllAssetsState", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.AllAssetsState == nil { - m.AllAssetsState = make(map[string]*OperatorAssetInfo) - } - var mapkey string - var mapvalue *OperatorAssetInfo - for iNdEx < postIndex { - entryPreIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - if fieldNum == 1 { - var stringLenmapkey uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLenmapkey |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLenmapkey := int(stringLenmapkey) - if intStringLenmapkey < 0 { - return ErrInvalidLengthTx - } - postStringIndexmapkey := iNdEx + intStringLenmapkey - if postStringIndexmapkey < 0 { - return ErrInvalidLengthTx - } - if postStringIndexmapkey > l { - return io.ErrUnexpectedEOF - } - mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) - iNdEx = postStringIndexmapkey - } else if fieldNum == 2 { - var mapmsglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - mapmsglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if mapmsglen < 0 { - return ErrInvalidLengthTx - } - postmsgIndex := iNdEx + mapmsglen - if postmsgIndex < 0 { - return ErrInvalidLengthTx - } - if postmsgIndex > l { - return io.ErrUnexpectedEOF - } - mapvalue = &OperatorAssetInfo{} - if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil { - return err - } - iNdEx = postmsgIndex - } else { - iNdEx = entryPreIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > postIndex { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - m.AllAssetsState[mapkey] = mapvalue - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *MsgSetExoCoreAddr) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/delegation/keeper/cross_chain_tx_process.go b/x/delegation/keeper/cross_chain_tx_process.go index 53933714e..ca2a39161 100644 --- a/x/delegation/keeper/cross_chain_tx_process.go +++ b/x/delegation/keeper/cross_chain_tx_process.go @@ -8,21 +8,8 @@ import ( assetstype "github.com/ExocoreNetwork/exocore/x/assets/types" delegationtype "github.com/ExocoreNetwork/exocore/x/delegation/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/common" ) -type DelegationOrUndelegationParams struct { - ClientChainLzID uint64 - Action assetstype.CrossChainOpType - AssetsAddress []byte - OperatorAddress sdk.AccAddress - StakerAddress []byte - OpAmount sdkmath.Int - LzNonce uint64 - TxHash common.Hash - // todo: The operator approved signature might be needed here in future -} - // The event hook process has been deprecated, now we use precompile contract to trigger the calls. // solidity encode: bytes memory actionArgs = abi.encodePacked(token, operator, msg.sender, amount); // _sendInterchainMsg(Action.DEPOSIT, actionArgs); @@ -108,15 +95,28 @@ type DelegationOrUndelegationParams struct { }, nil }*/ -// DelegateTo : It doesn't need to check the active status of the operator in middlewares when delegating assets to the operator. This is because it adds assets to the operator's amount. But it needs to check if operator has been slashed or frozen. -func (k *Keeper) DelegateTo(ctx sdk.Context, params *DelegationOrUndelegationParams) error { +// DelegateTo : It doesn't need to check the active status of the operator in middlewares when +// delegating assets to the operator. This is because it adds assets to the operator's amount. +// But it needs to check if operator has been slashed or frozen. +func (k Keeper) DelegateTo(ctx sdk.Context, params *delegationtype.DelegationOrUndelegationParams) error { + return k.delegateTo(ctx, params, true) +} + +// delegateTo is the internal private version of DelegateTo. if the notGenesis parameter is +// false, the operator keeper and the delegation hooks are not called. +func (k *Keeper) delegateTo( + ctx sdk.Context, + params *delegationtype.DelegationOrUndelegationParams, + notGenesis bool, +) error { // check if the delegatedTo address is an operator if !k.operatorKeeper.IsOperator(ctx, params.OperatorAddress) { return errorsmod.Wrap(delegationtype.ErrOperatorNotExist, fmt.Sprintf("input operatorAddr is:%s", params.OperatorAddress)) } // check if the operator has been slashed or frozen - if k.slashKeeper.IsOperatorFrozen(ctx, params.OperatorAddress) { + // skip the check if not genesis (or chain restart) + if notGenesis && k.slashKeeper.IsOperatorFrozen(ctx, params.OperatorAddress) { return delegationtype.ErrOperatorIsFrozen } @@ -166,21 +166,23 @@ func (k *Keeper) DelegateTo(ctx sdk.Context, params *DelegationOrUndelegationPar if err != nil { return err } - // call operator module to bond the increased assets to the opted-in AVS - err = k.operatorKeeper.UpdateOptedInAssetsState(ctx, stakerID, assetID, params.OperatorAddress.String(), params.OpAmount) - if err != nil { - return err - } - // call the hooks registered by the other modules - k.Hooks().AfterDelegation(ctx, params.OperatorAddress) + if notGenesis { + // call operator module to bond the increased assets to the opted-in AVS + err = k.operatorKeeper.UpdateOptedInAssetsState(ctx, stakerID, assetID, params.OperatorAddress.String(), params.OpAmount) + if err != nil { + return err + } + // call the hooks registered by the other modules + k.Hooks().AfterDelegation(ctx, params.OperatorAddress) + } return nil } // UndelegateFrom The undelegation needs to consider whether the operator's opted-in assets can exit from the AVS. // Because only after the operator has served the AVS can the staking asset be undelegated. // So we use two steps to handle the undelegation. Fist,record the undelegation request and the corresponding exit time which needs to be obtained from the operator opt-in module. Then,we handle the record when the exit time has expired. -func (k *Keeper) UndelegateFrom(ctx sdk.Context, params *DelegationOrUndelegationParams) error { +func (k *Keeper) UndelegateFrom(ctx sdk.Context, params *delegationtype.DelegationOrUndelegationParams) error { // check if the UndelegatedFrom address is an operator if !k.operatorKeeper.IsOperator(ctx, params.OperatorAddress) { return delegationtype.ErrOperatorNotExist diff --git a/x/delegation/keeper/delegation_op_test.go b/x/delegation/keeper/delegation_op_test.go index 84edfabda..185973621 100644 --- a/x/delegation/keeper/delegation_op_test.go +++ b/x/delegation/keeper/delegation_op_test.go @@ -32,7 +32,7 @@ func (suite *DelegationTestSuite) TestDelegateTo() { opAccAddr, err := sdk.AccAddressFromBech32("exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkjr") suite.NoError(err) - delegationParams := &keeper2.DelegationOrUndelegationParams{ + delegationParams := &delegationtype.DelegationOrUndelegationParams{ ClientChainLzID: clientChainLzID, Action: types.DelegateTo, AssetsAddress: usdtAddress[:], @@ -106,7 +106,7 @@ func (suite *DelegationTestSuite) TestUndelegateFrom() { opAccAddr, err := sdk.AccAddressFromBech32("exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkjr") suite.NoError(err) - delegationEvent := &keeper2.DelegationOrUndelegationParams{ + delegationEvent := &delegationtype.DelegationOrUndelegationParams{ ClientChainLzID: clientChainLzID, Action: types.DelegateTo, AssetsAddress: usdtAddress[:], @@ -205,7 +205,7 @@ func (suite *DelegationTestSuite) TestCompleteUndelegation() { opAccAddr, err := sdk.AccAddressFromBech32("exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkjr") suite.NoError(err) - delegationEvent := &keeper2.DelegationOrUndelegationParams{ + delegationEvent := &delegationtype.DelegationOrUndelegationParams{ ClientChainLzID: clientChainLzID, Action: types.DelegateTo, AssetsAddress: usdtAddress[:], diff --git a/x/delegation/keeper/genesis.go b/x/delegation/keeper/genesis.go new file mode 100644 index 000000000..7dd1577bd --- /dev/null +++ b/x/delegation/keeper/genesis.go @@ -0,0 +1,60 @@ +package keeper + +import ( + assetstype "github.com/ExocoreNetwork/exocore/x/assets/types" + delegationtype "github.com/ExocoreNetwork/exocore/x/delegation/types" + abci "github.com/cometbft/cometbft/abci/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" +) + +// InitGenesis initializes the module's state from a provided genesis state. +// Since this action typically occurs on chain starts, this function is allowed to panic. +func (k Keeper) InitGenesis( + ctx sdk.Context, + gs delegationtype.GenesisState, +) []abci.ValidatorUpdate { + // TODO(mm): is it possible to parallelize these without using goroutines? + for _, level1 := range gs.Delegations { + stakerID := level1.StakerID + // #nosec G703 // already validated + stakerAddress, lzID, _ := assetstype.ParseID(stakerID) + // we have checked IsHexAddress already + stakerAddressBytes := common.HexToAddress(stakerAddress) + for _, level2 := range level1.Delegations { + assetID := level2.AssetID + // #nosec G703 // already validated + assetAddress, _, _ := assetstype.ParseID(assetID) + // we have checked IsHexAddress already + assetAddressBytes := common.HexToAddress(assetAddress) + for _, level3 := range level2.PerOperatorAmounts { + operator := level3.Key + wrappedAmount := level3.Value + amount := wrappedAmount.Amount + // #nosec G703 // already validated + accAddress, _ := sdk.AccAddressFromBech32(operator) + delegationParams := &delegationtype.DelegationOrUndelegationParams{ + ClientChainLzID: lzID, + Action: assetstype.DelegateTo, + AssetsAddress: assetAddressBytes.Bytes(), + OperatorAddress: accAddress, + StakerAddress: stakerAddressBytes.Bytes(), + OpAmount: amount, + // the uninitialized members are not used in this context + // they are the LzNonce and TxHash + } + if err := k.delegateTo(ctx, delegationParams, false); err != nil { + panic(err) + } + } + } + } + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the module's exported genesis +func (Keeper) ExportGenesis(sdk.Context) *delegationtype.GenesisState { + genesis := delegationtype.DefaultGenesis() + // TODO + return genesis +} diff --git a/x/delegation/module.go b/x/delegation/module.go index b93a5ea35..aa5af3f8e 100644 --- a/x/delegation/module.go +++ b/x/delegation/module.go @@ -2,6 +2,8 @@ package delegation import ( "context" + "encoding/json" + "fmt" "github.com/ExocoreNetwork/exocore/x/delegation/client/cli" "github.com/ExocoreNetwork/exocore/x/delegation/keeper" @@ -38,7 +40,10 @@ func (b AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry delegationtype.RegisterInterfaces(registry) } -func (b AppModuleBasic) RegisterGRPCGatewayRoutes(c client.Context, serveMux *runtime.ServeMux) { +func (b AppModuleBasic) RegisterGRPCGatewayRoutes( + c client.Context, + serveMux *runtime.ServeMux, +) { if err := delegationtype.RegisterQueryHandlerClient(context.Background(), serveMux, delegationtype.NewQueryClient(c)); err != nil { panic(err) } @@ -92,3 +97,46 @@ func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.V am.keeper.EndBlock(ctx, req) return []abci.ValidatorUpdate{} } + +// DefaultGenesis returns a default GenesisState for the module, marshaled to json.RawMessage. +// The default GenesisState need to be defined by the module developer and is primarily used for +// testing +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(delegationtype.DefaultGenesis()) +} + +// ValidateGenesis used to validate the GenesisState, given in its json.RawMessage form +func (AppModuleBasic) ValidateGenesis( + cdc codec.JSONCodec, + _ client.TxEncodingConfig, + bz json.RawMessage, +) error { + var genState delegationtype.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf( + "failed to unmarshal %s genesis state: %w", + delegationtype.ModuleName, + err, + ) + } + return genState.Validate() +} + +// InitGenesis performs the module's genesis initialization. It returns no validator updates. +func (am AppModule) InitGenesis( + ctx sdk.Context, + cdc codec.JSONCodec, + gs json.RawMessage, +) []abci.ValidatorUpdate { + var genState delegationtype.GenesisState + // Initialize global index to index in genesis state + cdc.MustUnmarshalJSON(gs, &genState) + + return am.keeper.InitGenesis(ctx, genState) +} + +// ExportGenesis returns the module's exported genesis state as raw JSON bytes. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := am.keeper.ExportGenesis(ctx) + return cdc.MustMarshalJSON(genState) +} diff --git a/x/delegation/types/cross_chain_params.go b/x/delegation/types/cross_chain_params.go new file mode 100644 index 000000000..a43803c6e --- /dev/null +++ b/x/delegation/types/cross_chain_params.go @@ -0,0 +1,20 @@ +package types + +import ( + sdkmath "cosmossdk.io/math" + assetstype "github.com/ExocoreNetwork/exocore/x/assets/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" +) + +type DelegationOrUndelegationParams struct { + ClientChainLzID uint64 + Action assetstype.CrossChainOpType + AssetsAddress []byte + OperatorAddress sdk.AccAddress + StakerAddress []byte + OpAmount sdkmath.Int + LzNonce uint64 + TxHash common.Hash + // todo: The operator approved signature might be needed here in future +} diff --git a/x/delegation/types/errors.go b/x/delegation/types/errors.go index 1bb6446c7..e9ab8b8d6 100644 --- a/x/delegation/types/errors.go +++ b/x/delegation/types/errors.go @@ -3,28 +3,72 @@ package types import errorsmod "cosmossdk.io/errors" var ( - ErrNoKeyInTheStore = errorsmod.Register(ModuleName, 0, "there is not the key for in the store") - ErrOperatorIsFrozen = errorsmod.Register(ModuleName, 1, "the operator has been frozen") + ErrNoKeyInTheStore = errorsmod.Register( + ModuleName, 0, + "there is not the key for in the store", + ) + ErrOperatorIsFrozen = errorsmod.Register( + ModuleName, 1, + "the operator has been frozen", + ) - ErrOperatorNotExist = errorsmod.Register(ModuleName, 2, "the operator has not been registered") + ErrOperatorNotExist = errorsmod.Register( + ModuleName, 2, + "the operator has not been registered", + ) - ErrOpAmountIsNegative = errorsmod.Register(ModuleName, 3, "the delegation or Undelegation amount is negative") + ErrOpAmountIsNegative = errorsmod.Register( + ModuleName, 3, + "the delegation or Undelegation amount is negative", + ) - OperatorAddrIsNotAccAddr = errorsmod.Register(ModuleName, 4, "the operator address isn't a valid acc addr") + OperatorAddrIsNotAccAddr = errorsmod.Register( + ModuleName, 4, + "the operator address isn't a valid acc addr", + ) - ErrSubAmountIsGreaterThanOriginal = errorsmod.Register(ModuleName, 5, "the sub amount is greater than the original amount") + ErrSubAmountIsGreaterThanOriginal = errorsmod.Register( + ModuleName, 5, + "the sub amount is greater than the original amount", + ) - ErrParseDelegationKey = errorsmod.Register(ModuleName, 6, "delegation state key can't be parsed") + ErrParseDelegationKey = errorsmod.Register( + ModuleName, 6, + "delegation state key can't be parsed", + ) - ErrStakerGetRecordType = errorsmod.Register(ModuleName, 7, "the input getType is error when get staker Undelegation records") + ErrStakerGetRecordType = errorsmod.Register( + ModuleName, 7, + "the input getType is error when get staker Undelegation records", + ) - ErrUndelegationAmountTooBig = errorsmod.Register(ModuleName, 8, "the Undelegation amount is bigger than the delegated amount") + ErrUndelegationAmountTooBig = errorsmod.Register( + ModuleName, 8, + "the Undelegation amount is bigger than the delegated amount", + ) - ErrNotSupportYet = errorsmod.Register(ModuleName, 9, "don't have supported it yet") + ErrNotSupportYet = errorsmod.Register( + ModuleName, 9, + "don't have supported it yet", + ) - ErrDelegationAmountTooBig = errorsmod.Register(ModuleName, 10, "the delegation amount is bigger than the canWithdraw amount") + ErrDelegationAmountTooBig = errorsmod.Register( + ModuleName, 10, + "the delegation amount is bigger than the canWithdraw amount", + ) - ErrCannotIncHoldCount = errorsmod.Register(ModuleName, 11, "cannot increment undelegation hold count above max uint64") + ErrCannotIncHoldCount = errorsmod.Register( + ModuleName, 11, + "cannot increment undelegation hold count above max uint64", + ) - ErrCannotDecHoldCount = errorsmod.Register(ModuleName, 12, "cannot decrement undelegation hold count below zero") + ErrCannotDecHoldCount = errorsmod.Register( + ModuleName, 12, + "cannot decrement undelegation hold count below zero", + ) + + ErrInvalidGenesisData = errorsmod.Register( + ModuleName, 13, + "the genesis data supplied is invalid", + ) ) diff --git a/x/delegation/types/genesis.go b/x/delegation/types/genesis.go new file mode 100644 index 000000000..571cb0c10 --- /dev/null +++ b/x/delegation/types/genesis.go @@ -0,0 +1,106 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + assetstypes "github.com/ExocoreNetwork/exocore/x/assets/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// NewGenesis returns a new genesis state with the given inputs. +func NewGenesis( + delegations []DelegationsByStaker, +) *GenesisState { + return &GenesisState{ + Delegations: delegations, + } +} + +// DefaultGenesis returns the default genesis state +func DefaultGenesis() *GenesisState { + return NewGenesis([]DelegationsByStaker{}) +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + // TODO(mm): this can be a very big hash table and impact system performance. + // This is likely to be the biggest one amongst the three, and the others + // are garbage collected within the loop anyway. Maybe reordering the genesis + // structure could potentially help with this. + stakers := make(map[string]struct{}, len(gs.Delegations)) + for _, level1 := range gs.Delegations { + stakerID := level1.StakerID + // validate staker ID + var stakerClientChainID uint64 + var err error + if _, stakerClientChainID, err = assetstypes.ValidateID(stakerID, true); err != nil { + return errorsmod.Wrapf( + ErrInvalidGenesisData, "invalid staker ID %s: %s", stakerID, err, + ) + } + // check for duplicate stakers + if _, ok := stakers[stakerID]; ok { + return errorsmod.Wrapf(ErrInvalidGenesisData, "duplicate staker ID %s", stakerID) + } + stakers[stakerID] = struct{}{} + assets := make(map[string]struct{}, len(level1.Delegations)) + for _, level2 := range level1.Delegations { + assetID := level2.AssetID + // check for duplicate assets + if _, ok := assets[assetID]; ok { + return errorsmod.Wrapf(ErrInvalidGenesisData, "duplicate asset ID %s", assetID) + } + assets[assetID] = struct{}{} + // validate asset ID + var assetClientChainID uint64 + if _, assetClientChainID, err = assetstypes.ValidateID(assetID, true); err != nil { + return errorsmod.Wrapf( + ErrInvalidGenesisData, "invalid asset ID %s: %s", assetID, err, + ) + } + if assetClientChainID != stakerClientChainID { + // a staker from chain A is delegating an asset on chain B, which is not + // something we support right now. + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "asset %s client chain ID %d does not match staker %s client chain ID %d", + assetID, assetClientChainID, stakerID, stakerClientChainID, + ) + } + operators := make(map[string]struct{}, len(level2.PerOperatorAmounts)) + for _, level3 := range level2.PerOperatorAmounts { + operator := level3.Key + wrappedAmount := level3.Value + // check supplied amount + if wrappedAmount == nil { + return errorsmod.Wrapf( + ErrInvalidGenesisData, "nil operator amount for operator %s", operator, + ) + } + amount := wrappedAmount.Amount + if amount.IsNil() || amount.IsNegative() { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "invalid operator amount %s for operator %s", amount, operator, + ) + } + // check operator address + if _, err := sdk.AccAddressFromBech32(operator); err != nil { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "invalid operator address for operator %s", operator, + ) + } + // check for duplicate operators + if _, ok := operators[operator]; ok { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "duplicate operator %s for asset %s", operator, assetID, + ) + } + operators[operator] = struct{}{} + } + } + } + return nil +} diff --git a/x/delegation/types/genesis.pb.go b/x/delegation/types/genesis.pb.go new file mode 100644 index 000000000..88645d085 --- /dev/null +++ b/x/delegation/types/genesis.pb.go @@ -0,0 +1,577 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: exocore/delegation/v1/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the delegation module's state. It needs to encompass +// all of the state that is required to start the chain from the genesis +// or in the event of a restart. At this point, it is only built with +// the former in mind. There are no params in this module. +type GenesisState struct { + // delegations is a list of all delegations in the system. + Delegations []DelegationsByStaker `protobuf:"bytes,1,rep,name=delegations,proto3" json:"delegations"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_c26dd0d733927603, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetDelegations() []DelegationsByStaker { + if m != nil { + return m.Delegations + } + return nil +} + +// DelegationsByStaker is a list of delegations for a single staker. +type DelegationsByStaker struct { + // staker_id is the staker's account address + _ + l0 chain id (hex).`` + StakerID string `protobuf:"bytes,1,opt,name=staker_id,json=stakerId,proto3" json:"staker_id,omitempty"` + // delegations is the list of delegations for the staker, indexed by the + // asset_id. + Delegations []DelegatedSingleAssetInfo `protobuf:"bytes,2,rep,name=delegations,proto3" json:"delegations"` +} + +func (m *DelegationsByStaker) Reset() { *m = DelegationsByStaker{} } +func (m *DelegationsByStaker) String() string { return proto.CompactTextString(m) } +func (*DelegationsByStaker) ProtoMessage() {} +func (*DelegationsByStaker) Descriptor() ([]byte, []int) { + return fileDescriptor_c26dd0d733927603, []int{1} +} +func (m *DelegationsByStaker) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DelegationsByStaker) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DelegationsByStaker.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DelegationsByStaker) XXX_Merge(src proto.Message) { + xxx_messageInfo_DelegationsByStaker.Merge(m, src) +} +func (m *DelegationsByStaker) XXX_Size() int { + return m.Size() +} +func (m *DelegationsByStaker) XXX_DiscardUnknown() { + xxx_messageInfo_DelegationsByStaker.DiscardUnknown(m) +} + +var xxx_messageInfo_DelegationsByStaker proto.InternalMessageInfo + +func (m *DelegationsByStaker) GetStakerID() string { + if m != nil { + return m.StakerID + } + return "" +} + +func (m *DelegationsByStaker) GetDelegations() []DelegatedSingleAssetInfo { + if m != nil { + return m.Delegations + } + return nil +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "exocore.delegation.v1.GenesisState") + proto.RegisterType((*DelegationsByStaker)(nil), "exocore.delegation.v1.DelegationsByStaker") +} + +func init() { + proto.RegisterFile("exocore/delegation/v1/genesis.proto", fileDescriptor_c26dd0d733927603) +} + +var fileDescriptor_c26dd0d733927603 = []byte{ + // 282 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4e, 0xad, 0xc8, 0x4f, + 0xce, 0x2f, 0x4a, 0xd5, 0x4f, 0x49, 0xcd, 0x49, 0x4d, 0x4f, 0x2c, 0xc9, 0xcc, 0xcf, 0xd3, 0x2f, + 0x33, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, + 0x12, 0x85, 0x2a, 0xd2, 0x43, 0x28, 0xd2, 0x2b, 0x33, 0x94, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, + 0xab, 0xd0, 0x07, 0xb1, 0x20, 0x8a, 0xa5, 0xe4, 0xb0, 0x9b, 0x58, 0x52, 0x01, 0x91, 0x57, 0x4a, + 0xe2, 0xe2, 0x71, 0x87, 0x98, 0x1e, 0x5c, 0x92, 0x58, 0x92, 0x2a, 0x14, 0xc4, 0xc5, 0x8d, 0x50, + 0x59, 0x2c, 0xc1, 0xa8, 0xc0, 0xac, 0xc1, 0x6d, 0xa4, 0xa5, 0x87, 0xd5, 0x4a, 0x3d, 0x17, 0x84, + 0x4a, 0xa7, 0xca, 0xe0, 0x92, 0xc4, 0xec, 0xd4, 0x22, 0x27, 0x96, 0x13, 0xf7, 0xe4, 0x19, 0x82, + 0x90, 0x0d, 0x51, 0x9a, 0xc9, 0xc8, 0x25, 0x8c, 0x45, 0xa9, 0x90, 0x26, 0x17, 0x67, 0x31, 0x98, + 0x15, 0x9f, 0x99, 0x22, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0xe9, 0xc4, 0xf3, 0xe8, 0x9e, 0x3c, 0x07, + 0x44, 0xda, 0xd3, 0x25, 0x88, 0x03, 0x22, 0xed, 0x99, 0x22, 0x14, 0x8e, 0xea, 0x2c, 0x26, 0xb0, + 0xb3, 0xf4, 0xf1, 0x3b, 0x2b, 0x35, 0x25, 0x38, 0x33, 0x2f, 0x3d, 0x27, 0xd5, 0xb1, 0xb8, 0x38, + 0xb5, 0xc4, 0x33, 0x2f, 0x2d, 0x1f, 0x8b, 0xdb, 0x9c, 0xfc, 0x4e, 0x3c, 0x92, 0x63, 0xbc, 0xf0, + 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, + 0xf1, 0x58, 0x8e, 0x21, 0xca, 0x24, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, + 0xdf, 0x15, 0x62, 0x8f, 0x5f, 0x6a, 0x49, 0x79, 0x7e, 0x51, 0xb6, 0x3e, 0x2c, 0x4c, 0x2b, 0x90, + 0x43, 0xb5, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, 0x0d, 0x1c, 0xac, 0xc6, 0x80, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xa3, 0x40, 0xe3, 0x39, 0xca, 0x01, 0x00, 0x00, +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Delegations) > 0 { + for iNdEx := len(m.Delegations) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Delegations[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *DelegationsByStaker) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DelegationsByStaker) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DelegationsByStaker) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Delegations) > 0 { + for iNdEx := len(m.Delegations) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Delegations[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.StakerID) > 0 { + i -= len(m.StakerID) + copy(dAtA[i:], m.StakerID) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.StakerID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Delegations) > 0 { + for _, e := range m.Delegations { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *DelegationsByStaker) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.StakerID) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if len(m.Delegations) > 0 { + for _, e := range m.Delegations { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Delegations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Delegations = append(m.Delegations, DelegationsByStaker{}) + if err := m.Delegations[len(m.Delegations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DelegationsByStaker) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DelegationsByStaker: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DelegationsByStaker: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StakerID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StakerID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Delegations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Delegations = append(m.Delegations, DelegatedSingleAssetInfo{}) + if err := m.Delegations[len(m.Delegations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/delegation/types/genesis_test.go b/x/delegation/types/genesis_test.go new file mode 100644 index 000000000..b2fede925 --- /dev/null +++ b/x/delegation/types/genesis_test.go @@ -0,0 +1,204 @@ +package types_test + +import ( + "testing" + + "cosmossdk.io/math" + utiltx "github.com/ExocoreNetwork/exocore/testutil/tx" + assetstypes "github.com/ExocoreNetwork/exocore/x/assets/types" + "github.com/ExocoreNetwork/exocore/x/delegation/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/suite" +) + +type GenesisTestSuite struct { + suite.Suite +} + +func (suite *GenesisTestSuite) SetupTest() { +} + +func TestGenesisTestSuite(t *testing.T) { + suite.Run(t, new(GenesisTestSuite)) +} + +func (suite *GenesisTestSuite) TestValidateGenesis() { + assetAddress := utiltx.GenerateAddress() + stakerAddress := utiltx.GenerateAddress() + lzID := uint64(101) + stakerID, assetID := assetstypes.GetStakeIDAndAssetID( + lzID, stakerAddress[:], assetAddress[:], + ) + operatorAddress := sdk.AccAddress(utiltx.GenerateAddress().Bytes()) + delegations := []types.DelegationsByStaker{ + { + StakerID: stakerID, + Delegations: []types.DelegatedSingleAssetInfo{ + { + AssetID: assetID, + PerOperatorAmounts: []types.KeyValue{ + { + Key: operatorAddress.String(), + Value: &types.ValueField{ + Amount: math.NewInt(1000), + }, + }, + }, + }, + }, + }, + } + testCases := []struct { + name string + genState *types.GenesisState + expPass bool + malleate func(*types.GenesisState) + unmalleate func(*types.GenesisState) + }{ + { + name: "valid empty genesis", + genState: &types.GenesisState{}, + expPass: true, + }, + { + name: "default", + genState: types.DefaultGenesis(), + expPass: true, + }, + { + name: "base, should pass", + genState: types.NewGenesis(delegations), + expPass: true, + }, + { + name: "invalid staker id", + genState: types.NewGenesis(delegations), + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Delegations[0].StakerID = "invalid" + }, + unmalleate: func(gs *types.GenesisState) { + gs.Delegations[0].StakerID = stakerID + }, + }, + { + name: "duplicate staker id", + genState: types.NewGenesis(delegations), + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Delegations = append(gs.Delegations, gs.Delegations[0]) + }, + unmalleate: func(gs *types.GenesisState) { + gs.Delegations = gs.Delegations[:1] + }, + }, + { + name: "duplicate asset id", + genState: types.NewGenesis(delegations), + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Delegations[0].Delegations = append( + gs.Delegations[0].Delegations, + gs.Delegations[0].Delegations[0], + ) + }, + unmalleate: func(gs *types.GenesisState) { + gs.Delegations[0].Delegations = gs.Delegations[0].Delegations[:1] + }, + }, + { + name: "invalid asset id", + genState: types.NewGenesis(delegations), + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Delegations[0].Delegations[0].AssetID = "invalid" + }, + unmalleate: func(gs *types.GenesisState) { + gs.Delegations[0].Delegations[0].AssetID = assetID + }, + }, + { + name: "asset id mismatch", + genState: types.NewGenesis(delegations), + expPass: false, + malleate: func(gs *types.GenesisState) { + stakerID, _ := assetstypes.GetStakeIDAndAssetID( + lzID+1, stakerAddress[:], assetAddress[:], + ) + gs.Delegations[0].StakerID = stakerID + }, + unmalleate: func(gs *types.GenesisState) { + gs.Delegations[0].StakerID = stakerID + }, + }, + { + name: "nil wrapped amount", + genState: types.NewGenesis(delegations), + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Delegations[0].Delegations[0].PerOperatorAmounts[0].Value = nil + }, + unmalleate: func(gs *types.GenesisState) { + gs.Delegations[0].Delegations[0].PerOperatorAmounts[0].Value = + &types.ValueField{Amount: math.NewInt(1000)} + }, + }, + { + name: "nil unwrapped amount", + genState: types.NewGenesis(delegations), + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Delegations[0].Delegations[0].PerOperatorAmounts[0].Value = + &types.ValueField{} + }, + unmalleate: func(gs *types.GenesisState) { + gs.Delegations[0].Delegations[0].PerOperatorAmounts[0].Value = + &types.ValueField{Amount: math.NewInt(1000)} + }, + }, + { + name: "negative unwrapped amount", + genState: types.NewGenesis(delegations), + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Delegations[0].Delegations[0].PerOperatorAmounts[0].Value = + &types.ValueField{Amount: math.NewInt(-1)} + }, + unmalleate: func(gs *types.GenesisState) { + gs.Delegations[0].Delegations[0].PerOperatorAmounts[0].Value = + &types.ValueField{Amount: math.NewInt(1000)} + }, + }, + { + name: "invalid operator address", + genState: types.NewGenesis(delegations), + expPass: false, + malleate: func(gs *types.GenesisState) { + gs.Delegations[0].Delegations[0].PerOperatorAmounts[0].Key = "invalid" + }, + unmalleate: func(gs *types.GenesisState) { + gs.Delegations[0].Delegations[0].PerOperatorAmounts[0].Key = + operatorAddress.String() + }, + }, + } + + for _, tc := range testCases { + tc := tc + if tc.malleate != nil { + tc.malleate(tc.genState) + // require that unmalleate is defined + suite.Require().NotNil(tc.unmalleate, tc.name) + } + err := tc.genState.Validate() + if tc.expPass { + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Error(err, tc.name) + } + if tc.unmalleate != nil { + tc.unmalleate(tc.genState) + } + // fmt.Println(tc.name, err) + } +} diff --git a/x/delegation/types/tx.pb.go b/x/delegation/types/tx.pb.go index d9d9b36a2..99f3f0e45 100644 --- a/x/delegation/types/tx.pb.go +++ b/x/delegation/types/tx.pb.go @@ -75,10 +75,11 @@ var xxx_messageInfo_ValueField proto.InternalMessageInfo type DelegatedSingleAssetInfo struct { // asset_id is the asset id. AssetID string `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` - // total_delegated_amount is the total amount of the asset delegated. - TotalDelegatedAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=total_delegated_amount,json=totalDelegatedAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"total_delegated_amount"` - // per_operator_amounts is the amount of the asset delegated to each operator. - PerOperatorAmounts map[string]*ValueField `protobuf:"bytes,3,rep,name=per_operator_amounts,json=perOperatorAmounts,proto3" json:"per_operator_amounts,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // since Cosmos uses an IAVL+ tree where the order of insertion affects the state root (even + // if the items are unrelated), and deserializing a protobuf map into Golang does not + // guarantee order, we cannot use a map here. Instead, we use a repeated field of key-value + // pairs. + PerOperatorAmounts []KeyValue `protobuf:"bytes,3,rep,name=per_operator_amounts,json=perOperatorAmounts,proto3" json:"per_operator_amounts"` } func (m *DelegatedSingleAssetInfo) Reset() { *m = DelegatedSingleAssetInfo{} } @@ -121,13 +122,68 @@ func (m *DelegatedSingleAssetInfo) GetAssetID() string { return "" } -func (m *DelegatedSingleAssetInfo) GetPerOperatorAmounts() map[string]*ValueField { +func (m *DelegatedSingleAssetInfo) GetPerOperatorAmounts() []KeyValue { if m != nil { return m.PerOperatorAmounts } return nil } +// KeyValue is a key-value pair. It is a helper struct to represent a map in Protobuf. +type KeyValue struct { + // key is the key of the key-value pair. + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + // value is the value of the key-value pair. + Value *ValueField `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *KeyValue) Reset() { *m = KeyValue{} } +func (m *KeyValue) String() string { return proto.CompactTextString(m) } +func (*KeyValue) ProtoMessage() {} +func (*KeyValue) Descriptor() ([]byte, []int) { + return fileDescriptor_16596a15a828f109, []int{2} +} +func (m *KeyValue) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *KeyValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_KeyValue.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *KeyValue) XXX_Merge(src proto.Message) { + xxx_messageInfo_KeyValue.Merge(m, src) +} +func (m *KeyValue) XXX_Size() int { + return m.Size() +} +func (m *KeyValue) XXX_DiscardUnknown() { + xxx_messageInfo_KeyValue.DiscardUnknown(m) +} + +var xxx_messageInfo_KeyValue proto.InternalMessageInfo + +func (m *KeyValue) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +func (m *KeyValue) GetValue() *ValueField { + if m != nil { + return m.Value + } + return nil +} + // DelegationApproveInfo is the delegation approve info. type DelegationApproveInfo struct { // signature of the delegation approve info. @@ -140,7 +196,7 @@ func (m *DelegationApproveInfo) Reset() { *m = DelegationApproveInfo{} } func (m *DelegationApproveInfo) String() string { return proto.CompactTextString(m) } func (*DelegationApproveInfo) ProtoMessage() {} func (*DelegationApproveInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_16596a15a828f109, []int{2} + return fileDescriptor_16596a15a828f109, []int{3} } func (m *DelegationApproveInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -195,7 +251,7 @@ func (m *DelegationIncOrDecInfo) Reset() { *m = DelegationIncOrDecInfo{} func (m *DelegationIncOrDecInfo) String() string { return proto.CompactTextString(m) } func (*DelegationIncOrDecInfo) ProtoMessage() {} func (*DelegationIncOrDecInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_16596a15a828f109, []int{3} + return fileDescriptor_16596a15a828f109, []int{4} } func (m *DelegationIncOrDecInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -236,7 +292,7 @@ func (m *MsgDelegation) Reset() { *m = MsgDelegation{} } func (m *MsgDelegation) String() string { return proto.CompactTextString(m) } func (*MsgDelegation) ProtoMessage() {} func (*MsgDelegation) Descriptor() ([]byte, []int) { - return fileDescriptor_16596a15a828f109, []int{4} + return fileDescriptor_16596a15a828f109, []int{5} } func (m *MsgDelegation) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -309,7 +365,7 @@ func (m *UndelegationRecord) Reset() { *m = UndelegationRecord{} } func (m *UndelegationRecord) String() string { return proto.CompactTextString(m) } func (*UndelegationRecord) ProtoMessage() {} func (*UndelegationRecord) Descriptor() ([]byte, []int) { - return fileDescriptor_16596a15a828f109, []int{5} + return fileDescriptor_16596a15a828f109, []int{6} } func (m *UndelegationRecord) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -404,7 +460,7 @@ func (m *UndelegationRecordKeyList) Reset() { *m = UndelegationRecordKey func (m *UndelegationRecordKeyList) String() string { return proto.CompactTextString(m) } func (*UndelegationRecordKeyList) ProtoMessage() {} func (*UndelegationRecordKeyList) Descriptor() ([]byte, []int) { - return fileDescriptor_16596a15a828f109, []int{6} + return fileDescriptor_16596a15a828f109, []int{7} } func (m *UndelegationRecordKeyList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -448,7 +504,7 @@ func (m *DelegationResponse) Reset() { *m = DelegationResponse{} } func (m *DelegationResponse) String() string { return proto.CompactTextString(m) } func (*DelegationResponse) ProtoMessage() {} func (*DelegationResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_16596a15a828f109, []int{7} + return fileDescriptor_16596a15a828f109, []int{8} } func (m *DelegationResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -487,7 +543,7 @@ func (m *MsgUndelegation) Reset() { *m = MsgUndelegation{} } func (m *MsgUndelegation) String() string { return proto.CompactTextString(m) } func (*MsgUndelegation) ProtoMessage() {} func (*MsgUndelegation) Descriptor() ([]byte, []int) { - return fileDescriptor_16596a15a828f109, []int{8} + return fileDescriptor_16596a15a828f109, []int{9} } func (m *MsgUndelegation) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -531,7 +587,7 @@ func (m *UndelegationResponse) Reset() { *m = UndelegationResponse{} } func (m *UndelegationResponse) String() string { return proto.CompactTextString(m) } func (*UndelegationResponse) ProtoMessage() {} func (*UndelegationResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_16596a15a828f109, []int{9} + return fileDescriptor_16596a15a828f109, []int{10} } func (m *UndelegationResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -563,7 +619,7 @@ var xxx_messageInfo_UndelegationResponse proto.InternalMessageInfo func init() { proto.RegisterType((*ValueField)(nil), "exocore.delegation.v1.ValueField") proto.RegisterType((*DelegatedSingleAssetInfo)(nil), "exocore.delegation.v1.DelegatedSingleAssetInfo") - proto.RegisterMapType((map[string]*ValueField)(nil), "exocore.delegation.v1.DelegatedSingleAssetInfo.PerOperatorAmountsEntry") + proto.RegisterType((*KeyValue)(nil), "exocore.delegation.v1.KeyValue") proto.RegisterType((*DelegationApproveInfo)(nil), "exocore.delegation.v1.DelegationApproveInfo") proto.RegisterType((*DelegationIncOrDecInfo)(nil), "exocore.delegation.v1.DelegationIncOrDecInfo") proto.RegisterMapType((map[string]*ValueField)(nil), "exocore.delegation.v1.DelegationIncOrDecInfo.PerOperatorAmountsEntry") @@ -578,67 +634,67 @@ func init() { func init() { proto.RegisterFile("exocore/delegation/v1/tx.proto", fileDescriptor_16596a15a828f109) } var fileDescriptor_16596a15a828f109 = []byte{ - // 959 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0x41, 0x6f, 0xe3, 0x44, - 0x14, 0x8e, 0x9b, 0xb6, 0x49, 0x5e, 0x52, 0x01, 0x43, 0xda, 0xa4, 0x01, 0x92, 0xae, 0x05, 0x55, - 0xb6, 0xd0, 0x44, 0x1b, 0x10, 0xa0, 0x05, 0x0e, 0x29, 0xe9, 0x42, 0x80, 0x76, 0x17, 0xb7, 0x70, - 0x40, 0x42, 0x96, 0x63, 0x4f, 0x1d, 0x13, 0xdb, 0x63, 0xcd, 0x4c, 0xba, 0xc9, 0x9e, 0x10, 0x27, - 0xc4, 0x89, 0x3b, 0x97, 0xe5, 0x0f, 0xa0, 0x1e, 0xf6, 0x47, 0xec, 0x71, 0xb5, 0x27, 0xc4, 0xa1, - 0x42, 0xe9, 0xa1, 0x1c, 0xf8, 0x09, 0x1c, 0x90, 0x67, 0xec, 0xc4, 0x65, 0x37, 0x5b, 0x21, 0xf5, - 0xb0, 0x97, 0xc4, 0xf3, 0xde, 0x9b, 0xef, 0x7b, 0x6f, 0xbe, 0xe7, 0xe7, 0x81, 0x2a, 0x1e, 0x11, - 0x93, 0x50, 0xdc, 0xb4, 0xb0, 0x8b, 0x6d, 0x83, 0x3b, 0xc4, 0x6f, 0x1e, 0xdf, 0x68, 0xf2, 0x51, - 0x23, 0xa0, 0x84, 0x13, 0xb4, 0x1a, 0xf9, 0x1b, 0x33, 0x7f, 0xe3, 0xf8, 0x46, 0xe5, 0x25, 0xc3, - 0x73, 0x7c, 0xd2, 0x14, 0xbf, 0x32, 0xb2, 0x52, 0x32, 0x09, 0xf3, 0x08, 0x6b, 0x7a, 0xcc, 0x0e, - 0x11, 0x3c, 0x66, 0x47, 0x8e, 0x75, 0xe9, 0xd0, 0xc5, 0xaa, 0x29, 0x17, 0x91, 0xab, 0x68, 0x13, - 0x9b, 0x48, 0x7b, 0xf8, 0x24, 0xad, 0x6a, 0x0f, 0xe0, 0x6b, 0xc3, 0x1d, 0xe2, 0x5b, 0x0e, 0x76, - 0x2d, 0x74, 0x08, 0xcb, 0x86, 0x47, 0x86, 0x3e, 0x2f, 0x2b, 0x1b, 0x4a, 0x3d, 0xb7, 0xf3, 0xe1, - 0xc3, 0xd3, 0x5a, 0xea, 0x8f, 0xd3, 0xda, 0xa6, 0xed, 0xf0, 0xfe, 0xb0, 0xd7, 0x30, 0x89, 0x17, - 0x81, 0x46, 0x7f, 0xdb, 0xcc, 0x1a, 0x34, 0xf9, 0x38, 0xc0, 0xac, 0xd1, 0xf5, 0xf9, 0xe3, 0x07, - 0xdb, 0x10, 0x71, 0x76, 0x7d, 0xae, 0x45, 0x58, 0xea, 0x2f, 0x69, 0x28, 0x77, 0x64, 0x49, 0xd8, - 0x3a, 0x70, 0x7c, 0xdb, 0xc5, 0x6d, 0xc6, 0x30, 0xef, 0xfa, 0x47, 0x04, 0x6d, 0x42, 0xd6, 0x08, - 0x17, 0xba, 0x63, 0x45, 0xa4, 0xf9, 0xc9, 0x69, 0x2d, 0x23, 0x03, 0x3a, 0x5a, 0x46, 0x38, 0xbb, - 0x16, 0xa2, 0xb0, 0xc6, 0x09, 0x37, 0x5c, 0xdd, 0x8a, 0x91, 0xf4, 0x28, 0xd5, 0x85, 0x2b, 0x48, - 0xb5, 0x28, 0xb0, 0xa7, 0x49, 0xb6, 0x05, 0x32, 0x1a, 0x43, 0x31, 0xc0, 0x54, 0x27, 0x01, 0xa6, - 0x06, 0x27, 0x34, 0x22, 0x64, 0xe5, 0xf4, 0x46, 0xba, 0x9e, 0x6f, 0x7d, 0xd2, 0x78, 0xaa, 0x5e, - 0x8d, 0x79, 0xa5, 0x36, 0xee, 0x60, 0x7a, 0x3b, 0x82, 0x92, 0x04, 0x6c, 0xd7, 0xe7, 0x74, 0xac, - 0xa1, 0xe0, 0x09, 0x47, 0xa5, 0x0f, 0xa5, 0x39, 0xe1, 0xe8, 0x45, 0x48, 0x0f, 0xf0, 0x58, 0x1e, - 0x96, 0x16, 0x3e, 0xa2, 0xf7, 0x60, 0xe9, 0x38, 0x14, 0x51, 0x1c, 0x45, 0xbe, 0x75, 0x6d, 0x4e, - 0x62, 0x33, 0xa1, 0x35, 0x19, 0x7f, 0x73, 0xe1, 0x7d, 0x45, 0xed, 0xc2, 0x6a, 0x67, 0x1a, 0xd6, - 0x0e, 0x02, 0x4a, 0x8e, 0xb1, 0x50, 0xe6, 0x55, 0xc8, 0x31, 0xc7, 0xf6, 0x0d, 0x3e, 0xa4, 0x38, - 0x62, 0x9b, 0x19, 0x10, 0x82, 0x45, 0x66, 0xb8, 0xd1, 0xe9, 0x6b, 0xe2, 0x59, 0xfd, 0x67, 0x01, - 0xd6, 0x66, 0x58, 0x5d, 0xdf, 0xbc, 0x4d, 0x3b, 0xd8, 0x14, 0x60, 0x1f, 0x40, 0xe1, 0x88, 0x12, - 0x4f, 0x37, 0x2c, 0x8b, 0x62, 0xc6, 0x22, 0xa9, 0xcb, 0x8f, 0x1f, 0x6c, 0x17, 0x23, 0x19, 0xda, - 0xd2, 0x73, 0xc0, 0xa9, 0xe3, 0xdb, 0x5a, 0x3e, 0x8c, 0x8e, 0x4c, 0xe8, 0xee, 0x1c, 0x1d, 0x16, - 0x84, 0x0e, 0xbb, 0xcf, 0xd6, 0xe1, 0x3f, 0x99, 0x3c, 0x9f, 0x2a, 0xdc, 0xdc, 0xf9, 0xf1, 0x7e, - 0x2d, 0xf5, 0xd7, 0xfd, 0x5a, 0xea, 0x87, 0xf3, 0x93, 0xad, 0x64, 0xf1, 0x3f, 0x9d, 0x9f, 0x6c, - 0xbd, 0x91, 0xe8, 0xe0, 0x3d, 0x66, 0xb7, 0x2d, 0x4b, 0x94, 0x43, 0xb1, 0xc1, 0xf0, 0xac, 0x4a, - 0xf5, 0x37, 0x05, 0x56, 0xf6, 0x98, 0x3d, 0xb3, 0xa0, 0xcf, 0x20, 0xd7, 0x33, 0x18, 0xd6, 0x1d, - 0xff, 0x88, 0x88, 0x54, 0xf3, 0xad, 0xed, 0xff, 0x75, 0x5a, 0x5a, 0x36, 0xdc, 0x2f, 0x14, 0xfc, - 0x12, 0x56, 0x0c, 0xd9, 0x1d, 0x96, 0xc4, 0x93, 0x65, 0xbe, 0x75, 0x29, 0x5e, 0xa2, 0xa7, 0xb4, - 0x42, 0x0c, 0x11, 0xae, 0xd4, 0x5f, 0x17, 0x01, 0x7d, 0xe5, 0xcf, 0xf6, 0x69, 0xd8, 0x24, 0xd4, - 0x42, 0xd7, 0x21, 0xc7, 0xb8, 0x31, 0xc0, 0x74, 0x36, 0x13, 0x0a, 0x93, 0xd3, 0x5a, 0xf6, 0x40, - 0x18, 0xbb, 0x1d, 0x2d, 0x2b, 0xdd, 0x5d, 0xeb, 0xc2, 0xf4, 0x58, 0x78, 0xc6, 0xf4, 0xf8, 0x08, - 0x56, 0x66, 0xdd, 0x63, 0x59, 0xb4, 0x9c, 0xbe, 0xa4, 0xff, 0x0a, 0x71, 0x78, 0x68, 0x46, 0x25, - 0xc8, 0xf0, 0x91, 0xde, 0x37, 0x58, 0xbf, 0xbc, 0x28, 0x04, 0x5f, 0xe6, 0xa3, 0x4f, 0x0d, 0xd6, - 0x47, 0xaf, 0x01, 0x38, 0x4c, 0x0f, 0xb0, 0x6f, 0x39, 0xbe, 0x5d, 0x5e, 0xda, 0x50, 0xea, 0x59, - 0x2d, 0xe7, 0xb0, 0x3b, 0xd2, 0x80, 0xae, 0x41, 0xa1, 0xe7, 0x12, 0x73, 0xa0, 0xfb, 0x43, 0xaf, - 0x87, 0x69, 0x79, 0x79, 0x43, 0xa9, 0x2f, 0x6a, 0x79, 0x61, 0xdb, 0x17, 0x26, 0xd4, 0x82, 0x55, - 0x93, 0x78, 0x81, 0x8b, 0x39, 0xd6, 0x2f, 0xc4, 0x66, 0x44, 0xec, 0xcb, 0xb1, 0x73, 0x27, 0xb1, - 0xa7, 0x0a, 0x79, 0xf7, 0x9e, 0xce, 0x47, 0xba, 0x4f, 0x7c, 0x13, 0x97, 0xb3, 0x22, 0x32, 0xe7, - 0xde, 0x3b, 0x1c, 0xed, 0x87, 0x86, 0xc4, 0x18, 0xcf, 0x5d, 0xdd, 0x18, 0x47, 0x1c, 0x4a, 0x86, - 0xc9, 0x87, 0x86, 0xab, 0xc7, 0x39, 0x4d, 0x47, 0x30, 0x5c, 0x01, 0xcd, 0xaa, 0x04, 0xff, 0x38, - 0xc6, 0x96, 0x6f, 0x9b, 0xfa, 0x2e, 0xac, 0x3f, 0xd9, 0x22, 0x9f, 0xe3, 0xf1, 0x17, 0x0e, 0xe3, - 0x68, 0x1d, 0xb2, 0x03, 0x3c, 0xd6, 0x5d, 0x87, 0x85, 0x5f, 0xac, 0x74, 0x3d, 0xa7, 0x65, 0x06, - 0xd2, 0xa5, 0x16, 0x01, 0x75, 0x12, 0xbb, 0x58, 0x40, 0x7c, 0x86, 0xd5, 0x6f, 0xe1, 0x85, 0x3d, - 0x66, 0x27, 0x01, 0xaf, 0xf2, 0x1d, 0x51, 0xd7, 0xa0, 0x78, 0x31, 0x59, 0x49, 0xdb, 0xfa, 0x5b, - 0x81, 0xf4, 0x1e, 0xb3, 0xd1, 0x77, 0x50, 0x8a, 0xbf, 0x0e, 0xa2, 0x45, 0x0f, 0x49, 0x3c, 0x5b, - 0xd0, 0xeb, 0x73, 0x38, 0x2f, 0xbc, 0xd0, 0x95, 0xeb, 0x97, 0x66, 0x16, 0x73, 0x22, 0x0a, 0xaf, - 0x4c, 0x73, 0x91, 0x6c, 0xb7, 0x28, 0xf1, 0xa6, 0x7c, 0x9b, 0xf3, 0xf9, 0x92, 0x25, 0x54, 0xde, - 0x9c, 0x13, 0xf7, 0xb4, 0x3a, 0x2b, 0x4b, 0xdf, 0x9f, 0x9f, 0x6c, 0x29, 0x3b, 0xfb, 0x0f, 0x27, - 0x55, 0xe5, 0xd1, 0xa4, 0xaa, 0xfc, 0x39, 0xa9, 0x2a, 0x3f, 0x9f, 0x55, 0x53, 0x8f, 0xce, 0xaa, - 0xa9, 0xdf, 0xcf, 0xaa, 0xa9, 0x6f, 0xde, 0x49, 0xb4, 0xc6, 0xae, 0xc4, 0xdd, 0xc7, 0xfc, 0x2e, - 0xa1, 0x83, 0x66, 0x7c, 0x39, 0x1a, 0x25, 0xaf, 0x47, 0xa2, 0x59, 0x7a, 0xcb, 0xe2, 0xae, 0xf2, - 0xf6, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xb9, 0xd3, 0x67, 0x2f, 0x41, 0x09, 0x00, 0x00, + // 952 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x41, 0x6f, 0xe3, 0x44, + 0x14, 0x8e, 0x9b, 0x6e, 0x9b, 0xbc, 0xb4, 0x02, 0x86, 0x74, 0xe3, 0x06, 0x48, 0xb2, 0x16, 0x54, + 0xd9, 0x42, 0x13, 0x6d, 0x40, 0x80, 0x16, 0x38, 0x24, 0xa4, 0x2b, 0xc2, 0xd2, 0xee, 0xe2, 0x76, + 0x41, 0x42, 0x42, 0x96, 0x63, 0x4f, 0x1d, 0x13, 0xdb, 0x63, 0xcd, 0x4c, 0xba, 0xc9, 0x9e, 0x10, + 0x27, 0xc4, 0x89, 0x3b, 0x97, 0xe5, 0x0f, 0xa0, 0x1e, 0xf6, 0x47, 0xec, 0x71, 0xb5, 0x27, 0xc4, + 0xa1, 0x42, 0xe9, 0xa1, 0x1c, 0xf8, 0x09, 0x1c, 0x90, 0x67, 0xec, 0xc6, 0xd5, 0x36, 0x54, 0x48, + 0xbd, 0x24, 0x9e, 0xf7, 0xbe, 0xf9, 0xbe, 0xf7, 0xde, 0xbc, 0x67, 0x0f, 0x54, 0xf0, 0x98, 0x58, + 0x84, 0xe2, 0xa6, 0x8d, 0x3d, 0xec, 0x98, 0xdc, 0x25, 0x41, 0xf3, 0xf0, 0x56, 0x93, 0x8f, 0x1b, + 0x21, 0x25, 0x9c, 0xa0, 0xb5, 0xd8, 0xdf, 0x98, 0xf9, 0x1b, 0x87, 0xb7, 0xca, 0xaf, 0x98, 0xbe, + 0x1b, 0x90, 0xa6, 0xf8, 0x95, 0xc8, 0x72, 0xc9, 0x22, 0xcc, 0x27, 0xac, 0xe9, 0x33, 0x27, 0x62, + 0xf0, 0x99, 0x13, 0x3b, 0xd6, 0xa5, 0xc3, 0x10, 0xab, 0xa6, 0x5c, 0xc4, 0xae, 0xa2, 0x43, 0x1c, + 0x22, 0xed, 0xd1, 0x93, 0xb4, 0x6a, 0x7d, 0x80, 0xaf, 0x4c, 0x6f, 0x84, 0xef, 0xb8, 0xd8, 0xb3, + 0xd1, 0x3e, 0x2c, 0x99, 0x3e, 0x19, 0x05, 0x5c, 0x55, 0x6a, 0x4a, 0x3d, 0xdf, 0xf9, 0xf8, 0xe9, + 0x71, 0x35, 0xf3, 0xc7, 0x71, 0x75, 0xc3, 0x71, 0xf9, 0x60, 0xd4, 0x6f, 0x58, 0xc4, 0x8f, 0x49, + 0xe3, 0xbf, 0x2d, 0x66, 0x0f, 0x9b, 0x7c, 0x12, 0x62, 0xd6, 0xe8, 0x05, 0xfc, 0xf9, 0x93, 0x2d, + 0x88, 0x35, 0x7b, 0x01, 0xd7, 0x63, 0x2e, 0xed, 0x17, 0x05, 0xd4, 0xae, 0x4c, 0x09, 0xdb, 0x7b, + 0x6e, 0xe0, 0x78, 0xb8, 0xcd, 0x18, 0xe6, 0xbd, 0xe0, 0x80, 0xa0, 0x0d, 0xc8, 0x99, 0xd1, 0xc2, + 0x70, 0xed, 0x58, 0xb4, 0x30, 0x3d, 0xae, 0x2e, 0x4b, 0x40, 0x57, 0x5f, 0x16, 0xce, 0x9e, 0x8d, + 0xbe, 0x86, 0x62, 0x88, 0xa9, 0x41, 0x42, 0x4c, 0x4d, 0x4e, 0xa8, 0x21, 0xb9, 0x99, 0x9a, 0xad, + 0x65, 0xeb, 0x85, 0x56, 0xb5, 0x71, 0x61, 0xed, 0x1a, 0x77, 0xf1, 0x44, 0xa4, 0xd7, 0x59, 0x8c, + 0x32, 0xd1, 0x51, 0x88, 0xe9, 0xbd, 0x98, 0xa1, 0x2d, 0x09, 0xb4, 0x07, 0x90, 0x4b, 0x50, 0xe8, + 0x65, 0xc8, 0x0e, 0xf1, 0x44, 0xc6, 0xa1, 0x47, 0x8f, 0xe8, 0x03, 0xb8, 0x76, 0x18, 0xb9, 0xd4, + 0x85, 0x9a, 0x52, 0x2f, 0xb4, 0x6e, 0xcc, 0xd1, 0x99, 0xd5, 0x50, 0x97, 0x78, 0xad, 0x07, 0x6b, + 0xdd, 0x33, 0x48, 0x3b, 0x0c, 0x29, 0x39, 0xc4, 0x22, 0xe1, 0xd7, 0x21, 0xcf, 0x5c, 0x27, 0x30, + 0xf9, 0x88, 0xe2, 0x58, 0x69, 0x66, 0x40, 0x08, 0x16, 0x99, 0xe9, 0x71, 0x21, 0x97, 0xd7, 0xc5, + 0xb3, 0xf6, 0xcf, 0x02, 0x5c, 0x9f, 0x71, 0xf5, 0x02, 0xeb, 0x1e, 0xed, 0x62, 0x4b, 0x90, 0x7d, + 0x04, 0x2b, 0x07, 0x94, 0xf8, 0x86, 0x69, 0xdb, 0x14, 0x33, 0x16, 0x57, 0x50, 0x7d, 0xfe, 0x64, + 0xab, 0x18, 0x1f, 0x44, 0x5b, 0x7a, 0xf6, 0x38, 0x75, 0x03, 0x47, 0x2f, 0x44, 0xe8, 0xd8, 0x84, + 0x1e, 0xce, 0x29, 0xe9, 0x82, 0x28, 0xe9, 0xf6, 0x9c, 0x54, 0x2f, 0x8e, 0xa4, 0x71, 0xff, 0x85, + 0xca, 0x6e, 0x07, 0x9c, 0x4e, 0x2e, 0x2a, 0x79, 0x79, 0x00, 0xa5, 0x39, 0xf0, 0x2b, 0x3c, 0x81, + 0xdb, 0x0b, 0x1f, 0x2a, 0xb7, 0x3b, 0x3f, 0x3e, 0xae, 0x66, 0xfe, 0x7a, 0x5c, 0xcd, 0xfc, 0x70, + 0x7a, 0xb4, 0x99, 0x4e, 0xfe, 0xa7, 0xd3, 0xa3, 0xcd, 0xb7, 0x52, 0x3d, 0xbc, 0xc3, 0x9c, 0xb6, + 0x6d, 0x8b, 0x74, 0x28, 0x36, 0x19, 0x9e, 0x65, 0xa9, 0xfd, 0xa6, 0xc0, 0xea, 0x0e, 0x73, 0x66, + 0x16, 0xf4, 0x39, 0xe4, 0xfb, 0x26, 0xc3, 0x86, 0x1b, 0x1c, 0x10, 0x11, 0x6a, 0xa1, 0xb5, 0xf5, + 0xbf, 0xaa, 0xa5, 0xe7, 0xa2, 0xfd, 0xe2, 0x04, 0xbf, 0x84, 0x55, 0x53, 0x76, 0x87, 0x2d, 0xf9, + 0x64, 0x9a, 0xef, 0x5c, 0xca, 0x97, 0xea, 0x29, 0x7d, 0x25, 0xa1, 0x88, 0x56, 0xda, 0xaf, 0x8b, + 0x80, 0x1e, 0x04, 0xb3, 0x7d, 0x3a, 0xb6, 0x08, 0xb5, 0xd1, 0x4d, 0xc8, 0x33, 0x6e, 0x0e, 0x31, + 0x9d, 0x8d, 0xda, 0xca, 0xf4, 0xb8, 0x9a, 0xdb, 0x13, 0xc6, 0x5e, 0x57, 0xcf, 0x49, 0x77, 0xcf, + 0x3e, 0x37, 0x94, 0x0b, 0xff, 0x31, 0x94, 0x9f, 0xc0, 0xea, 0xac, 0x7b, 0x6c, 0x9b, 0xaa, 0xd9, + 0x4b, 0xfa, 0x6f, 0x25, 0x81, 0x47, 0x66, 0x54, 0x82, 0x65, 0x3e, 0x36, 0x06, 0x26, 0x1b, 0xa8, + 0x8b, 0xe2, 0xc0, 0x97, 0xf8, 0xf8, 0x33, 0x93, 0x0d, 0xd0, 0x1b, 0x00, 0x2e, 0x33, 0x42, 0x1c, + 0xd8, 0x6e, 0xe0, 0xa8, 0xd7, 0x6a, 0x4a, 0x3d, 0xa7, 0xe7, 0x5d, 0x76, 0x5f, 0x1a, 0xd0, 0x0d, + 0x58, 0xe9, 0x7b, 0xc4, 0x1a, 0x1a, 0xc1, 0xc8, 0xef, 0x63, 0xaa, 0x2e, 0xd5, 0x94, 0xfa, 0xa2, + 0x5e, 0x10, 0xb6, 0x5d, 0x61, 0x42, 0x2d, 0x58, 0xb3, 0x88, 0x1f, 0x7a, 0x98, 0x63, 0xe3, 0x1c, + 0x76, 0x59, 0x60, 0x5f, 0x4d, 0x9c, 0x9d, 0xd4, 0x9e, 0x0a, 0x14, 0xbc, 0x47, 0x06, 0x1f, 0x1b, + 0x01, 0x09, 0x2c, 0xac, 0xe6, 0x04, 0x32, 0xef, 0x3d, 0xda, 0x1f, 0xef, 0x46, 0x86, 0xd4, 0xdb, + 0x31, 0x7f, 0x75, 0x6f, 0x47, 0xc4, 0xa1, 0x64, 0x5a, 0x7c, 0x64, 0x7a, 0x46, 0x12, 0x93, 0x1d, + 0x4f, 0xa2, 0x0a, 0x57, 0x20, 0xb3, 0x26, 0xc9, 0x3f, 0x4d, 0xb8, 0xe5, 0xb4, 0x69, 0xef, 0xc3, + 0xfa, 0x8b, 0x2d, 0x72, 0x17, 0x4f, 0xbe, 0x70, 0x19, 0x47, 0xeb, 0x90, 0x1b, 0xe2, 0x89, 0xe1, + 0xb9, 0x2c, 0xfa, 0x10, 0x64, 0xeb, 0x79, 0x7d, 0x79, 0x28, 0x5d, 0x5a, 0x11, 0x50, 0x37, 0xb5, + 0x8b, 0x85, 0x24, 0x60, 0x58, 0xfb, 0x16, 0x5e, 0xda, 0x61, 0x4e, 0x9a, 0xf0, 0x2a, 0x67, 0x44, + 0xbb, 0x0e, 0xc5, 0xf3, 0xc1, 0x4a, 0xd9, 0xd6, 0xdf, 0x0a, 0x64, 0x77, 0x98, 0x83, 0xbe, 0x83, + 0x52, 0xf2, 0x7d, 0x11, 0x2d, 0xba, 0x4f, 0x92, 0x77, 0x0b, 0x7a, 0x73, 0x8e, 0xe6, 0xb9, 0x81, + 0x2e, 0xdf, 0xbc, 0x34, 0xb2, 0x44, 0x13, 0x51, 0x78, 0xed, 0x2c, 0x16, 0xa9, 0x76, 0x87, 0x12, + 0xff, 0x4c, 0x6f, 0x63, 0xbe, 0x5e, 0x3a, 0x85, 0xf2, 0xdb, 0x73, 0x70, 0x17, 0xe5, 0x59, 0xbe, + 0xf6, 0xfd, 0xe9, 0xd1, 0xa6, 0xd2, 0xd9, 0x7d, 0x3a, 0xad, 0x28, 0xcf, 0xa6, 0x15, 0xe5, 0xcf, + 0x69, 0x45, 0xf9, 0xf9, 0xa4, 0x92, 0x79, 0x76, 0x52, 0xc9, 0xfc, 0x7e, 0x52, 0xc9, 0x7c, 0xf3, + 0x5e, 0xaa, 0x35, 0xb6, 0x25, 0xef, 0x2e, 0xe6, 0x0f, 0x09, 0x1d, 0x36, 0x93, 0x3b, 0xc7, 0x38, + 0x7d, 0xeb, 0x10, 0xcd, 0xd2, 0x5f, 0x12, 0x57, 0x80, 0x77, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, + 0xd6, 0xc6, 0x2e, 0x6c, 0x98, 0x08, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -815,41 +871,19 @@ func (m *DelegatedSingleAssetInfo) MarshalToSizedBuffer(dAtA []byte) (int, error var l int _ = l if len(m.PerOperatorAmounts) > 0 { - for k := range m.PerOperatorAmounts { - v := m.PerOperatorAmounts[k] - baseI := i - if v != nil { - { - size, err := v.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) + for iNdEx := len(m.PerOperatorAmounts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.PerOperatorAmounts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0x12 + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) } - i -= len(k) - copy(dAtA[i:], k) - i = encodeVarintTx(dAtA, i, uint64(len(k))) - i-- - dAtA[i] = 0xa - i = encodeVarintTx(dAtA, i, uint64(baseI-i)) i-- dAtA[i] = 0x1a } } - { - size := m.TotalDelegatedAmount.Size() - i -= size - if _, err := m.TotalDelegatedAmount.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 if len(m.AssetID) > 0 { i -= len(m.AssetID) copy(dAtA[i:], m.AssetID) @@ -860,6 +894,48 @@ func (m *DelegatedSingleAssetInfo) MarshalToSizedBuffer(dAtA []byte) (int, error return len(dAtA) - i, nil } +func (m *KeyValue) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *KeyValue) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *KeyValue) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Value != nil { + { + size, err := m.Value.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintTx(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *DelegationApproveInfo) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1241,24 +1317,32 @@ func (m *DelegatedSingleAssetInfo) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = m.TotalDelegatedAmount.Size() - n += 1 + l + sovTx(uint64(l)) if len(m.PerOperatorAmounts) > 0 { - for k, v := range m.PerOperatorAmounts { - _ = k - _ = v - l = 0 - if v != nil { - l = v.Size() - l += 1 + sovTx(uint64(l)) - } - mapEntrySize := 1 + len(k) + sovTx(uint64(len(k))) + l - n += mapEntrySize + 1 + sovTx(uint64(mapEntrySize)) + for _, e := range m.PerOperatorAmounts { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) } } return n } +func (m *KeyValue) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Key) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.Value != nil { + l = m.Value.Size() + n += 1 + l + sovTx(uint64(l)) + } + return n +} + func (m *DelegationApproveInfo) Size() (n int) { if m == nil { return 0 @@ -1557,9 +1641,93 @@ func (m *DelegatedSingleAssetInfo) Unmarshal(dAtA []byte) error { } m.AssetID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 2: + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PerOperatorAmounts", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PerOperatorAmounts = append(m.PerOperatorAmounts, KeyValue{}) + if err := m.PerOperatorAmounts[len(m.PerOperatorAmounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *KeyValue) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: KeyValue: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: KeyValue: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalDelegatedAmount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1587,13 +1755,11 @@ func (m *DelegatedSingleAssetInfo) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.TotalDelegatedAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Key = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PerOperatorAmounts", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1620,105 +1786,12 @@ func (m *DelegatedSingleAssetInfo) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.PerOperatorAmounts == nil { - m.PerOperatorAmounts = make(map[string]*ValueField) + if m.Value == nil { + m.Value = &ValueField{} } - var mapkey string - var mapvalue *ValueField - for iNdEx < postIndex { - entryPreIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - if fieldNum == 1 { - var stringLenmapkey uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLenmapkey |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLenmapkey := int(stringLenmapkey) - if intStringLenmapkey < 0 { - return ErrInvalidLengthTx - } - postStringIndexmapkey := iNdEx + intStringLenmapkey - if postStringIndexmapkey < 0 { - return ErrInvalidLengthTx - } - if postStringIndexmapkey > l { - return io.ErrUnexpectedEOF - } - mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) - iNdEx = postStringIndexmapkey - } else if fieldNum == 2 { - var mapmsglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - mapmsglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if mapmsglen < 0 { - return ErrInvalidLengthTx - } - postmsgIndex := iNdEx + mapmsglen - if postmsgIndex < 0 { - return ErrInvalidLengthTx - } - if postmsgIndex > l { - return io.ErrUnexpectedEOF - } - mapvalue = &ValueField{} - if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil { - return err - } - iNdEx = postmsgIndex - } else { - iNdEx = entryPreIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > postIndex { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } + if err := m.Value.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } - m.PerOperatorAmounts[mapkey] = mapvalue iNdEx = postIndex default: iNdEx = preIndex diff --git a/x/dogfood/keeper/impl_sdk.go b/x/dogfood/keeper/impl_sdk.go index 5b342af5c..7986c2950 100644 --- a/x/dogfood/keeper/impl_sdk.go +++ b/x/dogfood/keeper/impl_sdk.go @@ -13,7 +13,11 @@ import ( // interface guards var ( + // the slashing module is responsible for downtime slashing. it tracks signing info and then + // asks the staking module (dogfood in our case) to slash the operator. _ slashingtypes.StakingKeeper = Keeper{} + // the evidence module is responsible for handling equivocation evidence. it validates the + // evidence and then asks the staking module (dogfood in our case) to slash the operator. _ evidencetypes.StakingKeeper = Keeper{} _ genutiltypes.StakingKeeper = Keeper{} _ clienttypes.StakingKeeper = Keeper{} // implemented in `validators.go` @@ -26,11 +30,8 @@ func (k Keeper) GetParams(sdk.Context) stakingtypes.Params { } // IterateValidators is an implementation of the staking interface expected by the SDK's -// slashing module. The slashing module uses it for two purposes: once at genesis to -// store a mapping of pub key to cons address (which is done by our operator module), -// and then during the invariants check to ensure that the total delegated amount -// matches that of each validator. Ideally, this invariant should be implemented -// by the delegation and/or deposit module(s) instead. +// slashing module. The slashing module uses it at genesis to store a mapping of pub key +// to cons address (which is done by our operator module), func (k Keeper) IterateValidators(sdk.Context, func(index int64, validator stakingtypes.ValidatorI) (stop bool), ) { diff --git a/x/evm/keeper/precompiles.go b/x/evm/keeper/precompiles.go index a26d157bc..1246457ea 100644 --- a/x/evm/keeper/precompiles.go +++ b/x/evm/keeper/precompiles.go @@ -19,25 +19,19 @@ import ( withdrawPrecompile "github.com/ExocoreNetwork/exocore/precompiles/withdraw" exoslashKeeper "github.com/ExocoreNetwork/exocore/x/slash/keeper" authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" - distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" channelkeeper "github.com/cosmos/ibc-go/v7/modules/core/04-channel/keeper" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" - distprecompile "github.com/evmos/evmos/v14/precompiles/distribution" ics20precompile "github.com/evmos/evmos/v14/precompiles/ics20" stakingprecompile "github.com/evmos/evmos/v14/precompiles/staking" - vestingprecompile "github.com/evmos/evmos/v14/precompiles/vesting" transferkeeper "github.com/evmos/evmos/v14/x/ibc/transfer/keeper" - vestingkeeper "github.com/evmos/evmos/v14/x/vesting/keeper" ) // AvailablePrecompiles returns the list of all available precompiled contracts. // NOTE: this should only be used during initialization of the Keeper. func AvailablePrecompiles( stakingKeeper stakingkeeper.Keeper, - distributionKeeper distributionkeeper.Keeper, - vestingKeeper vestingkeeper.Keeper, authzKeeper authzkeeper.Keeper, transferKeeper transferkeeper.Keeper, channelKeeper channelkeeper.Keeper, @@ -56,39 +50,53 @@ func AvailablePrecompiles( panic(fmt.Errorf("failed to load staking precompile: %w", err)) } - distributionPrecompile, err := distprecompile.NewPrecompile(distributionKeeper, authzKeeper) - if err != nil { - panic(fmt.Errorf("failed to load distribution precompile: %w", err)) - } - - ibcTransferPrecompile, err := ics20precompile.NewPrecompile(transferKeeper, channelKeeper, authzKeeper) + ibcTransferPrecompile, err := ics20precompile.NewPrecompile( + transferKeeper, + channelKeeper, + authzKeeper, + ) if err != nil { panic(fmt.Errorf("failed to load ICS20 precompile: %w", err)) } - vestingPrecompile, err := vestingprecompile.NewPrecompile(vestingKeeper, authzKeeper) - if err != nil { - panic(fmt.Errorf("failed to load vesting precompile: %w", err)) - } - // add exoCore chain preCompiles - depositPrecompile, err := depositprecompile.NewPrecompile(stakingStateKeeper, depositKeeper, authzKeeper) + depositPrecompile, err := depositprecompile.NewPrecompile( + stakingStateKeeper, + depositKeeper, + authzKeeper, + ) if err != nil { panic(fmt.Errorf("failed to load deposit precompile: %w", err)) } - delegationPrecompile, err := delegationprecompile.NewPrecompile(stakingStateKeeper, delegationKeeper, authzKeeper) + delegationPrecompile, err := delegationprecompile.NewPrecompile( + stakingStateKeeper, + delegationKeeper, + authzKeeper, + ) if err != nil { panic(fmt.Errorf("failed to load delegation precompile: %w", err)) } - withdrawPrecompile, err := withdrawPrecompile.NewPrecompile(stakingStateKeeper, withdrawKeeper, authzKeeper) + withdrawPrecompile, err := withdrawPrecompile.NewPrecompile( + stakingStateKeeper, + withdrawKeeper, + authzKeeper, + ) if err != nil { panic(fmt.Errorf("failed to load withdraw precompile: %w", err)) } - slashPrecompile, err := slashPrecompile.NewPrecompile(stakingStateKeeper, slashKeeper, authzKeeper) + slashPrecompile, err := slashPrecompile.NewPrecompile( + stakingStateKeeper, + slashKeeper, + authzKeeper, + ) if err != nil { panic(fmt.Errorf("failed to load slash precompile: %w", err)) } - rewardPrecompile, err := rewardPrecompile.NewPrecompile(stakingStateKeeper, rewardKeeper, authzKeeper) + rewardPrecompile, err := rewardPrecompile.NewPrecompile( + stakingStateKeeper, + rewardKeeper, + authzKeeper, + ) if err != nil { panic(fmt.Errorf("failed to load reward precompile: %w", err)) } @@ -99,14 +107,14 @@ func AvailablePrecompiles( precompiles[delegationPrecompile.Address()] = delegationPrecompile precompiles[stakingPrecompile.Address()] = stakingPrecompile - precompiles[distributionPrecompile.Address()] = distributionPrecompile - precompiles[vestingPrecompile.Address()] = vestingPrecompile precompiles[ibcTransferPrecompile.Address()] = ibcTransferPrecompile return precompiles } // WithPrecompiles sets the available precompiled contracts. -func (k *Keeper) WithPrecompiles(precompiles map[common.Address]vm.PrecompiledContract) *Keeper { +func (k *Keeper) WithPrecompiles( + precompiles map[common.Address]vm.PrecompiledContract, +) *Keeper { if k.precompiles != nil { panic("available precompiles map already set") } diff --git a/x/evm/types/params.go b/x/evm/types/params.go index 0dcacfceb..6349ee5ee 100644 --- a/x/evm/types/params.go +++ b/x/evm/types/params.go @@ -11,9 +11,7 @@ var ( DefaultEVMDenom = utils.BaseDenom ExocoreAvailableEVMExtensions = []string{ "0x0000000000000000000000000000000000000800", // Staking precompile - "0x0000000000000000000000000000000000000801", // Distribution precompile "0x0000000000000000000000000000000000000802", // ICS20 transfer precompile - "0x0000000000000000000000000000000000000803", // Vesting precompile "0x0000000000000000000000000000000000000804", // deposit precompile "0x0000000000000000000000000000000000000805", // delegation precompile "0x0000000000000000000000000000000000000806", // reward precompile @@ -24,8 +22,6 @@ var ( // ExocoreEvmDefaultParams returns default evm parameters // ExtraEIPs is empty to prevent overriding the latest hard fork instruction set -// ActivePrecompiles is empty to prevent overriding the default precompiles -// from the EVM configuration. func ExocoreEvmDefaultParams() evmtype.Params { return evmtype.Params{ EvmDenom: DefaultEVMDenom, diff --git a/x/operator/keeper/consensus_keys.go b/x/operator/keeper/consensus_keys.go index 52d154573..0c2a3c614 100644 --- a/x/operator/keeper/consensus_keys.go +++ b/x/operator/keeper/consensus_keys.go @@ -24,19 +24,33 @@ func (k *Keeper) Logger(ctx sdk.Context) log.Logger { // and chain id. By doing this, an operator is consenting to be an operator on the given chain. // If a key already exists, it will be overwritten and the change in voting power will flow // through to the validator set. +// TODO: Rationalize with k.OptIn func (k *Keeper) SetOperatorConsKeyForChainID( ctx sdk.Context, opAccAddr sdk.AccAddress, chainID string, // should be tm-ed25519 - consKey tmprotocrypto.PublicKey, + consKey *tmprotocrypto.PublicKey, +) error { + return k.setOperatorConsKeyForChainID(ctx, opAccAddr, chainID, consKey, false) +} + +// setOperatorConsKeyForChainID is the private version of SetOperatorConsKeyForChainID. +// it is used with a boolean flag to indicate that the call is from genesis. +// if so, operator freeze status is not checked and hooks are not called. +func (k *Keeper) setOperatorConsKeyForChainID( + ctx sdk.Context, + opAccAddr sdk.AccAddress, + chainID string, + consKey *tmprotocrypto.PublicKey, + genesis bool, ) error { // check if we are an operator if !k.IsOperator(ctx, opAccAddr) { return delegationtypes.ErrOperatorNotExist } // check for slashing - if k.slashKeeper.IsOperatorFrozen(ctx, opAccAddr) { + if !genesis && k.slashKeeper.IsOperatorFrozen(ctx, opAccAddr) { return delegationtypes.ErrOperatorIsFrozen } // check if the chain id is valid @@ -44,6 +58,7 @@ func (k *Keeper) SetOperatorConsKeyForChainID( return assetstypes.ErrUnknownAppChainID } // if opting out, do not allow key replacement + // TODO: merge with the functionality in state_update.go if k.IsOperatorOptingOutFromChainID(ctx, opAccAddr, chainID) { return types.ErrAlreadyOptingOut } @@ -51,16 +66,14 @@ func (k *Keeper) SetOperatorConsKeyForChainID( bz, err := consKey.Marshal() if err != nil { return errorsmod.Wrap( - err, - "SetOperatorConsKeyForChainID: error occurred when marshal public key", + err, "SetOperatorConsKeyForChainID: cannot marshal public key", ) } // convert to address for reverse lookup consAddr, err := types.TMCryptoPublicKeyToConsAddr(consKey) if err != nil { return errorsmod.Wrap( - err, - "SetOperatorConsKeyForChainID: error occurred when convert public key to consensus address", + err, "SetOperatorConsKeyForChainID: cannot convert pub key to consensus address", ) } // check if the key is already in use by another operator @@ -94,24 +107,34 @@ func (k *Keeper) SetOperatorConsKeyForChainID( panic(err) } if !alreadyRecorded { - if err := k.setOperatorPrevConsKeyForChainID(ctx, opAccAddr, chainID, prevKey); err != nil { + if err := k.setOperatorPrevConsKeyForChainID( + ctx, opAccAddr, chainID, prevKey, + ); err != nil { // this should not happen panic(err) } } } - // k.setOperatorConsKeyForChainID(ctx, opAccAddr, chainID, bz) - // return nil - // } + k.setOperatorConsKeyForChainIDUnchecked(ctx, opAccAddr, consAddr, chainID, bz) + if !genesis { + if found { + if !alreadyRecorded { + k.Hooks().AfterOperatorKeyReplacement(ctx, opAccAddr, prevKey, consKey, chainID) + } + } else { + k.Hooks().AfterOperatorOptIn(ctx, opAccAddr, chainID, consKey) + } + } + return nil +} - // // setOperatorConsKeyForChainID is the internal private version. It performs - // // no error checking of the input. - // func (k Keeper) setOperatorConsKeyForChainID( - // ctx sdk.Context, - // opAccAddr sdk.AccAddress, - // chainID string, - // bz []byte, - // ) { +// setOperatorConsKeyForChainIDUnchecked is the internal private version. It performs +// no error checking of the input. The caller must do the error checking +// and then call this function. +func (k Keeper) setOperatorConsKeyForChainIDUnchecked( + ctx sdk.Context, opAccAddr sdk.AccAddress, consAddr sdk.ConsAddress, + chainID string, bz []byte, +) { store := ctx.KVStore(k.storeKey) // forward lookup // given operator address and chain id, find the consensus key, @@ -132,14 +155,6 @@ func (k *Keeper) SetOperatorConsKeyForChainID( // this pruning will be triggered by the app chain module and will not be // recorded here. store.Set(types.KeyForChainIDAndConsKeyToOperator(chainID, consAddr), opAccAddr.Bytes()) - if found { - if !alreadyRecorded { - k.Hooks().AfterOperatorKeyReplacement(ctx, opAccAddr, prevKey, consKey, chainID) - } - } else { - k.Hooks().AfterOperatorOptIn(ctx, opAccAddr, chainID, consKey) - } - return nil } // setOperatorPrevConsKeyForChainID sets the previous (consensus) public key for the given @@ -150,7 +165,7 @@ func (k *Keeper) setOperatorPrevConsKeyForChainID( ctx sdk.Context, opAccAddr sdk.AccAddress, chainID string, - prevKey tmprotocrypto.PublicKey, + prevKey *tmprotocrypto.PublicKey, ) error { bz, err := prevKey.Marshal() if err != nil { @@ -169,7 +184,7 @@ func (k *Keeper) setOperatorPrevConsKeyForChainID( // to 0 in the validator update. func (k *Keeper) GetOperatorPrevConsKeyForChainID( ctx sdk.Context, opAccAddr sdk.AccAddress, chainID string, -) (found bool, key tmprotocrypto.PublicKey, err error) { +) (found bool, key *tmprotocrypto.PublicKey, err error) { // check if we are an operator if !k.IsOperator(ctx, opAccAddr) { err = delegationtypes.ErrOperatorNotExist @@ -184,19 +199,19 @@ func (k *Keeper) GetOperatorPrevConsKeyForChainID( return } -// getOperatorPrevConsKeyForChainID is the internal version of -// GetOperatorPrevConsKeyForChainID. +// getOperatorPrevConsKeyForChainID is the internal version of GetOperatorPrevConsKeyForChainID. // It performs no error checking of the input. func (k *Keeper) getOperatorPrevConsKeyForChainID( ctx sdk.Context, opAccAddr sdk.AccAddress, chainID string, -) (found bool, key tmprotocrypto.PublicKey, err error) { +) (found bool, key *tmprotocrypto.PublicKey, err error) { store := ctx.KVStore(k.storeKey) res := store.Get(types.KeyForOperatorAndChainIDToPrevConsKey(opAccAddr, chainID)) if res == nil { return } + key = &tmprotocrypto.PublicKey{} if err = key.Unmarshal(res); err != nil { return } @@ -210,7 +225,7 @@ func (k *Keeper) GetOperatorConsKeyForChainID( ctx sdk.Context, opAccAddr sdk.AccAddress, chainID string, -) (found bool, key tmprotocrypto.PublicKey, err error) { +) (found bool, key *tmprotocrypto.PublicKey, err error) { // check if we are an operator if !k.IsOperator(ctx, opAccAddr) { err = delegationtypes.ErrOperatorNotExist @@ -232,25 +247,27 @@ func (k *Keeper) getOperatorConsKeyForChainID( ctx sdk.Context, opAccAddr sdk.AccAddress, chainID string, -) (found bool, key tmprotocrypto.PublicKey, err error) { +) (found bool, key *tmprotocrypto.PublicKey, err error) { store := ctx.KVStore(k.storeKey) res := store.Get(types.KeyForOperatorAndChainIDToConsKey(opAccAddr, chainID)) if res == nil { return } + key = &tmprotocrypto.PublicKey{} if err = key.Unmarshal(res); err != nil { return } return true, key, nil } -// GetChainIDsAndKeysForOperator gets the chain ids for which the given operator address has set a +// GetChainIDsAndKeysForOperator gets the chain ids for which the given operator address has set +// a // (consensus) public key. TODO: would it be better to make this a key per operator? // This is intentionally an array of strings because I don't see the utility for the vote power // or the public key here. If we need it, we can add it later. func (k *Keeper) GetChainIDsAndKeysForOperator( ctx sdk.Context, opAccAddr sdk.AccAddress, -) (chainIDs []string, consKeys []tmprotocrypto.PublicKey) { +) (chainIDs []string, consKeys []*tmprotocrypto.PublicKey) { // check if we are an operator if !k.IsOperator(ctx, opAccAddr) { return @@ -268,7 +285,7 @@ func (k *Keeper) GetChainIDsAndKeysForOperator( for ; iterator.Valid(); iterator.Next() { // the key returned is the full key, with the prefix. drop the prefix and the length. chainID := string(iterator.Key()[len(prefix)+8:]) - var key tmprotocrypto.PublicKey + var key *tmprotocrypto.PublicKey if err := key.Unmarshal(iterator.Value()); err != nil { // grave error because we are the ones who stored this information in the first // place @@ -285,7 +302,7 @@ func (k *Keeper) GetChainIDsAndKeysForOperator( // jailed or frozen operators. func (k *Keeper) GetOperatorsForChainID( ctx sdk.Context, chainID string, -) (addrs []sdk.AccAddress, pubKeys []tmprotocrypto.PublicKey) { +) (addrs []sdk.AccAddress, pubKeys []*tmprotocrypto.PublicKey) { if !k.assetsKeeper.AppChainInfoIsExist(ctx, chainID) { return nil, nil } @@ -306,7 +323,7 @@ func (k *Keeper) GetOperatorsForChainID( // so just drop it and convert to sdk.AccAddress addr := iterator.Key()[len(prefix):] res := iterator.Value() - var ret tmprotocrypto.PublicKey + var ret *tmprotocrypto.PublicKey if err := ret.Unmarshal(res); err != nil { // grave error panic(err) diff --git a/x/operator/keeper/genesis.go b/x/operator/keeper/genesis.go new file mode 100644 index 000000000..c7fe9084b --- /dev/null +++ b/x/operator/keeper/genesis.go @@ -0,0 +1,47 @@ +package keeper + +import ( + "github.com/ExocoreNetwork/exocore/x/operator/types" + abci "github.com/cometbft/cometbft/abci/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) []abci.ValidatorUpdate { + for i := range state.Operators { + op := state.Operators[i] // avoid implicit memory aliasing + if err := k.SetOperatorInfo(ctx, op.EarningsAddr, &op); err != nil { + panic(err) + } + } + for _, record := range state.OperatorRecords { + addr := record.OperatorAddress + // #nosec G703 // already validated + operatorAddr, _ := sdk.AccAddressFromBech32(addr) + for _, detail := range record.Chains { + chainID := detail.ChainID + // validate that the chain exists + // TODO: move this to the avs keeper when it is merged. + if !k.assetsKeeper.AppChainInfoIsExist(ctx, chainID) { + panic("chain info not found") + } + // opt into the specified chain (TODO: avs address format) + if err := k.OptIn(ctx, operatorAddr, chainID); err != nil { + panic(err) + } + // #nosec G703 // already validated + key, _ := types.HexStringToPubKey(detail.ConsensusKey) + // then set pub key + if err := k.setOperatorConsKeyForChainID( + ctx, operatorAddr, chainID, key, true, + ); err != nil { + panic(err) + } + } + } + return []abci.ValidatorUpdate{} +} + +func (Keeper) ExportGenesis(sdk.Context) *types.GenesisState { + // TODO + return types.DefaultGenesis() +} diff --git a/x/operator/keeper/grpc_query.go b/x/operator/keeper/grpc_query.go index d86edeb0a..3865c6d36 100644 --- a/x/operator/keeper/grpc_query.go +++ b/x/operator/keeper/grpc_query.go @@ -35,6 +35,6 @@ func (k *Keeper) QueryOperatorConsKeyForChainID( return nil, errors.New("no key assigned") } return &operatortypes.QueryOperatorConsKeyResponse{ - PublicKey: key, + PublicKey: *key, }, nil } diff --git a/x/operator/keeper/msg_server.go b/x/operator/keeper/msg_server.go index 7a16c10c4..6eceba5f6 100644 --- a/x/operator/keeper/msg_server.go +++ b/x/operator/keeper/msg_server.go @@ -2,9 +2,6 @@ package keeper import ( context "context" - "encoding/base64" - - tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" "github.com/ExocoreNetwork/exocore/x/operator/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -34,7 +31,7 @@ func (k *Keeper) OptInToCosmosChain( if err != nil { return nil, err } - key, err := stringToPubKey(req.PublicKey) + key, err := types.StringToPubKey(req.PublicKey) if err != nil { return nil, err } @@ -74,16 +71,3 @@ func (k *Keeper) InitOptOutFromCosmosChain( } return &types.InitOptOutFromCosmosChainResponse{}, nil } - -func stringToPubKey(pubKey string) (key tmprotocrypto.PublicKey, err error) { - pubKeyBytes, err := base64.StdEncoding.DecodeString(pubKey) - if err != nil { - return - } - subscriberTMConsKey := tmprotocrypto.PublicKey{ - Sum: &tmprotocrypto.PublicKey_Ed25519{ - Ed25519: pubKeyBytes, - }, - } - return subscriberTMConsKey, nil -} diff --git a/x/operator/keeper/operator.go b/x/operator/keeper/operator.go index d5fc80d41..ebad2d5f3 100644 --- a/x/operator/keeper/operator.go +++ b/x/operator/keeper/operator.go @@ -24,6 +24,7 @@ func (k *Keeper) SetOperatorInfo(ctx sdk.Context, addr string, info *operatortyp // key := common.HexToAddress(incentive.Contract) bz := k.cdc.MustMarshal(info) + // TODO: check about client chain registration for earnings addresses provided? store.Set(opAccAddr, bz) return nil } diff --git a/x/operator/keeper/state_update_test.go b/x/operator/keeper/state_update_test.go index 10be7bf59..3f13d802e 100644 --- a/x/operator/keeper/state_update_test.go +++ b/x/operator/keeper/state_update_test.go @@ -5,7 +5,7 @@ import ( sdkmath "cosmossdk.io/math" assetstypes "github.com/ExocoreNetwork/exocore/x/assets/types" - delegationKeeper "github.com/ExocoreNetwork/exocore/x/delegation/keeper" + delegationtype "github.com/ExocoreNetwork/exocore/x/delegation/types" "github.com/ExocoreNetwork/exocore/x/deposit/keeper" operatorKeeper "github.com/ExocoreNetwork/exocore/x/operator/keeper" operatorTypes "github.com/ExocoreNetwork/exocore/x/operator/types" @@ -60,7 +60,7 @@ func (suite *OperatorTestSuite) prepare() { suite.NoError(err) // delegate to operator - delegationParam := &delegationKeeper.DelegationOrUndelegationParams{ + delegationParam := &delegationtype.DelegationOrUndelegationParams{ ClientChainLzID: suite.clientChainLzID, Action: assetstypes.DelegateTo, AssetsAddress: suite.assetAddr[:], diff --git a/x/operator/module.go b/x/operator/module.go index cf870c535..29999fbee 100644 --- a/x/operator/module.go +++ b/x/operator/module.go @@ -2,6 +2,8 @@ package operator import ( "context" + "encoding/json" + "fmt" "github.com/ExocoreNetwork/exocore/x/operator/client/cli" "github.com/ExocoreNetwork/exocore/x/operator/keeper" @@ -38,8 +40,13 @@ func (b AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry operatortypes.RegisterInterfaces(registry) } -func (b AppModuleBasic) RegisterGRPCGatewayRoutes(c client.Context, serveMux *runtime.ServeMux) { - if err := operatortypes.RegisterQueryHandlerClient(context.Background(), serveMux, operatortypes.NewQueryClient(c)); err != nil { +func (b AppModuleBasic) RegisterGRPCGatewayRoutes( + c client.Context, + serveMux *runtime.ServeMux, +) { + if err := operatortypes.RegisterQueryHandlerClient( + context.Background(), serveMux, operatortypes.NewQueryClient(c), + ); err != nil { panic(err) } } @@ -92,3 +99,44 @@ func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.V am.keeper.EndBlock(ctx, req) return []abci.ValidatorUpdate{} } + +// DefaultGenesis returns a default GenesisState for the module, marshaled to json.RawMessage. +// The default GenesisState need to be defined by the module developer and is primarily used for +// testing +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(operatortypes.DefaultGenesis()) +} + +// ValidateGenesis used to validate the GenesisState, given in its json.RawMessage form +func (AppModuleBasic) ValidateGenesis( + cdc codec.JSONCodec, + _ client.TxEncodingConfig, + bz json.RawMessage, +) error { + var genState operatortypes.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf( + "failed to unmarshal %s genesis state: %w", + operatortypes.ModuleName, + err, + ) + } + return genState.Validate() +} + +// InitGenesis performs the module's genesis initialization. +func (am AppModule) InitGenesis( + ctx sdk.Context, + cdc codec.JSONCodec, + gs json.RawMessage, +) []abci.ValidatorUpdate { + var genState operatortypes.GenesisState + cdc.MustUnmarshalJSON(gs, &genState) + return am.keeper.InitGenesis(ctx, genState) +} + +// ExportGenesis returns the module's exported genesis state as raw JSON bytes. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := am.keeper.ExportGenesis(ctx) + return cdc.MustMarshalJSON(genState) +} diff --git a/x/operator/types/consensus_keys.go b/x/operator/types/consensus_keys.go new file mode 100644 index 000000000..534409837 --- /dev/null +++ b/x/operator/types/consensus_keys.go @@ -0,0 +1,81 @@ +package types + +import ( + "encoding/base64" + "encoding/json" + + errorsmod "cosmossdk.io/errors" + + tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + "github.com/ethereum/go-ethereum/common/hexutil" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// HexStringToPubKey converts a 32-byte public key (from the Ethereum side of things), +// which is represented as a 66-byte string (with the 0x prefix) within Golang, +// to a tendermint public key. It is, in effect, a reverse of the command +// `exocored keys consensus-pubkey-to-bytes` +func HexStringToPubKey(key string) (*tmprotocrypto.PublicKey, error) { + if len(key) != 66 { + return nil, errorsmod.Wrapf( + ErrInvalidPubKey, + "expected 66 length string, got %d", + len(key), + ) + } + keyBytes, err := hexutil.Decode(key) + if err != nil { + return nil, errorsmod.Wrapf( + ErrInvalidPubKey, + "failed to decode hex string: %s", + err, + ) + } + return &tmprotocrypto.PublicKey{ + Sum: &tmprotocrypto.PublicKey_Ed25519{ + Ed25519: keyBytes, + }, + }, nil +} + +// StringToPubKey converts a base64-encoded public key to a tendermint public key. +// Typically, this function is fed an input from ParseConsumerKeyFromJSON. +func StringToPubKey(pubKey string) (key *tmprotocrypto.PublicKey, err error) { + pubKeyBytes, err := base64.StdEncoding.DecodeString(pubKey) + if err != nil { + return + } + subscriberTMConsKey := &tmprotocrypto.PublicKey{ + Sum: &tmprotocrypto.PublicKey_Ed25519{ + Ed25519: pubKeyBytes, + }, + } + return subscriberTMConsKey, nil +} + +// ParseConsumerKeyFromJSON parses the consumer key from a JSON string. +// This function replaces deserializing a protobuf any. +func ParseConsumerKeyFromJSON(jsonStr string) (pkType, key string, err error) { + type PubKey struct { + Type string `json:"type"` + Key string `json:"value"` + } + var pubKey PubKey + err = json.Unmarshal([]byte(jsonStr), &pubKey) + if err != nil { + return "", "", err + } + return pubKey.Type, pubKey.Key, nil +} + +// TMCryptoPublicKeyToConsAddr converts a TM public key to an SDK public key +// and returns the associated consensus address +func TMCryptoPublicKeyToConsAddr(k *tmprotocrypto.PublicKey) (sdk.ConsAddress, error) { + sdkK, err := cryptocodec.FromTmProtoPublicKey(*k) + if err != nil { + return nil, err + } + return sdk.GetConsAddress(sdkK), nil +} diff --git a/x/operator/types/errors.go b/x/operator/types/errors.go index b11e8ef2e..89e87c262 100644 --- a/x/operator/types/errors.go +++ b/x/operator/types/errors.go @@ -3,37 +3,76 @@ package types import errorsmod "cosmossdk.io/errors" var ( - ErrNoKeyInTheStore = errorsmod.Register(ModuleName, 0, "there is not the key for in the store") + ErrNoKeyInTheStore = errorsmod.Register( + ModuleName, 0, + "there is no such key in the store", + ) - ErrCliCmdInputArg = errorsmod.Register(ModuleName, 1, "there is an error in the input client command args") + ErrCliCmdInputArg = errorsmod.Register( + ModuleName, 1, + "there is an error in the input client command args", + ) - ErrSlashInfo = errorsmod.Register(ModuleName, 2, "there is an error in the field of slash info") + ErrSlashInfo = errorsmod.Register( + ModuleName, 2, + "there is an error in the field of slash info", + ) - ErrSlashInfoExist = errorsmod.Register(ModuleName, 3, "the slash info exists") + ErrSlashInfoExist = errorsmod.Register( + ModuleName, 3, + "the slash info exists", + ) - ErrParameterInvalid = errorsmod.Register(ModuleName, 4, "the input parameter is invalid") + ErrParameterInvalid = errorsmod.Register( + ModuleName, 4, + "the input parameter is invalid", + ) - ErrAlreadyOptedIn = errorsmod.Register(ModuleName, 5, "the operator has already opted in the avs") + ErrAlreadyOptedIn = errorsmod.Register( + ModuleName, 5, + "the operator has already opted in the avs", + ) - ErrNotOptedIn = errorsmod.Register(ModuleName, 6, "the operator hasn't opted in the avs") + ErrNotOptedIn = errorsmod.Register( + ModuleName, 6, + "the operator hasn't opted in the avs", + ) - ErrTheValueIsNegative = errorsmod.Register(ModuleName, 7, "the value is negative") + ErrTheValueIsNegative = errorsmod.Register( + ModuleName, 7, + "the value is negative", + ) - ErrSlashContractNotMatch = errorsmod.Register(ModuleName, 8, "the slash contract isn't the slash contract address saved in the opted-in info") + ErrSlashContractNotMatch = errorsmod.Register( + ModuleName, 8, + "the slash contract isn't the slash contract address saved in the opted-in info", + ) - ErrSlashOccurredHeight = errorsmod.Register(ModuleName, 9, "the occurred height of slash event is error") + ErrSlashOccurredHeight = errorsmod.Register( + ModuleName, 9, + "the occurred height of slash event is error", + ) - // add for dogfood ErrConsKeyAlreadyInUse = errorsmod.Register( - ModuleName, - 10, + ModuleName, 10, "consensus key already in use by another operator", ) + ErrAlreadyOptingOut = errorsmod.Register( ModuleName, 11, "operator already opting out", ) ErrInvalidAvsAddr = errorsmod.Register( ModuleName, 12, "avs address should be a hex evm contract address", + ) + + ErrInvalidPubKey = errorsmod.Register( + ModuleName, 13, + "invalid public key", + ) + + ErrInvalidGenesisData = errorsmod.Register( + ModuleName, 14, + "the genesis data supplied is invalid", ) ) diff --git a/x/operator/types/expected_keepers.go b/x/operator/types/expected_keepers.go index fc986ed44..03020079c 100644 --- a/x/operator/types/expected_keepers.go +++ b/x/operator/types/expected_keepers.go @@ -14,20 +14,46 @@ var ( ) type AssetsKeeper interface { - GetStakingAssetInfo(ctx sdk.Context, assetID string) (info *assetstype.StakingAssetInfo, err error) - IteratorOperatorAssetState(ctx sdk.Context, f func(operatorAddr, assetID string, state *assetstype.OperatorAssetInfo) error) error + GetStakingAssetInfo( + ctx sdk.Context, assetID string, + ) (info *assetstype.StakingAssetInfo, err error) + IteratorOperatorAssetState( + ctx sdk.Context, + f func(operatorAddr, assetID string, state *assetstype.OperatorAssetInfo) error, + ) error AppChainInfoIsExist(ctx sdk.Context, chainID string) bool - GetOperatorAssetInfos(ctx sdk.Context, operatorAddr sdk.Address, _ map[string]interface{}) (assetsInfo map[string]*assetstype.OperatorAssetInfo, err error) - UpdateStakerAssetState(ctx sdk.Context, stakerID string, assetID string, changeAmount assetstype.StakerSingleAssetChangeInfo) (err error) - UpdateOperatorAssetState(ctx sdk.Context, operatorAddr sdk.Address, assetID string, changeAmount assetstype.OperatorSingleAssetChangeInfo) (err error) + GetOperatorAssetInfos( + ctx sdk.Context, operatorAddr sdk.Address, _ map[string]interface{}, + ) (assetsInfo map[string]*assetstype.OperatorAssetInfo, err error) + UpdateStakerAssetState( + ctx sdk.Context, stakerID string, assetID string, + changeAmount assetstype.StakerSingleAssetChangeInfo, + ) (err error) + UpdateOperatorAssetState( + ctx sdk.Context, operatorAddr sdk.Address, assetID string, + changeAmount assetstype.OperatorSingleAssetChangeInfo, + ) (err error) } type DelegationKeeper interface { - DelegationStateByOperatorAssets(ctx sdk.Context, operatorAddr string, assetsFilter map[string]interface{}) (map[string]map[string]delegationtype.DelegationAmounts, error) - IterateDelegationState(ctx sdk.Context, f func(restakerID, assetID, operatorAddr string, state *delegationtype.DelegationAmounts) error) error - UpdateDelegationState(ctx sdk.Context, stakerID string, assetID string, delegationAmounts map[string]*delegationtype.DelegationAmounts) (err error) - - UpdateStakerDelegationTotalAmount(ctx sdk.Context, stakerID string, assetID string, opAmount sdkmath.Int) error + DelegationStateByOperatorAssets( + ctx sdk.Context, operatorAddr string, assetsFilter map[string]interface{}, + ) (map[string]map[string]delegationtype.DelegationAmounts, error) + IterateDelegationState( + ctx sdk.Context, + f func( + restakerID, assetID, operatorAddr string, + state *delegationtype.DelegationAmounts, + ) error, + ) error + UpdateDelegationState( + ctx sdk.Context, stakerID string, assetID string, + delegationAmounts map[string]*delegationtype.DelegationAmounts, + ) (err error) + UpdateStakerDelegationTotalAmount( + ctx sdk.Context, stakerID string, assetID string, + opAmount sdkmath.Int, + ) error } type PriceChange struct { @@ -39,12 +65,14 @@ type PriceChange struct { // OracleKeeper is the oracle interface expected by operator module // These functions need to be implemented by the oracle module type OracleKeeper interface { - // GetSpecifiedAssetsPrice is a function to retrieve the asset price according to the assetID - // the first return value is price, and the second return value is decimal of the price. + // GetSpecifiedAssetsPrice is a function to retrieve the asset price according to the + // assetID. the first return value is price, and the second return value is decimal of the + // price. GetSpecifiedAssetsPrice(ctx sdk.Context, assetID string) (sdkmath.Int, uint8, error) - // GetPriceChangeAssets the operator module expect a function that can retrieve all information - // about assets price change. Then it can update the USD share state according to the change - // information. This function need to return a map, the key is assetID and the value is PriceChange + // GetPriceChangeAssets the operator module expect a function that can retrieve all + // information about assets price change. Then it can update the USD share state according + // to the change information. This function need to return a map, the key is assetID and the + // value is PriceChange GetPriceChangeAssets(ctx sdk.Context) (map[string]*PriceChange, error) } @@ -89,9 +117,10 @@ func (MockAvs) GetOperatorsByAvs(_ sdk.Context, _ string) ([]string, error) { } type AvsKeeper interface { - // GetAvsSupportedAssets The ctx can be historical or current, depending on the state you wish to retrieve. - // If the caller want to retrieve a historical assets info supported by Avs, it needs to generate a historical - // context through calling `ContextForHistoricalState` implemented in x/assets/types/general.go + // GetAvsSupportedAssets The ctx can be historical or current, depending on the state you + // wish to retrieve. If the caller want to retrieve a historical assets info supported by + // Avs, it needs to generate a historical context through calling + // `ContextForHistoricalState` implemented in x/assets/types/general.go GetAvsSupportedAssets(ctx sdk.Context, avsAddr string) (map[string]interface{}, error) GetAvsSlashContract(ctx sdk.Context, avsAddr string) (string, error) // GetAvsAddrByChainID get the general Avs address for dogfood module. @@ -109,25 +138,17 @@ type SlashKeeper interface { type OperatorConsentHooks interface { // This hook is called when an operator opts in to a chain. AfterOperatorOptIn( - ctx sdk.Context, - addr sdk.AccAddress, - chainID string, - pubKey tmprotocrypto.PublicKey, + ctx sdk.Context, addr sdk.AccAddress, chainID string, + pubKey *tmprotocrypto.PublicKey, ) // This hook is called when an operator's consensus key is replaced for // a chain. AfterOperatorKeyReplacement( - ctx sdk.Context, - addr sdk.AccAddress, - oldKey tmprotocrypto.PublicKey, - newKey tmprotocrypto.PublicKey, - chainID string, + ctx sdk.Context, addr sdk.AccAddress, oldKey *tmprotocrypto.PublicKey, + newKey *tmprotocrypto.PublicKey, chainID string, ) // This hook is called when an operator opts out of a chain. AfterOperatorOptOutInitiated( - ctx sdk.Context, - addr sdk.AccAddress, - chainID string, - key tmprotocrypto.PublicKey, + ctx sdk.Context, addr sdk.AccAddress, chainID string, key *tmprotocrypto.PublicKey, ) } diff --git a/x/operator/types/genesis.go b/x/operator/types/genesis.go new file mode 100644 index 000000000..e73bbc3e6 --- /dev/null +++ b/x/operator/types/genesis.go @@ -0,0 +1,128 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" +) + +func NewGenesisState( + operators []OperatorInfo, + records []OperatorConsKeyRecord, +) *GenesisState { + return &GenesisState{ + Operators: operators, + OperatorRecords: records, + } +} + +// DefaultGenesis returns the default genesis state +func DefaultGenesis() *GenesisState { + return NewGenesisState([]OperatorInfo{}, []OperatorConsKeyRecord{}) +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + // checks list: + // - no duplicate addresses in `gs.Operators`. + // - correct bech32 format for each address in `gs.Operators` + // - no `chainID` duplicates for earnings addresses list in `gs.Operators`. + operators := make(map[string]struct{}, len(gs.Operators)) + for _, op := range gs.Operators { + address := op.EarningsAddr + if _, found := operators[address]; found { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "duplicate operator address %s", address, + ) + } + _, err := sdk.AccAddressFromBech32(address) + if err != nil { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "invalid operator address %s: %s", address, err, + ) + } + operators[address] = struct{}{} + if op.ClientChainEarningsAddr != nil { + lzIDs := make(map[uint64]struct{}, len(op.ClientChainEarningsAddr.EarningInfoList)) + for _, info := range op.ClientChainEarningsAddr.EarningInfoList { + lzID := info.LzClientChainID + if _, found := lzIDs[lzID]; found { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "duplicate lz client chain id %d", lzID, + ) + } + lzIDs[lzID] = struct{}{} + // TODO: when moving to support non-EVM chains, this check should be modified + // to work based on the `lzID` or possibly removed. + if !common.IsHexAddress(info.ClientChainEarningAddr) { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "invalid client chain earning address %s", info.ClientChainEarningAddr, + ) + } + } + } + } + // - correct bech32 format for each address in `gs.OperatorRecords`. + // - no duplicate addresses in `gs.OperatorRecords`. + // - no operator that is in `gs.OperatorRecords` but not in `gs.Operators`. + // - validity of consensus key format for each entry in `gs.OperatorRecords`. + // - within each chainID, no duplicate consensus keys. + operatorRecords := make(map[string]struct{}, len(gs.OperatorRecords)) + keysByChainID := make(map[string]map[string]struct{}) + for _, record := range gs.OperatorRecords { + addr := record.OperatorAddress + if _, err := sdk.AccAddressFromBech32(addr); err != nil { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "invalid operator address %s: %s", record.OperatorAddress, err, + ) + } + if _, found := operatorRecords[addr]; found { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "duplicate operator record for operator %s", addr, + ) + } + operatorRecords[addr] = struct{}{} + if _, opFound := operators[addr]; !opFound { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "operator record for un-registered operator %s", addr, + ) + } + for _, chain := range record.Chains { + consensusKeyString := chain.ConsensusKey + chainID := chain.ChainID + // Cosmos does not describe a specific `chainID` format, so can't validate it. + if _, found := keysByChainID[chainID]; !found { + keysByChainID[chainID] = make(map[string]struct{}) + } + if _, err := HexStringToPubKey(consensusKeyString); err != nil { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "invalid consensus key for operator %s: %s", addr, err, + ) + } + // within a chain id, there should not be duplicate consensus keys + if _, found := keysByChainID[chainID][consensusKeyString]; found { + return errorsmod.Wrapf( + ErrInvalidGenesisData, + "duplicate consensus key for operator %s on chain %s", addr, chainID, + ) + } + keysByChainID[chainID][consensusKeyString] = struct{}{} + } + } + // rationale for the validations above: + // 1. since this function should support chain restarts and upgrades, we cannot require + // the format of the earnings address be EVM only. + // 2. since the operator module is not meant to handle dogfooding, we should not check + // whether an operator has keys defined for our chainID. this is left for the dogfood + // module. + return nil +} diff --git a/x/operator/types/genesis.pb.go b/x/operator/types/genesis.pb.go new file mode 100644 index 000000000..aa066e84c --- /dev/null +++ b/x/operator/types/genesis.pb.go @@ -0,0 +1,1579 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: exocore/operator/v1/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the operator module's genesis state. +type GenesisState struct { + // there are no params for this module. + // operators is a list of the registered operators. + Operators []OperatorInfo `protobuf:"bytes,1,rep,name=operators,proto3" json:"operators"` + // operator_records refers to a list of operator records. each record + // contains an operator address and a list of chain id + + // cons key combination. + OperatorRecords []OperatorConsKeyRecord `protobuf:"bytes,2,rep,name=operator_records,json=operatorRecords,proto3" json:"operator_records"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_bb7040bc6ae6ddee, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetOperators() []OperatorInfo { + if m != nil { + return m.Operators + } + return nil +} + +func (m *GenesisState) GetOperatorRecords() []OperatorConsKeyRecord { + if m != nil { + return m.OperatorRecords + } + return nil +} + +// OperatorConsKeyRecord is a helper structure for the genesis state. Each record +// contains an operator address and a list of chain id + cons key combination. +type OperatorConsKeyRecord struct { + // operator_address is the address of the operator as the bech32 + // encoded version of sdk.AccAddress. + OperatorAddress string `protobuf:"bytes,1,opt,name=operator_address,json=operatorAddress,proto3" json:"operator_address,omitempty"` + // chains is a list of chain id + consensus key combination. + Chains []ChainDetails `protobuf:"bytes,2,rep,name=chains,proto3" json:"chains"` +} + +func (m *OperatorConsKeyRecord) Reset() { *m = OperatorConsKeyRecord{} } +func (m *OperatorConsKeyRecord) String() string { return proto.CompactTextString(m) } +func (*OperatorConsKeyRecord) ProtoMessage() {} +func (*OperatorConsKeyRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_bb7040bc6ae6ddee, []int{1} +} +func (m *OperatorConsKeyRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *OperatorConsKeyRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_OperatorConsKeyRecord.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *OperatorConsKeyRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_OperatorConsKeyRecord.Merge(m, src) +} +func (m *OperatorConsKeyRecord) XXX_Size() int { + return m.Size() +} +func (m *OperatorConsKeyRecord) XXX_DiscardUnknown() { + xxx_messageInfo_OperatorConsKeyRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_OperatorConsKeyRecord proto.InternalMessageInfo + +func (m *OperatorConsKeyRecord) GetOperatorAddress() string { + if m != nil { + return m.OperatorAddress + } + return "" +} + +func (m *OperatorConsKeyRecord) GetChains() []ChainDetails { + if m != nil { + return m.Chains + } + return nil +} + +// ChainDetails is a helper structure for the genesis state. Each record +// contains a chain id and a consensus key. +type ChainDetails struct { + // chain_id is the unique identifier of the chain. + ChainID string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + // consensus_key is the consensus key of the operator on the chain. + // the length of this key should be exactly 32 bytes, and must be enforced + // outside of protobuf. + ConsensusKey string `protobuf:"bytes,2,opt,name=consensus_key,json=consensusKey,proto3" json:"consensus_key,omitempty"` +} + +func (m *ChainDetails) Reset() { *m = ChainDetails{} } +func (m *ChainDetails) String() string { return proto.CompactTextString(m) } +func (*ChainDetails) ProtoMessage() {} +func (*ChainDetails) Descriptor() ([]byte, []int) { + return fileDescriptor_bb7040bc6ae6ddee, []int{2} +} +func (m *ChainDetails) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ChainDetails) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ChainDetails.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ChainDetails) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChainDetails.Merge(m, src) +} +func (m *ChainDetails) XXX_Size() int { + return m.Size() +} +func (m *ChainDetails) XXX_DiscardUnknown() { + xxx_messageInfo_ChainDetails.DiscardUnknown(m) +} + +var xxx_messageInfo_ChainDetails proto.InternalMessageInfo + +func (m *ChainDetails) GetChainID() string { + if m != nil { + return m.ChainID + } + return "" +} + +func (m *ChainDetails) GetConsensusKey() string { + if m != nil { + return m.ConsensusKey + } + return "" +} + +// StakerRecord is a helper structure for the genesis state. Each record +// contains a staker address and a list of asset IDs with their operator + +// amount combination. +type StakerRecord struct { + // staker_id denotes the address + l0id of the staker. + StakerID string `protobuf:"bytes,1,opt,name=staker_id,json=stakerId,proto3" json:"staker_id,omitempty"` + // staker_details is a list of asset ID + operator + amount combination. + StakerDetails []StakerDetails `protobuf:"bytes,2,rep,name=staker_details,json=stakerDetails,proto3" json:"staker_details"` +} + +func (m *StakerRecord) Reset() { *m = StakerRecord{} } +func (m *StakerRecord) String() string { return proto.CompactTextString(m) } +func (*StakerRecord) ProtoMessage() {} +func (*StakerRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_bb7040bc6ae6ddee, []int{3} +} +func (m *StakerRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StakerRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StakerRecord.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StakerRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_StakerRecord.Merge(m, src) +} +func (m *StakerRecord) XXX_Size() int { + return m.Size() +} +func (m *StakerRecord) XXX_DiscardUnknown() { + xxx_messageInfo_StakerRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_StakerRecord proto.InternalMessageInfo + +func (m *StakerRecord) GetStakerID() string { + if m != nil { + return m.StakerID + } + return "" +} + +func (m *StakerRecord) GetStakerDetails() []StakerDetails { + if m != nil { + return m.StakerDetails + } + return nil +} + +// StakerDetails is a helper structure for the genesis state. Each record +// contains an asset ID and a list of operator + amount combination. +type StakerDetails struct { + // asset_id is the unique identifier of the asset. + AssetID string `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` + // details is a list of operator + amount combination. + Details []AssetDetails `protobuf:"bytes,2,rep,name=details,proto3" json:"details"` +} + +func (m *StakerDetails) Reset() { *m = StakerDetails{} } +func (m *StakerDetails) String() string { return proto.CompactTextString(m) } +func (*StakerDetails) ProtoMessage() {} +func (*StakerDetails) Descriptor() ([]byte, []int) { + return fileDescriptor_bb7040bc6ae6ddee, []int{4} +} +func (m *StakerDetails) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StakerDetails) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StakerDetails.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StakerDetails) XXX_Merge(src proto.Message) { + xxx_messageInfo_StakerDetails.Merge(m, src) +} +func (m *StakerDetails) XXX_Size() int { + return m.Size() +} +func (m *StakerDetails) XXX_DiscardUnknown() { + xxx_messageInfo_StakerDetails.DiscardUnknown(m) +} + +var xxx_messageInfo_StakerDetails proto.InternalMessageInfo + +func (m *StakerDetails) GetAssetID() string { + if m != nil { + return m.AssetID + } + return "" +} + +func (m *StakerDetails) GetDetails() []AssetDetails { + if m != nil { + return m.Details + } + return nil +} + +// AssetDetails is a helper structure for the genesis state. Each record +// contains an operator and an amount. +type AssetDetails struct { + // operator_address is the address of the operator as the bech32 + // version of sdk.AccAddress. + OperatorAddress string `protobuf:"bytes,1,opt,name=operator_address,json=operatorAddress,proto3" json:"operator_address,omitempty"` + // amount is the amount of the asset staked by the staker for this + // asset and operator. + Amount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"amount"` +} + +func (m *AssetDetails) Reset() { *m = AssetDetails{} } +func (m *AssetDetails) String() string { return proto.CompactTextString(m) } +func (*AssetDetails) ProtoMessage() {} +func (*AssetDetails) Descriptor() ([]byte, []int) { + return fileDescriptor_bb7040bc6ae6ddee, []int{5} +} +func (m *AssetDetails) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AssetDetails) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AssetDetails.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AssetDetails) XXX_Merge(src proto.Message) { + xxx_messageInfo_AssetDetails.Merge(m, src) +} +func (m *AssetDetails) XXX_Size() int { + return m.Size() +} +func (m *AssetDetails) XXX_DiscardUnknown() { + xxx_messageInfo_AssetDetails.DiscardUnknown(m) +} + +var xxx_messageInfo_AssetDetails proto.InternalMessageInfo + +func (m *AssetDetails) GetOperatorAddress() string { + if m != nil { + return m.OperatorAddress + } + return "" +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "exocore.operator.v1.GenesisState") + proto.RegisterType((*OperatorConsKeyRecord)(nil), "exocore.operator.v1.OperatorConsKeyRecord") + proto.RegisterType((*ChainDetails)(nil), "exocore.operator.v1.ChainDetails") + proto.RegisterType((*StakerRecord)(nil), "exocore.operator.v1.StakerRecord") + proto.RegisterType((*StakerDetails)(nil), "exocore.operator.v1.StakerDetails") + proto.RegisterType((*AssetDetails)(nil), "exocore.operator.v1.AssetDetails") +} + +func init() { proto.RegisterFile("exocore/operator/v1/genesis.proto", fileDescriptor_bb7040bc6ae6ddee) } + +var fileDescriptor_bb7040bc6ae6ddee = []byte{ + // 513 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0xcf, 0x6b, 0x13, 0x41, + 0x14, 0xce, 0x56, 0xc9, 0x8f, 0xe9, 0x46, 0x65, 0x54, 0x88, 0x45, 0x36, 0x76, 0x85, 0x52, 0x85, + 0xee, 0xd2, 0x7a, 0x15, 0x24, 0x69, 0x8a, 0x2c, 0x15, 0x0b, 0x5b, 0x4f, 0xf6, 0x10, 0xb6, 0x3b, + 0x63, 0xba, 0xc4, 0xcc, 0x84, 0x79, 0x93, 0x9a, 0x78, 0xf5, 0xe6, 0x45, 0xff, 0x16, 0xf1, 0x8f, + 0xe8, 0xb1, 0x78, 0x12, 0x0f, 0x41, 0x36, 0xff, 0x88, 0xec, 0xcc, 0x6c, 0xb2, 0x91, 0x45, 0xf0, + 0xb4, 0x33, 0xef, 0xfb, 0xde, 0xf7, 0xbe, 0x6f, 0x96, 0x87, 0xb6, 0xe9, 0x94, 0xc7, 0x5c, 0x50, + 0x9f, 0x8f, 0xa9, 0x88, 0x24, 0x17, 0xfe, 0xe5, 0xbe, 0x3f, 0xa0, 0x8c, 0x42, 0x02, 0xde, 0x58, + 0x70, 0xc9, 0xf1, 0x5d, 0x43, 0xf1, 0x72, 0x8a, 0x77, 0xb9, 0xbf, 0xf5, 0x20, 0xe6, 0x30, 0xe2, + 0xd0, 0x57, 0x14, 0x5f, 0x5f, 0x34, 0x7f, 0xeb, 0xde, 0x80, 0x0f, 0xb8, 0xae, 0x67, 0x27, 0x53, + 0x7d, 0x58, 0x36, 0x48, 0x4e, 0x35, 0xea, 0x7e, 0xb3, 0x90, 0xfd, 0x52, 0x4f, 0x3d, 0x95, 0x91, + 0xa4, 0xf8, 0x08, 0x35, 0x72, 0x22, 0xb4, 0xac, 0x47, 0x37, 0x76, 0x37, 0x0f, 0xb6, 0xbd, 0x12, + 0x23, 0xde, 0x89, 0x39, 0x07, 0xec, 0x1d, 0xef, 0xde, 0xbc, 0x9a, 0xb7, 0x2b, 0xe1, 0xaa, 0x13, + 0x9f, 0xa1, 0x3b, 0xf9, 0xa5, 0x2f, 0x68, 0xcc, 0x05, 0x81, 0xd6, 0x86, 0x52, 0x7b, 0xfa, 0x4f, + 0xb5, 0x43, 0xce, 0xe0, 0x98, 0xce, 0x42, 0xd5, 0x62, 0x64, 0x6f, 0xe7, 0x44, 0x5d, 0x05, 0xf7, + 0x93, 0x85, 0xee, 0x97, 0x36, 0xe0, 0x27, 0x85, 0xb1, 0x11, 0x21, 0x82, 0x42, 0x16, 0xc2, 0xda, + 0x6d, 0xac, 0x44, 0x3a, 0xba, 0x8c, 0x5f, 0xa0, 0x6a, 0x7c, 0x11, 0x25, 0x2c, 0xf7, 0x55, 0x9e, + 0xf2, 0x30, 0xa3, 0xf4, 0xa8, 0x8c, 0x92, 0xf7, 0x60, 0xec, 0x98, 0x36, 0xf7, 0x0c, 0xd9, 0x45, + 0x14, 0xef, 0xa0, 0xba, 0x42, 0xfa, 0x09, 0xd1, 0x33, 0xbb, 0x9b, 0xe9, 0xbc, 0x5d, 0x53, 0x9c, + 0xa0, 0x17, 0xd6, 0x14, 0x18, 0x10, 0xfc, 0x18, 0x35, 0x63, 0xce, 0x80, 0x32, 0x98, 0x40, 0x7f, + 0x48, 0x67, 0xad, 0x0d, 0x65, 0xd0, 0x5e, 0x16, 0x8f, 0xe9, 0xcc, 0xfd, 0x6c, 0x21, 0xfb, 0x54, + 0x46, 0x43, 0x2a, 0x96, 0xc9, 0x1a, 0xa0, 0xee, 0x2b, 0x79, 0x3b, 0x9d, 0xb7, 0xeb, 0x9a, 0x14, + 0xf4, 0xc2, 0xba, 0x86, 0x03, 0x82, 0x4f, 0xd0, 0x2d, 0x43, 0x25, 0xda, 0x9a, 0x49, 0xe8, 0x96, + 0x26, 0xd4, 0x02, 0xeb, 0x11, 0x9b, 0x50, 0x2c, 0xba, 0x1f, 0x51, 0x73, 0x8d, 0x95, 0x45, 0x8d, + 0x00, 0xa8, 0xfc, 0x2b, 0x6a, 0x27, 0xab, 0x65, 0x51, 0x15, 0x18, 0x10, 0xdc, 0x41, 0xb5, 0x75, + 0x0b, 0xe5, 0x8f, 0xac, 0xfa, 0xd6, 0x1d, 0xe4, 0x7d, 0xee, 0x17, 0x0b, 0xd9, 0x45, 0xfc, 0x7f, + 0x7e, 0xf1, 0x1b, 0x54, 0x8d, 0x46, 0x7c, 0xc2, 0xa4, 0x7e, 0xe2, 0xee, 0xf3, 0x4c, 0xfa, 0xd7, + 0xbc, 0xbd, 0x33, 0x48, 0xe4, 0xc5, 0xe4, 0xdc, 0x8b, 0xf9, 0xc8, 0x6c, 0x90, 0xf9, 0xec, 0x01, + 0x19, 0xfa, 0x72, 0x36, 0xa6, 0xe0, 0x05, 0x4c, 0xfe, 0xf8, 0xbe, 0x87, 0xcc, 0x82, 0x05, 0x4c, + 0x86, 0x46, 0xab, 0xfb, 0xea, 0x2a, 0x75, 0xac, 0xeb, 0xd4, 0xb1, 0x7e, 0xa7, 0x8e, 0xf5, 0x75, + 0xe1, 0x54, 0xae, 0x17, 0x4e, 0xe5, 0xe7, 0xc2, 0xa9, 0xbc, 0x3d, 0x28, 0xe8, 0x1e, 0xe9, 0x9c, + 0xaf, 0xa9, 0xfc, 0xc0, 0xc5, 0xd0, 0xcf, 0x97, 0x70, 0xba, 0x5a, 0x43, 0x35, 0xe7, 0xbc, 0xaa, + 0xf6, 0xf0, 0xd9, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xbb, 0x29, 0x6e, 0x10, 0x04, 0x00, + 0x00, +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.OperatorRecords) > 0 { + for iNdEx := len(m.OperatorRecords) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.OperatorRecords[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Operators) > 0 { + for iNdEx := len(m.Operators) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Operators[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *OperatorConsKeyRecord) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *OperatorConsKeyRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *OperatorConsKeyRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Chains) > 0 { + for iNdEx := len(m.Chains) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Chains[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.OperatorAddress) > 0 { + i -= len(m.OperatorAddress) + copy(dAtA[i:], m.OperatorAddress) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.OperatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ChainDetails) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ChainDetails) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ChainDetails) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ConsensusKey) > 0 { + i -= len(m.ConsensusKey) + copy(dAtA[i:], m.ConsensusKey) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ConsensusKey))) + i-- + dAtA[i] = 0x12 + } + if len(m.ChainID) > 0 { + i -= len(m.ChainID) + copy(dAtA[i:], m.ChainID) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ChainID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *StakerRecord) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StakerRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StakerRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.StakerDetails) > 0 { + for iNdEx := len(m.StakerDetails) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.StakerDetails[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.StakerID) > 0 { + i -= len(m.StakerID) + copy(dAtA[i:], m.StakerID) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.StakerID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *StakerDetails) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StakerDetails) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StakerDetails) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Details) > 0 { + for iNdEx := len(m.Details) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Details[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.AssetID) > 0 { + i -= len(m.AssetID) + copy(dAtA[i:], m.AssetID) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.AssetID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AssetDetails) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AssetDetails) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AssetDetails) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.OperatorAddress) > 0 { + i -= len(m.OperatorAddress) + copy(dAtA[i:], m.OperatorAddress) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.OperatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Operators) > 0 { + for _, e := range m.Operators { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.OperatorRecords) > 0 { + for _, e := range m.OperatorRecords { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *OperatorConsKeyRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.OperatorAddress) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if len(m.Chains) > 0 { + for _, e := range m.Chains { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *ChainDetails) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainID) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.ConsensusKey) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *StakerRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.StakerID) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if len(m.StakerDetails) > 0 { + for _, e := range m.StakerDetails { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *StakerDetails) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.AssetID) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if len(m.Details) > 0 { + for _, e := range m.Details { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *AssetDetails) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.OperatorAddress) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Operators", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Operators = append(m.Operators, OperatorInfo{}) + if err := m.Operators[len(m.Operators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OperatorRecords", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OperatorRecords = append(m.OperatorRecords, OperatorConsKeyRecord{}) + if err := m.OperatorRecords[len(m.OperatorRecords)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *OperatorConsKeyRecord) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: OperatorConsKeyRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: OperatorConsKeyRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OperatorAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OperatorAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Chains", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Chains = append(m.Chains, ChainDetails{}) + if err := m.Chains[len(m.Chains)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ChainDetails) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ChainDetails: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ChainDetails: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsensusKey", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsensusKey = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StakerRecord) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StakerRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StakerRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StakerID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StakerID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StakerDetails", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StakerDetails = append(m.StakerDetails, StakerDetails{}) + if err := m.StakerDetails[len(m.StakerDetails)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StakerDetails) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StakerDetails: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StakerDetails: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AssetID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AssetID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Details", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Details = append(m.Details, AssetDetails{}) + if err := m.Details[len(m.Details)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AssetDetails) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AssetDetails: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AssetDetails: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OperatorAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OperatorAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/operator/types/genesis_test.go b/x/operator/types/genesis_test.go new file mode 100644 index 000000000..f222bb852 --- /dev/null +++ b/x/operator/types/genesis_test.go @@ -0,0 +1,233 @@ +package types_test + +import ( + "testing" + + utiltx "github.com/ExocoreNetwork/exocore/testutil/tx" + "github.com/ExocoreNetwork/exocore/utils" + "github.com/ExocoreNetwork/exocore/x/operator/types" + "github.com/cometbft/cometbft/crypto/ed25519" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/stretchr/testify/suite" +) + +type GenesisTestSuite struct { + suite.Suite +} + +func (suite *GenesisTestSuite) SetupTest() { +} + +func TestGenesisTestSuite(t *testing.T) { + suite.Run(t, new(GenesisTestSuite)) +} + +func (suite *GenesisTestSuite) TestValidateGenesis() { + key := hexutil.Encode(ed25519.GenPrivKey().PubKey().Bytes()) + accAddress1 := sdk.AccAddress(utiltx.GenerateAddress().Bytes()) + accAddress2 := sdk.AccAddress(utiltx.GenerateAddress().Bytes()) + newGen := &types.GenesisState{} + + testCases := []struct { + name string + genState *types.GenesisState + expPass bool + malleate func(*types.GenesisState) + }{ + { + name: "valid genesis constructor", + genState: newGen, + expPass: true, + }, + { + name: "default", + genState: types.DefaultGenesis(), + expPass: true, + }, + { + name: "invalid genesis state due to non bech32 operator address", + genState: &types.GenesisState{ + Operators: []types.OperatorInfo{ + { + EarningsAddr: "invalid", + }, + }, + }, + expPass: false, + }, + { + name: "invalid genesis state due to duplicate operator address", + genState: &types.GenesisState{ + Operators: []types.OperatorInfo{ + { + EarningsAddr: accAddress1.String(), + }, + { + EarningsAddr: accAddress1.String(), + }, + }, + }, + expPass: false, + }, + { + name: "invalid genesis state due to duplicate lz chain id", + genState: &types.GenesisState{ + Operators: []types.OperatorInfo{ + { + EarningsAddr: accAddress1.String(), + ClientChainEarningsAddr: &types.ClientChainEarningAddrList{ + EarningInfoList: []*types.ClientChainEarningAddrInfo{ + { + LzClientChainID: 1, + ClientChainEarningAddr: utiltx.GenerateAddress().String(), + }, + { + LzClientChainID: 1, + ClientChainEarningAddr: utiltx.GenerateAddress().String(), + }, + }, + }, + }, + }, + }, + expPass: false, + }, + { + name: "invalid genesis state due to invalid cons key operator address", + genState: &types.GenesisState{ + Operators: []types.OperatorInfo{ + { + EarningsAddr: accAddress1.String(), + }, + }, + OperatorRecords: []types.OperatorConsKeyRecord{ + { + OperatorAddress: "invalid", + }, + }, + }, + expPass: false, + }, + { + name: "invalid genesis state due to unregistered operator in cons key", + genState: &types.GenesisState{ + Operators: []types.OperatorInfo{ + { + EarningsAddr: accAddress1.String(), + }, + }, + OperatorRecords: []types.OperatorConsKeyRecord{ + { + OperatorAddress: accAddress2.String(), + }, + }, + }, + expPass: false, + }, + { + name: "invalid genesis state due to duplicate operator in cons key", + genState: &types.GenesisState{ + Operators: []types.OperatorInfo{ + { + EarningsAddr: accAddress1.String(), + }, + { + EarningsAddr: accAddress2.String(), + }, + }, + OperatorRecords: []types.OperatorConsKeyRecord{ + { + OperatorAddress: accAddress1.String(), + Chains: []types.ChainDetails{ + { + ChainID: utils.TestnetChainID, + ConsensusKey: key, + }, + }, + }, + { + OperatorAddress: accAddress1.String(), + Chains: []types.ChainDetails{ + { + ChainID: utils.TestnetChainID, + ConsensusKey: hexutil.Encode(ed25519.GenPrivKey().PubKey().Bytes()), + }, + }, + }, + }, + }, + expPass: false, + }, + { + name: "invalid genesis state due to invalid cons key", + genState: &types.GenesisState{ + Operators: []types.OperatorInfo{ + { + EarningsAddr: accAddress1.String(), + }, + }, + OperatorRecords: []types.OperatorConsKeyRecord{ + { + OperatorAddress: accAddress1.String(), + Chains: []types.ChainDetails{ + { + ChainID: utils.TestnetChainID, + ConsensusKey: key + "fake", + }, + }, + }, + }, + }, + expPass: false, + }, + { + name: "invalid genesis state due to duplicate cons key for the same chain id", + genState: &types.GenesisState{ + Operators: []types.OperatorInfo{ + { + EarningsAddr: accAddress1.String(), + }, + { + EarningsAddr: accAddress2.String(), + }, + }, + OperatorRecords: []types.OperatorConsKeyRecord{ + { + OperatorAddress: accAddress1.String(), + Chains: []types.ChainDetails{ + { + ChainID: utils.TestnetChainID, + ConsensusKey: key, + }, + }, + }, + { + OperatorAddress: accAddress2.String(), + Chains: []types.ChainDetails{ + { + ChainID: utils.TestnetChainID, + ConsensusKey: key, + }, + }, + }, + }, + }, + expPass: false, + }, + } + + for _, tc := range testCases { + tc := tc + if tc.malleate != nil { + tc.malleate(tc.genState) + } + err := tc.genState.Validate() + if tc.expPass { + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Error(err, tc.name) + } + // fmt.Println(tc.name, err) + } +} diff --git a/x/operator/types/hooks.go b/x/operator/types/hooks.go index 0c3441ab6..f27d2b411 100644 --- a/x/operator/types/hooks.go +++ b/x/operator/types/hooks.go @@ -17,7 +17,7 @@ func (hooks MultiOperatorConsentHooks) AfterOperatorOptIn( ctx sdk.Context, addr sdk.AccAddress, chainID string, - pubKey tmprotocrypto.PublicKey, + pubKey *tmprotocrypto.PublicKey, ) { for _, hook := range hooks { hook.AfterOperatorOptIn(ctx, addr, chainID, pubKey) @@ -27,8 +27,8 @@ func (hooks MultiOperatorConsentHooks) AfterOperatorOptIn( func (hooks MultiOperatorConsentHooks) AfterOperatorKeyReplacement( ctx sdk.Context, addr sdk.AccAddress, - oldKey tmprotocrypto.PublicKey, - newAddr tmprotocrypto.PublicKey, + oldKey *tmprotocrypto.PublicKey, + newAddr *tmprotocrypto.PublicKey, chainID string, ) { for _, hook := range hooks { @@ -37,7 +37,7 @@ func (hooks MultiOperatorConsentHooks) AfterOperatorKeyReplacement( } func (hooks MultiOperatorConsentHooks) AfterOperatorOptOutInitiated( - ctx sdk.Context, addr sdk.AccAddress, chainID string, key tmprotocrypto.PublicKey, + ctx sdk.Context, addr sdk.AccAddress, chainID string, key *tmprotocrypto.PublicKey, ) { for _, hook := range hooks { hook.AfterOperatorOptOutInitiated(ctx, addr, chainID, key) diff --git a/x/operator/types/app_chain_utils.go b/x/operator/types/utils.go similarity index 57% rename from x/operator/types/app_chain_utils.go rename to x/operator/types/utils.go index d776a976b..6ec7351a9 100644 --- a/x/operator/types/app_chain_utils.go +++ b/x/operator/types/utils.go @@ -1,13 +1,9 @@ package types import ( - tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" ) -// add for dogfood - // AppendMany appends a variable number of byte slices together func AppendMany(byteses ...[]byte) (out []byte) { for _, bytes := range byteses { @@ -29,13 +25,3 @@ func ChainIDWithLenKey(chainID string) []byte { []byte(chainID), ) } - -// TMCryptoPublicKeyToConsAddr converts a TM public key to an SDK public key -// and returns the associated consensus address -func TMCryptoPublicKeyToConsAddr(k tmprotocrypto.PublicKey) (sdk.ConsAddress, error) { - sdkK, err := cryptocodec.FromTmProtoPublicKey(k) - if err != nil { - return nil, err - } - return sdk.GetConsAddress(sdkK), nil -} diff --git a/x/reward/keeper/claim_reward.go b/x/reward/keeper/claim_reward.go index 182b074f8..aa7af650e 100644 --- a/x/reward/keeper/claim_reward.go +++ b/x/reward/keeper/claim_reward.go @@ -149,3 +149,13 @@ func (k Keeper) RewardForWithdraw(ctx sdk.Context, event *RewardParams) error { } return nil } + +// WithdrawDelegationRewards is an implementation of a function in the distribution interface. +// Since this module acts as the distribution module for our network, this function is here. +// When implemented, this function should find the pending (native token) rewards for the +// specified delegator and validator address combination and send them to the delegator address. +func (Keeper) WithdrawDelegationRewards( + sdk.Context, sdk.AccAddress, sdk.ValAddress, +) (sdk.Coins, error) { + return nil, rtypes.ErrNotSupportYet +} diff --git a/x/reward/types/errors.go b/x/reward/types/errors.go index 75688e4d1..320b86b51 100644 --- a/x/reward/types/errors.go +++ b/x/reward/types/errors.go @@ -14,4 +14,5 @@ var ( ErrNoParamsKey = errorsmod.Register(ModuleName, 2, "there is no stored key for params") ErrRewardAmountIsNegative = errorsmod.Register(ModuleName, 3, "the reward amount is negative") ErrRewardAssetNotExist = errorsmod.Register(ModuleName, 4, "the reward asset doesn't exist") + ErrNotSupportYet = errorsmod.Register(ModuleName, 5, "don't have supported it yet") )