Skip to content

Commit 9a89ca6

Browse files
authored
[graphql]suins lookup (#14197)
## Description implement resolveNameServiceAddress on top-level Query resolver + nameServiceConnection for objectOwner. Not keen on importing all of sui-json-rpc just to get access to the NameService type. Made a copy in sui-graphql-rpc, but thoughts on doing something like lifting the type to sui-json-rpc-types? <img width="965" alt="Screenshot 2023-10-10 at 3 47 22 PM" src="https://github.com/MystenLabs/sui/assets/127570466/01ffaf21-dba5-493f-a5dd-8f637af24c15"> Not clear on what defaultNameServiceName should be ... is this intended to be the first/ primary name returned by https://docs.sui.io/sui-jsonrpc#suix_resolveNameServiceNames ## Test Plan How did you test the new or updated feature? --- If your changes are not user-facing and not a breaking change, you can skip the following section. Otherwise, please indicate what changed, and then add to the Release Notes section as highlighted during the release process. ### Type of Change (Check all that apply) - [ ] protocol change - [ ] user-visible impact - [ ] breaking change for a client SDKs - [ ] breaking change for FNs (FN binary must upgrade) - [ ] breaking change for validators or node operators (must upgrade binaries) - [ ] breaking change for on-chain data layout - [ ] necessitate either a data wipe or data migration ### Release notes
1 parent c7a8831 commit 9a89ca6

File tree

15 files changed

+144
-20
lines changed

15 files changed

+144
-20
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/sui-graphql-rpc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ uuid.workspace = true
3939
# Used for dummy data
4040
bcs.workspace = true
4141
sui-sdk.workspace = true
42+
sui-json-rpc.workspace = true
4243
sui-json-rpc-types.workspace = true
4344
sui-indexer.workspace = true
4445
sui-types.workspace = true
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
resolveNameServiceAddress(name:"example.sui") {
3+
location
4+
}
5+
address(address:"0x0b86be5d779fac217b41d484b8040ad5145dc9ba0cba099d083c6cbda50d983e"){
6+
location
7+
balance(type:"0x2::sui::SUI") {
8+
coinType
9+
coinObjectCount
10+
totalBalance
11+
}
12+
defaultNameServiceName
13+
}
14+
}

crates/sui-graphql-rpc/schema/current_progress_schema.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,7 @@ type Query {
498498
transactionBlockConnection(first: Int, after: String, last: Int, before: String, filter: TransactionBlockFilter): TransactionBlockConnection
499499
objectConnection(first: Int, after: String, last: Int, before: String, filter: ObjectFilter): ObjectConnection
500500
protocolConfig(protocolVersion: Int): ProtocolConfigs!
501+
resolveNameServiceAddress(name: String!): Address
501502
}
502503

503504
type SafeMode {

crates/sui-graphql-rpc/src/context_data/db_data_provider.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,10 @@ use sui_indexer::{
4545
schema_v2::{checkpoints, epochs, objects, packages, transactions, tx_indices},
4646
PgConnectionPoolConfig,
4747
};
48+
use sui_json_rpc::name_service::{Domain, NameRecord, NameServiceConfig};
4849
use sui_json_rpc_types::SuiTransactionBlockEffects;
4950
use sui_sdk::types::{
51+
base_types::SuiAddress as NativeSuiAddress,
5052
digests::ChainIdentifier,
5153
effects::TransactionEffects,
5254
messages_checkpoint::{
@@ -58,6 +60,7 @@ use sui_sdk::types::{
5860
GenesisObject, SenderSignedData, TransactionDataAPI, TransactionExpiration, TransactionKind,
5961
},
6062
};
63+
use sui_types::dynamic_field::Field;
6164

6265
use super::DEFAULT_PAGE_SIZE;
6366

@@ -958,6 +961,55 @@ impl PgManager {
958961
Ok(None)
959962
}
960963
}
964+
965+
pub(crate) async fn resolve_name_service_address(
966+
&self,
967+
name_service_config: &NameServiceConfig,
968+
name: String,
969+
) -> Result<Option<Address>, Error> {
970+
let domain = name.parse::<Domain>()?;
971+
972+
let record_id = name_service_config.record_field_id(&domain);
973+
974+
let field_record_object = match self.inner.get_object_in_blocking_task(record_id).await? {
975+
Some(o) => o,
976+
None => return Ok(None),
977+
};
978+
979+
let record = field_record_object
980+
.to_rust::<Field<Domain, NameRecord>>()
981+
.ok_or_else(|| Error::Internal(format!("Malformed Object {record_id}")))?
982+
.value;
983+
984+
Ok(record.target_address.map(|address| Address {
985+
address: SuiAddress::from_array(address.to_inner()),
986+
}))
987+
}
988+
989+
pub(crate) async fn default_name_service_name(
990+
&self,
991+
name_service_config: &NameServiceConfig,
992+
address: SuiAddress,
993+
) -> Result<Option<String>, Error> {
994+
let reverse_record_id =
995+
name_service_config.reverse_record_field_id(NativeSuiAddress::from(address));
996+
997+
let field_reverse_record_object = match self
998+
.inner
999+
.get_object_in_blocking_task(reverse_record_id)
1000+
.await?
1001+
{
1002+
Some(o) => o,
1003+
None => return Ok(None),
1004+
};
1005+
1006+
let domain = field_reverse_record_object
1007+
.to_rust::<Field<SuiAddress, Domain>>()
1008+
.ok_or_else(|| Error::Internal(format!("Malformed Object {reverse_record_id}")))?
1009+
.value;
1010+
1011+
Ok(Some(domain.to_string()))
1012+
}
9611013
}
9621014

