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

Store information about operators' validator status #37

Merged
merged 4 commits into from
Jan 27, 2022

Conversation

uint
Copy link
Contributor

@uint uint commented Jan 25, 2022

Closes #23

Waiting for confirmation from @alpe that this is what he wanted before moving this out of draft.

.keys(deps.storage, None, None, Order::Ascending)
.collect::<StdResult<_>>()?;
for op in ops {
let active = validators.iter().any(|val| val.operator == op);
Copy link
Contributor Author

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?

Copy link

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..

Copy link
Contributor

@ethanfrey ethanfrey left a 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()
Copy link
Contributor

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| {
Copy link
Contributor

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

@uint uint requested a review from ueco-jb January 26, 2022 17:38
@uint uint marked this pull request as ready for review January 26, 2022 17:38
@uint uint requested a review from ethanfrey January 26, 2022 17:38
@uint
Copy link
Contributor Author

uint commented Jan 26, 2022

Optimized this following Ethan's suggestion (using the diff we already have to update the active_validator flags).

The CI error seems unrelated - it fails on installing cosmwasm_vm check_contract.

@uint
Copy link
Contributor Author

uint commented Jan 27, 2022

Rebased to fix CI problems.

@@ -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);
Copy link
Contributor

@maurolacy maurolacy Jan 27, 2022

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.

Comment on lines +556 to +599
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)
})?;
}
Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor

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.

@maurolacy
Copy link
Contributor

Can you rebase from main? And we merge.

Copy link
Contributor

@ethanfrey ethanfrey left a 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 {
Copy link
Contributor

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.

Copy link
Contributor

Choose a reason for hiding this comment

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

Good idea.

Copy link
Contributor Author

@uint uint Jan 27, 2022

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.

Copy link
Contributor

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.

@uint
Copy link
Contributor Author

uint commented Jan 27, 2022

Can you rebase from main? And we merge.

Done!

@maurolacy maurolacy merged commit 05e0c1d into main Jan 27, 2022
@maurolacy maurolacy deleted the 23-validator-status branch January 27, 2022 12:57
maurolacy added a commit that referenced this pull request Jan 27, 2022
Store information about operators' validator status
@uint uint added breaking Breaking changes (API or State) breaking-state Storage breaking: Requires migration labels Feb 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking Breaking changes (API or State) breaking-state Storage breaking: Requires migration
Projects
None yet
Development

Successfully merging this pull request may close these issues.

valset: mark "active" validators in ValidatorInfo
4 participants