Skip to content

Commit 380e4b1

Browse files
guidiazaesedepece
authored andcommitted
feat(json_rpc): improve queryStakes optional params: distinct, limit, offset, since, order
1 parent 1a37310 commit 380e4b1

File tree

4 files changed

+174
-58
lines changed

4 files changed

+174
-58
lines changed

node/src/actors/chain_manager/handlers.rs

Lines changed: 94 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ use crate::{
4646
GetMemoryTransaction, GetMempool, GetMempoolResult, GetNodeStats, GetProtocolInfo,
4747
GetReputation, GetReputationResult, GetSignalingInfo, GetState, GetSuperBlockVotes,
4848
GetSupplyInfo, GetSupplyInfo2, GetUtxoInfo, IsConfirmedBlock, PeersBeacons,
49-
QueryStakePowers, QueryStakes, QueryStakesFilter, ReputationStats, Rewind,
49+
QueryStakePowers, QueryStakes, QueryStakesOrderByOptions, ReputationStats, Rewind,
5050
SendLastBeacon, SessionUnitResult, SetLastBeacon, SetPeersLimits, SignalingInfo,
5151
SnapshotExport, SnapshotImport, TryMineBlock,
5252
},
@@ -1543,39 +1543,112 @@ impl Handler<QueryStakes> for ChainManager {
15431543
type Result = <QueryStakes as Message>::Result;
15441544

15451545
fn handle(&mut self, msg: QueryStakes, _ctx: &mut Self::Context) -> Self::Result {
1546-
// query stakes from current chain state
1546+
let filter = msg.filter.unwrap_or_default();
1547+
let params = msg.params.unwrap_or_default();
1548+
let since = params.since.unwrap_or_default();
1549+
let order = params.order.unwrap_or_default();
1550+
let order_desc = order.reverse.unwrap_or_default();
1551+
let distinct = params.distinct.unwrap_or_default();
1552+
let offset = params.offset.unwrap_or_default();
1553+
let limit = params.limit.unwrap_or(u16::MAX) as usize;
1554+
1555+
// fetch filtered stake entries from current chain state:
15471556
let mut stakes = self
15481557
.chain_state
15491558
.stakes
1550-
.query_stakes(msg.filter)
1559+
.query_stakes(filter.clone())
15511560
.map_err(StakesError::from)?;
1552-
// filter out stake entries whose last mining and witnessing epochs are previous to `epoch`
1553-
let epoch: u32 = if msg.limits.since >= 0 {
1554-
msg.limits.since.try_into().inspect_err(|&e| {
1561+
1562+
// filter out stake entries having a nonce, last mining or witnessing epochs (depending
1563+
// on actual ordering field) older than calculated `since_epoch`:
1564+
let since_epoch: u64 = if since >= 0 {
1565+
since.try_into().inspect_err(|&e| {
15551566
log::warn!("Invalid 'since' limit on QueryStakes: {}", e);
15561567
})?
15571568
} else {
1558-
(self.current_epoch.unwrap() as i64 + msg.limits.since)
1569+
(self.current_epoch.unwrap() as i64 + since)
15591570
.try_into()
15601571
.unwrap_or_default()
15611572
};
1562-
stakes.retain(|stake| {
1563-
let nonce: u32 = stake.value.nonce.try_into().unwrap_or_default();
1564-
stake.value.epochs.mining >= epoch && stake.value.epochs.mining != nonce
1565-
|| (stake.value.epochs.witnessing >= epoch
1566-
&& stake.value.epochs.witnessing != nonce)
1567-
});
1568-
if msg.limits.distinct {
1569-
// if only distinct validators are required, retain only first appearence in the stakes array:
1570-
let stakes = stakes
1573+
if since_epoch > 0 {
1574+
match order.by {
1575+
QueryStakesOrderByOptions::Coins | QueryStakesOrderByOptions::Nonce => {
1576+
stakes.retain(|stake| stake.value.nonce >= since_epoch);
1577+
}
1578+
QueryStakesOrderByOptions::Mining => {
1579+
stakes.retain(|stake| {
1580+
stake.value.epochs.mining as u64 >= since_epoch
1581+
&& stake.value.epochs.mining as u64 >= stake.value.nonce
1582+
});
1583+
}
1584+
QueryStakesOrderByOptions::Witnessing => {
1585+
stakes.retain(|stake| {
1586+
stake.value.epochs.witnessing as u64 >= since_epoch
1587+
&& stake.value.epochs.witnessing as u64 >= stake.value.nonce
1588+
});
1589+
}
1590+
}
1591+
}
1592+
1593+
// sort stake entries by specified field, worst case costing n * log (n) ...
1594+
match order.by {
1595+
QueryStakesOrderByOptions::Coins => {
1596+
stakes.sort_by(|a, b| {
1597+
if order_desc {
1598+
b.value.coins.cmp(&a.value.coins)
1599+
} else {
1600+
a.value.coins.cmp(&b.value.coins)
1601+
}
1602+
});
1603+
}
1604+
QueryStakesOrderByOptions::Nonce => {
1605+
stakes.sort_by(|a, b| {
1606+
if order_desc {
1607+
b.value.nonce.cmp(&a.value.nonce)
1608+
} else {
1609+
a.value.nonce.cmp(&b.value.nonce)
1610+
}
1611+
});
1612+
}
1613+
QueryStakesOrderByOptions::Mining => {
1614+
stakes.sort_by(|a, b| {
1615+
if order_desc {
1616+
b.value.epochs.mining.cmp(&a.value.epochs.mining)
1617+
} else {
1618+
a.value.epochs.mining.cmp(&b.value.epochs.mining)
1619+
}
1620+
});
1621+
}
1622+
QueryStakesOrderByOptions::Witnessing => {
1623+
stakes.sort_by(|a, b| {
1624+
if order_desc {
1625+
b.value.epochs.witnessing.cmp(&a.value.epochs.witnessing)
1626+
} else {
1627+
a.value.epochs.witnessing.cmp(&b.value.epochs.witnessing)
1628+
}
1629+
});
1630+
}
1631+
}
1632+
1633+
// if `distinct` is required, retain first appearence per validator:
1634+
let stakes = if distinct {
1635+
stakes
15711636
.into_iter()
15721637
.unique_by(|stake| stake.key.validator)
1573-
.collect();
1574-
1575-
Ok(stakes)
1638+
.collect()
15761639
} else {
1577-
Ok(stakes)
1578-
}
1640+
stakes
1641+
};
1642+
1643+
log::info!(
1644+
"queryStakes => found {} entries after filter {:?} w/ params {:?}",
1645+
stakes.len(),
1646+
filter,
1647+
params,
1648+
);
1649+
1650+
// applies `offset`, if any, and limits number of returned records to `limit``
1651+
Ok(stakes.into_iter().skip(offset).take(limit).collect())
15791652
}
15801653
}
15811654

node/src/actors/json_rpc/api.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1471,7 +1471,9 @@ pub async fn get_balance(params: Params) -> JsonRpcResult {
14711471
};
14721472

14731473
if target == GetBalanceTarget::Own {
1474-
return Err(Error::invalid_params("Providing server's balance is not allowed"));
1474+
return Err(Error::invalid_params(
1475+
"Providing server's balance is not allowed",
1476+
));
14751477
};
14761478

14771479
let chain_manager_addr = ChainManager::from_registry();

node/src/actors/messages.rs

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -357,35 +357,83 @@ impl Message for QueryStakePowers {
357357
}
358358

359359
/// Stake key for quering stakes
360-
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
361-
#[derive(Default)]
360+
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, Default)]
362361
pub struct QueryStakesFilter {
363362
/// To search by the validator public key hash
364363
pub validator: Option<MagicEither<String, PublicKeyHash>>,
365364
/// To search by the withdrawer public key hash
366365
pub withdrawer: Option<MagicEither<String, PublicKeyHash>>,
367366
}
368367

369-
370368
/// Limits when querying stake entries
371-
#[derive(Clone, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
369+
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
372370
#[serde(rename_all = "camelCase")]
373-
#[derive(Default)]
374-
pub struct QueryStakesLimits {
375-
/// Retrieve only first appearence for every distinct validator
376-
pub distinct: bool,
377-
/// Either absolute or relative epoch (negative values) when stake entries were last modified
378-
pub since: i64,
371+
pub struct QueryStakesParams {
372+
/// Retrieve only first appearence for every distinct validator (default: false)
373+
pub distinct: Option<bool>,
374+
/// Limits max number of entries to return (default: 0 == u16::MAX)
375+
pub limit: Option<u16>,
376+
/// Skips first found entries (default: 0)
377+
pub offset: Option<usize>,
378+
/// Order by specified stake entry field (default: reverse order by coins)
379+
pub order: Option<QueryStakesOrderBy>,
380+
/// Select entries having either the nonce, last mining or last witnessing epoch,
381+
/// greater than specified absolute epoch, or relative epoch if negative (default: 0)
382+
pub since: Option<i64>,
383+
}
384+
385+
impl Default for QueryStakesParams {
386+
fn default() -> Self {
387+
QueryStakesParams {
388+
distinct: Some(false),
389+
limit: Some(u16::MAX),
390+
offset: Some(0),
391+
order: Some(QueryStakesOrderBy::default()),
392+
since: Some(0),
393+
}
394+
}
395+
}
396+
397+
/// Order by parameter for QueryStakes
398+
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
399+
#[serde(rename_all = "lowercase")]
400+
pub struct QueryStakesOrderBy {
401+
/// Data field to order by
402+
pub by: QueryStakesOrderByOptions,
403+
/// Reverse order (default: false)
404+
pub reverse: Option<bool>,
405+
}
406+
407+
impl Default for QueryStakesOrderBy {
408+
fn default() -> Self {
409+
QueryStakesOrderBy {
410+
by: QueryStakesOrderByOptions::Coins,
411+
reverse: Some(true),
412+
}
413+
}
379414
}
380415

416+
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
417+
#[serde(rename_all = "lowercase")]
418+
/// Ordering options for QueryStakes
419+
pub enum QueryStakesOrderByOptions {
420+
/// Order by stake entry coins
421+
Coins = 0,
422+
/// Order by stake entry nonce
423+
Nonce = 1,
424+
/// Order by last validation epoch
425+
Mining = 2,
426+
/// Order by last witnessing epoch
427+
Witnessing = 3,
428+
}
381429

382430
/// Message for querying stakes
383431
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
384432
pub struct QueryStakes {
385433
/// query's where clause
386-
pub filter: QueryStakesFilter,
434+
pub filter: Option<QueryStakesFilter>,
387435
/// query's limit params
388-
pub limits: QueryStakesLimits,
436+
pub params: Option<QueryStakesParams>,
389437
}
390438

391439
impl Message for QueryStakes {
@@ -403,21 +451,17 @@ where
403451

404452
fn try_from(filter: QueryStakesFilter) -> Result<Self, Self::Error> {
405453
Ok(match (filter.validator, filter.withdrawer) {
406-
(Some(validator), Some(withdrawer)) => {
407-
QueryStakesKey::Key(StakeKey {
408-
validator: try_do_magic_into_pkh(validator)?.into(),
409-
withdrawer: try_do_magic_into_pkh(withdrawer)?.into(),
410-
})
411-
},
454+
(Some(validator), Some(withdrawer)) => QueryStakesKey::Key(StakeKey {
455+
validator: try_do_magic_into_pkh(validator)?.into(),
456+
withdrawer: try_do_magic_into_pkh(withdrawer)?.into(),
457+
}),
412458
(Some(validator), None) => {
413459
QueryStakesKey::Validator(try_do_magic_into_pkh(validator)?.into())
414-
},
460+
}
415461
(None, Some(withdrawer)) => {
416462
QueryStakesKey::Withdrawer(try_do_magic_into_pkh(withdrawer)?.into())
417-
},
418-
(None, None) => {
419-
QueryStakesKey::All
420-
},
463+
}
464+
(None, None) => QueryStakesKey::All,
421465
})
422466
}
423467
}