9631015
impl TryFrom<StoredCheckpoint> for Checkpoint {

crates/sui-graphql-rpc/src/error.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use async_graphql::{ErrorExtensionValues, ErrorExtensions, Response, ServerError};
55
use async_graphql_axum::GraphQLResponse;
66
use sui_indexer::errors::IndexerError;
7+
use sui_json_rpc::name_service::DomainParseError;
78

89
use crate::context_data::db_data_provider::DbValidationError;
910

@@ -45,6 +46,8 @@ pub(crate) fn graphql_error(code: &str, message: impl Into<String>) -> ServerErr
4546

4647
#[derive(Debug, thiserror::Error)]
4748
pub enum Error {
49+
#[error(transparent)]
50+
DomainParse(#[from] DomainParseError),
4851
#[error(transparent)]
4952
DbValidation(#[from] DbValidationError),
5053
#[error("Provide one of digest or sequence_number, not both")]
@@ -72,7 +75,8 @@ pub enum Error {
7275
impl ErrorExtensions for Error {
7376
fn extend(&self) -> async_graphql::Error {
7477
async_graphql::Error::new(format!("{}", self)).extend_with(|_err, e| match self {
75-
Error::DbValidation(_)
78+
Error::DomainParse(_)
79+
| Error::DbValidation(_)
7680
| Error::InvalidCheckpointQuery
7781
| Error::CursorNoBeforeAfter
7882
| Error::CursorNoFirstLast

crates/sui-graphql-rpc/src/functional_group.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ mod tests {
137137
("Query", "coinMetadata"),
138138
("Query", "moveCallMetrics"),
139139
("Query", "networkMetrics"),
140-
("Query", "resolveNameServiceAddress"),
141140
("Subscription", "events"),
142141
("Subscription", "transactions"),
143142
]);

crates/sui-graphql-rpc/src/server/simple_server.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use std::default::Default;
1717
use std::env;
1818
use std::net::SocketAddr;
1919
use std::sync::Arc;
20+
use sui_json_rpc::name_service::NameServiceConfig;
2021

2122
static PROM_ADDR: &str = "0.0.0.0:9184";
2223

@@ -37,6 +38,7 @@ pub async fn start_example_server(conn: ConnectionConfig, service_config: Servic
3738
e
3839
})
3940
.unwrap();
41+
let name_service_config = NameServiceConfig::default();
4042

4143
let prom_addr: SocketAddr = PROM_ADDR.parse().unwrap();
4244
let registry = start_prom(prom_addr);
@@ -52,6 +54,7 @@ pub async fn start_example_server(conn: ConnectionConfig, service_config: Servic
5254
.context_data(data_loader)
5355
.context_data(service_config)
5456
.context_data(pg_conn_pool)
57+
.context_data(name_service_config)
5558
.context_data(Arc::new(metrics))
5659
.extension(QueryLimitsChecker::default())
5760
.extension(FeatureGate)

crates/sui-graphql-rpc/src/types/address.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
use async_graphql::{connection::Connection, *};
5+
use sui_json_rpc::name_service::NameServiceConfig;
56

67
use crate::context_data::db_data_provider::PgManager;
78

8-
use super::name_service::NameService;
99
use super::{
1010
balance::Balance,
1111
coin::Coin,
12+
name_service::NameService,
1213
object::{Object, ObjectFilter},
1314
stake::Stake,
1415
sui_address::SuiAddress,
@@ -128,17 +129,21 @@ impl Address {
128129
unimplemented!()
129130
}
130131

131-
pub async fn default_name_service_name(&self) -> Option<String> {
132-
unimplemented!()
132+
pub async fn default_name_service_name(&self, ctx: &Context<'_>) -> Result<Option<String>> {
133+
ctx.data_unchecked::<PgManager>()
134+
.default_name_service_name(ctx.data_unchecked::<NameServiceConfig>(), self.address)
135+
.await
136+
.extend()
133137
}
134138

135139
pub async fn name_service_connection(
136140
&self,
141+
ctx: &Context<'_>,
137142
first: Option<u64>,
138143
after: Option<String>,
139144
last: Option<u64>,
140145
before: Option<String>,
141-
) -> Option<Connection<String, NameService>> {
146+
) -> Result<Option<Connection<String, NameService>>> {
142147
unimplemented!()
143148
}
144149
}

crates/sui-graphql-rpc/src/types/name_service.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ use async_graphql::*;
55
use serde::{Deserialize, Serialize};
66

77
#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
8-
pub(crate) struct NameService(String);
8+
pub(crate) struct NameService(pub String);
99
scalar!(NameService, "NameService");

0 commit comments

Comments
 (0)