Merge PR #4865: Add security contact to Validator description

This commit is contained in:
frog power 4000 2019-08-12 09:10:16 -04:00 committed by Alexander Bezobchuk
parent a6e776c47e
commit 771f8a04f3
21 changed files with 247 additions and 82 deletions

View File

@ -0,0 +1 @@
#4814 Add security contact to Validator description

View File

@ -2343,6 +2343,8 @@ definitions:
type: string
website:
type: string
security_contact:
type: string
details:
type: string
bond_height:

View File

@ -85,10 +85,11 @@ CommissionRates struct {
}
type Description struct {
Moniker string // name
Identity string // optional identity signature (ex. UPort or Keybase)
Website string // optional website link
Details string // optional details
Moniker string // name
Identity string // optional identity signature (ex. UPort or Keybase)
Website string // optional website link
SecurityContact string // optional email for security contact
Details string // optional details
}
```

View File

@ -211,7 +211,7 @@ func TestDecodeStakingStore(t *testing.T) {
bondTime := time.Now().UTC()
val := staking.NewValidator(valAddr1, delPk1, staking.NewDescription("test", "test", "test", "test"))
val := staking.NewValidator(valAddr1, delPk1, staking.NewDescription("test", "test", "test", "test", "test"))
del := staking.NewDelegation(delAddr1, valAddr1, sdk.OneDec())
ubd := staking.NewUnbondingDelegation(delAddr1, valAddr1, 15, bondTime, sdk.OneInt())
red := staking.NewRedelegation(delAddr1, valAddr1, valAddr1, 12, bondTime, sdk.OneInt(), sdk.OneDec())

View File

@ -12,7 +12,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
extypes "github.com/cosmos/cosmos-sdk/x/genutil"
v036 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v036"
v036 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v0_36"
)
var migrationMap = extypes.MigrationMap{

View File

@ -18,7 +18,7 @@ var (
func TestValidateGenesisMultipleMessages(t *testing.T) {
desc := stakingtypes.NewDescription("testname", "", "", "")
desc := stakingtypes.NewDescription("testname", "", "", "", "")
comm := stakingtypes.CommissionRates{}
msg1 := stakingtypes.NewMsgCreateValidator(sdk.ValAddress(pk1.Address()), pk1,
@ -35,7 +35,7 @@ func TestValidateGenesisMultipleMessages(t *testing.T) {
}
func TestValidateGenesisBadMessage(t *testing.T) {
desc := stakingtypes.NewDescription("testname", "", "", "")
desc := stakingtypes.NewDescription("testname", "", "", "", "")
msg1 := stakingtypes.NewMsgEditValidator(sdk.ValAddress(pk1.Address()), desc, nil, nil)

View File

@ -14,9 +14,9 @@ import (
"github.com/tendermint/tendermint/crypto/ed25519"
abci "github.com/tendermint/tendermint/abci/types"
dbm "github.com/tendermint/tm-db"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store"
@ -61,7 +61,7 @@ var (
// TODO: remove dependency with staking
var (
TestProposal = types.NewTextProposal("Test", "description")
TestDescription = staking.NewDescription("T", "E", "S", "T")
TestDescription = staking.NewDescription("T", "E", "S", "T", "Z")
TestCommissionRates = staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec())
)
@ -153,7 +153,7 @@ func createTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context
AddRoute(types.RouterKey, types.ProposalHandler)
keeper := NewKeeper(cdc, keyGov, pk.Subspace(types.DefaultParamspace).WithKeyTable(types.ParamKeyTable()),
supplyKeeper, sk, types.DefaultCodespace, rtr)
supplyKeeper, sk, types.DefaultCodespace, rtr)
keeper.SetProposalID(ctx, types.DefaultStartingProposalID)
keeper.SetDepositParams(ctx, types.DefaultDepositParams())

View File

@ -81,7 +81,7 @@ func getMockApp(t *testing.T, numGenAccs int, genState types.GenesisState, genAc
sk := staking.NewKeeper(mApp.Cdc, keyStaking, tKeyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace)
keeper := keep.NewKeeper(mApp.Cdc, keyGov, pk.Subspace(DefaultParamspace).WithKeyTable(ParamKeyTable()),
supplyKeeper, sk, types.DefaultCodespace, rtr)
supplyKeeper, sk, types.DefaultCodespace, rtr)
mApp.Router().AddRoute(types.RouterKey, NewHandler(keeper))
mApp.QueryRouter().AddRoute(types.QuerierRoute, keep.NewQuerier(keeper))

View File

@ -127,7 +127,7 @@ func TestSlashingMsgs(t *testing.T) {
accs := []auth.Account{acc1}
mock.SetGenesis(mapp, accs)
description := staking.NewDescription("foo_moniker", "", "", "")
description := staking.NewDescription("foo_moniker", "", "", "", "")
commission := staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec())
createValidatorMsg := staking.NewMsgCreateValidator(

View File

@ -136,7 +136,7 @@ func TestStakingMsgs(t *testing.T) {
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin})
// create validator
description := NewDescription("foo_moniker", "", "", "")
description := NewDescription("foo_moniker", "", "", "", "")
createValidatorMsg := NewMsgCreateValidator(
sdk.ValAddress(addr1), priv1.PubKey(), bondCoin, description, commissionRates, sdk.OneInt(),
)
@ -157,7 +157,7 @@ func TestStakingMsgs(t *testing.T) {
mApp.BeginBlock(abci.RequestBeginBlock{Header: header})
// edit the validator
description = NewDescription("bar_moniker", "", "", "")
description = NewDescription("bar_moniker", "", "", "", "")
editValidatorMsg := NewMsgEditValidator(sdk.ValAddress(addr1), description, nil, nil)
header = abci.Header{Height: mApp.LastBlockHeight() + 1}

View File

@ -16,10 +16,11 @@ const (
FlagSharesAmount = "shares-amount"
FlagSharesFraction = "shares-fraction"
FlagMoniker = "moniker"
FlagIdentity = "identity"
FlagWebsite = "website"
FlagDetails = "details"
FlagMoniker = "moniker"
FlagIdentity = "identity"
FlagWebsite = "website"
FlagSecurityContact = "security-contact"
FlagDetails = "details"
FlagCommissionRate = "commission-rate"
FlagCommissionMaxRate = "commission-max-rate"
@ -54,6 +55,7 @@ func init() {
fsDescriptionCreate.String(FlagMoniker, "", "The validator's name")
fsDescriptionCreate.String(FlagIdentity, "", "The optional identity signature (ex. UPort or Keybase)")
fsDescriptionCreate.String(FlagWebsite, "", "The validator's (optional) website")
fsDescriptionCreate.String(FlagSecurityContact, "", "The validator's (optional) security contact email")
fsDescriptionCreate.String(FlagDetails, "", "The validator's (optional) details")
fsCommissionUpdate.String(FlagCommissionRate, "", "The new commission rate percentage")
FsCommissionCreate.String(FlagCommissionRate, "", "The initial commission rate percentage")
@ -63,6 +65,7 @@ func init() {
fsDescriptionEdit.String(FlagMoniker, types.DoNotModifyDesc, "The validator's name")
fsDescriptionEdit.String(FlagIdentity, types.DoNotModifyDesc, "The (optional) identity signature (ex. UPort or Keybase)")
fsDescriptionEdit.String(FlagWebsite, types.DoNotModifyDesc, "The validator's (optional) website")
fsDescriptionEdit.String(FlagSecurityContact, types.DoNotModifyDesc, "The validator's (optional) security contact email")
fsDescriptionEdit.String(FlagDetails, types.DoNotModifyDesc, "The validator's (optional) details")
fsValidator.String(FlagAddressValidator, "", "The Bech32 address of the validator")
fsRedelegation.String(FlagAddressValidatorSrc, "", "The Bech32 address of the source validator")

View File

@ -89,12 +89,13 @@ func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command {
cliCtx := context.NewCLIContext().WithCodec(cdc)
valAddr := cliCtx.GetFromAddress()
description := types.Description{
Moniker: viper.GetString(FlagMoniker),
Identity: viper.GetString(FlagIdentity),
Website: viper.GetString(FlagWebsite),
Details: viper.GetString(FlagDetails),
}
description := types.NewDescription(
viper.GetString(FlagMoniker),
viper.GetString(FlagIdentity),
viper.GetString(FlagWebsite),
viper.GetString(FlagSecurityContact),
viper.GetString(FlagDetails),
)
var newRate *sdk.Dec
@ -265,6 +266,7 @@ func CreateValidatorMsgHelpers(ipDefault string) (fs *flag.FlagSet, nodeIDFlag,
fsCreateValidator.String(FlagIP, ipDefault, "The node's public IP")
fsCreateValidator.String(FlagNodeID, "", "The node's NodeID")
fsCreateValidator.String(FlagWebsite, "", "The validator's (optional) website")
fsCreateValidator.String(FlagSecurityContact, "", "The validator's (optional) security contact email")
fsCreateValidator.String(FlagDetails, "", "The validator's (optional) details")
fsCreateValidator.String(FlagIdentity, "", "The (optional) identity signature (ex. UPort or Keybase)")
fsCreateValidator.AddFlagSet(FsCommissionCreate)
@ -297,6 +299,7 @@ func PrepareFlagsForTxCreateValidator(
}
website := viper.GetString(FlagWebsite)
securityContact := viper.GetString(FlagSecurityContact)
details := viper.GetString(FlagDetails)
identity := viper.GetString(FlagIdentity)
@ -307,6 +310,7 @@ func PrepareFlagsForTxCreateValidator(
viper.Set(FlagPubKey, sdk.MustBech32ifyConsPub(valPubKey))
viper.Set(FlagMoniker, config.Moniker)
viper.Set(FlagWebsite, website)
viper.Set(FlagSecurityContact, securityContact)
viper.Set(FlagDetails, details)
viper.Set(FlagIdentity, identity)
@ -350,6 +354,7 @@ func BuildCreateValidatorMsg(cliCtx context.CLIContext, txBldr auth.TxBuilder) (
viper.GetString(FlagMoniker),
viper.GetString(FlagIdentity),
viper.GetString(FlagWebsite),
viper.GetString(FlagSecurityContact),
viper.GetString(FlagDetails),
)

View File

@ -28,13 +28,13 @@ func TestInitGenesis(t *testing.T) {
// initialize the validators
validators[0].OperatorAddress = sdk.ValAddress(keep.Addrs[0])
validators[0].ConsPubKey = keep.PKs[0]
validators[0].Description = NewDescription("hoop", "", "", "")
validators[0].Description = NewDescription("hoop", "", "", "", "")
validators[0].Status = sdk.Bonded
validators[0].Tokens = valTokens
validators[0].DelegatorShares = valTokens.ToDec()
validators[1].OperatorAddress = sdk.ValAddress(keep.Addrs[1])
validators[1].ConsPubKey = keep.PKs[1]
validators[1].Description = NewDescription("bloop", "", "", "")
validators[1].Description = NewDescription("bloop", "", "", "", "")
validators[1].Status = sdk.Bonded
validators[1].Tokens = valTokens
validators[1].DelegatorShares = valTokens.ToDec()
@ -76,7 +76,7 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) {
for i := range validators {
validators[i] = NewValidator(sdk.ValAddress(keep.Addrs[i]),
keep.PKs[i], NewDescription(fmt.Sprintf("#%d", i), "", "", ""))
keep.PKs[i], NewDescription(fmt.Sprintf("#%d", i), "", "", "", ""))
validators[i].Status = sdk.Bonded
@ -102,7 +102,7 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) {
func TestValidateGenesis(t *testing.T) {
genValidators1 := make([]types.Validator, 1, 5)
pk := ed25519.GenPrivKey().PubKey()
genValidators1[0] = types.NewValidator(sdk.ValAddress(pk.Address()), pk, types.NewDescription("", "", "", ""))
genValidators1[0] = types.NewValidator(sdk.ValAddress(pk.Address()), pk, types.NewDescription("", "", "", "", ""))
genValidators1[0].Tokens = sdk.OneInt()
genValidators1[0].DelegatorShares = sdk.OneDec()

View File

@ -0,0 +1,51 @@
// DONTCOVER
// nolint
package v0_37
import (
v036staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v0_36"
)
// Migrate accepts exported genesis state from v0.34 and migrates it to v0.36
// genesis state. All entries are identical except for validator slashing events
// which now include the period.
func Migrate(oldGenState v036staking.GenesisState) GenesisState {
return NewGenesisState(
oldGenState.Params,
oldGenState.LastTotalPower,
oldGenState.LastValidatorPowers,
migrateValidators(oldGenState.Validators),
oldGenState.Delegations,
oldGenState.UnbondingDelegations,
oldGenState.Redelegations,
oldGenState.Exported,
)
}
func migrateValidators(oldValidators v036staking.Validators) Validators {
validators := make(Validators, len(oldValidators))
for i, val := range oldValidators {
validators[i] = Validator{
OperatorAddress: val.OperatorAddress,
ConsPubKey: val.ConsPubKey,
Jailed: val.Jailed,
Status: val.Status,
Tokens: val.Tokens,
DelegatorShares: val.DelegatorShares,
Description: NewDescription(
val.Description.Moniker,
val.Description.Identity,
val.Description.Website,
"", // security contact field
val.Description.Details,
),
UnbondingHeight: val.UnbondingHeight,
UnbondingCompletionTime: val.UnbondingCompletionTime,
Commission: val.Commission,
MinSelfDelegation: val.MinSelfDelegation,
}
}
return validators
}

View File

@ -0,0 +1,86 @@
// DONTCOVER
// nolint
package v0_37
import (
"time"
"github.com/tendermint/tendermint/crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
v034staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v0_34"
v036staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v0_36"
)
const (
ModuleName = "staking"
)
type (
Description struct {
Moniker string `json:"moniker" yaml:"moniker"`
Identity string `json:"identity" yaml:"identity"`
Website string `json:"website" yaml:"website"`
SecurityContact string `json:"security_contact" yaml:"security_contact"`
Details string `json:"details" yaml:"details"`
}
Validator struct {
OperatorAddress sdk.ValAddress `json:"operator_address" yaml:"operator_address"`
ConsPubKey crypto.PubKey `json:"consensus_pubkey" yaml:"consensus_pubkey"`
Jailed bool `json:"jailed" yaml:"jailed"`
Status sdk.BondStatus `json:"status" yaml:"status"`
Tokens sdk.Int `json:"tokens" yaml:"tokens"`
DelegatorShares sdk.Dec `json:"delegator_shares" yaml:"delegator_shares"`
Description Description `json:"description" yaml:"description"`
UnbondingHeight int64 `json:"unbonding_height" yaml:"unbonding_height"`
UnbondingCompletionTime time.Time `json:"unbonding_time" yaml:"unbonding_time"`
Commission v036staking.Commission `json:"commission" yaml:"commission"`
MinSelfDelegation sdk.Int `json:"min_self_delegation" yaml:"min_self_delegation"`
}
Validators []Validator
GenesisState struct {
Params v034staking.Params `json:"params"`
LastTotalPower sdk.Int `json:"last_total_power"`
LastValidatorPowers []v034staking.LastValidatorPower `json:"last_validator_powers"`
Validators Validators `json:"validators"`
Delegations v034staking.Delegations `json:"delegations"`
UnbondingDelegations []v034staking.UnbondingDelegation `json:"unbonding_delegations"`
Redelegations []v034staking.Redelegation `json:"redelegations"`
Exported bool `json:"exported"`
}
)
// NewDescription creates a new Description object
func NewDescription(moniker, identity, website,
securityContact, details string) Description {
return Description{
Moniker: moniker,
Identity: identity,
Website: website,
SecurityContact: securityContact,
Details: details,
}
}
// NewGenesisState creates a new GenesisState object
func NewGenesisState(
params v034staking.Params, lastTotalPower sdk.Int, lastValPowers []v034staking.LastValidatorPower,
validators Validators, delegations v034staking.Delegations,
ubds []v034staking.UnbondingDelegation, reds []v034staking.Redelegation, exported bool,
) GenesisState {
return GenesisState{
Params: params,
LastTotalPower: lastTotalPower,
LastValidatorPowers: lastValPowers,
Validators: validators,
Delegations: delegations,
UnbondingDelegations: ubds,
Redelegations: reds,
Exported: exported,
}
}

View File

@ -20,9 +20,13 @@ func SimulateMsgCreateValidator(m auth.AccountKeeper, k staking.Keeper) simulati
opMsg simulation.OperationMsg, fOps []simulation.FutureOperation, err error) {
denom := k.GetParams(ctx).BondDenom
description := staking.Description{
Moniker: simulation.RandStringOfLength(r, 10),
}
description := staking.NewDescription(
simulation.RandStringOfLength(r, 10),
simulation.RandStringOfLength(r, 10),
simulation.RandStringOfLength(r, 10),
simulation.RandStringOfLength(r, 10),
simulation.RandStringOfLength(r, 10),
)
maxCommission := sdk.NewDecWithPrec(r.Int63n(1000), 3)
commission := staking.NewCommissionRates(
@ -67,12 +71,13 @@ func SimulateMsgEditValidator(k staking.Keeper) simulation.Operation {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
accs []simulation.Account) (opMsg simulation.OperationMsg, fOps []simulation.FutureOperation, err error) {
description := staking.Description{
Moniker: simulation.RandStringOfLength(r, 10),
Identity: simulation.RandStringOfLength(r, 10),
Website: simulation.RandStringOfLength(r, 10),
Details: simulation.RandStringOfLength(r, 10),
}
description := staking.NewDescription(
simulation.RandStringOfLength(r, 10),
simulation.RandStringOfLength(r, 10),
simulation.RandStringOfLength(r, 10),
simulation.RandStringOfLength(r, 10),
simulation.RandStringOfLength(r, 10),
)
if len(k.GetAllValidators(ctx)) == 0 {
return simulation.NoOpMsg(staking.ModuleName), nil, nil

View File

@ -20,27 +20,27 @@ func TestMsgCreateValidator(t *testing.T) {
commission2 := NewCommissionRates(sdk.NewDec(5), sdk.NewDec(5), sdk.NewDec(5))
tests := []struct {
name, moniker, identity, website, details string
CommissionRates CommissionRates
minSelfDelegation sdk.Int
validatorAddr sdk.ValAddress
pubkey crypto.PubKey
bond sdk.Coin
expectPass bool
name, moniker, identity, website, securityContact, details string
CommissionRates CommissionRates
minSelfDelegation sdk.Int
validatorAddr sdk.ValAddress
pubkey crypto.PubKey
bond sdk.Coin
expectPass bool
}{
{"basic good", "a", "b", "c", "d", commission1, sdk.OneInt(), valAddr1, pk1, coinPos, true},
{"partial description", "", "", "c", "", commission1, sdk.OneInt(), valAddr1, pk1, coinPos, true},
{"empty description", "", "", "", "", commission2, sdk.OneInt(), valAddr1, pk1, coinPos, false},
{"empty address", "a", "b", "c", "d", commission2, sdk.OneInt(), emptyAddr, pk1, coinPos, false},
{"empty pubkey", "a", "b", "c", "d", commission1, sdk.OneInt(), valAddr1, emptyPubkey, coinPos, true},
{"empty bond", "a", "b", "c", "d", commission2, sdk.OneInt(), valAddr1, pk1, coinZero, false},
{"zero min self delegation", "a", "b", "c", "d", commission1, sdk.ZeroInt(), valAddr1, pk1, coinPos, false},
{"negative min self delegation", "a", "b", "c", "d", commission1, sdk.NewInt(-1), valAddr1, pk1, coinPos, false},
{"delegation less than min self delegation", "a", "b", "c", "d", commission1, coinPos.Amount.Add(sdk.OneInt()), valAddr1, pk1, coinPos, false},
{"basic good", "a", "b", "c", "d", "e", commission1, sdk.OneInt(), valAddr1, pk1, coinPos, true},
{"partial description", "", "", "c", "", "", commission1, sdk.OneInt(), valAddr1, pk1, coinPos, true},
{"empty description", "", "", "", "", "", commission2, sdk.OneInt(), valAddr1, pk1, coinPos, false},
{"empty address", "a", "b", "c", "d", "e", commission2, sdk.OneInt(), emptyAddr, pk1, coinPos, false},
{"empty pubkey", "a", "b", "c", "d", "e", commission1, sdk.OneInt(), valAddr1, emptyPubkey, coinPos, true},
{"empty bond", "a", "b", "c", "d", "e", commission2, sdk.OneInt(), valAddr1, pk1, coinZero, false},
{"zero min self delegation", "a", "b", "c", "d", "e", commission1, sdk.ZeroInt(), valAddr1, pk1, coinPos, false},
{"negative min self delegation", "a", "b", "c", "d", "e", commission1, sdk.NewInt(-1), valAddr1, pk1, coinPos, false},
{"delegation less than min self delegation", "a", "b", "c", "d", "e", commission1, coinPos.Amount.Add(sdk.OneInt()), valAddr1, pk1, coinPos, false},
}
for _, tc := range tests {
description := NewDescription(tc.moniker, tc.identity, tc.website, tc.details)
description := NewDescription(tc.moniker, tc.identity, tc.website, tc.securityContact, tc.details)
msg := NewMsgCreateValidator(tc.validatorAddr, tc.pubkey, tc.bond, description, tc.CommissionRates, tc.minSelfDelegation)
if tc.expectPass {
require.Nil(t, msg.ValidateBasic(), "test: %v", tc.name)
@ -53,18 +53,18 @@ func TestMsgCreateValidator(t *testing.T) {
// test ValidateBasic for MsgEditValidator
func TestMsgEditValidator(t *testing.T) {
tests := []struct {
name, moniker, identity, website, details string
validatorAddr sdk.ValAddress
expectPass bool
name, moniker, identity, website, securityContact, details string
validatorAddr sdk.ValAddress
expectPass bool
}{
{"basic good", "a", "b", "c", "d", valAddr1, true},
{"partial description", "", "", "c", "", valAddr1, true},
{"empty description", "", "", "", "", valAddr1, false},
{"empty address", "a", "b", "c", "d", emptyAddr, false},
{"basic good", "a", "b", "c", "d", "e", valAddr1, true},
{"partial description", "", "", "c", "", "", valAddr1, true},
{"empty description", "", "", "", "", "", valAddr1, false},
{"empty address", "a", "b", "c", "d", "e", emptyAddr, false},
}
for _, tc := range tests {
description := NewDescription(tc.moniker, tc.identity, tc.website, tc.details)
description := NewDescription(tc.moniker, tc.identity, tc.website, tc.securityContact, tc.details)
newRate := sdk.ZeroDec()
newMinSelfDelegation := sdk.OneInt()

View File

@ -19,10 +19,11 @@ import (
// nolint
const (
// TODO: Why can't we just have one string description which can be JSON by convention
MaxMonikerLength = 70
MaxIdentityLength = 3000
MaxWebsiteLength = 140
MaxDetailsLength = 280
MaxMonikerLength = 70
MaxIdentityLength = 3000
MaxWebsiteLength = 140
MaxSecurityContactLength = 140
MaxDetailsLength = 280
)
// Implements Validator interface
@ -260,19 +261,21 @@ const DoNotModifyDesc = "[do-not-modify]"
// Description - description fields for a validator
type Description struct {
Moniker string `json:"moniker" yaml:"moniker"` // name
Identity string `json:"identity" yaml:"identity"` // optional identity signature (ex. UPort or Keybase)
Website string `json:"website" yaml:"website"` // optional website link
Details string `json:"details" yaml:"details"` // optional details
Moniker string `json:"moniker" yaml:"moniker"` // name
Identity string `json:"identity" yaml:"identity"` // optional identity signature (ex. UPort or Keybase)
Website string `json:"website" yaml:"website"` // optional website link
SecurityContact string `json:"security_contact" yaml:"security_contact"` // optional security contact info
Details string `json:"details" yaml:"details"` // optional details
}
// NewDescription returns a new Description with the provided values.
func NewDescription(moniker, identity, website, details string) Description {
func NewDescription(moniker, identity, website, securityContact, details string) Description {
return Description{
Moniker: moniker,
Identity: identity,
Website: website,
Details: details,
Moniker: moniker,
Identity: identity,
Website: website,
SecurityContact: securityContact,
Details: details,
}
}
@ -288,16 +291,20 @@ func (d Description) UpdateDescription(d2 Description) (Description, sdk.Error)
if d2.Website == DoNotModifyDesc {
d2.Website = d.Website
}
if d2.SecurityContact == DoNotModifyDesc {
d2.SecurityContact = d.SecurityContact
}
if d2.Details == DoNotModifyDesc {
d2.Details = d.Details
}
return Description{
Moniker: d2.Moniker,
Identity: d2.Identity,
Website: d2.Website,
Details: d2.Details,
}.EnsureLength()
return NewDescription(
d2.Moniker,
d2.Identity,
d2.Website,
d2.SecurityContact,
d2.Details,
).EnsureLength()
}
// EnsureLength ensures the length of a validator's description.
@ -311,6 +318,9 @@ func (d Description) EnsureLength() (Description, sdk.Error) {
if len(d.Website) > MaxWebsiteLength {
return d, ErrDescriptionLength(DefaultCodespace, "website", len(d.Website), MaxWebsiteLength)
}
if len(d.SecurityContact) > MaxSecurityContactLength {
return d, ErrDescriptionLength(DefaultCodespace, "security contact", len(d.SecurityContact), MaxSecurityContactLength)
}
if len(d.Details) > MaxDetailsLength {
return d, ErrDescriptionLength(DefaultCodespace, "details", len(d.Details), MaxDetailsLength)
}

View File

@ -289,6 +289,7 @@ func TestValidatorMarshalYAML(t *testing.T) {
moniker: ""
identity: ""
website: ""
security_contact: ""
details: ""
unbondingheight: 0
unbondingcompletiontime: 1970-01-01T00:00:00Z