src/cli/node/json_rpc_client.rs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ use witnet_node::actors::{
5656
messages::{
5757
AuthorizeStake, BuildDrt, BuildStakeParams, BuildStakeResponse, BuildUnstakeParams,
5858
BuildVtt, GetBalanceTarget, GetReputationResult, MagicEither, QueryStakes,
59-
QueryStakesFilter, QueryStakesLimits, SignalingInfo, StakeAuthorization,
59+
QueryStakesFilter, SignalingInfo, StakeAuthorization,
6060
},
6161
};
6262
use witnet_rad::types::RadonTypes;
@@ -1957,26 +1957,23 @@ pub fn query_stakes(
19571957
let mut stream = start_client(addr)?;
19581958
let params = QueryStakes {
19591959
filter: match (validator, withdrawer) {
1960-
(Some(validator), Some(withdrawer)) => QueryStakesFilter {
1960+
(Some(validator), Some(withdrawer)) => Some(QueryStakesFilter {
19611961
validator: Some(MagicEither::Left(validator)),
19621962
withdrawer: Some(MagicEither::Left(withdrawer)),
1963-
},
1964-
(Some(validator), None) => QueryStakesFilter {
1963+
}),
1964+
(Some(validator), None) => Some(QueryStakesFilter {
19651965
validator: Some(MagicEither::Left(validator)),
19661966
withdrawer: None,
1967-
},
1968-
(None, Some(withdrawer)) => QueryStakesFilter {
1967+
}),
1968+
(None, Some(withdrawer)) => Some(QueryStakesFilter {
19691969
validator: None,
19701970
withdrawer: Some(MagicEither::Left(withdrawer)),
1971-
},
1972-
(None, None) => QueryStakesFilter {
1973-
validator: None,
1974-
withdrawer: None,
1975-
},
1971+
}),
1972+
(None, None) => None,
19761973
},
1977-
limits: QueryStakesLimits::default(),
1974+
params: None,
19781975
};
1979-
1976+
19801977
let response = send_request(
19811978
&mut stream,
19821979
&format!(

0 commit comments

Comments
 (0)