-
Notifications
You must be signed in to change notification settings - Fork 11
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
Store information about operators' validator status #37
Conversation
.keys(deps.storage, None, None, Order::Ascending) | ||
.collect::<StdResult<_>>()?; | ||
for op in ops { | ||
let active = validators.iter().any(|val| val.operator == op); |
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.
Not very efficient, but since the validators list is expected to be small, it probably doesn't matter?
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.
Actually, if you'll look at my PR I'm fighting similar inefficiency issue: #35 (comment)
Validators amount may be up to 300, so it doesn't seem much - but this is end block. So every end block there will be loop within loop for X(<=300) validators, and in worst case there will be 3 additional loops from me. :)
I think this starts to add up.
Not necessarily disarding your implementation, just pointing that out.
I still think that all those separate loops (along with calculating validators diff at 562) could be made into more tight implementation - although probably much more complex..
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.
Maybe Mauro can explain more
@@ -532,6 +538,19 @@ fn end_block(deps: DepsMut, env: Env) -> Result<Response, ContractError> { | |||
// calculate and store new validator set | |||
let (validators, auto_unjail) = calculate_validators(deps.as_ref(), &env)?; | |||
|
|||
// update operators list with info about whether or not they're active validators | |||
let ops: Vec<_> = operators() |
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.
This is the beginning of the problem.
the validators set is bounded: (eg 100 or 300) based on config settings.
Operators list is unbounded (anyone can register, this stays forever)... it can be 10.000 easily if people register.
Do not range this
.collect::<StdResult<_>>()?; | ||
for op in ops { | ||
let active = validators.iter().any(|val| val.operator == op); | ||
operators().update::<_, StdError>(deps.storage, &op, |op| { |
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.
You need to use the diff in the active set to do this. We do this somewhere internally inside calculate_validators
and update the weight of each operator.
At that point we can efficiently update the active flag (set it when None -> Some(), unset it when Some() -> None, do nothing for all other cases
Optimized this following Ethan's suggestion (using the diff we already have to update the The CI error seems unrelated - it fails on installing |
e0f4667
to
f6269bd
Compare
Rebased to fix CI problems. |
f6269bd
to
b8b95ad
Compare
@@ -540,7 +546,27 @@ fn end_block(deps: DepsMut, env: Env) -> Result<Response, ContractError> { | |||
let old_validators = VALIDATORS.load(deps.storage)?; | |||
VALIDATORS.save(deps.storage, &validators)?; | |||
// determine the diff to send back to tendermint | |||
let (diff, update_members) = calculate_diff(validators, old_validators); | |||
let (diff, add, remove) = calculate_diff(validators, old_validators); |
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.
Alternatively, you could use diff
directly below, with the convention that zero power means removal.
That way you can keep the calculate_diff
signature the same, and keep rewards the distribution computation internal.
for op in add { | ||
operators().update::<_, StdError>(deps.storage, &Addr::unchecked(op.addr), |op| { | ||
let mut op = op.ok_or_else(|| StdError::generic_err("operator doesn't exist"))?; | ||
op.active_validator = true; | ||
Ok(op) | ||
})?; | ||
} | ||
for op in remove { | ||
operators().update::<_, StdError>(deps.storage, &Addr::unchecked(op), |op| { | ||
let mut op = op.ok_or_else(|| StdError::generic_err("operator doesn't exist"))?; | ||
op.active_validator = false; | ||
Ok(op) | ||
})?; | ||
} |
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.
Looks good. Consider using diff
directly, as mentioned above.
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.
Ah, but you need the operator
key. Makes sense.
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.
The alternative then would be to do this update internally, as part of calculate_diff
. But I think this is good / better for clarity.
Can you rebase from main? And we merge. |
b8b95ad
to
41d7206
Compare
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.
Looks correct and only touches the diff which is much nicer than the first version.
Minor style comment, but nothing blocking merge
@@ -540,7 +546,27 @@ fn end_block(deps: DepsMut, env: Env) -> Result<Response, ContractError> { | |||
let old_validators = VALIDATORS.load(deps.storage)?; | |||
VALIDATORS.save(deps.storage, &validators)?; | |||
// determine the diff to send back to tendermint | |||
let (diff, update_members) = calculate_diff(validators, old_validators); | |||
let (diff, add, remove) = calculate_diff(validators, old_validators); | |||
let update_members = RewardsDistribution::UpdateMembers { |
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.
Hmm... Why not just return this as it was before (same function signature for calculate_diff
) and iterate over
for op in update_members.add
for example? It should avoid a clone even.
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 idea.
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'd end up in this situation:
A function called calculate_diff
actually calculates the rewards distribution msg for use with a specific contract's interface, and then we use that message to get back the diff for another use.
I'd rather make calculate_diff
do what it advertises in the first place. Feels less convoluted.
As for the cloning, I think we'd still end up cloning those strings (Addr::unchecked
does that when it's constructed from a &str
), except they'd be cloned implicitly rather than explicitly. I could be missing something.
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.
Makes sense, i.e. moving the rewards distribution out of calculate_diff
is a good thing:tm:. Let's merge as it is.
Done! |
Store information about operators' validator status
Closes #23
Waiting for confirmation from @alpe that this is what he wanted before moving this out of draft.