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

Integration tests staking v4 #3951

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
5133860
FEAT: Add file placeholder
mariusmihaic Mar 30, 2022
8ebc25f
FEAT: Add intermediary code
mariusmihaic Mar 31, 2022
6cb1275
FEAT: Refactor
mariusmihaic Mar 31, 2022
4ebd97e
FEAT: Refactor 2
mariusmihaic Mar 31, 2022
fca992d
FEAT: Refactor 3
mariusmihaic Mar 31, 2022
d4e9a1e
FEAT: Refactor 4
mariusmihaic Apr 1, 2022
f3dbe32
FEAT: Refactor 5
mariusmihaic Apr 1, 2022
1856d58
FEAT: Ugly version with 2 committed blocks
mariusmihaic Apr 4, 2022
4ea2b9d
FEAT: Test with epoch start prepare
mariusmihaic Apr 4, 2022
1449bcc
FEAT: Register bls keys + bugfixes
mariusmihaic Apr 5, 2022
3c26053
FEAT: Add Process for num of rounds
mariusmihaic Apr 5, 2022
53a59e0
FIX: Sub bug, add safeSub
mariusmihaic Apr 5, 2022
65d9a69
FIX: Waiting list + stubs
mariusmihaic Apr 7, 2022
23407f8
FIX: Refactor 1
mariusmihaic Apr 7, 2022
28b4285
FIX: Refactor 2
mariusmihaic Apr 7, 2022
cda1ce3
FIX: Refactor 3
mariusmihaic Apr 7, 2022
b37fc76
FIX: Refactor 4
mariusmihaic Apr 7, 2022
da98d43
FIX: Refactor 5
mariusmihaic Apr 8, 2022
0869a57
FIX: Refactor6
mariusmihaic Apr 8, 2022
4226a2d
FIX: Refactor 7
mariusmihaic Apr 8, 2022
16efa27
FIX: Refactor 8
mariusmihaic Apr 11, 2022
11f7dc5
FIX: Refactor 9
mariusmihaic Apr 11, 2022
cd02f3a
FIX: Refactor 10
mariusmihaic Apr 12, 2022
f1bd22b
FIX: Refactor 11
mariusmihaic Apr 12, 2022
82a4a3a
FIX: Import cycle
mariusmihaic Apr 13, 2022
a0e443a
FIX: Race condition + add StakingV4DistributeAuctionToWaiting enable …
mariusmihaic Apr 13, 2022
e0d68a7
FIX: Staking v4 complete test
mariusmihaic Apr 13, 2022
9d5cee2
FIX: Roothash mismatch
mariusmihaic Apr 14, 2022
9de7aec
FIX: Minor fixes
mariusmihaic Apr 14, 2022
149bd22
FIX: Rename StakingV4DistributeAuctionToWaiting epoch
mariusmihaic Apr 15, 2022
1cf4bb0
FIX: Package names
mariusmihaic Apr 15, 2022
b32c79f
Merge branch 'feat/liquid-staking' into EN-11927-integration-tests-st…
mariusmihaic Apr 19, 2022
0f3e91a
FIX: Delete error condition for maxNumNodes decrease
mariusmihaic Apr 20, 2022
07ff0da
Merge branch 'feat/liquid-staking' into EN-11927-integration-tests-st…
mariusmihaic Apr 20, 2022
e9b8e72
FIX: Linter errors
mariusmihaic Apr 20, 2022
f3fe6c5
FIX: Review findings
mariusmihaic Apr 27, 2022
063a1c3
FIX: Simplify logic in calcNormRand
mariusmihaic Apr 28, 2022
2e921fa
Merge branch 'feat/liquid-staking' into EN-11927-integration-tests-st…
mariusmihaic Apr 28, 2022
c1f8aec
FIX: Merge conflict
mariusmihaic Apr 28, 2022
a98dcee
FIX: Build after merge
mariusmihaic Apr 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 9 additions & 1 deletion cmd/node/config/enableEpochs.toml
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,18 @@
# StakingV4EnableEpoch represents the epoch when staking v4 is enabled. Should have a greater value than StakingV4InitEnableEpoch
StakingV4EnableEpoch = 5

# StakingV4DistributeAuctionToWaitingEpoch represents the epoch in which selected nodes from auction will be distributed to waiting list
StakingV4DistributeAuctionToWaitingEpoch = 6

