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

GQL updates for replay v2 #89

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/sui-graphql-client-build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ version = "0.1.0"
edition = "2021"

[dependencies]
cynic-codegen = "3.8.0"
cynic-codegen = "3.7.3"

6 changes: 3 additions & 3 deletions crates/sui-graphql-client/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl Error {
// Private constructors

/// Convert the given error into a generic error.
pub(crate) fn from_error<E: Into<BoxError>>(kind: Kind, error: E) -> Self {
pub fn from_error<E: Into<BoxError>>(kind: Kind, error: E) -> Self {
Self {
inner: Box::new(InnerError {
kind,
Expand All @@ -74,7 +74,7 @@ impl Error {
}

/// Special constructor for queries that expect to return data but it's none.
pub(crate) fn empty_response_error() -> Self {
pub fn empty_response_error() -> Self {
Self {
inner: Box::new(InnerError {
kind: Kind::Query,
Expand All @@ -85,7 +85,7 @@ impl Error {
}

/// Create a Query kind of error with the original graphql errors.
pub(crate) fn graphql_error(errors: Vec<GraphQlError>) -> Self {
pub fn graphql_error(errors: Vec<GraphQlError>) -> Self {
Self {
inner: Box::new(InnerError {
kind: Kind::Query,
Expand Down
84 changes: 76 additions & 8 deletions crates/sui-graphql-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ use query_types::DynamicFieldConnectionArgs;
use query_types::DynamicFieldQuery;
use query_types::DynamicFieldsOwnerQuery;
use query_types::DynamicObjectFieldQuery;
use query_types::EpochSummaryArgs;
use query_types::Epoch;
use query_types::EpochArgs;
use query_types::EpochQuery;
use query_types::EpochSummaryQuery;
use query_types::EventFilter;
use query_types::EventsQuery;
Expand Down Expand Up @@ -110,6 +112,8 @@ use std::str::FromStr;
use crate::error::Kind;
use crate::error::Result;
use crate::query_types::CheckpointTotalTxQuery;
use query_types::EpochsArgs;
use query_types::EpochsQuery;

const DEFAULT_ITEMS_PER_PAGE: i32 = 10;
const MAINNET_HOST: &str = "https://sui-mainnet.mystenlabs.com/graphql";
Expand Down Expand Up @@ -179,8 +183,8 @@ impl<T> Page<T> {
&self.data
}

/// Internal function to create a new page with the provided data and page information.
fn new(page_info: PageInfo, data: Vec<T>) -> Self {
/// Create a new page with the provided data and page information.
pub fn new(page_info: PageInfo, data: Vec<T>) -> Self {
Self { page_info, data }
}

Expand All @@ -189,8 +193,8 @@ impl<T> Page<T> {
self.data.is_empty()
}

/// Internal function to create a page with no data.
fn new_empty() -> Self {
/// Create a page with no data.
pub fn new_empty() -> Self {
Self::new(PageInfo::default(), vec![])
}

Expand Down Expand Up @@ -328,7 +332,7 @@ impl Client {

/// Internal function to handle pagination filters and return the appropriate values.
/// If limit is omitted, it will use the max page size from the service config.
async fn pagination_filter(
pub async fn pagination_filter(
&self,
pagination_filter: PaginationFilter,
) -> (Option<String>, Option<String>, Option<i32>, Option<i32>) {
Expand Down Expand Up @@ -392,7 +396,7 @@ impl Client {
/// This will return `Ok(None)` if the epoch requested is not available in the GraphQL service
/// (e.g., due to pruning).
pub async fn reference_gas_price(&self, epoch: Option<u64>) -> Result<Option<u64>> {
let operation = EpochSummaryQuery::build(EpochSummaryArgs { id: epoch });
let operation = EpochSummaryQuery::build(EpochArgs { id: epoch });
let response = self.run_query(&operation).await?;

if let Some(errors) = response.errors {
Expand Down Expand Up @@ -874,6 +878,52 @@ impl Client {
// Epoch API
// ===========================================================================

/// Return the epoch information for the provided epoch. If no epoch is provided, it will
/// return the last known epoch.
pub async fn epoch(&self, epoch: Option<u64>) -> Result<Option<Epoch>> {
let operation = EpochQuery::build(EpochArgs { id: epoch });
let response = self.run_query(&operation).await?;

if let Some(errors) = response.errors {
return Err(Error::graphql_error(errors));
}

Ok(response.data.and_then(|d| d.epoch))
}

/// Return a page of epochs.
pub async fn epochs(&self, pagination_filter: PaginationFilter) -> Result<Page<Epoch>> {
let (after, before, first, last) = self.pagination_filter(pagination_filter).await;
let operation = EpochsQuery::build(EpochsArgs {
after: after.as_deref(),
before: before.as_deref(),
first,
last,
});
let response = self.run_query(&operation).await?;

if let Some(errors) = response.errors {
return Err(Error::graphql_error(errors));
}

if let Some(epochs) = response.data {
Ok(Page::new(epochs.epochs.page_info, epochs.epochs.nodes))
} else {
Ok(Page::new_empty())
}
}

/// Return a stream of epochs based on the (optional) object filter.
pub async fn epochs_stream(
&self,
streaming_direction: Direction,
) -> impl Stream<Item = Result<Epoch>> + '_ {
stream_paginated_query(
move |pag_filter| self.epochs(pag_filter),
streaming_direction,
)
}

/// Return the number of checkpoints in this epoch. This will return `Ok(None)` if the epoch
/// requested is not available in the GraphQL service (e.g., due to pruning).
pub async fn epoch_total_checkpoints(&self, epoch: Option<u64>) -> Result<Option<u64>> {
Expand Down Expand Up @@ -910,7 +960,7 @@ impl Client {
&self,
epoch: Option<u64>,
) -> Result<GraphQlResponse<EpochSummaryQuery>> {
let operation = EpochSummaryQuery::build(EpochSummaryArgs { id: epoch });
let operation = EpochSummaryQuery::build(EpochArgs { id: epoch });
self.run_query(&operation).await
}

Expand Down Expand Up @@ -1889,6 +1939,24 @@ mod tests {
);
}

#[tokio::test]
async fn test_epoch_query() {
let client = test_client();
let e = client.epoch(None).await;
assert!(
e.is_ok(),
"Epoch query failed for {} network. Error: {}",
client.rpc_server(),
e.unwrap_err()
);

assert!(
e.unwrap().is_some(),
"Epoch query returned None for {} network",
client.rpc_server()
);
}

#[tokio::test]
async fn test_epoch_total_checkpoints_query() {
let client = test_client();
Expand Down
78 changes: 73 additions & 5 deletions crates/sui-graphql-client/src/query_types/epoch.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,60 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0
//
use super::PageInfo;
use crate::query_types::schema;
use crate::query_types::Address;
use crate::query_types::BigInt;
use crate::query_types::DateTime;
use crate::query_types::ProtocolConfigs;

// ===========================================================================
// Epoch Queries
// ===========================================================================
#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "Query", variables = "EpochArgs")]
pub struct EpochQuery {
#[arguments(id: $id)]
pub epoch: Option<Epoch>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "Query", variables = "EpochsArgs")]
pub struct EpochsQuery {
#[arguments(first: $first, after: $after, last: $last, before: $before)]
pub epochs: EpochConnection,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "Query", variables = "EpochSummaryArgs")]
#[cynic(schema = "rpc", graphql_type = "Query", variables = "EpochArgs")]
pub struct EpochSummaryQuery {
#[arguments(id: $id)]
pub epoch: Option<EpochSummary>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "EpochConnection")]
pub struct EpochConnection {
pub nodes: Vec<Epoch>,
pub page_info: PageInfo,
}
// ===========================================================================
// Epoch Summary Args
// ===========================================================================

#[derive(cynic::QueryVariables, Debug)]
pub struct EpochSummaryArgs {
pub struct EpochArgs {
pub id: Option<u64>,
}

#[derive(cynic::QueryVariables, Debug)]
pub struct EpochsArgs<'a> {
pub first: Option<i32>,
pub after: Option<&'a str>,
pub last: Option<i32>,
pub before: Option<&'a str>,
}

/// A summary of the epoch.
#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "Epoch")]
Expand All @@ -44,38 +73,77 @@ pub struct EpochSummary {
// Epoch Types
// ===========================================================================

#[derive(cynic::QueryFragment, Debug)]
#[derive(cynic::QueryFragment, Debug, Clone)]
#[cynic(schema = "rpc", graphql_type = "Epoch")]
pub struct Epoch {
pub end_timestamp: Option<DateTime>,
/// The epoch's id as a sequence number that starts at 0 and is incremented by one at every epoch change.
pub epoch_id: u64,
/// The storage fees paid for transactions executed during the epoch.
pub fund_inflow: Option<BigInt>,
/// The storage fee rebates paid to users who deleted the data associated with past
/// transactions.
pub fund_outflow: Option<BigInt>,
/// The storage fund available in this epoch.
/// This fund is used to redistribute storage fees from past transactions
/// to future validators.
pub fund_size: Option<BigInt>,
/// A commitment by the committee at the end of epoch on the contents of the live object set at
/// that time. This can be used to verify state snapshots.
pub live_object_set_digest: Option<String>,
/// The difference between the fund inflow and outflow, representing
/// the net amount of storage fees accumulated in this epoch.
pub net_inflow: Option<BigInt>,
/// The epoch's corresponding protocol configuration, including the feature flags and the
/// configuration options.
pub protocol_configs: Option<ProtocolConfigs>,
/// The minimum gas price that a quorum of validators are guaranteed to sign a transaction for.
pub reference_gas_price: Option<BigInt>,
/// The epoch's starting timestamp.
pub start_timestamp: DateTime,
/// The epoch's ending timestamp. Note that this is available only on epochs that have ended.
pub end_timestamp: Option<DateTime>,
/// The value of the `version` field of `0x5`, the `0x3::sui::SuiSystemState` object. This
/// version changes whenever the fields contained in the system state object (held in a dynamic
/// field attached to `0x5`) change.
pub system_state_version: Option<u64>,
/// The total number of checkpoints in this epoch.
pub total_checkpoints: Option<u64>,
/// The total amount of gas fees (in MIST) that were paid in this epoch.
pub total_gas_fees: Option<BigInt>,
/// The total MIST rewarded as stake.
pub total_stake_rewards: Option<BigInt>,
/// The amount added to total gas fees to make up the total stake rewards.
pub total_stake_subsidies: Option<BigInt>,
/// The total number of transaction in this epoch.
pub total_transactions: Option<u64>,
/// Validator related properties. For active validators, see [`active_validators`] API.
pub validator_set: Option<ValidatorSet>,
}

#[derive(cynic::QueryFragment, Debug)]
#[derive(cynic::QueryFragment, Debug, Clone)]
#[cynic(schema = "rpc", graphql_type = "ValidatorSet")]
pub struct ValidatorSet {
/// Object ID of the `Table` storing the inactive staking pools.
pub inactive_pools_id: Option<Address>,
/// Size of the inactive pools `Table`.
pub inactive_pools_size: Option<i32>,
/// Object ID of the wrapped object `TableVec` storing the pending active validators.
pub pending_active_validators_id: Option<Address>,
/// Size of the pending active validators table.
pub pending_active_validators_size: Option<i32>,
/// Validators that are pending removal from the active validator set, expressed as indices in
/// to `activeValidators`.
pub pending_removals: Option<Vec<i32>>,
/// Object ID of the `Table` storing the mapping from staking pool ids to the addresses
/// of the corresponding validators. This is needed because a validator's address
/// can potentially change but the object ID of its pool will not.
pub staking_pool_mappings_id: Option<Address>,
/// Size of the stake pool mappings `Table`.
pub staking_pool_mappings_size: Option<i32>,
/// Total amount of stake for all active validators at the beginning of the epoch.
pub total_stake: Option<BigInt>,
/// Size of the validator candidates `Table`.
pub validator_candidates_size: Option<i32>,
/// Object ID of the `Table` storing the validator candidates.
pub validator_candidates_id: Option<Address>,
}
6 changes: 5 additions & 1 deletion crates/sui-graphql-client/src/query_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,11 @@ pub use dynamic_fields::DynamicFieldQuery;
pub use dynamic_fields::DynamicFieldsOwnerQuery;
pub use dynamic_fields::DynamicObjectFieldQuery;
pub use epoch::Epoch;
pub use epoch::EpochSummaryArgs;
pub use epoch::EpochArgs;
pub use epoch::EpochQuery;
pub use epoch::EpochSummaryQuery;
pub use epoch::EpochsArgs;
pub use epoch::EpochsQuery;
pub use events::Event;
pub use events::EventConnection;
pub use events::EventFilter;
Expand All @@ -78,6 +81,7 @@ pub use object::ObjectsQuery;
pub use object::ObjectsQueryArgs;
pub use packages::LatestPackageQuery;
pub use packages::MovePackage;
pub use packages::MovePackageConnection;
pub use packages::MovePackageVersionFilter;
pub use packages::PackageArgs;
pub use packages::PackageByNameArgs;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub struct ProtocolVersionArgs {
/// Information about the configuration of the protocol.
/// Constants that control how the chain operates.
/// These can only change during protocol upgrades which happen on epoch boundaries.
#[derive(cynic::QueryFragment, Debug)]
#[derive(cynic::QueryFragment, Clone, Debug)]
#[cynic(schema = "rpc", graphql_type = "ProtocolConfigs")]
pub struct ProtocolConfigs {
/// The protocol is not required to change on every epoch boundary, so the protocol version
Expand All @@ -51,15 +51,15 @@ pub struct ProtocolConfigs {

/// Feature flags are a form of boolean configuration that are usually used to gate features while
/// they are in development. Once a lag has been enabled, it is rare for it to be disabled.
#[derive(cynic::QueryFragment, Debug)]
#[derive(cynic::QueryFragment, Clone, Debug)]
#[cynic(schema = "rpc", graphql_type = "ProtocolConfigFeatureFlag")]
pub struct ProtocolConfigFeatureFlag {
pub key: String,
pub value: bool,
}

/// A key-value protocol configuration attribute.
#[derive(cynic::QueryFragment, Debug)]
#[derive(cynic::QueryFragment, Clone, Debug)]
#[cynic(schema = "rpc", graphql_type = "ProtocolConfigAttr")]
pub struct ProtocolConfigAttr {
pub key: String,
Expand Down
1 change: 1 addition & 0 deletions crates/sui-graphql-client/src/query_types/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub struct TransactionBlocksQueryArgs<'a> {
#[cynic(schema = "rpc", graphql_type = "TransactionBlock")]
pub struct TransactionBlock {
pub bcs: Option<Base64>,
pub effects: Option<TransactionBlockEffects>,
pub signatures: Option<Vec<Base64>>,
}

Expand Down
Loading