From 044c2dcd4c57d4d561bec8401c49246c6a9fbc79 Mon Sep 17 00:00:00 2001 From: Rongjian Lan Date: Sat, 25 Apr 2020 10:34:22 -0700 Subject: [PATCH] Validator dedup on identity and bls keys (#2883) * Remove same-validator redelegation feature which is useless and confusing * Fix comments * Detect duplicate name or identity * check bls dups * Remove name dedup as it's risky * equal rather than compare on address * Add better error content * Fix travis --- core/evm.go | 3 +++ core/state_transition.go | 58 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/core/evm.go b/core/evm.go index 70b490a25..5b98e41d4 100644 --- a/core/evm.go +++ b/core/evm.go @@ -41,6 +41,9 @@ type ChainContext interface { // ReadValidatorSnapshot returns the snapshot of validator at the beginning of current epoch. ReadValidatorSnapshot(common.Address) (*staking.ValidatorSnapshot, error) + + // ReadValidatorList returns the list of all validators + ReadValidatorList() ([]common.Address, error) } // NewEVMContext creates a new context for use in the EVM. diff --git a/core/state_transition.go b/core/state_transition.go index 247f588ee..90716b08d 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -17,9 +17,12 @@ package core import ( + "bytes" "math" "math/big" + "github.com/harmony-one/harmony/shard" + staking2 "github.com/harmony-one/harmony/staking" "github.com/harmony-one/harmony/staking/network" @@ -44,6 +47,8 @@ var ( errCommissionRateChangeTooHigh = errors.New("commission rate can not be higher than maximum commission rate") errNoRewardsToCollect = errors.New("no rewards to collect") errNegativeAmount = errors.New("amount can not be negative") + errDupIdentity = errors.New("validator identity exists") + errDupBlsKey = errors.New("BLS key exists") ) /* @@ -384,9 +389,52 @@ func (st *StateTransition) StakingTransitionDb() (usedGas uint64, err error) { return st.gasUsed(), err } +func (st *StateTransition) checkDuplicateFields(validator common.Address, identity string, blsKeys []shard.BLSPublicKey) error { + addrs, err := st.bc.ReadValidatorList() + if err != nil { + return err + } + + checkIdentity := identity != "" + checkBlsKeys := len(blsKeys) != 0 + + blsKeyMap := map[shard.BLSPublicKey]struct{}{} + for _, key := range blsKeys { + blsKeyMap[key] = struct{}{} + } + + for _, addr := range addrs { + if !bytes.Equal(validator.Bytes(), addr.Bytes()) { + wrapper, err := st.state.ValidatorWrapperCopy(addr) + + if err != nil { + return err + } + + if checkIdentity && wrapper.Identity == identity { + return errors.Wrapf(errDupIdentity, "duplicate identity %s", identity) + } + if checkBlsKeys { + for _, existingKey := range wrapper.SlotPubKeys { + if _, ok := blsKeyMap[existingKey]; ok { + return errors.Wrapf(errDupBlsKey, "duplicate bls key %x", existingKey) + } + } + } + } + } + return nil +} + func (st *StateTransition) verifyAndApplyCreateValidatorTx( createValidator *staking.CreateValidator, blockNum *big.Int, ) error { + if err := st.checkDuplicateFields( + createValidator.ValidatorAddress, + createValidator.Identity, + createValidator.SlotPubKeys); err != nil { + return err + } wrapper, err := VerifyAndCreateValidatorFromMsg( st.state, st.evm.EpochNumber, blockNum, createValidator, ) @@ -404,6 +452,16 @@ func (st *StateTransition) verifyAndApplyCreateValidatorTx( func (st *StateTransition) verifyAndApplyEditValidatorTx( editValidator *staking.EditValidator, blockNum *big.Int, ) error { + newBlsKeys := []shard.BLSPublicKey{} + if editValidator.SlotKeyToAdd != nil { + newBlsKeys = append(newBlsKeys, *editValidator.SlotKeyToAdd) + } + if err := st.checkDuplicateFields( + editValidator.ValidatorAddress, + editValidator.Identity, + newBlsKeys); err != nil { + return err + } wrapper, err := VerifyAndEditValidatorFromMsg( st.state, st.bc, st.evm.EpochNumber, blockNum, editValidator, )