Skip to content

Commit 5151f32

Browse files
committed
feat(sui): add gRPC migration level 6 for service info methods
1 parent 8633fc9 commit 5151f32

File tree

2 files changed

+182
-32
lines changed

2 files changed

+182
-32
lines changed

crates/walrus-sui/src/client/dual_client.rs

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@ use sui_rpc::{
1818
BatchGetObjectsResponse,
1919
Bcs,
2020
DynamicField,
21+
Epoch as GrpcEpoch,
2122
ExecutedTransaction,
2223
GetBalanceRequest,
24+
GetEpochRequest,
2325
GetObjectRequest,
26+
GetServiceInfoRequest,
2427
GetTransactionRequest,
2528
ListDynamicFieldsRequest,
2629
ListOwnedObjectsRequest,
@@ -30,11 +33,11 @@ use sui_rpc::{
3033
state_service_client::StateServiceClient,
3134
},
3235
};
33-
use sui_sdk::{SuiClient, SuiClientBuilder};
36+
use sui_sdk::{SuiClient, SuiClientBuilder, rpc_types::SuiCommittee};
3437
use sui_types::{
3538
TypeTag,
3639
base_types::{ObjectID, ObjectRef, SuiAddress},
37-
crypto::ToFromBytes,
40+
crypto::{AuthorityPublicKeyBytes, ToFromBytes},
3841
digests::TransactionDigest,
3942
event::EventID,
4043
signature::GenericSignature,
@@ -594,6 +597,74 @@ impl DualClient {
594597
next_cursor: response.next_page_token,
595598
})
596599
}
600+
601+
/// Get the chain identifier via gRPC.
602+
pub async fn get_chain_identifier_grpc(&self) -> Result<String, SuiClientError> {
603+
let mut grpc_client = self.grpc_client.clone();
604+
let response = grpc_client
605+
.ledger_client()
606+
.get_service_info(GetServiceInfoRequest::default())
607+
.await?;
608+
Ok(response
609+
.into_inner()
610+
.chain_id
611+
.context("no chain_id in get_service_info response")?)
612+
}
613+
614+
/// Get the reference gas price for the current epoch via gRPC.
615+
pub async fn get_reference_gas_price_grpc(&self) -> Result<u64, SuiClientError> {
616+
let request = GetEpochRequest::default().with_read_mask(FieldMask::from_paths([
617+
GrpcEpoch::path_builder().reference_gas_price(),
618+
]));
619+
let mut grpc_client = self.grpc_client.clone();
620+
let response = grpc_client.ledger_client().get_epoch(request).await?;
621+
Ok(response
622+
.into_inner()
623+
.epoch
624+
.context("no epoch in get_epoch response")?
625+
.reference_gas_price
626+
.context("no reference_gas_price in epoch")?)
627+
}
628+
629+
/// Get the committee info for the given epoch via gRPC.
630+
pub async fn get_committee_info_grpc(
631+
&self,
632+
epoch: Option<u64>,
633+
) -> Result<SuiCommittee, SuiClientError> {
634+
let mut request = GetEpochRequest::default().with_read_mask(FieldMask::from_paths([
635+
GrpcEpoch::path_builder().epoch(),
636+
GrpcEpoch::path_builder().committee().finish(),
637+
]));
638+
if let Some(e) = epoch {
639+
request = request.with_epoch(e);
640+
}
641+
642+
let mut grpc_client = self.grpc_client.clone();
643+
let response = grpc_client.ledger_client().get_epoch(request).await?;
644+
let epoch_data = response
645+
.into_inner()
646+
.epoch
647+
.context("no epoch in get_epoch response")?;
648+
let committee = epoch_data.committee.context("no committee in epoch")?;
649+
let validators = committee
650+
.members
651+
.iter()
652+
.map(|member| {
653+
let pk_bytes = member
654+
.public_key
655+
.as_ref()
656+
.context("no public_key in committee member")?;
657+
let pk = AuthorityPublicKeyBytes::from_bytes(pk_bytes)
658+
.map_err(|e| anyhow::anyhow!("invalid authority public key: {e}"))?;
659+
let weight = member.weight.context("no weight in committee member")?;
660+
Ok((pk, weight))
661+
})
662+
.collect::<Result<Vec<_>, anyhow::Error>>()?;
663+
Ok(SuiCommittee {
664+
epoch: epoch_data.epoch.context("no epoch number")?,
665+
validators,
666+
})
667+
}
597668
}
598669

