diff --git a/cmd/staking/root.go b/cmd/staking/root.go index 2f07513bb..88b605dab 100644 --- a/cmd/staking/root.go +++ b/cmd/staking/root.go @@ -22,7 +22,6 @@ import ( "github.com/harmony-one/harmony/shard" staking "github.com/harmony-one/harmony/staking/types" "github.com/spf13/cobra" - "github.com/spf13/viper" ) const ( @@ -52,6 +51,7 @@ var ( name = "NewName" index = 0 minDele = 777 + rate = "0.0" testAccounts = []string{ "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", @@ -74,6 +74,10 @@ func (s *staker) run(cmd *cobra.Command, args []string) error { p.DeserializeHexStr(testBLSPubKeys[index]) pub := shard.BlsPublicKey{} pub.FromLibBLSPublicKey(p) + + ra, _ := numeric.NewDecFromStr("27.27") + maxRate, _ := numeric.NewDecFromStr("150.99") + maxChangeRate, _ := numeric.NewDecFromStr("0.5") if cmdType == "create" { return staking.DirectiveCreateValidator, staking.CreateValidator{ Description: &staking.Description{ @@ -84,9 +88,9 @@ func (s *staker) run(cmd *cobra.Command, args []string) error { Details: "blah blah blah", }, CommissionRates: staking.CommissionRates{ - Rate: numeric.NewDec(100), - MaxRate: numeric.NewDec(150), - MaxChangeRate: numeric.NewDec(5), + Rate: ra, + MaxRate: maxRate, + MaxChangeRate: maxChangeRate, }, MinSelfDelegation: big.NewInt(10), MaxTotalDelegation: big.NewInt(3000), @@ -106,11 +110,13 @@ func (s *staker) run(cmd *cobra.Command, args []string) error { } */ + newRate, _ := numeric.NewDecFromStr(rate) return staking.DirectiveEditValidator, staking.EditValidator{ Description: &staking.Description{ Name: name, }, MinSelfDelegation: big.NewInt(int64(minDele)), + CommissionRate: &newRate, ValidatorAddress: common.Address(dAddr), } } @@ -189,8 +195,8 @@ func init() { rootCmd.PersistentFlags().StringVarP(&cmdType, "type", "t", "create", "type of commands: create|edit") rootCmd.PersistentFlags().StringVarP(&name, "name", "m", "ANewName", "Name of Validator") rootCmd.PersistentFlags().IntVarP(&minDele, "minDele", "d", 666, "MinSelfDelegation Fee") + rootCmd.PersistentFlags().StringVarP(&rate, "rate", "r", "22.22", "Commision Rate") - viper.BindPFlag("nonce", rootCmd.PersistentFlags().Lookup("nonce")) rootCmd.AddCommand(&cobra.Command{ Use: "staking-iterate", Short: "run through staking process", diff --git a/core/blockchain.go b/core/blockchain.go index 169928b72..f6fefdc1d 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2370,12 +2370,36 @@ func (bc *BlockChain) UpdateValidatorList(tx *staking.StakingTransaction) error // CurrentValidatorAddresses returns the address of active validators for current epoch func (bc *BlockChain) CurrentValidatorAddresses() []common.Address { - return make([]common.Address, 0) + list, err := bc.ReadValidatorList() + if err != nil { + return make([]common.Address, 0) + } + + currentEpoch := bc.CurrentBlock().Epoch() + + filtered := []common.Address{} + for _, addr := range list { + val, err := bc.ValidatorInformation(addr) + if err != nil { + continue + } + epoch := ShardingSchedule.CalcEpochNumber(val.CreationHeight.Uint64()) + if epoch.Cmp(currentEpoch) >= 0 { + // wait for next epoch + continue + } + filtered = append(filtered, addr) + } + return filtered } // ValidatorCandidates returns the up to date validator candidates for next epoch func (bc *BlockChain) ValidatorCandidates() []common.Address { - return make([]common.Address, 0) + list, err := bc.ReadValidatorList() + if err != nil { + return make([]common.Address, 0) + } + return list } // ValidatorInformation returns the information of validator diff --git a/core/state_transition.go b/core/state_transition.go index 934c3f222..dc68c62f6 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -335,6 +335,7 @@ func (st *StateTransition) applyCreateValidatorTx(nv *staking.CreateValidator, b return err } v.UpdateHeight = blockNum + v.CreationHeight = blockNum wrapper := staking.ValidatorWrapper{*v, nil, nil, nil} if err := st.state.UpdateStakingInfo(v.Address, &wrapper); err != nil { return err @@ -348,10 +349,16 @@ func (st *StateTransition) applyEditValidatorTx(ev *staking.EditValidator, block return errValidatorNotExist } wrapper := st.state.GetStakingInfo(ev.ValidatorAddress) + + oldRate := wrapper.Validator.Rate if err := staking.UpdateValidatorFromEditMsg(&wrapper.Validator, ev); err != nil { return err } - wrapper.Validator.UpdateHeight = blockNum + newRate := wrapper.Validator.Rate + // update the commision rate change height + if oldRate.IsNil() || (!newRate.IsNil() && !oldRate.Equal(newRate)) { + wrapper.Validator.UpdateHeight = blockNum + } if err := st.state.UpdateStakingInfo(ev.ValidatorAddress, wrapper); err != nil { return err } diff --git a/node/node_handler.go b/node/node_handler.go index 184e45575..57f2d89ae 100644 --- a/node/node_handler.go +++ b/node/node_handler.go @@ -421,6 +421,11 @@ func (node *Node) AddNewBlock(newBlock *types.Block) error { } utils.Logger().Debug().Msgf("ValidatorInformation %v: %v", i, val) } + currAddrs := node.Blockchain().CurrentValidatorAddresses() + utils.Logger().Debug().Msgf("CurrentValidators : %v", currAddrs) + candidates := node.Blockchain().ValidatorCandidates() + utils.Logger().Debug().Msgf("CandidateValidators : %v", candidates) + // Finish debug if err != nil { utils.Logger().Error(). diff --git a/staking/types/commission.go b/staking/types/commission.go index 3176ba807..43de6565c 100644 --- a/staking/types/commission.go +++ b/staking/types/commission.go @@ -1,6 +1,7 @@ package types import ( + "fmt" "math/big" "github.com/harmony-one/harmony/numeric" @@ -22,3 +23,15 @@ type ( MaxChangeRate numeric.Dec `json:"max_change_rate" yaml:"max_change_rate"` // maximum increase of the validator commission every epoch, as a fraction } ) + +// String returns a human readable string representation of a validator. +func (c Commission) String() string { + return fmt.Sprintf(` + Commission: + Rate: %s + MaxRate: %s + MaxChangeRate: %s + UpdateHeight: %v`, + c.Rate, c.MaxRate, c.MaxChangeRate, + c.UpdateHeight) +} diff --git a/staking/types/validator.go b/staking/types/validator.go index 99960d54d..3edbf831b 100644 --- a/staking/types/validator.go +++ b/staking/types/validator.go @@ -46,12 +46,16 @@ type Validator struct { UnbondingHeight *big.Int `json:"unbonding_height" yaml:"unbonding_height"` // validator's self declared minimum self delegation MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"` + // maximum total delgation allowed + MaxTotalDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"` // Is the validator active in the validating process or not Active bool `json:"active" yaml:"active"` // commission parameters Commission `json:"commission" yaml:"commission"` // description for the validator Description `json:"description" yaml:"description"` + // CreationHeight is the height of creation + CreationHeight *big.Int `json:"creation_height" yaml:"creation_height"` } func printSlotPubKeys(pubKeys []shard.BlsPublicKey) string { @@ -153,12 +157,13 @@ func CreateValidatorFromNewMsg(val *CreateValidator) (*Validator, error) { pubKeys := []shard.BlsPublicKey{} pubKeys = append(pubKeys, val.SlotPubKeys...) v := Validator{val.ValidatorAddress, pubKeys, - val.Amount, new(big.Int), val.MinSelfDelegation, false, - commission, desc} + val.Amount, new(big.Int), val.MinSelfDelegation, val.MaxTotalDelegation, false, + commission, desc, big.NewInt(0)} return &v, nil } // UpdateValidatorFromEditMsg updates validator from EditValidator message +// TODO check the validity of the fields of edit message func UpdateValidatorFromEditMsg(validator *Validator, edit *EditValidator) error { if validator.Address != edit.ValidatorAddress { return errAddressNotMatch @@ -172,11 +177,41 @@ func UpdateValidatorFromEditMsg(validator *Validator, edit *EditValidator) error if edit.CommissionRate != nil { validator.Rate = *edit.CommissionRate + if err != nil { + return err + } + //TODO update other rates } if edit.MinSelfDelegation != nil { validator.MinSelfDelegation = edit.MinSelfDelegation } + + if edit.MaxTotalDelegation != nil { + validator.MaxTotalDelegation = edit.MaxTotalDelegation + } + + if edit.SlotKeyToAdd != nil { + for _, key := range validator.SlotPubKeys { + if key == *edit.SlotKeyToAdd { + break + } + validator.SlotPubKeys = append(validator.SlotPubKeys, *edit.SlotKeyToAdd) + } + } + + if edit.SlotKeyToRemove != nil { + index := -1 + for i, key := range validator.SlotPubKeys { + if key == *edit.SlotKeyToRemove { + index = i + } + } + // we found key to be removed + if index >= 0 { + validator.SlotPubKeys = append(validator.SlotPubKeys[:index], validator.SlotPubKeys[index+1:]...) + } + } return nil }