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

Add package queries #33

Open
wants to merge 6 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
263 changes: 263 additions & 0 deletions crates/sui-graphql-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,22 @@ use query_types::EventsQuery;
use query_types::EventsQueryArgs;
use query_types::ExecuteTransactionArgs;
use query_types::ExecuteTransactionQuery;
use query_types::LatestPackageQuery;
use query_types::MovePackageVersionFilter;
use query_types::ObjectFilter;
use query_types::ObjectQuery;
use query_types::ObjectQueryArgs;
use query_types::ObjectsQuery;
use query_types::ObjectsQueryArgs;
use query_types::PackageArgs;
use query_types::PackageByNameArgs;
use query_types::PackageByNameQuery;
use query_types::PackageCheckpointFilter;
use query_types::PackageQuery;
use query_types::PackageVersionsArgs;
use query_types::PackageVersionsQuery;
use query_types::PackagesQuery;
use query_types::PackagesQueryArgs;
use query_types::PageInfo;
use query_types::ProtocolConfigQuery;
use query_types::ProtocolConfigs;
Expand All @@ -51,6 +62,7 @@ use sui_types::types::Address;
use sui_types::types::CheckpointSequenceNumber;
use sui_types::types::CheckpointSummary;
use sui_types::types::Event;
use sui_types::types::MovePackage;
use sui_types::types::Object;
use sui_types::types::SignedTransaction;
use sui_types::types::Transaction;
Expand Down Expand Up @@ -708,6 +720,215 @@ impl Client {
}
}

// ===========================================================================
// Package API
// ===========================================================================

/// The package corresponding to the given address (at the optionally given version).
/// When no version is given, the package is loaded directly from the address given. Otherwise,
/// the address is translated before loading to point to the package whose original ID matches
/// the package at address, but whose version is version. For non-system packages, this
/// might result in a different address than address because different versions of a package,
/// introduced by upgrades, exist at distinct addresses.
///
/// Note that this interpretation of version is different from a historical object read (the
/// interpretation of version for the object query).
pub async fn package(
&self,
address: Address,
version: Option<u64>,
) -> Result<Option<MovePackage>, Error> {
let operation = PackageQuery::build(PackageArgs { address, version });

let response = self.run_query(&operation).await?;

if let Some(errors) = response.errors {
return Err(Error::msg(format!("{:?}", errors)));
}

let pkg = response
.data
.and_then(|x| x.package)
.and_then(|x| x.package_bcs)
.map(|bcs| base64ct::Base64::decode_vec(bcs.0.as_str()))
.transpose()
.map_err(|e| Error::msg(format!("Cannot decode Base64 package bcs bytes: {e}")))?
.map(|bcs| bcs::from_bytes::<MovePackage>(&bcs))
.transpose()
.map_err(|e| Error::msg(format!("Cannot decode bcs bytes into MovePackage: {e}")))?;

Ok(pkg)
}

/// Fetch all versions of package at address (packages that share this package's original ID),
/// optionally bounding the versions exclusively from below with afterVersion, or from above
/// with beforeVersion.
#[allow(clippy::too_many_arguments)]
pub async fn package_versions(
&self,
address: Address,
after: Option<&str>,
before: Option<&str>,
first: Option<i32>,
last: Option<i32>,
after_version: Option<u64>,
before_version: Option<u64>,
) -> Result<Option<Page<MovePackage>>, Error> {
let operation = PackageVersionsQuery::build(PackageVersionsArgs {
address,
after,
before,
first,
last,
filter: Some(MovePackageVersionFilter {
after_version,
before_version,
}),
});

let response = self.run_query(&operation).await?;

if let Some(errors) = response.errors {
return Err(Error::msg(format!("{:?}", errors)));
}

if let Some(packages) = response.data {
let pc = packages.package_versions;
let page_info = pc.page_info;
let bcs = pc
.nodes
.iter()
.map(|p| &p.package_bcs)
.filter_map(|b64| {
b64.as_ref()
.map(|b| base64ct::Base64::decode_vec(b.0.as_str()))
})
.collect::<Result<Vec<_>, base64ct::Error>>()
.map_err(|e| Error::msg(format!("Cannot decode Base64 package bcs bytes: {e}")))?;
let packages = bcs
.iter()
.map(|b| bcs::from_bytes::<MovePackage>(b))
.collect::<Result<Vec<_>, bcs::Error>>()
.map_err(|e| {
Error::msg(format!("Cannot decode bcs bytes into MovePackage: {e}"))
})?;

Ok(Some(Page::new(page_info, packages)))
} else {
Ok(None)
}
}

/// Fetch the latest version of the package at address.
/// This corresponds to the package with the highest version that shares its original ID with
/// the package at address.
pub async fn package_latest(&self, address: Address) -> Result<Option<MovePackage>, Error> {
let operation = LatestPackageQuery::build(PackageArgs {
address,
version: None,
});

let response = self.run_query(&operation).await?;

if let Some(errors) = response.errors {
return Err(Error::msg(format!("{:?}", errors)));
}

let pkg = response
.data
.and_then(|x| x.latest_package)
.and_then(|x| x.package_bcs)
.map(|bcs| base64ct::Base64::decode_vec(bcs.0.as_str()))
.transpose()
.map_err(|e| Error::msg(format!("Cannot decode Base64 package bcs bytes: {e}")))?
.map(|bcs| bcs::from_bytes::<MovePackage>(&bcs))
.transpose()
.map_err(|e| Error::msg(format!("Cannot decode bcs bytes into MovePackage: {e}")))?;

Ok(pkg)
}

