From 08bb9022e08bace950085672cfce6f52cbd92749 Mon Sep 17 00:00:00 2001 From: peekpi <894646171@qq.com> Date: Sat, 19 Mar 2022 23:46:07 +0800 Subject: [PATCH] [consensus] HIP-16: Enforce a 6% max keys per shard limit for each validator --- cmd/harmony/default.go | 1 + cmd/harmony/main.go | 2 +- hmy/staking.go | 3 +- internal/chain/engine.go | 3 +- internal/configs/harmony/harmony.go | 1 + internal/configs/sharding/instance.go | 13 ++++++-- internal/configs/sharding/localnet.go | 10 +++--- internal/configs/sharding/mainnet.go | 37 +++++++++++---------- internal/configs/sharding/pangaea.go | 4 +-- internal/configs/sharding/partner.go | 4 +-- internal/configs/sharding/shardingconfig.go | 2 ++ internal/configs/sharding/stress.go | 6 ++-- internal/configs/sharding/testnet.go | 13 +++++--- internal/params/config.go | 16 +++++++++ shard/committee/assignment.go | 6 ++-- staking/effective/calculate.go | 31 +++++++++++++---- 16 files changed, 102 insertions(+), 50 deletions(-) diff --git a/cmd/harmony/default.go b/cmd/harmony/default.go index 3ce5887d4..5fd622b15 100644 --- a/cmd/harmony/default.go +++ b/cmd/harmony/default.go @@ -106,6 +106,7 @@ var defaultDevnetConfig = harmonyconfig.DevnetConfig{ NumShards: 2, ShardSize: 10, HmyNodeSize: 10, + SlotsLimit: 0, } var defaultRevertConfig = harmonyconfig.RevertConfig{ diff --git a/cmd/harmony/main.go b/cmd/harmony/main.go index e1f565d58..40fd8c41c 100644 --- a/cmd/harmony/main.go +++ b/cmd/harmony/main.go @@ -485,7 +485,7 @@ func nodeconfigSetShardSchedule(config harmonyconfig.HarmonyConfig) { } 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 { _, _ = fmt.Fprintf(os.Stderr, "ERROR invalid devnet sharding config: %s", err) diff --git a/hmy/staking.go b/hmy/staking.go index a95170cd6..118a52593 100644 --- a/hmy/staking.go +++ b/hmy/staking.go @@ -445,7 +445,8 @@ func (hmy *Harmony) GetMedianRawStakeSnapshot() ( func() (interface{}, error) { // Compute for next epoch 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 { diff --git a/internal/chain/engine.go b/internal/chain/engine.go index 674feb199..6429acd77 100644 --- a/internal/chain/engine.go +++ b/internal/chain/engine.go @@ -725,7 +725,8 @@ func readShardState(chain engine.ChainReader, epoch *big.Int, targetShardID uint return shardState, nil } else { - shardState, err := chain.ReadShardState(epoch) + //shardState, err := chain.ReadShardState(epoch) + shardState, err := committee.WithStakingEnabled.ReadFromDB(epoch, chain) if err != nil { return nil, errors.Wrapf(err, "read shard state for epoch %v", epoch) } diff --git a/internal/configs/harmony/harmony.go b/internal/configs/harmony/harmony.go index a59d47d6e..2ede248d7 100644 --- a/internal/configs/harmony/harmony.go +++ b/internal/configs/harmony/harmony.go @@ -174,6 +174,7 @@ type DevnetConfig struct { NumShards int ShardSize 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 diff --git a/internal/configs/sharding/instance.go b/internal/configs/sharding/instance.go index 7601c2899..a127db744 100644 --- a/internal/configs/sharding/instance.go +++ b/internal/configs/sharding/instance.go @@ -32,12 +32,13 @@ type instance struct { fnAccounts []genesis.DeployAccount reshardingEpoch []*big.Int 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 // upon given parameters. func NewInstance( - numShards uint32, numNodesPerShard, numHarmonyOperatedNodesPerShard int, harmonyVotePercent numeric.Dec, + numShards uint32, numNodesPerShard, numHarmonyOperatedNodesPerShard, slotsLimit int, harmonyVotePercent numeric.Dec, hmyAccounts []genesis.DeployAccount, fnAccounts []genesis.DeployAccount, reshardingEpoch []*big.Int, blocksE uint64, @@ -82,6 +83,7 @@ func NewInstance( fnAccounts: fnAccounts, reshardingEpoch: reshardingEpoch, blocksPerEpoch: blocksE, + slotsLimit: slotsLimit, }, nil } @@ -90,14 +92,14 @@ func NewInstance( // It is intended to be used for static initialization. func MustNewInstance( numShards uint32, - numNodesPerShard, numHarmonyOperatedNodesPerShard int, + numNodesPerShard, numHarmonyOperatedNodesPerShard, slotsLimit int, harmonyVotePercent numeric.Dec, hmyAccounts []genesis.DeployAccount, fnAccounts []genesis.DeployAccount, reshardingEpoch []*big.Int, blocksPerEpoch uint64, ) Instance { sc, err := NewInstance( - numShards, numNodesPerShard, numHarmonyOperatedNodesPerShard, harmonyVotePercent, + numShards, numNodesPerShard, numHarmonyOperatedNodesPerShard, slotsLimit, harmonyVotePercent, hmyAccounts, fnAccounts, reshardingEpoch, blocksPerEpoch, ) if err != nil { @@ -116,6 +118,11 @@ func (sc instance) NumShards() uint32 { 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. func (sc instance) HarmonyVotePercent() numeric.Dec { return sc.harmonyVotePercent diff --git a/internal/configs/sharding/localnet.go b/internal/configs/sharding/localnet.go index a434451f9..1437b5db6 100644 --- a/internal/configs/sharding/localnet.go +++ b/internal/configs/sharding/localnet.go @@ -142,9 +142,9 @@ var ( 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 - localnetV0 = MustNewInstance(2, 7, 5, numeric.OneDec(), genesis.LocalHarmonyAccounts, genesis.LocalFnAccounts, localnetReshardingEpoch, LocalnetSchedule.BlocksPerEpochOld()) - localnetV1 = MustNewInstance(2, 8, 5, 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()) - localnetV3 = MustNewInstance(2, 9, 6, 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()) + localnetV0 = MustNewInstance(2, 7, 5, 0, numeric.OneDec(), genesis.LocalHarmonyAccounts, genesis.LocalFnAccounts, localnetReshardingEpoch, LocalnetSchedule.BlocksPerEpochOld()) + localnetV1 = MustNewInstance(2, 8, 5, 0, numeric.OneDec(), genesis.LocalHarmonyAccountsV1, genesis.LocalFnAccountsV1, 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, 0, 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()) ) diff --git a/internal/configs/sharding/mainnet.go b/internal/configs/sharding/mainnet.go index 7f859d743..791937313 100644 --- a/internal/configs/sharding/mainnet.go +++ b/internal/configs/sharding/mainnet.go @@ -53,6 +53,8 @@ type mainnetSchedule struct{} func (ms mainnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { switch { + case params.MainnetChainConfig.IsSlotsLimited(epoch): + return mainnetV3_3 case params.MainnetChainConfig.IsHIP6And8Epoch(epoch): // Decrease internal voting power from 60% to 49% // 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 ( - mainnetV0 = MustNewInstance(4, 150, 112, 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_2 = MustNewInstance(4, 200, 148, 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_4 = MustNewInstance(4, 216, 148, 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_1 = MustNewInstance(4, 250, 170, 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_3 = MustNewInstance(4, 250, 170, 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_5 = MustNewInstance(4, 250, 170, 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_1 = MustNewInstance(4, 250, 130, 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()) - mainnetV3 = MustNewInstance(4, 250, 90, 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_2 = MustNewInstance(4, 250, 25, numeric.MustNewDecFromStr("0.49"), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_5, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpoch()) + mainnetV0 = MustNewInstance(4, 150, 112, 0, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccounts, 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, 0, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV0_2, 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, 0, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV0_4, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld()) + mainnetV1 = MustNewInstance(4, 250, 170, 0, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1, 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, 0, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_2, 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, 0, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_4, 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, 0, 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, 0, numeric.MustNewDecFromStr("0.68"), genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1_5, mainnetReshardingEpoch, MainnetSchedule.BlocksPerEpochOld()) + mainnetV3 = MustNewInstance(4, 250, 90, 0, numeric.MustNewDecFromStr("0.68"), 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, 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()) ) diff --git a/internal/configs/sharding/pangaea.go b/internal/configs/sharding/pangaea.go index ac0bdf5bd..730d6fc64 100644 --- a/internal/configs/sharding/pangaea.go +++ b/internal/configs/sharding/pangaea.go @@ -75,5 +75,5 @@ var pangaeaReshardingEpoch = []*big.Int{ params.PangaeaChainConfig.StakingEpoch, } -var pangaeaV0 = MustNewInstance(4, 30, 30, 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 pangaeaV0 = MustNewInstance(4, 30, 30, 0, numeric.OneDec(), 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()) diff --git a/internal/configs/sharding/partner.go b/internal/configs/sharding/partner.go index c04fff27b..2a2d1501b 100644 --- a/internal/configs/sharding/partner.go +++ b/internal/configs/sharding/partner.go @@ -76,5 +76,5 @@ var partnerReshardingEpoch = []*big.Int{ params.PartnerChainConfig.StakingEpoch, } -var partnerV0 = MustNewInstance(2, 5, 5, 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 partnerV0 = MustNewInstance(2, 5, 5, 0, numeric.OneDec(), 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()) diff --git a/internal/configs/sharding/shardingconfig.go b/internal/configs/sharding/shardingconfig.go index 1e6122e1d..50d21a8ff 100644 --- a/internal/configs/sharding/shardingconfig.go +++ b/internal/configs/sharding/shardingconfig.go @@ -72,6 +72,8 @@ type Instance interface { // Count of blocks per epoch 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. diff --git a/internal/configs/sharding/stress.go b/internal/configs/sharding/stress.go index f98e664ab..42bce4c41 100644 --- a/internal/configs/sharding/stress.go +++ b/internal/configs/sharding/stress.go @@ -78,6 +78,6 @@ var stressnetReshardingEpoch = []*big.Int{ params.StressnetChainConfig.StakingEpoch, } -var stressnetV0 = MustNewInstance(2, 10, 10, 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 stressnetV2 = MustNewInstance(2, 30, 10, numeric.MustNewDecFromStr("0.6"), 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, 0, numeric.MustNewDecFromStr("0.9"), 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()) diff --git a/internal/configs/sharding/testnet.go b/internal/configs/sharding/testnet.go index 1e332da86..5ac679812 100644 --- a/internal/configs/sharding/testnet.go +++ b/internal/configs/sharding/testnet.go @@ -33,6 +33,8 @@ const ( func (ts testnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { switch { + case params.TestnetChainConfig.IsSlotsLimited(epoch): + return testnetV3_2 case params.TestnetChainConfig.IsSixtyPercent(epoch): return testnetV3_1 case params.TestnetChainConfig.IsTwoSeconds(epoch): @@ -114,8 +116,9 @@ var testnetReshardingEpoch = []*big.Int{ params.TestnetChainConfig.TwoSecondsEpoch, } -var testnetV0 = MustNewInstance(4, 16, 15, 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 testnetV2 = MustNewInstance(4, 30, 8, 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_1 = MustNewInstance(4, 30, 8, numeric.MustNewDecFromStr("0.60"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch, TestnetSchedule.BlocksPerEpoch()) +var testnetV0 = MustNewInstance(4, 16, 15, 0, numeric.OneDec(), 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, 0, numeric.MustNewDecFromStr("0.90"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch, TestnetSchedule.BlocksPerEpochOld()) +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, 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()) diff --git a/internal/params/config.go b/internal/params/config.go index f1bbd8d7b..c0097d84f 100644 --- a/internal/params/config.go +++ b/internal/params/config.go @@ -65,6 +65,7 @@ var ( SHA3Epoch: 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 + SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16 } // TestnetChainConfig contains the chain parameters to run a node on the harmony test network. @@ -98,6 +99,7 @@ var ( SHA3Epoch: big.NewInt(74570), HIP6And8Epoch: big.NewInt(74570), StakingPrecompileEpoch: big.NewInt(75175), + SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16 } // PangaeaChainConfig contains the chain parameters for the Pangaea network. @@ -132,6 +134,7 @@ var ( SHA3Epoch: big.NewInt(0), HIP6And8Epoch: big.NewInt(0), StakingPrecompileEpoch: big.NewInt(2), // same as staking + SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16 } // PartnerChainConfig contains the chain parameters for the Partner network. @@ -166,6 +169,7 @@ var ( SHA3Epoch: big.NewInt(0), HIP6And8Epoch: big.NewInt(0), StakingPrecompileEpoch: big.NewInt(2), + SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16 } // StressnetChainConfig contains the chain parameters for the Stress test network. @@ -200,6 +204,7 @@ var ( SHA3Epoch: big.NewInt(0), HIP6And8Epoch: big.NewInt(0), StakingPrecompileEpoch: big.NewInt(2), + SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16 } // LocalnetChainConfig contains the chain parameters to run for local development. @@ -233,6 +238,7 @@ var ( SHA3Epoch: big.NewInt(0), HIP6And8Epoch: EpochTBD, // Never enable it for localnet as localnet has no external validator setup StakingPrecompileEpoch: big.NewInt(2), + SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16 } // AllProtocolChanges ... @@ -268,6 +274,7 @@ var ( big.NewInt(0), // SHA3Epoch big.NewInt(0), // HIP6And8Epoch big.NewInt(0), // StakingPrecompileEpoch + big.NewInt(0), // SlotsLimitedEpoch } // TestChainConfig ... @@ -303,6 +310,7 @@ var ( big.NewInt(0), // SHA3Epoch big.NewInt(0), // HIP6And8Epoch big.NewInt(0), // StakingPrecompileEpoch + big.NewInt(0), // SlotsLimitedEpoch } // TestRules ... @@ -420,6 +428,9 @@ type ChainConfig struct { // StakingPrecompileEpoch is the first epoch to support the staking precompiles 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. @@ -477,6 +488,11 @@ func (c *ChainConfig) IsStaking(epoch *big.Int) bool { 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 func (c *ChainConfig) IsFiveSeconds(epoch *big.Int) bool { return isForked(c.FiveSecondsEpoch, epoch) diff --git a/shard/committee/assignment.go b/shard/committee/assignment.go index ccfcdca90..bb79b9e45 100644 --- a/shard/committee/assignment.go +++ b/shard/committee/assignment.go @@ -85,7 +85,7 @@ func (p CandidateOrder) MarshalJSON() ([]byte, error) { // NewEPoSRound runs a fresh computation of EPoS using // 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, ) { eligibleCandidate, err := prepareOrders(stakedReader) @@ -96,7 +96,7 @@ func NewEPoSRound(epoch *big.Int, stakedReader StakingCandidatesReader, isExtend epoch, ) median, winners := effective.Apply( - eligibleCandidate, maxExternalSlots, isExtendedBound, + eligibleCandidate, maxExternalSlots, isExtendedBound, slotsLimit, shardCount, ) 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 - completedEPoSRound, err := NewEPoSRound(epoch, stakerReader, stakerReader.Config().IsEPoSBound35(epoch)) + completedEPoSRound, err := NewEPoSRound(epoch, stakerReader, stakerReader.Config().IsEPoSBound35(epoch), s.SlotsLimit(), shardCount) if err != nil { return nil, err diff --git a/staking/effective/calculate.go b/staking/effective/calculate.go index 1f37426b4..d7f98a3e5 100644 --- a/staking/effective/calculate.go +++ b/staking/effective/calculate.go @@ -79,11 +79,10 @@ func Median(stakes []SlotPurchase) numeric.Dec { // Compute .. func Compute( - shortHand map[common.Address]*SlotOrder, pull int, + shortHand map[common.Address]*SlotOrder, pull, slotsLimit, shardCount int, ) (numeric.Dec, []SlotPurchase) { - eposedSlots := []SlotPurchase{} if len(shortHand) == 0 { - return numeric.ZeroDec(), eposedSlots + return numeric.ZeroDec(), []SlotPurchase{} } type t struct { @@ -91,10 +90,13 @@ func Compute( slot *SlotOrder } + totalSlots := 0 shorter := []t{} for key, value := range shortHand { + totalSlots += len(value.SpreadAmong) shorter = append(shorter, t{key, value}) } + eposedSlots := make([]SlotPurchase, 0, totalSlots) sort.SliceStable( shorter, @@ -111,16 +113,31 @@ func Compute( if slotsCount == 0 { continue } + shardSlotsCount := make([]int, shardCount) spread := numeric.NewDecFromBigInt(staker.slot.Stake). QuoInt64(int64(slotsCount)) + startIndex := len(eposedSlots) for i := 0; i < slotsCount; i++ { - eposedSlots = append(eposedSlots, SlotPurchase{ + slot := SlotPurchase{ Addr: staker.addr, Key: staker.slot.SpreadAmong[i], // NOTE these are same because later the .EPoSStake mutated RawStake: 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 .. -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, ) { - median, picks := Compute(shortHand, pull) + median, picks := Compute(shortHand, pull, slotsLimit, shardCount) max := onePlusC.Mul(median) min := oneMinusC.Mul(median) if isExtendedBound {