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
Filter auction nodes list #3822
Filter auction nodes list #3822
Conversation
…N-11662-filter-new-nodes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job! 👍
Some findings that will improve performance
@@ -191,6 +191,9 @@ | |||
# all nodes from staking queue are moved in the auction list | |||
StakingV4InitEnableEpoch = 4 | |||
|
|||
# StakingV4EnableEpoch represents the epoch when staking v4 is enabled. Should have a greater value than StakingV4InitEnableEpoch | |||
StakingV4EnableEpoch = 5 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so this should always be StakingV4InitEnableEpoch + 1? What happens if we wrongly configure this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Theoretically, code should not panic or anything. If EnableEpoch < InitEpoch => auction list will be empty => no sorting/selection will be made.
Logic-wise, if they are inverted it shouldn't cause any bugs for NOW. I'm not sure how the implementation on nodes coordinator
side will look like to give an educated opinion. Depending how it will be designed, it might cause some bugs
epochStart/metachain/systemSCs.go
Outdated
@@ -214,6 +220,7 @@ func (s *systemSCProcessor) ProcessSystemSmartContract( | |||
validatorInfos map[uint32][]*state.ValidatorInfo, | |||
nonce uint64, | |||
epoch uint32, | |||
randomness []byte, | |||
) error { | |||
if s.flagHystNodesEnabled.IsSet() { | |||
err := s.updateSystemSCConfigMinNodes() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need a sort of refactor here - like adding a separate function with old / inactive flags - all those things which were once activated on the mainnet. That we we make it easier to read this function. like flagHystNodes, flagSetOwner, flagChangeMaxNodes, flagCorrectlastUnJailed, flagDelegationEnabled, flagCorrectNumNodesToStake
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those are called only once - so you could add flagESDTEnabled there. Move to new activation function which are not yet enabled, like flagGovernance, flagBuiltInOnMetachain, flagStakingV4Init
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Decided to split them in 2 functions with pretty "trivial" names:
checkOldFlags
(which contains: flagHystNodes, flagSetOwner,...)checkNewFlags
(which contains flagGovernance, flagStakingV4Init,...)
process/block/metablock.go
Outdated
@@ -403,7 +403,7 @@ func (mp *metaProcessor) processEpochStartMetaBlock( | |||
} | |||
|
|||
if mp.isRewardsV2Enabled(header) { | |||
err = mp.epochSystemSCProcessor.ProcessSystemSmartContract(allValidatorsInfo, header.Nonce, header.Epoch) | |||
err = mp.epochSystemSCProcessor.ProcessSystemSmartContract(allValidatorsInfo, header.Nonce, header.Epoch, header.GetPrevRandSeed()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it would be better to send the whole header. instead of 3 arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably in this case would be better; since maybe in the future we might need additional data from header;
Will refactor it
epochStart/metachain/systemSCs.go
Outdated
} | ||
|
||
auctionListSize := uint32(len(auctionList)) | ||
numOfAvailableNodeSlots := core.MinUint32(auctionListSize, s.maxNodes-numOfValidators) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make a check on numValidators < s.maxNodes -> return -> do not do anything - it means there are not enough nodes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still add the sanity check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added sanity check as an early exit point
epochStart/metachain/systemSCs.go
Outdated
return compareByXORWithRandomness(pubKey1, pubKey2, randomness) | ||
} | ||
|
||
return nodeTopUpPubKey1.Cmp(nodeTopUpPubKey2) == 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
0 instead of == 1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why 0
?
We want to compare which node has the highest top up. Cmp
documentation says:
// Cmp compares x and y and returns:
//
// -1 if x < y
// 0 if x == y
// +1 if x > y
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use bigger than 0. like ">0"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed it to >0
epochStart/metachain/systemSCs.go
Outdated
s.displayAuctionList(auctionList, numOfAvailableNodeSlots) | ||
|
||
for i := uint32(0); i < numOfAvailableNodeSlots; i++ { | ||
auctionList[i].List = string(common.NewList) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to somewhat rewrite the map[uint32][]*state.ValidatorInfo - like use an interface and set new values there. It is ok for now - but it is super easy to make a mistake - modifying a value under a wrong pointer - hard to catch. Add a task for this rework.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, current implementation it is pretty prone to errors; however I'm not sure how this interface might look like -> seems a bit of overhead; will add a TODO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add Jira task as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will add task in Jira as well
|
||
for _, validator := range validators { | ||
pubKey := validator.PublicKey | ||
topUp, err := s.stakingDataProvider.GetNodeStakedTopUp(pubKey) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
discussion is needed here in order to see if we want the following: one entity might register 10 nodes with 3000eGLD, meaning 500 topup per node. but if the topUp limit is at 2500 - that entity might have 5 nodes which enter and 5 which will not. However the first auction system was designed like that - selecting the most possible for an account. So add a task for this - let's discuss and it should be another task if we decide that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will leave this topic open and create a new Jira task
epochStart/metachain/systemSCs.go
Outdated
validatorsInfoMap map[uint32][]*state.ValidatorInfo, | ||
header data.HeaderHandler, | ||
) error { | ||
err := s.checkOldFlags(validatorsInfoMap, header.GetNonce(), header.GetEpoch()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename processingWithOldFlags
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed it
epochStart/metachain/systemSCs.go
Outdated
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
if s.flagStakingV2Enabled.IsSet() { | ||
err := s.prepareRewardsData(validatorInfos) | ||
numUnStaked, err := s.prepareStakingAndUnStakeNodesWithNotEnoughFunds(validatorsInfoMap, epoch) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please leave functions as it was.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and make completely new functions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored this code
epochStart/metachain/systemSCs.go
Outdated
return err | ||
func (s *systemSCProcessor) prepareStakingData(validatorsInfoMap map[uint32][]*state.ValidatorInfo) error { | ||
nodes := make(map[uint32][][]byte) | ||
if s.flagStakingV2Enabled.IsSet() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no 2 flags on the same function. it is better to have duplicated code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored it so we don't have 2 flags
epochStart/metachain/systemSCs.go
Outdated
if err != nil { | ||
return err | ||
} | ||
|
||
numUnStaked, err := s.unStakeNodesWithNotEnoughFunds(validatorInfos, epoch) | ||
err = s.stakeNodesFromQueue(validatorsInfoMap, numUnStaked, nonce, common.NewList) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
flag is missing here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stakeNodesFromQueue (numUnstaked) is missing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, forgot about the flag, added it;
stakeNodesFromQueue
is called on L301
epochStart/metachain/systemSCs.go
Outdated
if err != nil { | ||
return err | ||
} | ||
|
||
err = s.fillStakingDataForNonEligible(validatorInfos) | ||
numUnStaked, err := s.unStakeNonEligibleNodes(validatorsInfoMap, epoch) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add "withNotEnoughFunds"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed it to unStakeNonEligibleNodesWithNotEnoughFunds
validatorsInfoMap map[uint32][]*state.ValidatorInfo, | ||
header data.HeaderHandler, | ||
) error { | ||
err := s.processWithOldFlags(validatorsInfoMap, header.GetNonce(), header.GetEpoch()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does "new" and "old" mean? They are so relative based on the epoch flags.
This just became a hard to comprehend function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
according to my last comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code separation in a different PR
Staking v4 nodes filtering
auction list
will be sorted based on their top up per node. If >= 2 bls keys have the same top up, they will be sorted based on XOR with previous block rand seed. The number of available node slots will be computed and only the first nodes in the sorted auction list will fill these slots.new list
(to be further used by nodes coordinator to select them as eligible), e.g. from an auction of 5 bls keys, only 3 will be selected (pubKey2
,pubKey9
,pubKey4
):Refactor
stakingDataProvider.go
, refactoredGetBlsKeyOwner
to be an exported funcsystemSCs_test
refactored test funcs which added validator data and staking data, so that we can easily register an owner and its staked bls keys and top up per nodeProcessSystemSmartContract
fromEpochStartSystemSCProcessor
interface to accept an extra param:randomness []byte
for sorting bls keys