Skip to content

Commit

Permalink
Merge pull request #51 from confio/33-valset-limit-active-valset-query-2
Browse files Browse the repository at this point in the history
Validator set query pagination
  • Loading branch information
maurolacy committed Jan 27, 2022
1 parent 52cd173 commit a6979f1
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 16 deletions.
31 changes: 27 additions & 4 deletions contracts/tgrade-valset/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::cmp::max;
use std::cmp::{max, min};
use std::collections::BTreeSet;
use std::convert::TryInto;

Expand Down Expand Up @@ -380,7 +380,11 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result<Binary, ContractErro
start_after,
limit,
)?)?),
ListActiveValidators {} => Ok(to_binary(&list_active_validators(deps, env)?)?),
ListActiveValidators { start_after, limit } => Ok(to_binary(&list_active_validators(
deps,
start_after,
limit,
)?)?),
SimulateActiveValidators {} => Ok(to_binary(&simulate_active_validators(deps, env)?)?),
ListValidatorSlashing { operator } => {
Ok(to_binary(&list_validator_slashing(deps, env, operator)?)?)
Expand Down Expand Up @@ -468,10 +472,28 @@ fn list_validator_keys(

fn list_active_validators(
deps: Deps,
_env: Env,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<ListActiveValidatorsResponse, ContractError> {
let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize;
let start_after = maybe_addr(deps.api, start_after)?;

let validators = VALIDATORS.load(deps.storage)?;
Ok(ListActiveValidatorsResponse { validators })
// Simulate a range query
let mut i = 0;
if let Some(start_after) = start_after {
for v in &validators {
if v.operator == start_after {
i += 1;
break;
}
i += 1;
}
}
let validators = &validators[i..min(i + limit, validators.len())];
Ok(ListActiveValidatorsResponse {
validators: Vec::from(validators),
})
}

fn simulate_active_validators(
Expand Down Expand Up @@ -574,6 +596,7 @@ 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, add, remove) = calculate_diff(validators, old_validators);
Expand Down
6 changes: 4 additions & 2 deletions contracts/tgrade-valset/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,10 @@ pub enum QueryMsg {
},

/// List the current validator set, sorted by power descending
/// (no pagination - reasonable limit from max_validators)
ListActiveValidators {},
ListActiveValidators {
start_after: Option<String>,
limit: Option<u32>,
},

/// This will calculate who the new validators would be if
/// we recalculated end block right now.
Expand Down
50 changes: 48 additions & 2 deletions contracts/tgrade-valset/src/multitest/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ fn initialization() {

// Validators should be set on genesis processing block
assert_active_validators(
&suite.list_active_validators().unwrap(),
&suite.list_active_validators(None, None).unwrap(),
&[(members[2], 5), (members[3], 8)],
);

Expand All @@ -71,6 +71,52 @@ fn initialization() {
}
}

#[test]
fn validators_query_pagination() {
let members = vec!["member1", "member2", "member3", "member4", "member5"];

let suite = SuiteBuilder::new()
.with_engagement(&members_init(&members, &[2, 3, 5, 8, 4]))
.with_operators(&members)
.with_epoch_reward(coin(100, "eth"))
.with_max_validators(10)
.with_min_weight(2)
.with_epoch_length(3600)
.build();

// Query without pagination
assert_active_validators(
&suite.list_active_validators(None, None).unwrap(),
&[
(members[0], 2),
(members[1], 3),
(members[2], 5),
(members[3], 8),
(members[4], 4),
],
);

// List only first 3
let page = suite.list_active_validators(None, 3).unwrap();
assert_active_validators(&page, &[(members[2], 5), (members[3], 8), (members[4], 4)]);

// List 2 entries after 2rd validator
assert_active_validators(
&suite
.list_active_validators(page.last().unwrap().operator.to_string(), 2)
.unwrap(),
&[(members[0], 2), (members[1], 3)],
);

// Starting at unknown validator will return empty query result
assert_active_validators(
&suite
.list_active_validators("unknown_member".to_owned(), None)
.unwrap(),
&[],
);
}

#[test]
fn simulate_validators() {
let members = vec![
Expand All @@ -90,7 +136,7 @@ fn simulate_validators() {
);

assert_active_validators(
&suite.list_active_validators().unwrap(),
&suite.list_active_validators(None, None).unwrap(),
&[(members[4], 13), (members[5], 21)],
);
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/tgrade-valset/src/multitest/jailing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ fn enb_block_ignores_jailed_validators() {
suite.advance_epoch().unwrap();

assert_active_validators(
&suite.list_active_validators().unwrap(),
&suite.list_active_validators(None, None).unwrap(),
&[(members[2], 5), (members[3], 8)],
);
}
Expand Down
4 changes: 2 additions & 2 deletions contracts/tgrade-valset/src/multitest/stake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ fn init_and_query_state() {
);

// no initial active set
let active = suite.list_active_validators().unwrap();
let active = suite.list_active_validators(None, None).unwrap();
assert_eq!(active, vec![]);

// check a validator is set
Expand Down Expand Up @@ -82,7 +82,7 @@ fn simulate_validators() {

// what do we expect?
// 1..24 have pubkeys registered, we take the top 10, but none have stake yet, so zero
let active = suite.list_active_validators().unwrap();
let active = suite.list_active_validators(None, None).unwrap();
assert_eq!(0, active.len());

// One member bonds needed tokens to have enough weight
Expand Down
17 changes: 12 additions & 5 deletions contracts/tgrade-valset/src/multitest/suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -671,11 +671,18 @@ impl Suite {
Ok(resp.validators)
}

pub fn list_active_validators(&self) -> StdResult<Vec<ValidatorInfo>> {
let resp: ListActiveValidatorsResponse = self
.app
.wrap()
.query_wasm_smart(self.valset.clone(), &QueryMsg::ListActiveValidators {})?;
pub fn list_active_validators(
&self,
start_after: impl Into<Option<String>>,
limit: impl Into<Option<u32>>,
) -> StdResult<Vec<ValidatorInfo>> {
let resp: ListActiveValidatorsResponse = self.app.wrap().query_wasm_smart(
self.valset.clone(),
&QueryMsg::ListActiveValidators {
start_after: start_after.into(),
limit: limit.into(),
},
)?;

Ok(resp.validators)
}
Expand Down

0 comments on commit a6979f1

Please sign in to comment.