# MaxNodesChangeEnableEpoch holds configuration for changing the maximum number of nodes and the enabling epoch
MaxNodesChangeEnableEpoch = [
{ EpochEnable = 0, MaxNumNodes = 36, NodesToShufflePerShard = 4 },
{ EpochEnable = 1, MaxNumNodes = 56, NodesToShufflePerShard = 2 }
{ EpochEnable = 1, MaxNumNodes = 56, NodesToShufflePerShard = 2 },
# Staking v4 configuration, where:
# - Enable epoch = StakingV4DistributeAuctionToWaitingEpoch
# - NodesToShufflePerShard = same as previous entry in MaxNodesChangeEnableEpoch
# - MaxNumNodes = (MaxNumNodesFromPreviousEpochEnable - (numOfShards+1)*NodesToShufflePerShard)
{ EpochEnable = 6, MaxNumNodes = 48, NodesToShufflePerShard = 2 },
]

[GasSchedule]
Expand Down
1 change: 1 addition & 0 deletions config/epochConfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ type EnableEpochs struct {
StakeLimitsEnableEpoch uint32
StakingV4InitEnableEpoch uint32
StakingV4EnableEpoch uint32
StakingV4DistributeAuctionToWaitingEpoch uint32
}

// GasScheduleByEpochs represents a gas schedule toml entry that will be applied from the provided epoch
Expand Down
11 changes: 6 additions & 5 deletions epochStart/metachain/legacySystemSCs.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type legacySystemSCProcessor struct {
mapNumSwitchedPerShard map[uint32]uint32
mapNumSwitchablePerShard map[uint32]uint32
maxNodesEnableConfig []config.MaxNodesChangeConfig
currentNodesEnableConfig config.MaxNodesChangeConfig
maxNodes uint32

switchEnableEpoch uint32
Expand All @@ -56,6 +57,7 @@ type legacySystemSCProcessor struct {
esdtEnableEpoch uint32
saveJailedAlwaysEnableEpoch uint32
stakingV4InitEnableEpoch uint32
stakingV4EnableEpoch uint32

flagSwitchJailedWaiting atomic.Flag
flagHystNodesEnabled atomic.Flag
Expand Down Expand Up @@ -101,6 +103,7 @@ func newLegacySystemSCProcessor(args ArgsNewEpochStartSystemSCProcessing) (*lega
esdtOwnerAddressBytes: args.ESDTOwnerAddressBytes,
saveJailedAlwaysEnableEpoch: args.EpochConfig.EnableEpochs.SaveJailedAlwaysEnableEpoch,
stakingV4InitEnableEpoch: args.EpochConfig.EnableEpochs.StakingV4InitEnableEpoch,
stakingV4EnableEpoch: args.EpochConfig.EnableEpochs.StakingV4EnableEpoch,
}

log.Debug("legacySystemSC: enable epoch for switch jail waiting", "epoch", legacy.switchEnableEpoch)
Expand All @@ -111,6 +114,7 @@ func newLegacySystemSCProcessor(args ArgsNewEpochStartSystemSCProcessing) (*lega
log.Debug("legacySystemSC: enable epoch for correct last unjailed", "epoch", legacy.correctLastUnJailEpoch)
log.Debug("legacySystemSC: enable epoch for save jailed always", "epoch", legacy.saveJailedAlwaysEnableEpoch)
log.Debug("legacySystemSC: enable epoch for initializing staking v4", "epoch", legacy.stakingV4InitEnableEpoch)
log.Debug("legacySystemSC: enable epoch for staking v4", "epoch", legacy.stakingV4EnableEpoch)

legacy.maxNodesEnableConfig = make([]config.MaxNodesChangeConfig, len(args.MaxNodesEnableConfig))
copy(legacy.maxNodesEnableConfig, args.MaxNodesEnableConfig)
Expand Down Expand Up @@ -615,10 +619,6 @@ func (s *legacySystemSCProcessor) updateMaxNodes(validatorsInfoMap state.ShardVa
return err
}

if maxNumberOfNodes < prevMaxNumberOfNodes {
return epochStart.ErrInvalidMaxNumberOfNodes
}

if s.flagStakingQueueEnabled.IsSet() {
AdoAdoAdo marked this conversation as resolved.
Show resolved Hide resolved
sw.Start("stakeNodesFromQueue")
err = s.stakeNodesFromQueue(validatorsInfoMap, maxNumberOfNodes-prevMaxNumberOfNodes, nonce, common.NewList)
Expand Down Expand Up @@ -1364,6 +1364,7 @@ func (s *legacySystemSCProcessor) legacyEpochConfirmed(epoch uint32) {
if epoch == maxNodesConfig.EpochEnable {
s.flagChangeMaxNodesEnabled.SetValue(true)
s.maxNodes = maxNodesConfig.MaxNumNodes
s.currentNodesEnableConfig = maxNodesConfig
break
}
}
Expand All @@ -1387,7 +1388,7 @@ func (s *legacySystemSCProcessor) legacyEpochConfirmed(epoch uint32) {
s.flagCorrectLastUnjailedEnabled.SetValue(epoch == s.correctLastUnJailEpoch)
log.Debug("legacySystemSC: correct last unjailed", "enabled", s.flagCorrectLastUnjailedEnabled.IsSet())

s.flagCorrectNumNodesToStake.SetValue(epoch >= s.correctLastUnJailEpoch)
s.flagCorrectNumNodesToStake.SetValue(epoch >= s.correctLastUnJailEpoch && epoch < s.stakingV4EnableEpoch)
log.Debug("legacySystemSC: correct last unjailed", "enabled", s.flagCorrectNumNodesToStake.IsSet())

s.flagESDTEnabled.SetValue(epoch == s.esdtEnableEpoch)
Expand Down
77 changes: 64 additions & 13 deletions epochStart/metachain/systemSCs.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ type systemSCProcessor struct {

governanceEnableEpoch uint32
builtInOnMetaEnableEpoch uint32
stakingV4EnableEpoch uint32

flagGovernanceEnabled atomic.Flag
flagBuiltInOnMetaEnabled atomic.Flag
Expand All @@ -77,7 +76,6 @@ func NewSystemSCProcessor(args ArgsNewEpochStartSystemSCProcessing) (*systemSCPr
legacySystemSCProcessor: legacy,
governanceEnableEpoch: args.EpochConfig.EnableEpochs.GovernanceEnableEpoch,
builtInOnMetaEnableEpoch: args.EpochConfig.EnableEpochs.BuiltInFunctionOnMetaEnableEpoch,
stakingV4EnableEpoch: args.EpochConfig.EnableEpochs.StakingV4EnableEpoch,
}

log.Debug("systemSC: enable epoch for governanceV2 init", "epoch", s.governanceEnableEpoch)
Expand Down Expand Up @@ -150,20 +148,46 @@ func (s *systemSCProcessor) processWithNewFlags(
return nil
}

// TODO: Staking v4: perhaps create a subcomponent which handles selection, which would be also very useful in tests
func (s *systemSCProcessor) selectNodesFromAuctionList(validatorsInfoMap state.ShardValidatorsInfoMapHandler, randomness []byte) error {
auctionList, numOfValidators := getAuctionListAndNumOfValidators(validatorsInfoMap)
availableSlots := s.maxNodes - numOfValidators
if availableSlots <= 0 {
log.Info("not enough available slots for auction nodes; skip selecting nodes from auction list")
auctionList, currNumOfValidators := getAuctionListAndNumOfValidators(validatorsInfoMap)
numOfShuffledNodes := s.currentNodesEnableConfig.NodesToShufflePerShard * (s.shardCoordinator.NumberOfShards() + 1)

numOfValidatorsAfterShuffling, err := safeSub(currNumOfValidators, numOfShuffledNodes)
if err != nil {
log.Warn(fmt.Sprintf("%v when trying to compute numOfValidatorsAfterShuffling = %v - %v (currNumOfValidators - numOfShuffledNodes)",
err,
currNumOfValidators,
numOfShuffledNodes,
))
numOfValidatorsAfterShuffling = 0
}

availableSlots, err := safeSub(s.maxNodes, numOfValidatorsAfterShuffling)
if availableSlots == 0 || err != nil {
log.Info(fmt.Sprintf("%v or zero value when trying to compute availableSlots = %v - %v (maxNodes - numOfValidatorsAfterShuffling); skip selecting nodes from auction list",
err,
s.maxNodes,
numOfValidatorsAfterShuffling,
))
return nil
}

err := s.sortAuctionList(auctionList, randomness)
auctionListSize := uint32(len(auctionList))
log.Info("systemSCProcessor.selectNodesFromAuctionList",
"max nodes", s.maxNodes,
"current number of validators", currNumOfValidators,
"num of nodes which will be shuffled out", numOfShuffledNodes,
"num of validators after shuffling", numOfValidatorsAfterShuffling,
"auction list size", auctionListSize,
fmt.Sprintf("available slots (%v -%v)", s.maxNodes, numOfValidatorsAfterShuffling), availableSlots,
)

err = s.sortAuctionList(auctionList, randomness)
if err != nil {
return err
}

auctionListSize := uint32(len(auctionList))
numOfAvailableNodeSlots := core.MinUint32(auctionListSize, availableSlots)
s.displayAuctionList(auctionList, numOfAvailableNodeSlots)

Expand All @@ -179,6 +203,14 @@ func (s *systemSCProcessor) selectNodesFromAuctionList(validatorsInfoMap state.S
return nil
}

// TODO: Move this in elrond-go-core
func safeSub(a, b uint32) (uint32, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have this for Uint64

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but I didn't want to cast to uint64, but have a separate function for it. Will move it in elrond-go-core in a separate task

if a < b {
return 0, core.ErrSubtractionOverflow
}
return a - b, nil
}

func getAuctionListAndNumOfValidators(validatorsInfoMap state.ShardValidatorsInfoMapHandler) ([]state.ValidatorInfoHandler, uint32) {
auctionList := make([]state.ValidatorInfoHandler, 0)
numOfValidators := uint32(0)
Expand All @@ -197,11 +229,17 @@ func getAuctionListAndNumOfValidators(validatorsInfoMap state.ShardValidatorsInf
}

func (s *systemSCProcessor) sortAuctionList(auctionList []state.ValidatorInfoHandler, randomness []byte) error {
if len(auctionList) == 0 {
return nil
}

validatorTopUpMap, err := s.getValidatorTopUpMap(auctionList)
if err != nil {
return fmt.Errorf("%w: %v", epochStart.ErrSortAuctionList, err)
}

pubKeyLen := len(auctionList[0].GetPublicKey())
normRandomness := calcNormRand(randomness, pubKeyLen)
sort.SliceStable(auctionList, func(i, j int) bool {
pubKey1 := auctionList[i].GetPublicKey()
pubKey2 := auctionList[j].GetPublicKey()
Expand All @@ -210,7 +248,7 @@ func (s *systemSCProcessor) sortAuctionList(auctionList []state.ValidatorInfoHan
nodeTopUpPubKey2 := validatorTopUpMap[string(pubKey2)]

if nodeTopUpPubKey1.Cmp(nodeTopUpPubKey2) == 0 {
return compareByXORWithRandomness(pubKey1, pubKey2, randomness)
return compareByXORWithRandomness(pubKey1, pubKey2, normRandomness)
}

return nodeTopUpPubKey1.Cmp(nodeTopUpPubKey2) > 0
Expand All @@ -235,13 +273,26 @@ func (s *systemSCProcessor) getValidatorTopUpMap(validators []state.ValidatorInf
return ret, nil
}

func calcNormRand(randomness []byte, expectedLen int) []byte {
rand := randomness
randLen := len(rand)

if expectedLen > randLen {
repeatedCt := expectedLen/randLen + 1
rand = bytes.Repeat(randomness, repeatedCt)
}

rand = rand[:expectedLen]
return rand
}

func compareByXORWithRandomness(pubKey1, pubKey2, randomness []byte) bool {
minLen := core.MinInt(len(pubKey1), len(randomness))
xorLen := len(randomness)

key1Xor := make([]byte, minLen)
key2Xor := make([]byte, minLen)
key1Xor := make([]byte, xorLen)
key2Xor := make([]byte, xorLen)

for idx := 0; idx < minLen; idx++ {
for idx := 0; idx < xorLen; idx++ {
key1Xor[idx] = pubKey1[idx] ^ randomness[idx]
key2Xor[idx] = pubKey2[idx] ^ randomness[idx]
}
Expand Down