diff --git a/simapp/helpers/test_helpers.go b/simapp/helpers/test_helpers.go index a0888c09019e..2afb4e59c6a2 100644 --- a/simapp/helpers/test_helpers.go +++ b/simapp/helpers/test_helpers.go @@ -13,7 +13,7 @@ import ( // SimAppChainID hardcoded chainID for simulation const ( - DefaultGenTxGas = 10000000 + DefaultGenTxGas = 2600000 // An increase is needed when adding checks to staking/msg_server.go SimAppChainID = "simulation-app" ) diff --git a/x/staking/keeper/msg_server.go b/x/staking/keeper/msg_server.go index 4c3da3a79985..5cae6a123bc9 100644 --- a/x/staking/keeper/msg_server.go +++ b/x/staking/keeper/msg_server.go @@ -85,17 +85,17 @@ func (k msgServer) CreateValidator(goCtx context.Context, msg *types.MsgCreateVa } } - orchAddr, err := sdk.AccAddressFromBech32(msg.Orchestrator) + orchAddr, err := k.validateOrchestratorAddress(ctx, msg.Orchestrator) if err != nil { return nil, err } - evmAddr, err := types.NewEthAddress(msg.EthAddress) + evmAddr, err := k.validateEthereumAddress(ctx, msg.EthAddress) if err != nil { return nil, err } - validator, err := types.NewValidator(valAddr, pk, msg.Description, orchAddr, *evmAddr) + validator, err := types.NewValidator(valAddr, pk, msg.Description, orchAddr, evmAddr) if err != nil { return nil, err } @@ -197,14 +197,22 @@ func (k msgServer) EditValidator(goCtx context.Context, msg *types.MsgEditValida validator.MinSelfDelegation = *msg.MinSelfDelegation } - if msg.EthAddress != "" { - validator.EthAddress = msg.EthAddress - } - if msg.Orchestrator != "" { + _, err := k.validateOrchestratorAddress(ctx, msg.Orchestrator) + if err != nil { + return nil, err + } validator.Orchestrator = msg.Orchestrator } + if msg.EthAddress != "" { + _, err := k.validateEthereumAddress(ctx, msg.EthAddress) + if err != nil { + return nil, err + } + validator.EthAddress = msg.EthAddress + } + k.SetValidator(ctx, validator) ctx.EventManager().EmitEvents(sdk.Events{ @@ -411,6 +419,32 @@ func (k msgServer) Undelegate(goCtx context.Context, msg *types.MsgUndelegate) ( }, nil } +func (k msgServer) validateEthereumAddress(ctx sdk.Context, ethAddr string) (types.EthAddress, error) { + evmAddr, err := types.NewEthAddress(ethAddr) + if err != nil { + return types.EthAddress{}, err + } + if evmAddr.GetAddress() == types.EthZeroAddress { + return types.EthAddress{}, types.ErrValidatorEthereumZeroAddress + } + if _, found := k.GetValidatorByEthereumAddress(ctx, *evmAddr); found { + return types.EthAddress{}, types.ErrValidatorEthereumAddressExists + } + return *evmAddr, nil +} + +func (k msgServer) validateOrchestratorAddress(ctx sdk.Context, orchAddr string) (sdk.AccAddress, error) { + addr, err := sdk.AccAddressFromBech32(orchAddr) + if err != nil { + return sdk.AccAddress{}, err + } + // FIXME should we add the zero accAddr check? + if _, found := k.GetValidatorByOrchestratorAddress(ctx, addr); found { + return sdk.AccAddress{}, types.ErrValidatorOrchestratorAddressExists + } + return addr, nil +} + // CancelUnbondingDelegation defines a method for canceling the unbonding delegation // and delegate back to the validator. func (k msgServer) CancelUnbondingDelegation(goCtx context.Context, msg *types.MsgCancelUnbondingDelegation) (*types.MsgCancelUnbondingDelegationResponse, error) { diff --git a/x/staking/keeper/validator.go b/x/staking/keeper/validator.go index bd1d9842c021..47bbd74409ef 100644 --- a/x/staking/keeper/validator.go +++ b/x/staking/keeper/validator.go @@ -79,6 +79,32 @@ func (k Keeper) mustGetValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAdd return validator } +func (k Keeper) GetValidatorByOrchestratorAddress(ctx sdk.Context, orch sdk.AccAddress) (types.Validator, bool) { + // TODO optimise these queries and even add grpc queries for them. + // Issue: https://github.com/celestiaorg/cosmos-sdk/issues/129 + validators := k.GetAllValidators(ctx) + for _, val := range validators { + if val.Orchestrator == orch.String() { + return val, true + } + } + + return types.Validator{}, false +} + +func (k Keeper) GetValidatorByEthereumAddress(ctx sdk.Context, eth types.EthAddress) (types.Validator, bool) { + // TODO optimise these queries and even add grpc queries for them. + // Issue: https://github.com/celestiaorg/cosmos-sdk/issues/129 + validators := k.GetAllValidators(ctx) + for _, val := range validators { + if val.EthAddress == eth.GetAddress() { + return val, true + } + } + + return types.Validator{}, false +} + // set the main record holding validator details func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) diff --git a/x/staking/simulation/operations.go b/x/staking/simulation/operations.go index 47a8ea187b44..6ab94ce2ce9b 100644 --- a/x/staking/simulation/operations.go +++ b/x/staking/simulation/operations.go @@ -158,8 +158,10 @@ func SimulateMsgCreateValidator(ak types.AccountKeeper, bk types.BankKeeper, k k simtypes.RandomDecAmount(r, maxCommission), ) - ethAddr, _ := types.NewEthAddress("0x91DEd26b5f38B065FC0204c7929Da6b2A21277Cd") orchAddr := simAccount.Address + // create an Ethereum address from the orchestrator address + // this is mainly to have a deterministic way of generating an Ethereum address on every run // to have a long enough bytes array + ethAddr, _ := types.NewEthAddress("0x" + fmt.Sprintf("%X", simAccount.Address.Bytes())) msg, err := types.NewMsgCreateValidator(address, simAccount.ConsKey.PubKey(), selfDelegation, description, commission, sdk.OneInt(), orchAddr, *ethAddr) if err != nil { diff --git a/x/staking/types/errors.go b/x/staking/types/errors.go index a9a6e43e35b6..1f14c0391be6 100644 --- a/x/staking/types/errors.go +++ b/x/staking/types/errors.go @@ -11,43 +11,46 @@ import ( // // REF: https://github.com/cosmos/cosmos-sdk/issues/5450 var ( - ErrEmptyValidatorAddr = sdkerrors.Register(ModuleName, 2, "empty validator address") - ErrNoValidatorFound = sdkerrors.Register(ModuleName, 3, "validator does not exist") - ErrValidatorOwnerExists = sdkerrors.Register(ModuleName, 4, "validator already exist for this operator address; must use new validator operator address") - ErrValidatorPubKeyExists = sdkerrors.Register(ModuleName, 5, "validator already exist for this pubkey; must use new validator pubkey") - ErrValidatorPubKeyTypeNotSupported = sdkerrors.Register(ModuleName, 6, "validator pubkey type is not supported") - ErrValidatorJailed = sdkerrors.Register(ModuleName, 7, "validator for this address is currently jailed") - ErrBadRemoveValidator = sdkerrors.Register(ModuleName, 8, "failed to remove validator") - ErrCommissionNegative = sdkerrors.Register(ModuleName, 9, "commission must be positive") - ErrCommissionHuge = sdkerrors.Register(ModuleName, 10, "commission cannot be more than 100%") - ErrCommissionGTMaxRate = sdkerrors.Register(ModuleName, 11, "commission cannot be more than the max rate") - ErrCommissionUpdateTime = sdkerrors.Register(ModuleName, 12, "commission cannot be changed more than once in 24h") - ErrCommissionChangeRateNegative = sdkerrors.Register(ModuleName, 13, "commission change rate must be positive") - ErrCommissionChangeRateGTMaxRate = sdkerrors.Register(ModuleName, 14, "commission change rate cannot be more than the max rate") - ErrCommissionGTMaxChangeRate = sdkerrors.Register(ModuleName, 15, "commission cannot be changed more than max change rate") - ErrSelfDelegationBelowMinimum = sdkerrors.Register(ModuleName, 16, "validator's self delegation must be greater than their minimum self delegation") - ErrMinSelfDelegationDecreased = sdkerrors.Register(ModuleName, 17, "minimum self delegation cannot be decrease") - ErrEmptyDelegatorAddr = sdkerrors.Register(ModuleName, 18, "empty delegator address") - ErrNoDelegation = sdkerrors.Register(ModuleName, 19, "no delegation for (address, validator) tuple") - ErrBadDelegatorAddr = sdkerrors.Register(ModuleName, 20, "delegator does not exist with address") - ErrNoDelegatorForAddress = sdkerrors.Register(ModuleName, 21, "delegator does not contain delegation") - ErrInsufficientShares = sdkerrors.Register(ModuleName, 22, "insufficient delegation shares") - ErrDelegationValidatorEmpty = sdkerrors.Register(ModuleName, 23, "cannot delegate to an empty validator") - ErrNotEnoughDelegationShares = sdkerrors.Register(ModuleName, 24, "not enough delegation shares") - ErrNotMature = sdkerrors.Register(ModuleName, 25, "entry not mature") - ErrNoUnbondingDelegation = sdkerrors.Register(ModuleName, 26, "no unbonding delegation found") - ErrMaxUnbondingDelegationEntries = sdkerrors.Register(ModuleName, 27, "too many unbonding delegation entries for (delegator, validator) tuple") - ErrNoRedelegation = sdkerrors.Register(ModuleName, 28, "no redelegation found") - ErrSelfRedelegation = sdkerrors.Register(ModuleName, 29, "cannot redelegate to the same validator") - ErrTinyRedelegationAmount = sdkerrors.Register(ModuleName, 30, "too few tokens to redelegate (truncates to zero tokens)") - ErrBadRedelegationDst = sdkerrors.Register(ModuleName, 31, "redelegation destination validator not found") - ErrTransitiveRedelegation = sdkerrors.Register(ModuleName, 32, "redelegation to this validator already in progress; first redelegation to this validator must complete before next redelegation") - ErrMaxRedelegationEntries = sdkerrors.Register(ModuleName, 33, "too many redelegation entries for (delegator, src-validator, dst-validator) tuple") - ErrDelegatorShareExRateInvalid = sdkerrors.Register(ModuleName, 34, "cannot delegate to validators with invalid (zero) ex-rate") - ErrBothShareMsgsGiven = sdkerrors.Register(ModuleName, 35, "both shares amount and shares percent provided") - ErrNeitherShareMsgsGiven = sdkerrors.Register(ModuleName, 36, "neither shares amount nor shares percent provided") - ErrInvalidHistoricalInfo = sdkerrors.Register(ModuleName, 37, "invalid historical info") - ErrNoHistoricalInfo = sdkerrors.Register(ModuleName, 38, "no historical info found") - ErrEmptyValidatorPubKey = sdkerrors.Register(ModuleName, 39, "empty validator public key") - ErrCommissionLTMinRate = sdkerrors.Register(ModuleName, 40, "commission cannot be less than min rate") + ErrEmptyValidatorAddr = sdkerrors.Register(ModuleName, 2, "empty validator address") + ErrNoValidatorFound = sdkerrors.Register(ModuleName, 3, "validator does not exist") + ErrValidatorOwnerExists = sdkerrors.Register(ModuleName, 4, "validator already exist for this operator address; must use new validator operator address") + ErrValidatorPubKeyExists = sdkerrors.Register(ModuleName, 5, "validator already exist for this pubkey; must use new validator pubkey") + ErrValidatorPubKeyTypeNotSupported = sdkerrors.Register(ModuleName, 6, "validator pubkey type is not supported") + ErrValidatorJailed = sdkerrors.Register(ModuleName, 7, "validator for this address is currently jailed") + ErrBadRemoveValidator = sdkerrors.Register(ModuleName, 8, "failed to remove validator") + ErrCommissionNegative = sdkerrors.Register(ModuleName, 9, "commission must be positive") + ErrCommissionHuge = sdkerrors.Register(ModuleName, 10, "commission cannot be more than 100%") + ErrCommissionGTMaxRate = sdkerrors.Register(ModuleName, 11, "commission cannot be more than the max rate") + ErrCommissionUpdateTime = sdkerrors.Register(ModuleName, 12, "commission cannot be changed more than once in 24h") + ErrCommissionChangeRateNegative = sdkerrors.Register(ModuleName, 13, "commission change rate must be positive") + ErrCommissionChangeRateGTMaxRate = sdkerrors.Register(ModuleName, 14, "commission change rate cannot be more than the max rate") + ErrCommissionGTMaxChangeRate = sdkerrors.Register(ModuleName, 15, "commission cannot be changed more than max change rate") + ErrSelfDelegationBelowMinimum = sdkerrors.Register(ModuleName, 16, "validator's self delegation must be greater than their minimum self delegation") + ErrMinSelfDelegationDecreased = sdkerrors.Register(ModuleName, 17, "minimum self delegation cannot be decrease") + ErrEmptyDelegatorAddr = sdkerrors.Register(ModuleName, 18, "empty delegator address") + ErrNoDelegation = sdkerrors.Register(ModuleName, 19, "no delegation for (address, validator) tuple") + ErrBadDelegatorAddr = sdkerrors.Register(ModuleName, 20, "delegator does not exist with address") + ErrNoDelegatorForAddress = sdkerrors.Register(ModuleName, 21, "delegator does not contain delegation") + ErrInsufficientShares = sdkerrors.Register(ModuleName, 22, "insufficient delegation shares") + ErrDelegationValidatorEmpty = sdkerrors.Register(ModuleName, 23, "cannot delegate to an empty validator") + ErrNotEnoughDelegationShares = sdkerrors.Register(ModuleName, 24, "not enough delegation shares") + ErrNotMature = sdkerrors.Register(ModuleName, 25, "entry not mature") + ErrNoUnbondingDelegation = sdkerrors.Register(ModuleName, 26, "no unbonding delegation found") + ErrMaxUnbondingDelegationEntries = sdkerrors.Register(ModuleName, 27, "too many unbonding delegation entries for (delegator, validator) tuple") + ErrNoRedelegation = sdkerrors.Register(ModuleName, 28, "no redelegation found") + ErrSelfRedelegation = sdkerrors.Register(ModuleName, 29, "cannot redelegate to the same validator") + ErrTinyRedelegationAmount = sdkerrors.Register(ModuleName, 30, "too few tokens to redelegate (truncates to zero tokens)") + ErrBadRedelegationDst = sdkerrors.Register(ModuleName, 31, "redelegation destination validator not found") + ErrTransitiveRedelegation = sdkerrors.Register(ModuleName, 32, "redelegation to this validator already in progress; first redelegation to this validator must complete before next redelegation") + ErrMaxRedelegationEntries = sdkerrors.Register(ModuleName, 33, "too many redelegation entries for (delegator, src-validator, dst-validator) tuple") + ErrDelegatorShareExRateInvalid = sdkerrors.Register(ModuleName, 34, "cannot delegate to validators with invalid (zero) ex-rate") + ErrBothShareMsgsGiven = sdkerrors.Register(ModuleName, 35, "both shares amount and shares percent provided") + ErrNeitherShareMsgsGiven = sdkerrors.Register(ModuleName, 36, "neither shares amount nor shares percent provided") + ErrInvalidHistoricalInfo = sdkerrors.Register(ModuleName, 37, "invalid historical info") + ErrNoHistoricalInfo = sdkerrors.Register(ModuleName, 38, "no historical info found") + ErrEmptyValidatorPubKey = sdkerrors.Register(ModuleName, 39, "empty validator public key") + ErrCommissionLTMinRate = sdkerrors.Register(ModuleName, 40, "commission cannot be less than min rate") + ErrValidatorOrchestratorAddressExists = sdkerrors.Register(ModuleName, 40, "validator already exist for this orchestrator address; must use new validator orchestrator address") + ErrValidatorEthereumAddressExists = sdkerrors.Register(ModuleName, 41, "validator already exist for this ethereum address; must use new validator ethereum address") + ErrValidatorEthereumZeroAddress = sdkerrors.Register(ModuleName, 42, "cannot use zero address for ethereum address; must use a non zero validator ethereum address") ) diff --git a/x/staking/types/ethereum.go b/x/staking/types/ethereum.go index 5d4114708579..61bfe749efda 100644 --- a/x/staking/types/ethereum.go +++ b/x/staking/types/ethereum.go @@ -13,6 +13,7 @@ import ( const ( // ETHContractAddressLen is the length of contract address strings ETHContractAddressLen = 42 + EthZeroAddress = "0x0000000000000000000000000000000000000000" ) // EthAddress Regular EthAddress