[consensus] HIP-16: Enforce a 6% max keys per shard limit for each validator

pull/4163/head
peekpi 3 years ago committed by Soph
parent df0a56b775
commit 08bb9022e0
  1. 1
      cmd/harmony/default.go
  2. 2
      cmd/harmony/main.go
  3. 3
      hmy/staking.go
  4. 3
      internal/chain/engine.go
  5. 1
      internal/configs/harmony/harmony.go
  6. 13
      internal/configs/sharding/instance.go
  7. 10
      internal/configs/sharding/localnet.go
  8. 37
      internal/configs/sharding/mainnet.go
  9. 4
      internal/configs/sharding/pangaea.go
  10. 4
      internal/configs/sharding/partner.go
  11. 2
      internal/configs/sharding/shardingconfig.go
  12. 6
      internal/configs/sharding/stress.go
  13. 13
      internal/configs/sharding/testnet.go
  14. 16
      internal/params/config.go
  15. 6
      shard/committee/assignment.go
  16. 31
      staking/effective/calculate.go

@ -106,6 +106,7 @@ var defaultDevnetConfig = harmonyconfig.DevnetConfig{
NumShards: 2, NumShards: 2,
ShardSize: 10, ShardSize: 10,
HmyNodeSize: 10, HmyNodeSize: 10,
SlotsLimit: 0,
} }
var defaultRevertConfig = harmonyconfig.RevertConfig{ var defaultRevertConfig = harmonyconfig.RevertConfig{

@ -485,7 +485,7 @@ func nodeconfigSetShardSchedule(config harmonyconfig.HarmonyConfig) {
} }
devnetConfig, err := shardingconfig.NewInstance( devnetConfig, err := shardingconfig.NewInstance(
uint32(dnConfig.NumShards), dnConfig.ShardSize, dnConfig.HmyNodeSize, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccounts, nil, shardingconfig.VLBPE) uint32(dnConfig.NumShards), dnConfig.ShardSize, dnConfig.HmyNodeSize, dnConfig.SlotsLimit, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccounts, nil, shardingconfig.VLBPE)
if err != nil { if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "ERROR invalid devnet sharding config: %s", _, _ = fmt.Fprintf(os.Stderr, "ERROR invalid devnet sharding config: %s",
err) err)

@ -445,7 +445,8 @@ func (hmy *Harmony) GetMedianRawStakeSnapshot() (
func() (interface{}, error) { func() (interface{}, error) {
// Compute for next epoch // Compute for next epoch
epoch := big.NewInt(0).Add(hmy.CurrentBlock().Epoch(), big.NewInt(1)) epoch := big.NewInt(0).Add(hmy.CurrentBlock().Epoch(), big.NewInt(1))
return committee.NewEPoSRound(epoch, hmy.BlockChain, hmy.BlockChain.Config().IsEPoSBound35(epoch)) instance := shard.Schedule.InstanceForEpoch(epoch)
return committee.NewEPoSRound(epoch, hmy.BlockChain, hmy.BlockChain.Config().IsEPoSBound35(epoch), instance.SlotsLimit(), int(instance.NumShards()))
}, },
) )
if err != nil { if err != nil {

@ -725,7 +725,8 @@ func readShardState(chain engine.ChainReader, epoch *big.Int, targetShardID uint
return shardState, nil return shardState, nil
} else { } else {
shardState, err := chain.ReadShardState(epoch) //shardState, err := chain.ReadShardState(epoch)
shardState, err := committee.WithStakingEnabled.ReadFromDB(epoch, chain)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "read shard state for epoch %v", epoch) return nil, errors.Wrapf(err, "read shard state for epoch %v", epoch)
} }

@ -174,6 +174,7 @@ type DevnetConfig struct {
NumShards int NumShards int
ShardSize int ShardSize int
HmyNodeSize int HmyNodeSize int
SlotsLimit int // HIP-16: Enforce a 6% max keys per shard limit for each validator
} }
// TODO: make `revert` to a separate command // TODO: make `revert` to a separate command