/// Fetch a package by its name (using Move Registry Service)
pub async fn package_by_name(&self, name: &str) -> Result<Option<MovePackage>, Error> {
let operation = PackageByNameQuery::build(PackageByNameArgs { name });

let response = self.run_query(&operation).await?;

if let Some(errors) = response.errors {
println!("{:?}", errors);
return Err(Error::msg(format!("{:?}", errors)));
}

Ok(response
.data
.and_then(|x| x.package_by_name)
.and_then(|x| x.package_bcs)
.and_then(|bcs| base64ct::Base64::decode_vec(bcs.0.as_str()).ok())
.and_then(|bcs| bcs::from_bytes::<MovePackage>(&bcs).ok()))
}

/// The Move packages that exist in the network, optionally filtered to be strictly before
/// beforeCheckpoint and/or strictly after afterCheckpoint.
///
/// This query returns all versions of a given user package that appear between the specified
/// checkpoints, but only records the latest versions of system packages.
pub async fn packages(
&self,
after: Option<&str>,
before: Option<&str>,
first: Option<i32>,
last: Option<i32>,
after_checkpoint: Option<u64>,
before_checkpoint: Option<u64>,
) -> Result<Option<Page<MovePackage>>, Error> {
if first.is_some() && last.is_some() {
return Err(Error::msg("Cannot specify both first and last"));
}

let operation = PackagesQuery::build(PackagesQueryArgs {
after,
before,
first,
last,
filter: Some(PackageCheckpointFilter {
after_checkpoint,
before_checkpoint,
}),
});

let response = self.run_query(&operation).await?;

if let Some(errors) = response.errors {
return Err(Error::msg(format!("{:?}", errors)));
}

if let Some(packages) = response.data {
let pc = packages.packages;
let page_info = pc.page_info;
let bcs = pc
.nodes
.iter()
.map(|p| &p.package_bcs)
.filter_map(|b64| {
b64.as_ref()
.map(|b| base64ct::Base64::decode_vec(b.0.as_str()))
})
.collect::<Result<Vec<_>, base64ct::Error>>()
.map_err(|e| Error::msg(format!("Cannot decode Base64 package bcs bytes: {e}")))?;
let packages = bcs
.iter()
.map(|b| bcs::from_bytes::<MovePackage>(b))
.collect::<Result<Vec<_>, bcs::Error>>()
.map_err(|e| {
Error::msg(format!("Cannot decode bcs bytes into MovePackage: {e}"))
})?;

Ok(Some(Page::new(page_info, packages)))
} else {
Ok(None)
}
}

// ===========================================================================
// Dry Run API
// ===========================================================================
Expand Down Expand Up @@ -1189,4 +1410,46 @@ mod tests {

assert!(dry_run.is_ok());
}

#[tokio::test]
async fn test_package() {
let client = Client::new_testnet();
let package = client.package("0x2".parse().unwrap(), None).await;
assert!(package.is_ok());
}

#[tokio::test]
#[ignore] // don't know which name is not malformed
async fn test_package_by_name() {
let client = Client::new_testnet();
let package = client.package_by_name("sui@sui").await;
assert!(package.is_ok());
}

#[tokio::test]
async fn test_latest_package_query() {
for (n, _) in NETWORKS {
let client = Client::new(n).unwrap();
let package = client.package_latest("0x2".parse().unwrap()).await;
assert!(
package.is_ok(),
"Latest package query failed for network: {n}. Error: {}",
package.unwrap_err()
);
}
}

#[tokio::test]
#[ignore] // TIMES OUT FOR NOW
async fn test_packages_query() {
for (n, _) in NETWORKS {
let client = Client::new(n).unwrap();
let packages = client.packages(None, None, None, None, None, None).await;
assert!(
packages.is_ok(),
"Packages query failed for network: {n}. Error: {}",
packages.unwrap_err()
);
}
}
}
13 changes: 13 additions & 0 deletions crates/sui-graphql-client/src/query_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod epoch;
mod events;
mod execute_tx;
mod object;
mod packages;
mod protocol_config;
mod service_config;
mod transaction;
Expand Down Expand Up @@ -53,6 +54,18 @@ pub use object::ObjectQuery;
pub use object::ObjectQueryArgs;
pub use object::ObjectsQuery;
pub use object::ObjectsQueryArgs;
pub use packages::LatestPackageQuery;
pub use packages::MovePackage;
pub use packages::MovePackageVersionFilter;
pub use packages::PackageArgs;
pub use packages::PackageByNameArgs;
pub use packages::PackageByNameQuery;
pub use packages::PackageCheckpointFilter;
pub use packages::PackageQuery;
pub use packages::PackageVersionsArgs;
pub use packages::PackageVersionsQuery;
pub use packages::PackagesQuery;
pub use packages::PackagesQueryArgs;
pub use protocol_config::ProtocolConfigQuery;
pub use protocol_config::ProtocolConfigs;
pub use protocol_config::ProtocolVersionArgs;
Expand Down
Loading
Loading