Skip to content

Commit

Permalink
grpc: introduce FieldMasks for partial responses
Browse files Browse the repository at this point in the history
Instead of defining custom "options" types for each endpoint to control
the amount of data being returned, leverage the standard
google.protobuf.FieldMask type and inspiration from
https://google.aip.dev/157 in order to provide users fine-grained
control over what fields are returned.

Initially the provided field masks will support parity with the existing
options and in the future provided field masks may support more
fine-grained control over nested fields.
  • Loading branch information
bmwill committed Feb 12, 2025
1 parent 059946d commit 5ea14a0
Show file tree
Hide file tree
Showing 15 changed files with 380 additions and 141 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/sui-e2e-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ shared-crypto.workspace = true
sui-sdk-types.workspace = true
sui-sdk-transaction-builder.workspace = true
tonic.workspace = true
prost-types.workspace = true

passkey-types.workspace = true
passkey-client.workspace = true
Expand Down
10 changes: 9 additions & 1 deletion crates/sui-e2e-tests/tests/rpc/checkpoints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ async fn get_checkpoint() {
sequence_number: Some(sequence_number.unwrap()),
digest: Some(digest.clone().unwrap()),
options: None,
read_mask: None,
})
.await
.unwrap_err();
Expand Down Expand Up @@ -401,6 +402,7 @@ async fn get_full_checkpoint() {
sequence_number: Some(sequence_number.unwrap()),
digest: Some(digest.clone().unwrap()),
options: None,
read_mask: None,
})
.await
.unwrap_err();
Expand All @@ -420,8 +422,14 @@ async fn subscribe_checkpoint() {
.await
.unwrap();

let request = SubscribeCheckpointsRequest {
read_mask: Some(prost_types::FieldMask {
paths: vec!["sequence_number".to_owned()],
}),
};

let mut stream = client
.subscribe_checkpoints(SubscribeCheckpointsRequest::default())
.subscribe_checkpoints(request)
.await
.unwrap()
.into_inner();
Expand Down
11 changes: 9 additions & 2 deletions crates/sui-e2e-tests/tests/rpc/resolve.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use prost_types::FieldMask;
use shared_crypto::intent::Intent;
use sui_keys::keystore::AccountKeystore;
use sui_macros::sim_test;
Expand All @@ -20,10 +21,16 @@ fn build_resolve_request(
transaction: &unresolved::Transaction,
simulate: bool,
) -> ResolveTransactionRequest {
let read_mask = if simulate {
Some(FieldMask {
paths: vec!["simulation".to_string()],
})
} else {
None
};
ResolveTransactionRequest {
unresolved_transaction: Some(serde_json::to_string(transaction).unwrap()),
simulate: Some(simulate),
simulate_options: None,
read_mask,
}
}

Expand Down
42 changes: 28 additions & 14 deletions crates/sui-rpc-api/proto/sui/node/v2/node_service.proto
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
// The sui.node.v2 package contains API definitions for services that are
// expected to run on Full nodes.
// expected to run on Fullnodes.
syntax = "proto3";

package sui.node.v2;

import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/timestamp.proto";
import "sui/types/types.proto";

//
// RPC Node interface
//

// Service for reading data from a Sui Full node.
// Service for reading data from a Sui Fullnode.
service NodeService {
// Query a node for information about its current state.
rpc GetNodeInfo(GetNodeInfoRequest) returns (GetNodeInfoResponse);
Expand Down Expand Up @@ -138,12 +139,14 @@ message GetTransactionRequest {
// Required. The digest of the requested transaction.
optional sui.types.Digest digest = 1;

// Optional. Options for specifying which parts of the `GetTransactionResponse`
// should be returned.
// DEPRECATED To be removed in the next release
optional GetTransactionOptions options = 3;
// Optional. Mask for specifying which parts of the `GetTransactionResponse`
// should be returned.
optional google.protobuf.FieldMask read_mask = 4;
}

// Options for which parts of the `GetTransactionResponse` should be returned.
// DEPRECATED To be removed in the next release
message GetTransactionOptions {
// Include the `sui.types.Transaction` message in the response.
//
Expand Down Expand Up @@ -239,10 +242,14 @@ message GetObjectRequest {
// the object is returned.
optional uint64 version = 2;

// Optional. Options for specifying which parts of the `GetObjectResponse` should be returned.
// DEPRECATED To be removed in the next release
optional GetObjectOptions options = 3;
// Optional. Mask for specifying which parts of the `GetObjectResponse`
// should be returned.
optional google.protobuf.FieldMask read_mask = 4;
}

// DEPRECATED To be removed in the next release
message GetObjectOptions {
// Include the `sui.types.Object` message in the response.
//
Expand Down Expand Up @@ -287,12 +294,14 @@ message GetCheckpointRequest {
// Optional. The digest of the requested checkpoint.
optional sui.types.Digest digest = 2;

// Optional. Options for specifying which parts of the `GetCheckpointResponse`
// should be returned.
// DEPRECATED To be removed in the next release
optional GetCheckpointOptions options = 3;
// Optional. Mask for specifying which parts of the `GetCheckpointResponse`
// should be returned.
optional google.protobuf.FieldMask read_mask = 4;
}

// Options for which parts of the `GetCheckpointResponse` should be returned.
// DEPRECATED To be removed in the next release
message GetCheckpointOptions {
// Include the `sui.types.CheckpointSummary` in the response.
//
Expand Down Expand Up @@ -361,12 +370,14 @@ message GetFullCheckpointRequest {
// Optional. The digest of the requested checkpoint.
optional sui.types.Digest digest = 2;

// Optional. Options for specifying which parts of the
// `GetFullCheckpointResponse` should be returned.
// DEPRECATED To be removed in the next release
optional GetFullCheckpointOptions options = 3;
// Optional. Mask for specifying which parts of the `GetFullCheckpointResponse`
// should be returned.
optional google.protobuf.FieldMask read_mask = 4;
}

// Options for which parts of the `GetFullCheckpointResponse` should be returned.
// DEPRECATED To be removed in the next release
message GetFullCheckpointOptions {
// Include the `sui.types.CheckpointSummary` in the response.
//
Expand Down Expand Up @@ -566,11 +577,14 @@ message ExecuteTransactionRequest {
// transaction, encoded as bytes.
repeated bytes signatures_bytes = 4;

// Optional. Options for specifying which parts of the
// `ExecuteTransactionResponse` should be returned.
// DEPRECATED To be removed in the next release
optional ExecuteTransactionOptions options = 5;
// Optional. Mask for specifying which parts of the
// `ExecuteTransactionResponse` should be returned.
optional google.protobuf.FieldMask read_mask = 6;
}

// DEPRECATED To be removed in the next release
message ExecuteTransactionOptions {
// Include the `sui.types.TransactionEffects` message in the response.
//
Expand Down
13 changes: 3 additions & 10 deletions crates/sui-rpc-api/proto/sui/node/v2alpha/node_service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ syntax = "proto3";

package sui.node.v2alpha;

import "google/protobuf/field_mask.proto";
import "sui/node/v2/node_service.proto";
import "sui/types/types.proto";

Expand Down Expand Up @@ -160,14 +161,7 @@ message GetGasInfoResponse {

message SimulateTransactionRequest {
optional sui.types.Bcs transaction_bcs = 2;
optional SimulateTransactionOptions options = 3;
}

message SimulateTransactionOptions {
// Include the `BalanceChange`s in the response.
//
// Defaults to `false` if not included.
optional bool balance_changes = 8;
optional google.protobuf.FieldMask read_mask = 3;
}

message SimulateTransactionResponse {
Expand All @@ -180,8 +174,7 @@ message ResolveTransactionRequest {
// TODO FIX TYPE
// Json unresolved transaction type
optional string unresolved_transaction = 1;
optional bool simulate = 2;
optional SimulateTransactionOptions simulate_options = 3;
optional google.protobuf.FieldMask read_mask = 3;
}

message ResolveTransactionResponse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ syntax = "proto3";

package sui.node.v2alpha;

import "google/protobuf/field_mask.proto";
import "sui/node/v2/node_service.proto";

// Service for subscribing to data from a Sui Fullnode
Expand All @@ -21,16 +22,16 @@ service SubscriptionService {
// event the subscription terminates (either by the client/server or by the
// connection breaking), clients will be able to reinitailize a subscription
// and then leverage other APIs (e.g.
// sui.node.v1.NodeService.GetFullCheckpoint) in order to request data for
// sui.node.v2.NodeService.GetFullCheckpoint) in order to request data for
// the checkpoints they missed.
rpc SubscribeCheckpoints(SubscribeCheckpointsRequest) returns (stream SubscribeCheckpointsResponse);
}

// Request message for SubscriptionService.SubscribeCheckpoints
message SubscribeCheckpointsRequest {
// Optional. Options for specifiying which parts of the
// Optional. Mask for specifiying which parts of the
// SubscribeCheckpointsResponse should be returned.
optional sui.node.v2.GetFullCheckpointOptions options = 1;
optional google.protobuf.FieldMask read_mask = 3;
}

// Response message for SubscriptionService.SubscribeCheckpoints
Expand Down
31 changes: 31 additions & 0 deletions crates/sui-rpc-api/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

mod response_ext;
use prost_types::FieldMask;
pub use response_ext::ResponseExt;

use tap::Pipe;
Expand Down Expand Up @@ -99,6 +100,12 @@ impl Client {
contents: Some(false),
contents_bcs: Some(false),
}),
read_mask: Some(FieldMask {
paths: ["summary_bcs", "signature"]
.into_iter()
.map(ToOwned::to_owned)
.collect(),
}),
};

let (
Expand Down Expand Up @@ -143,6 +150,21 @@ impl Client {
object: Some(false),
object_bcs: Some(true),
}),
read_mask: Some(FieldMask {
paths: [
"summary_bcs",
"signature",
"contents_bcs",
"transactions.transaction_bcs",
"transactions.effects_bcs",
"transactions.events_bcs",
"transactions.input_objects.object_bcs",
"transactions.output_objects.object_bcs",
]
.into_iter()
.map(ToOwned::to_owned)
.collect(),
}),
};

let (metadata, response, _extentions) = self
Expand Down Expand Up @@ -181,6 +203,9 @@ impl Client {
object: Some(false),
object_bcs: Some(true),
}),
read_mask: Some(FieldMask {
paths: ["object_bcs"].into_iter().map(ToOwned::to_owned).collect(),
}),
};

let (metadata, GetObjectResponse { object_bcs, .. }, _extentions) =
Expand Down Expand Up @@ -217,6 +242,12 @@ impl Client {
events_bcs: Some(true),
..(parameters.to_owned().into())
}),
read_mask: Some(FieldMask {
paths: ["effects_bcs", "events_bcs", "balance_changes"]
.into_iter()
.map(ToOwned::to_owned)
.collect(),
}),
};

let (metadata, response, _extentions) = self
Expand Down
Loading

0 comments on commit 5ea14a0

Please sign in to comment.