@ -32,12 +32,13 @@ type instance struct {
fnAccounts []genesis.DeployAccount fnAccounts []genesis.DeployAccount
reshardingEpoch []*big.Int reshardingEpoch []*big.Int
blocksPerEpoch uint64 blocksPerEpoch uint64
slotsLimit int // HIP-16: Enforce a 6% max keys per shard limit for each validator
} }
// NewInstance creates and validates a new sharding configuration based // NewInstance creates and validates a new sharding configuration based
// upon given parameters. // upon given parameters.
func NewInstance( func NewInstance(
numShards uint32, numNodesPerShard, numHarmonyOperatedNodesPerShard int, harmonyVotePercent numeric.Dec, numShards uint32, numNodesPerShard, numHarmonyOperatedNodesPerShard, slotsLimit int, harmonyVotePercent numeric.Dec,
hmyAccounts []genesis.DeployAccount, hmyAccounts []genesis.DeployAccount,
fnAccounts []genesis.DeployAccount, fnAccounts []genesis.DeployAccount,
reshardingEpoch []*big.Int, blocksE uint64, reshardingEpoch []*big.Int, blocksE uint64,
@ -82,6 +83,7 @@ func NewInstance(
fnAccounts: fnAccounts, fnAccounts: fnAccounts,
reshardingEpoch: reshardingEpoch, reshardingEpoch: reshardingEpoch,
blocksPerEpoch: blocksE, blocksPerEpoch: blocksE,
slotsLimit: slotsLimit,
}, nil }, nil
} }
@ -90,14 +92,14 @@ func NewInstance(
// It is intended to be used for static initialization. // It is intended to be used for static initialization.
func MustNewInstance( func MustNewInstance(
numShards uint32, numShards uint32,
numNodesPerShard, numHarmonyOperatedNodesPerShard int, numNodesPerShard, numHarmonyOperatedNodesPerShard, slotsLimit int,
harmonyVotePercent numeric.Dec, harmonyVotePercent numeric.Dec,
hmyAccounts []genesis.DeployAccount, hmyAccounts []genesis.DeployAccount,
fnAccounts []genesis.DeployAccount, fnAccounts []genesis.DeployAccount,
reshardingEpoch []*big.Int, blocksPerEpoch uint64, reshardingEpoch []*big.Int, blocksPerEpoch uint64,
) Instance { ) Instance {
sc, err := NewInstance( sc, err := NewInstance(
numShards, numNodesPerShard, numHarmonyOperatedNodesPerShard, harmonyVotePercent, numShards, numNodesPerShard, numHarmonyOperatedNodesPerShard, slotsLimit, harmonyVotePercent,
hmyAccounts, fnAccounts, reshardingEpoch, blocksPerEpoch, hmyAccounts, fnAccounts, reshardingEpoch, blocksPerEpoch,
) )
if err != nil { if err != nil {
@ -116,6 +118,11 @@ func (sc instance) NumShards() uint32 {
return sc.numShards return sc.numShards
} }
// SlotsLimit returns the max slots per shard limit for each validator
func (sc instance) SlotsLimit() int {
return sc.slotsLimit
}
// HarmonyVotePercent returns total percentage of voting power harmony nodes possess. // HarmonyVotePercent returns total percentage of voting power harmony nodes possess.
func (sc instance) HarmonyVotePercent() numeric.Dec { func (sc instance) HarmonyVotePercent() numeric.Dec {
return sc.harmonyVotePercent return sc.harmonyVotePercent

@ -142,9 +142,9 @@ var (
big.NewInt(0), big.NewInt(localnetV1Epoch), params.LocalnetChainConfig.StakingEpoch, params.LocalnetChainConfig.TwoSecondsEpoch, big.NewInt(0), big.NewInt(localnetV1Epoch), params.LocalnetChainConfig.StakingEpoch, params.LocalnetChainConfig.TwoSecondsEpoch,
} }
// Number of shards, how many slots on each , how many slots owned by Harmony // Number of shards, how many slots on each , how many slots owned by Harmony
localnetV0 = MustNewInstance(2, 7, 5, numeric.OneDec(), genesis.LocalHarmonyAccounts, genesis.LocalFnAccounts, localnetReshardingEpoch, LocalnetSchedule.BlocksPerEpochOld()) localnetV0 = MustNewInstance(2, 7, 5, 0, numeric.OneDec(), genesis.LocalHarmonyAccounts, genesis.LocalFnAccounts, localnetReshardingEpoch, LocalnetSchedule.BlocksPerEpochOld())
localnetV1 = MustNewInstance(2, 8, 5, numeric.OneDec(), genesis.LocalHarmonyAccountsV1, genesis.LocalFnAccountsV1, localnetReshardingEpoch, LocalnetSchedule.BlocksPerEpochOld()) localnetV1 = MustNewInstance(2, 8, 5, 0, numeric.OneDec(), genesis.LocalHarmonyAccountsV1, genesis.LocalFnAccountsV1, localnetReshardingEpoch, LocalnetSchedule.BlocksPerEpochOld())
localnetV2 = MustNewInstance(2, 9, 6, numeric.MustNewDecFromStr("0.68"), genesis.LocalHarmonyAccountsV2, genesis.LocalFnAccountsV2, localnetReshardingEpoch, LocalnetSchedule.BlocksPerEpochOld()) localnetV2 = MustNewInstance(2, 9, 6, 0, numeric.MustNewDecFromStr("0.68"), genesis.LocalHarmonyAccountsV2, genesis.LocalFnAccountsV2, localnetReshardingEpoch, LocalnetSchedule.BlocksPerEpochOld())
localnetV3 = MustNewInstance(2, 9, 6, numeric.MustNewDecFromStr("0.68"), genesis.LocalHarmonyAccountsV2, genesis.LocalFnAccountsV2, localnetReshardingEpoch, LocalnetSchedule.BlocksPerEpoch()) localnetV3 = MustNewInstance(2, 9, 6, 0, numeric.MustNewDecFromStr("0.68"), genesis.LocalHarmonyAccountsV2, genesis.LocalFnAccountsV2, localnetReshardingEpoch, LocalnetSchedule.BlocksPerEpoch())
localnetV3_1 = MustNewInstance(2, 9, 6, numeric.MustNewDecFromStr("0.68"), genesis.LocalHarmonyAccountsV2, genesis.LocalFnAccountsV2, localnetReshardingEpoch, LocalnetSchedule.BlocksPerEpoch()) localnetV3_1 = MustNewInstance(2, 9, 6, 0, numeric.MustNewDecFromStr("0.68"), genesis.LocalHarmonyAccountsV2, genesis.LocalFnAccountsV2, localnetReshardingEpoch, LocalnetSchedule.BlocksPerEpoch())
) )

@ -53,6 +53,8 @@ type mainnetSchedule struct{}
func (ms mainnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { func (ms mainnetSchedule) InstanceForEpoch(epoch *big.Int) Instance {
switch { switch {
case params.MainnetChainConfig.IsSlotsLimited(epoch):
return mainnetV3_3
case params.MainnetChainConfig.IsHIP6And8Epoch(epoch): case params.MainnetChainConfig.IsHIP6And8Epoch(epoch):
// Decrease internal voting power from 60% to 49% // Decrease internal voting power from 60% to 49%
// Increase external nodes from 800 to 900 // Increase external nodes from 800 to 900
@ -202,21 +204,22 @@ func (ms mainnetSchedule) IsSkippedEpoch(shardID uint32, epoch *big.Int) bool {
var mainnetReshardingEpoch = []*big.Int{big.NewInt(0), big.NewInt(mainnetV0_1Epoch), big.NewInt(mainnetV0_2Epoch), big.NewInt(mainnetV0_3Epoch), big.NewInt(mainnetV0_4Epoch), big.NewInt(mainnetV1Epoch), big.NewInt(mainnetV1_1Epoch), big.NewInt(mainnetV1_2Epoch), big.NewInt(mainnetV1_3Epoch), big.NewInt(mainnetV1_4Epoch), big.NewInt(mainnetV1_5Epoch), big.NewInt(mainnetV2_0Epoch), big.NewInt(mainnetV2_1Epoch), big.NewInt(mainnetV2_2Epoch), params.MainnetChainConfig.TwoSecondsEpoch, params.MainnetChainConfig.SixtyPercentEpoch, params.MainnetChainConfig.HIP6And8Epoch} var mainnetReshardingEpoch = []*big.Int{big.NewInt(0), big.NewInt(mainnetV0_1Epoch), big.NewInt(mainnetV0_2Epoch), big.NewInt(mainnetV0_3Epoch), big.NewInt(mainnetV0_4Epoch), big.NewInt(mainnetV1Epoch), big.NewInt(mainnetV1_1Epoch), big.NewInt(mainnetV1_2Epoch), big.NewInt(mainnetV1_3Epoch), big.NewInt(mainnetV1_4Epoch), big.NewInt(mainnetV1_5Epoch), big.NewInt(mainnetV2_0Epoch), big.NewInt(mainnetV2_1Epoch), big.NewInt(mainnetV2_2Epoch), params.MainnetChainConfig.TwoSecondsEpoch, params.MainnetChainConfig.SixtyPercentEpoch, params.MainnetChainConfig.HIP6And8Epoch}
var ( var (
mainnetV0 = MustNewInstance(4, 150, 112, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccounts, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld()) mainnetV0 = MustNewInstance(4, 150, 112, 0, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccounts, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld())
mainnetV0_1 = MustNewInstance(4, 152, 112, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV0_1, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld()) mainnetV0_1 = MustNewInstance(4, 152, 112, 0, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV0_1, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld())
mainnetV0_2 = MustNewInstance(4, 200, 148, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV0_2, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld()) mainnetV0_2 = MustNewInstance(4, 200, 148, 0, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV0_2, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld())
mainnetV0_3 = MustNewInstance(4, 210, 148, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV0_3, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld()) mainnetV0_3 = MustNewInstance(4, 210, 148, 0, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV0_3, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld())
mainnetV0_4 = MustNewInstance(4, 216, 148, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV0_4, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld()) mainnetV0_4 = MustNewInstance(4, 216, 148, 0, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV0_4, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld())
mainnetV1 = MustNewInstance(4, 250, 170, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld()) mainnetV1 = MustNewInstance(4, 250, 170, 0, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld())
mainnetV1_1 = MustNewInstance(4, 250, 170, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_1, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld()) mainnetV1_1 = MustNewInstance(4, 250, 170, 0, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_1, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld())
mainnetV1_2 = MustNewInstance(4, 250, 170, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_2, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld()) mainnetV1_2 = MustNewInstance(4, 250, 170, 0, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_2, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld())
mainnetV1_3 = MustNewInstance(4, 250, 170, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_3, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld()) mainnetV1_3 = MustNewInstance(4, 250, 170, 0, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_3, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld())
mainnetV1_4 = MustNewInstance(4, 250, 170, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_4, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld()) mainnetV1_4 = MustNewInstance(4, 250, 170, 0, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_4, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld())
mainnetV1_5 = MustNewInstance(4, 250, 170, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_5, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld()) mainnetV1_5 = MustNewInstance(4, 250, 170, 0, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_5, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld())
mainnetV2_0 = MustNewInstance(4, 250, 170, numeric.MustNewDecFromStr("0.68"), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_5, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld()) mainnetV2_0 = MustNewInstance(4, 250, 170, 0, numeric.MustNewDecFromStr("0.68"), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_5, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld())
mainnetV2_1 = MustNewInstance(4, 250, 130, numeric.MustNewDecFromStr("0.68"), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_5, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld()) mainnetV2_1 = MustNewInstance(4, 250, 130, 0, numeric.MustNewDecFromStr("0.68"), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_5, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld())
mainnetV2_2 = MustNewInstance(4, 250, 90, numeric.MustNewDecFromStr("0.68"), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_5, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld()) mainnetV2_2 = MustNewInstance(4, 250, 90, 0, numeric.MustNewDecFromStr("0.68"), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_5, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld())
mainnetV3 = MustNewInstance(4, 250, 90, numeric.MustNewDecFromStr("0.68"), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_5, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpoch()) mainnetV3 = MustNewInstance(4, 250, 90, 0, numeric.MustNewDecFromStr("0.68"), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_5, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpoch())
mainnetV3_1 = MustNewInstance(4, 250, 50, numeric.MustNewDecFromStr("0.60"), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_5, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpoch()) mainnetV3_1 = MustNewInstance(4, 250, 50, 0, numeric.MustNewDecFromStr("0.60"), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_5, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpoch())
mainnetV3_2 = MustNewInstance(4, 250, 25, numeric.MustNewDecFromStr("0.49"), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_5, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpoch()) mainnetV3_2 = MustNewInstance(4, 250, 25, 0, numeric.MustNewDecFromStr("0.49"), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_5, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpoch())
mainnetV3_3 = MustNewInstance(4, 250, 25, 250*6/100, numeric.MustNewDecFromStr("0.49"), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_5, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpoch())
) )

@ -75,5 +75,5 @@ var pangaeaReshardingEpoch = []*big.Int{
params.PangaeaChainConfig.StakingEpoch, params.PangaeaChainConfig.StakingEpoch,
} }
var pangaeaV0 = MustNewInstance(4, 30, 30, numeric.OneDec(), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, pangaeaReshardingEpoch, PangaeaSchedule.BlocksPerEpoch()) var pangaeaV0 = MustNewInstance(4, 30, 30, 0, numeric.OneDec(), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, pangaeaReshardingEpoch, PangaeaSchedule.BlocksPerEpoch())
var pangaeaV1 = MustNewInstance(4, 110, 30, numeric.MustNewDecFromStr("0.68"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, pangaeaReshardingEpoch, PangaeaSchedule.BlocksPerEpoch()) var pangaeaV1 = MustNewInstance(4, 110, 30, 0, numeric.MustNewDecFromStr("0.68"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, pangaeaReshardingEpoch, PangaeaSchedule.BlocksPerEpoch())

@ -76,5 +76,5 @@ var partnerReshardingEpoch = []*big.Int{
params.PartnerChainConfig.StakingEpoch, params.PartnerChainConfig.StakingEpoch,
} }
var partnerV0 = MustNewInstance(2, 5, 5, numeric.OneDec(), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, partnerReshardingEpoch, PartnerSchedule.BlocksPerEpoch()) var partnerV0 = MustNewInstance(2, 5, 5, 0, numeric.OneDec(), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, partnerReshardingEpoch, PartnerSchedule.BlocksPerEpoch())
var partnerV1 = MustNewInstance(2, 5, 4, numeric.MustNewDecFromStr("0.9"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, partnerReshardingEpoch, PartnerSchedule.BlocksPerEpoch()) var partnerV1 = MustNewInstance(2, 5, 4, 0, numeric.MustNewDecFromStr("0.9"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, partnerReshardingEpoch, PartnerSchedule.BlocksPerEpoch())

@ -72,6 +72,8 @@ type Instance interface {
// Count of blocks per epoch // Count of blocks per epoch
BlocksPerEpoch() uint64 BlocksPerEpoch() uint64
// HIP-16: Enforce a 6% max keys per shard limit for each validator
SlotsLimit() int
} }
// genShardingStructure return sharding structure, given shard number and its patterns. // genShardingStructure return sharding structure, given shard number and its patterns.

@ -78,6 +78,6 @@ var stressnetReshardingEpoch = []*big.Int{
params.StressnetChainConfig.StakingEpoch, params.StressnetChainConfig.StakingEpoch,
} }
var stressnetV0 = MustNewInstance(2, 10, 10, numeric.OneDec(), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, stressnetReshardingEpoch, StressNetSchedule.BlocksPerEpoch()) var stressnetV0 = MustNewInstance(2, 10, 10, 0, numeric.OneDec(), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, stressnetReshardingEpoch, StressNetSchedule.BlocksPerEpoch())
var stressnetV1 = MustNewInstance(2, 30, 10, numeric.MustNewDecFromStr("0.9"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, stressnetReshardingEpoch, StressNetSchedule.BlocksPerEpoch()) var stressnetV1 = MustNewInstance(2, 30, 10, 0, numeric.MustNewDecFromStr("0.9"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, stressnetReshardingEpoch, StressNetSchedule.BlocksPerEpoch())
var stressnetV2 = MustNewInstance(2, 30, 10, numeric.MustNewDecFromStr("0.6"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, stressnetReshardingEpoch, StressNetSchedule.BlocksPerEpoch()) var stressnetV2 = MustNewInstance(2, 30, 10, 0, numeric.MustNewDecFromStr("0.6"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, stressnetReshardingEpoch, StressNetSchedule.BlocksPerEpoch())

@ -33,6 +33,8 @@ const (
func (ts testnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { func (ts testnetSchedule) InstanceForEpoch(epoch *big.Int) Instance {
switch { switch {
case params.TestnetChainConfig.IsSlotsLimited(epoch):
return testnetV3_2
case params.TestnetChainConfig.IsSixtyPercent(epoch): case params.TestnetChainConfig.IsSixtyPercent(epoch):
return testnetV3_1 return testnetV3_1
case params.TestnetChainConfig.IsTwoSeconds(epoch): case params.TestnetChainConfig.IsTwoSeconds(epoch):
@ -114,8 +116,9 @@ var testnetReshardingEpoch = []*big.Int{
params.TestnetChainConfig.TwoSecondsEpoch, params.TestnetChainConfig.TwoSecondsEpoch,
} }
var testnetV0 = MustNewInstance(4, 16, 15, numeric.OneDec(), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch, TestnetSchedule.BlocksPerEpochOld()) var testnetV0 = MustNewInstance(4, 16, 15, 0, numeric.OneDec(), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch, TestnetSchedule.BlocksPerEpochOld())
var testnetV1 = MustNewInstance(4, 20, 15, numeric.MustNewDecFromStr("0.90"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch, TestnetSchedule.BlocksPerEpochOld()) var testnetV1 = MustNewInstance(4, 20, 15, 0, numeric.MustNewDecFromStr("0.90"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch, TestnetSchedule.BlocksPerEpochOld())
var testnetV2 = MustNewInstance(4, 30, 8, numeric.MustNewDecFromStr("0.90"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch, TestnetSchedule.BlocksPerEpochOld()) var testnetV2 = MustNewInstance(4, 30, 8, 0, numeric.MustNewDecFromStr("0.90"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch, TestnetSchedule.BlocksPerEpochOld())
var testnetV3 = MustNewInstance(4, 30, 8, numeric.MustNewDecFromStr("0.90"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch, TestnetSchedule.BlocksPerEpoch()) var testnetV3 = MustNewInstance(4, 30, 8, 0, numeric.MustNewDecFromStr("0.90"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch, TestnetSchedule.BlocksPerEpoch())
var testnetV3_1 = MustNewInstance(4, 30, 8, numeric.MustNewDecFromStr("0.60"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch, TestnetSchedule.BlocksPerEpoch()) var testnetV3_1 = MustNewInstance(4, 30, 8, 0, numeric.MustNewDecFromStr("0.60"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch, TestnetSchedule.BlocksPerEpoch())
var testnetV3_2 = MustNewInstance(4, 30, 8, 30*6/100, numeric.MustNewDecFromStr("0.60"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch, TestnetSchedule.BlocksPerEpoch())

@ -65,6 +65,7 @@ var (
SHA3Epoch: big.NewInt(725), // Around Mon Oct 11 2021, 19:00 UTC SHA3Epoch: big.NewInt(725), // Around Mon Oct 11 2021, 19:00 UTC
HIP6And8Epoch: big.NewInt(725), // Around Mon Oct 11 2021, 19:00 UTC HIP6And8Epoch: big.NewInt(725), // Around Mon Oct 11 2021, 19:00 UTC
StakingPrecompileEpoch: big.NewInt(871), // Around Tue Feb 11 2022 StakingPrecompileEpoch: big.NewInt(871), // Around Tue Feb 11 2022
SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16
} }
// TestnetChainConfig contains the chain parameters to run a node on the harmony test network. // TestnetChainConfig contains the chain parameters to run a node on the harmony test network.
@ -98,6 +99,7 @@ var (
SHA3Epoch: big.NewInt(74570), SHA3Epoch: big.NewInt(74570),
HIP6And8Epoch: big.NewInt(74570), HIP6And8Epoch: big.NewInt(74570),
StakingPrecompileEpoch: big.NewInt(75175), StakingPrecompileEpoch: big.NewInt(75175),
SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16
} }
// PangaeaChainConfig contains the chain parameters for the Pangaea network. // PangaeaChainConfig contains the chain parameters for the Pangaea network.
@ -132,6 +134,7 @@ var (
SHA3Epoch: big.NewInt(0), SHA3Epoch: big.NewInt(0),
HIP6And8Epoch: big.NewInt(0), HIP6And8Epoch: big.NewInt(0),
StakingPrecompileEpoch: big.NewInt(2), // same as staking StakingPrecompileEpoch: big.NewInt(2), // same as staking
SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16
} }
// PartnerChainConfig contains the chain parameters for the Partner network. // PartnerChainConfig contains the chain parameters for the Partner network.
@ -166,6 +169,7 @@ var (
SHA3Epoch: big.NewInt(0), SHA3Epoch: big.NewInt(0),
HIP6And8Epoch: big.NewInt(0), HIP6And8Epoch: big.NewInt(0),
StakingPrecompileEpoch: big.NewInt(2), StakingPrecompileEpoch: big.NewInt(2),
SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16
} }
// StressnetChainConfig contains the chain parameters for the Stress test network. // StressnetChainConfig contains the chain parameters for the Stress test network.
@ -200,6 +204,7 @@ var (
SHA3Epoch: big.NewInt(0), SHA3Epoch: big.NewInt(0),
HIP6And8Epoch: big.NewInt(0), HIP6And8Epoch: big.NewInt(0),
StakingPrecompileEpoch: big.NewInt(2), StakingPrecompileEpoch: big.NewInt(2),
SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16
} }
// LocalnetChainConfig contains the chain parameters to run for local development. // LocalnetChainConfig contains the chain parameters to run for local development.
@ -233,6 +238,7 @@ var (
SHA3Epoch: big.NewInt(0), SHA3Epoch: big.NewInt(0),
HIP6And8Epoch: EpochTBD, // Never enable it for localnet as localnet has no external validator setup HIP6And8Epoch: EpochTBD, // Never enable it for localnet as localnet has no external validator setup
StakingPrecompileEpoch: big.NewInt(2), StakingPrecompileEpoch: big.NewInt(2),
SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16
} }
// AllProtocolChanges ... // AllProtocolChanges ...
@ -268,6 +274,7 @@ var (
big.NewInt(0), // SHA3Epoch big.NewInt(0), // SHA3Epoch
big.NewInt(0), // HIP6And8Epoch big.NewInt(0), // HIP6And8Epoch
big.NewInt(0), // StakingPrecompileEpoch big.NewInt(0), // StakingPrecompileEpoch
big.NewInt(0), // SlotsLimitedEpoch
} }
// TestChainConfig ... // TestChainConfig ...
@ -303,6 +310,7 @@ var (
big.NewInt(0), // SHA3Epoch big.NewInt(0), // SHA3Epoch
big.NewInt(0), // HIP6And8Epoch big.NewInt(0), // HIP6And8Epoch
big.NewInt(0), // StakingPrecompileEpoch big.NewInt(0), // StakingPrecompileEpoch
big.NewInt(0), // SlotsLimitedEpoch
} }
// TestRules ... // TestRules ...
@ -420,6 +428,9 @@ type ChainConfig struct {
// StakingPrecompileEpoch is the first epoch to support the staking precompiles // StakingPrecompileEpoch is the first epoch to support the staking precompiles
StakingPrecompileEpoch *big.Int `json:"staking-precompile-epoch,omitempty"` StakingPrecompileEpoch *big.Int `json:"staking-precompile-epoch,omitempty"`
// SlotsLimitedEpoch is the first epoch to enable HIP-16.
SlotsLimitedEpoch *big.Int `json:"slots-limit,omitempty"`
} }
// String implements the fmt.Stringer interface. // String implements the fmt.Stringer interface.
@ -477,6 +488,11 @@ func (c *ChainConfig) IsStaking(epoch *big.Int) bool {
return isForked(c.StakingEpoch, epoch) return isForked(c.StakingEpoch, epoch)
} }
// IsSlotsLimited determines whether HIP-16 is enabled
func (c *ChainConfig) IsSlotsLimited(epoch *big.Int) bool {
return isForked(c.SlotsLimitedEpoch, epoch)
}
// IsFiveSeconds determines whether it is the epoch to change to 5 seconds block time // IsFiveSeconds determines whether it is the epoch to change to 5 seconds block time
func (c *ChainConfig) IsFiveSeconds(epoch *big.Int) bool { func (c *ChainConfig) IsFiveSeconds(epoch *big.Int) bool {
return isForked(c.FiveSecondsEpoch, epoch) return isForked(c.FiveSecondsEpoch, epoch)

@ -85,7 +85,7 @@ func (p CandidateOrder) MarshalJSON() ([]byte, error) {
// NewEPoSRound runs a fresh computation of EPoS using // NewEPoSRound runs a fresh computation of EPoS using
// latest data always // latest data always
func NewEPoSRound(epoch *big.Int, stakedReader StakingCandidatesReader, isExtendedBound bool) ( func NewEPoSRound(epoch *big.Int, stakedReader StakingCandidatesReader, isExtendedBound bool, slotsLimit, shardCount int) (
*CompletedEPoSRound, error, *CompletedEPoSRound, error,
) { ) {
eligibleCandidate, err := prepareOrders(stakedReader) eligibleCandidate, err := prepareOrders(stakedReader)
@ -96,7 +96,7 @@ func NewEPoSRound(epoch *big.Int, stakedReader StakingCandidatesReader, isExtend
epoch, epoch,
) )
median, winners := effective.Apply( median, winners := effective.Apply(
eligibleCandidate, maxExternalSlots, isExtendedBound, eligibleCandidate, maxExternalSlots, isExtendedBound, slotsLimit, shardCount,
) )
auctionCandidates := make([]*CandidateOrder, len(eligibleCandidate)) auctionCandidates := make([]*CandidateOrder, len(eligibleCandidate))
@ -353,7 +353,7 @@ func eposStakedCommittee(
} }
// TODO(audit): make sure external validator BLS key are also not duplicate to Harmony's keys // TODO(audit): make sure external validator BLS key are also not duplicate to Harmony's keys
completedEPoSRound, err := NewEPoSRound(epoch, stakerReader, stakerReader.Config().IsEPoSBound35(epoch)) completedEPoSRound, err := NewEPoSRound(epoch, stakerReader, stakerReader.Config().IsEPoSBound35(epoch), s.SlotsLimit(), shardCount)
if err != nil { if err != nil {
return nil, err return nil, err

@ -79,11 +79,10 @@ func Median(stakes []SlotPurchase) numeric.Dec {
// Compute .. // Compute ..
func Compute( func Compute(
shortHand map[common.Address]*SlotOrder, pull int, shortHand map[common.Address]*SlotOrder, pull, slotsLimit, shardCount int,
) (numeric.Dec, []SlotPurchase) { ) (numeric.Dec, []SlotPurchase) {
eposedSlots := []SlotPurchase{}
if len(shortHand) == 0 { if len(shortHand) == 0 {
return numeric.ZeroDec(), eposedSlots return numeric.ZeroDec(), []SlotPurchase{}
} }
type t struct { type t struct {
@ -91,10 +90,13 @@ func Compute(
slot *SlotOrder slot *SlotOrder
} }
totalSlots := 0
shorter := []t{} shorter := []t{}
for key, value := range shortHand { for key, value := range shortHand {
totalSlots += len(value.SpreadAmong)
shorter = append(shorter, t{key, value}) shorter = append(shorter, t{key, value})
} }
eposedSlots := make([]SlotPurchase, 0, totalSlots)
sort.SliceStable( sort.SliceStable(
shorter, shorter,
@ -111,16 +113,31 @@ func Compute(
if slotsCount == 0 { if slotsCount == 0 {
continue continue
} }
shardSlotsCount := make([]int, shardCount)
spread := numeric.NewDecFromBigInt(staker.slot.Stake). spread := numeric.NewDecFromBigInt(staker.slot.Stake).
QuoInt64(int64(slotsCount)) QuoInt64(int64(slotsCount))
startIndex := len(eposedSlots)
for i := 0; i < slotsCount; i++ { for i := 0; i < slotsCount; i++ {
eposedSlots = append(eposedSlots, SlotPurchase{ slot := SlotPurchase{
Addr: staker.addr, Addr: staker.addr,
Key: staker.slot.SpreadAmong[i], Key: staker.slot.SpreadAmong[i],
// NOTE these are same because later the .EPoSStake mutated // NOTE these are same because later the .EPoSStake mutated
RawStake: spread, RawStake: spread,
EPoSStake: spread, EPoSStake: spread,
}) }
shard := new(big.Int).Mod(slot.Key.Big(), big.NewInt(int64(shardCount))).Int64()
shardSlotsCount[int(shard)]++
if slotsLimit > 0 && shardSlotsCount[int(shard)] > slotsLimit {
continue
}
eposedSlots = append(eposedSlots, slot)
}
if effectiveSlotsCount := len(eposedSlots) - startIndex; effectiveSlotsCount != slotsCount {
effectiveSpread := numeric.NewDecFromBigInt(staker.slot.Stake).QuoInt64(int64(effectiveSlotsCount))
for _, slot := range eposedSlots[startIndex:] {
slot.RawStake = effectiveSpread
slot.EPoSStake = effectiveSpread
}
} }
} }
@ -145,10 +162,10 @@ func Compute(
} }
// Apply .. // Apply ..
func Apply(shortHand map[common.Address]*SlotOrder, pull int, isExtendedBound bool) ( func Apply(shortHand map[common.Address]*SlotOrder, pull int, isExtendedBound bool, slotsLimit int, shardCount int) (
numeric.Dec, []SlotPurchase, numeric.Dec, []SlotPurchase,
) { ) {
median, picks := Compute(shortHand, pull) median, picks := Compute(shortHand, pull, slotsLimit, shardCount)
max := onePlusC.Mul(median) max := onePlusC.Mul(median)
min := oneMinusC.Mul(median) min := oneMinusC.Mul(median)
if isExtendedBound { if isExtendedBound {

Loading…
Cancel
Save