Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

max number of shards for genesis config #2521

Merged
merged 7 commits into from Dec 4, 2020
3 changes: 3 additions & 0 deletions cmd/node/config/config.toml
Expand Up @@ -46,6 +46,9 @@
# GenesisString represents the encoded string for the genesis block
GenesisString = "67656E65736973"

# GenesisMaxNumberOfShards represents the maximum number of shards to be created at genesis (excluding metaChain shard)
GenesisMaxNumberOfShards = 3

[Versions]
DefaultVersion = "default"
VersionsByEpochs = [
Expand Down
1 change: 1 addition & 0 deletions cmd/node/main.go
Expand Up @@ -635,6 +635,7 @@ func startNode(ctx *cli.Context, log logger.Logger, version string) error {
nodesSetupPath,
addressPubkeyConverter,
validatorPubkeyConverter,
generalConfig.GeneralSettings.GenesisMaxNumberOfShards,
)
if err != nil {
return err
Expand Down
1 change: 1 addition & 0 deletions cmd/storer2elastic/main.go
Expand Up @@ -185,6 +185,7 @@ func startStorer2Elastic(ctx *cli.Context) error {
flagsValues.nodesSetupFilePath,
addressPubKeyConverter,
validatorPubKeyConverter,
nodeConfig.GeneralSettings.GenesisMaxNumberOfShards,
)
if err != nil {
return err
Expand Down
1 change: 1 addition & 0 deletions config/config.go
Expand Up @@ -221,6 +221,7 @@ type GeneralSettingsConfig struct {
MetaProtectionEnableEpoch uint32
AheadOfTimeGasUsageEnableEpoch uint32
GenesisString string
GenesisMaxNumberOfShards uint32
}

// FacadeConfig will hold different configuration option that will be passed to the main ElrondFacade
Expand Down
3 changes: 3 additions & 0 deletions sharding/errors.go
Expand Up @@ -37,6 +37,9 @@ var ErrNilShardCoordinator = errors.New("trying to set nil shard coordinator")
// ErrNilPubkeyConverter signals that a nil public key converter has been provided
var ErrNilPubkeyConverter = errors.New("trying to set nil pubkey converter")

// ErrInvalidMaximumNumberOfShards signals that an invalid maximum number of shards has been provided
var ErrInvalidMaximumNumberOfShards = errors.New("trying to set an invalid maximum number of shards")

// ErrCouldNotParsePubKey signals that a given public key could not be parsed
var ErrCouldNotParsePubKey = errors.New("could not parse node's public key")

Expand Down
10 changes: 10 additions & 0 deletions sharding/nodesSetup.go
Expand Up @@ -71,6 +71,7 @@ type NodesSetup struct {

InitialNodes []*InitialNode `json:"initialNodes"`

genesisMaxNumShards uint32
nrOfShards uint32
nrOfNodes uint32
nrOfMetaChainNodes uint32
Expand All @@ -85,6 +86,7 @@ func NewNodesSetup(
nodesFilePath string,
addressPubkeyConverter core.PubkeyConverter,
validatorPubkeyConverter core.PubkeyConverter,
genesisMaxNumShards uint32,
) (*NodesSetup, error) {

if check.IfNil(addressPubkeyConverter) {
Expand All @@ -93,10 +95,14 @@ func NewNodesSetup(
if check.IfNil(validatorPubkeyConverter) {
return nil, fmt.Errorf("%w for validatorPubkeyConverter", ErrNilPubkeyConverter)
}
if genesisMaxNumShards < 1 {
return nil, fmt.Errorf("%w for genesisMaxNumShards", ErrInvalidMaximumNumberOfShards)
}

nodes := &NodesSetup{
addressPubkeyConverter: addressPubkeyConverter,
validatorPubkeyConverter: validatorPubkeyConverter,
genesisMaxNumShards: genesisMaxNumShards,
}

err := core.LoadJsonFile(nodes, nodesFilePath)
Expand Down Expand Up @@ -200,6 +206,10 @@ func (ns *NodesSetup) processMetaChainAssigment() {
hystShard := uint32(float32(ns.MinNodesPerShard) * ns.Hysteresis)

ns.nrOfShards = (ns.nrOfNodes - ns.nrOfMetaChainNodes - hystMeta) / (ns.MinNodesPerShard + hystShard)

if ns.nrOfShards > ns.genesisMaxNumShards {
ns.nrOfShards = ns.genesisMaxNumShards
}
}

func (ns *NodesSetup) processShardAssignment() {
Expand Down
118 changes: 118 additions & 0 deletions sharding/nodesSetup_test.go
Expand Up @@ -55,6 +55,7 @@ func createNodesSetupOneShardOneNodeWithOneMeta() *NodesSetup {
ns := &NodesSetup{
addressPubkeyConverter: mock.NewPubkeyConverterMock(32),
validatorPubkeyConverter: mock.NewPubkeyConverterMock(96),
genesisMaxNumShards: 100,
}
ns.ConsensusGroupSize = 1
ns.MinNodesPerShard = 1
Expand Down Expand Up @@ -108,6 +109,7 @@ func createNodesSetupTwoShardTwoNodesWithOneMeta() *NodesSetup {
ns := &NodesSetup{
addressPubkeyConverter: mock.NewPubkeyConverterMock(32),
validatorPubkeyConverter: mock.NewPubkeyConverterMock(96),
genesisMaxNumShards: 100,
}
ns.ConsensusGroupSize = 1
ns.MinNodesPerShard = 2
Expand All @@ -126,6 +128,7 @@ func createNodesSetupTwoShard5NodesWithMeta() *NodesSetup {
ns := &NodesSetup{
addressPubkeyConverter: mock.NewPubkeyConverterMock(32),
validatorPubkeyConverter: mock.NewPubkeyConverterMock(96),
genesisMaxNumShards: 100,
}
ns.ConsensusGroupSize = 1
ns.MinNodesPerShard = 2
Expand All @@ -144,6 +147,7 @@ func createNodesSetupTwoShard6NodesMeta() *NodesSetup {
ns := &NodesSetup{
addressPubkeyConverter: mock.NewPubkeyConverterMock(32),
validatorPubkeyConverter: mock.NewPubkeyConverterMock(96),
genesisMaxNumShards: 100,
}
ns.ConsensusGroupSize = 1
ns.MinNodesPerShard = 2
Expand All @@ -164,6 +168,7 @@ func TestNodesSetup_NewNodesSetupWrongFile(t *testing.T) {
"",
mock.NewPubkeyConverterMock(32),
mock.NewPubkeyConverterMock(96),
100,
)

assert.Nil(t, ns)
Expand All @@ -177,6 +182,7 @@ func TestNodesSetup_NewNodesSetupWrongDataInFile(t *testing.T) {
"mock/invalidNodesSetupMock.json",
mock.NewPubkeyConverterMock(32),
mock.NewPubkeyConverterMock(96),
100,
)

assert.Nil(t, ns)
Expand All @@ -190,6 +196,7 @@ func TestNodesSetup_NewNodesShouldWork(t *testing.T) {
"mock/nodesSetupMock.json",
mock.NewPubkeyConverterMock(32),
mock.NewPubkeyConverterMock(96),
100,
)

assert.NotNil(t, ns)
Expand Down Expand Up @@ -466,6 +473,7 @@ func TestNodesSetup_InitialNodesPubKeysWithHysteresis(t *testing.T) {
Adaptivity: false,
addressPubkeyConverter: mock.NewPubkeyConverterMock(32),
validatorPubkeyConverter: mock.NewPubkeyConverterMock(96),
genesisMaxNumShards: 100,
}

ns = createAndAssignNodes(*ns, 3000)
Expand Down Expand Up @@ -590,6 +598,7 @@ func TestNodesSetup_MinNumberOfNodes(t *testing.T) {
Adaptivity: false,
addressPubkeyConverter: mock.NewPubkeyConverterMock(32),
validatorPubkeyConverter: mock.NewPubkeyConverterMock(96),
genesisMaxNumShards: 100,
}

ns = createAndAssignNodes(*ns, 2169)
Expand All @@ -609,3 +618,112 @@ func TestNodesSetup_MinNumberOfNodes(t *testing.T) {
minHysteresisNodesMeta := ns.MinMetaHysteresisNodes()
assert.Equal(t, uint32(80), minHysteresisNodesMeta)
}

func TestNewNodesSetup_InvalidMaxNumShardsShouldErr(t *testing.T) {
t.Parallel()

ns, err := NewNodesSetup(
"",
mock.NewPubkeyConverterMock(32),
mock.NewPubkeyConverterMock(96),
0,
)

assert.Nil(t, ns)
assert.NotNil(t, err)
assert.Contains(t, err.Error(), ErrInvalidMaximumNumberOfShards.Error())
}

func TestNodesSetup_IfNodesWithinMaxShardLimitEquivalentDistribution(t *testing.T) {
t.Parallel()

ns := &NodesSetup{
ConsensusGroupSize: 63,
MinNodesPerShard: 400,
MetaChainConsensusGroupSize: 400,
MetaChainMinNodes: 400,
Hysteresis: 0.2,
Adaptivity: false,
addressPubkeyConverter: mock.NewPubkeyConverterMock(32),
validatorPubkeyConverter: mock.NewPubkeyConverterMock(96),
genesisMaxNumShards: 3,
}

ns = createAndAssignNodes(*ns, 2169)

ns2 := &(*ns)
ns2.genesisMaxNumShards = 3
ns2 = createAndAssignNodes(*ns2, 2169)

assert.Equal(t, 4, len(ns.eligible))
assert.Equal(t, 4, len(ns2.eligible))
for shard, shardNodes := range ns.eligible {
assert.Equal(t, len(shardNodes), len(ns2.eligible[shard]))
assert.Equal(t, len(ns.waiting[shard]), len(ns2.waiting[shard]))
assert.GreaterOrEqual(t, len(ns.waiting[shard]), 142)
assert.Equal(t, len(ns.waiting[shard]), len(ns2.waiting[shard]))
for i, node := range shardNodes {
assert.Equal(t, node, ns2.eligible[shard][i])
}
for i, node := range ns.waiting[shard] {
assert.Equal(t, node, ns2.waiting[shard][i])
}
}

minNumNodes := ns.MinNumberOfNodes()
assert.Equal(t, minNumNodes, ns2.MinNumberOfNodes())

minHysteresisNodesShard := ns.MinShardHysteresisNodes()
assert.Equal(t, minHysteresisNodesShard, ns2.MinShardHysteresisNodes())

minHysteresisNodesMeta := ns.MinMetaHysteresisNodes()
assert.Equal(t, minHysteresisNodesMeta, ns2.MinMetaHysteresisNodes())
}

func TestNodesSetup_NodesAboveMaxShardLimit(t *testing.T) {
t.Parallel()

ns := &NodesSetup{
ConsensusGroupSize: 63,
MinNodesPerShard: 400,
MetaChainConsensusGroupSize: 400,
MetaChainMinNodes: 400,
Hysteresis: 0.2,
Adaptivity: false,
addressPubkeyConverter: mock.NewPubkeyConverterMock(32),
validatorPubkeyConverter: mock.NewPubkeyConverterMock(96),
genesisMaxNumShards: 3,
}

ns = createAndAssignNodes(*ns, 3200)

assert.Equal(t, 4, len(ns.eligible))
for shard, shardNodes := range ns.eligible {
assert.Equal(t, 400, len(shardNodes))
assert.Equal(t, len(ns.waiting[shard]), 400)
}

minNumNodes := ns.MinNumberOfNodes()
assert.Equal(t, uint32(1600), minNumNodes)

minHysteresisNodesShard := ns.MinShardHysteresisNodes()
assert.Equal(t, uint32(80), minHysteresisNodesShard)

minHysteresisNodesMeta := ns.MinMetaHysteresisNodes()
assert.Equal(t, uint32(80), minHysteresisNodesMeta)

ns = createAndAssignNodes(*ns, 3600)
for shard, shardNodes := range ns.eligible {
assert.Equal(t, 400, len(shardNodes))
assert.Equal(t, len(ns.waiting[shard]), 500)
}

minNumNodes = ns.MinNumberOfNodes()
assert.Equal(t, uint32(1600), minNumNodes)

minHysteresisNodesShard = ns.MinShardHysteresisNodes()
assert.Equal(t, uint32(80), minHysteresisNodesShard)

minHysteresisNodesMeta = ns.MinMetaHysteresisNodes()
assert.Equal(t, uint32(80), minHysteresisNodesMeta)
}
3 changes: 2 additions & 1 deletion testscommon/generalConfig.go
Expand Up @@ -8,7 +8,8 @@ import (
func GetGeneralConfig() config.Config {
return config.Config{
GeneralSettings: config.GeneralSettingsConfig{
StartInEpochEnabled: true,
StartInEpochEnabled: true,
GenesisMaxNumberOfShards: 100,
},
EpochStartConfig: config.EpochStartConfig{
MinRoundsBetweenEpochs: 5,
Expand Down