599670
async fn list_owned_objects(

crates/walrus-sui/src/client/retry_client/retriable_sui_client.rs

Lines changed: 109 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ const GRPC_MIGRATION_LEVEL_BATCH_OBJECTS: GrpcMigrationLevel = GrpcMigrationLeve
214214
const GRPC_MIGRATION_LEVEL_SELECT_COINS: GrpcMigrationLevel = GrpcMigrationLevel(3);
215215
const GRPC_MIGRATION_LEVEL_GET_BALANCE: GrpcMigrationLevel = GrpcMigrationLevel(4);
216216
const GRPC_MIGRATION_LEVEL_TRANSACTION_READS: GrpcMigrationLevel = GrpcMigrationLevel(5);
217+
const GRPC_MIGRATION_LEVEL_SERVICE_INFO: GrpcMigrationLevel = GrpcMigrationLevel(6);
217218

218219
impl Default for GrpcMigrationLevel {
219220
fn default() -> Self {
@@ -1245,54 +1246,105 @@ impl RetriableSuiClient {
12451246
}
12461247

12471248
/// Returns the committee information for the given epoch.
1248-
///
1249-
/// Calls [`sui_sdk::apis::GovernanceApi::get_committee_info`] internally.
12501249
pub async fn get_committee_info(
12511250
&self,
12521251
epoch: Option<BigInt<u64>>,
12531252
) -> SuiClientResult<SuiCommittee> {
1254-
async fn make_request(
1255-
client: Arc<DualClient>,
1256-
epoch: Option<BigInt<u64>>,
1257-
) -> SuiClientResult<SuiCommittee> {
1258-
Ok(client
1259-
.sui_client()
1260-
.governance_api()
1261-
.get_committee_info(epoch)
1262-
.await?)
1253+
if self.grpc_migration_level >= GRPC_MIGRATION_LEVEL_SERVICE_INFO {
1254+
self.get_committee_info_grpc(epoch.map(|b| *b)).await
1255+
} else {
1256+
self.get_committee_info_json_rpc(epoch).await
12631257
}
1258+
}
12641259

1260+
/// JSON-RPC implementation of `get_committee_info`.
1261+
async fn get_committee_info_json_rpc(
1262+
&self,
1263+
epoch: Option<BigInt<u64>>,
1264+
) -> SuiClientResult<SuiCommittee> {
12651265
let request = move |client: Arc<DualClient>, method| {
12661266
retry_rpc_errors(
12671267
self.get_strategy(),
1268-
move || make_request(client.clone(), epoch),
1268+
move || {
1269+
let client = client.clone();
1270+
async move {
1271+
Ok(client
1272+
.sui_client()
1273+
.governance_api()
1274+
.get_committee_info(epoch)
1275+
.await?)
1276+
}
1277+
},
12691278
self.metrics.clone(),
12701279
method,
12711280
)
12721281
};
1282+
self.failover_sui_client
1283+
.with_failover(request, None, "get_committee_info")
1284+
.await
1285+
}
12731286

1287+
/// gRPC implementation of `get_committee_info`.
1288+
async fn get_committee_info_grpc(&self, epoch: Option<u64>) -> SuiClientResult<SuiCommittee> {
1289+
let request = move |client: Arc<DualClient>, method| {
1290+
retry_rpc_errors(
1291+
self.get_strategy(),
1292+
move || {
1293+
let client = client.clone();
1294+
async move { client.get_committee_info_grpc(epoch).await }
1295+
},
1296+
self.metrics.clone(),
1297+
method,
1298+
)
1299+
};
12741300
self.failover_sui_client
12751301
.with_failover(request, None, "get_committee_info")
12761302
.await
12771303
}
12781304

12791305
/// Returns the reference gas price.
1280-
///
1281-
/// Calls [`sui_sdk::apis::ReadApi::get_reference_gas_price`] internally.
12821306
#[tracing::instrument(level = Level::DEBUG, skip_all)]
12831307
pub async fn get_reference_gas_price(&self) -> SuiClientResult<u64> {
1284-
async fn make_request(client: Arc<DualClient>) -> SuiClientResult<u64> {
1285-
Ok(client
1286-
.sui_client()
1287-
.read_api()
1288-
.get_reference_gas_price()
1289-
.await?)
1308+
if self.grpc_migration_level >= GRPC_MIGRATION_LEVEL_SERVICE_INFO {
1309+
self.get_reference_gas_price_grpc().await
1310+
} else {
1311+
self.get_reference_gas_price_json_rpc().await
12901312
}
1313+
}
1314+
1315+
/// JSON-RPC implementation of `get_reference_gas_price`.
1316+
async fn get_reference_gas_price_json_rpc(&self) -> SuiClientResult<u64> {
1317+
let request = move |client: Arc<DualClient>, method| {
1318+
retry_rpc_errors(
1319+
self.get_strategy(),
1320+
move || {
1321+
let client = client.clone();
1322+
async move {
1323+
Ok(client
1324+
.sui_client()
1325+
.read_api()
1326+
.get_reference_gas_price()
1327+
.await?)
1328+
}
1329+
},
1330+
self.metrics.clone(),
1331+
method,
1332+
)
1333+
};
1334+
self.failover_sui_client
1335+
.with_failover(request, None, "get_reference_gas_price")
1336+
.await
1337+
}
12911338

1339+
/// gRPC implementation of `get_reference_gas_price`.
1340+
async fn get_reference_gas_price_grpc(&self) -> SuiClientResult<u64> {
12921341
let request = move |client: Arc<DualClient>, method| {
12931342
retry_rpc_errors(
12941343
self.get_strategy(),
1295-
move || make_request(client.clone()),
1344+
move || {
1345+
let client = client.clone();
1346+
async move { client.get_reference_gas_price_grpc().await }
1347+
},
12961348
self.metrics.clone(),
12971349
method,
12981350
)
@@ -1466,20 +1518,47 @@ impl RetriableSuiClient {
14661518
}
14671519

14681520
/// Returns the chain identifier.
1469-
///
1470-
/// Calls [`sui_sdk::apis::ReadApi::get_chain_identifier`] internally.
14711521
pub async fn get_chain_identifier(&self) -> SuiClientResult<String> {
1472-
async fn make_request(client: Arc<DualClient>) -> SuiClientResult<String> {
1473-
Ok(client
1474-
.sui_client()
1475-
.read_api()
1476-
.get_chain_identifier()
1477-
.await?)
1522+
if self.grpc_migration_level >= GRPC_MIGRATION_LEVEL_SERVICE_INFO {
1523+
self.get_chain_identifier_grpc().await
1524+
} else {
1525+
self.get_chain_identifier_json_rpc().await
14781526
}
1527+
}
1528+
1529+
/// JSON-RPC implementation of `get_chain_identifier`.
1530+
async fn get_chain_identifier_json_rpc(&self) -> SuiClientResult<String> {
1531+
let request = move |client: Arc<DualClient>, method| {
1532+
retry_rpc_errors(
1533+
self.get_strategy(),
1534+
move || {
1535+
let client = client.clone();
1536+
async move {
1537+
Ok(client
1538+
.sui_client()
1539+
.read_api()
1540+
.get_chain_identifier()
1541+
.await?)
1542+
}
1543+
},
1544+
self.metrics.clone(),
1545+
method,
1546+
)
1547+
};
1548+
self.failover_sui_client
1549+
.with_failover(request, None, "get_chain_identifier")
1550+
.await
1551+
}
1552+
1553+
/// gRPC implementation of `get_chain_identifier`.
1554+
async fn get_chain_identifier_grpc(&self) -> SuiClientResult<String> {
14791555
let request = move |client: Arc<DualClient>, method| {
14801556
retry_rpc_errors(
14811557
self.get_strategy(),
1482-
move || make_request(client.clone()),
1558+
move || {
1559+
let client = client.clone();
1560+
async move { client.get_chain_identifier_grpc().await }
1561+
},
14831562
self.metrics.clone(),
14841563
method,
14851564
)

0 commit comments

Comments
 (0)