Skip to content

Conversation

bingyanglin
Copy link
Contributor

@bingyanglin bingyanglin commented Sep 12, 2025

Description of change

  • Added transaction filters for client subscription
    • WASP team has provided the feedback that the transaction filter subscriber works as expected
  • Added node service including GetLatestCheckpoint, ExecuteTransaction, and GetObject.
    • The GetLatestCheckpoint support get the latest checkpoint data or checkpoint summary
    • The ExecuteTransaction is fully aligned with the current JSON-RPC design in IOTA and SUI (for the request, see the function execute_transaction_block in pub trait WriteApi; for the response, see IOTATransactionBlockResponse and SuiTransactionBlockResponse, respectively.).
      • For iota-rest-api, there is an additional field EffectsFinality in the response, but it is not used in our codebase, so we do not implement this field.
    • The GetObject is also aligned with the current JSON-RPC design in IOTA and SUI (see the function get_object in the pub trait ReadApi for more details).
  • (deprecated) To be fully compatible with the current JSON-RPC, the return types (i.e., IotaTransactionBlockEffects, IotaTransactionBlockResponse, and IotaObjectData for transaction filter, ExecuteTransaction, and GetObject, respectively) we use serialized Json data for ease of usage and avoid additional effort, like we have the following for some of the fields. These annotations work for JSON but break BCS round-trips. In addition, to avoid repetitive work, we leveraged the existing types and functions (if available) in the JSON-RPC api.
      #[serde(skip_serializing_if = "Option::is_none")]
      #[serde(skip_serializing_if = "Vec::is_empty", default)]
      #[serde_as(as = "Base64")]
      #[serde_as(as = "Option<BigInt<u64>>")]

(NOTE: The above is deprecated, after discussion, we need to do bcs streaming for the response data, instead of using JSON string)

  • Moved the GrpcApiConfig to iota-config, and implemented the subscribe_events and subscribe_transactions in SubscriptionHandler of iota-node directly, so as to resolve the cyclic dependency for iota-grpc-api to use iota-core.
  • Implemented WriteService and ReadService to ease of future extension of more API calls.
  • Removed the GrpcStateReader and RestStateReaderAdapter in iota-grpc-api crate, and leveraged the existing REST API infrastructure (including the RestStateReader and RestReadStore four our use cases). The plan is after REST API is deprecated, we can directly rename them to be Grpc*, so as to avoid repetitive work in the future.
  • Enhanced RestStateReader and RestReadStore to access AuthorityState and AuthorityPerEpochStore for usage in ReadGrpcService and WriteGrpcServce. This is required to return more information like what JSON-RPC does.
  • Added test utils for cleaner code.
  • NOTE THAT the document will be enhanced/updated after more APIs are added and the design pattern is finalized, otherwise we might need to modify the document back and forth. (see gRPC: Document the finalised internal gRPC #8695)

Links to any relevant issues

fixes #7724

How the change has been tested

  • Basic tests (linting, compilation, formatting, unit/integration tests)
  • Patch-specific tests (correctness, functionality coverage)
  • I have added tests that prove my fix is effective or that my feature works
  • I have checked that new and existing unit tests pass locally with my changes

Release Notes

  • Nodes (Validators and Full nodes): For gPRC, added transaction filters for client subscription, and added 3 APIs including GetLatestCheckpoint, ExecuteTransaction, and GetObject.

@bingyanglin bingyanglin self-assigned this Sep 12, 2025
Copy link

vercel bot commented Sep 12, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

6 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
apps-backend Ignored Ignored Preview Sep 30, 2025 10:19am
apps-ui-kit Ignored Ignored Preview Sep 30, 2025 10:19am
iota-evm-bridge Ignored Ignored Preview Sep 30, 2025 10:19am
iota-multisig-toolkit Ignored Ignored Preview Sep 30, 2025 10:19am
rebased-explorer Ignored Ignored Preview Sep 30, 2025 10:19am
wallet-dashboard Ignored Ignored Preview Sep 30, 2025 10:19am

@github-actions github-actions bot added the ci Issues related to our CI pipeline label Sep 12, 2025
@iota-ci iota-ci added core-protocol node Issues related to the Core Node team labels Sep 12, 2025
@bingyanglin bingyanglin changed the title Feat/grpc transaction filter gRPC: Add subscription to transaction including filtering Sep 12, 2025
@bingyanglin bingyanglin changed the title gRPC: Add subscription to transaction including filtering feat(gRPC): Add subscription to transaction including filtering Sep 12, 2025
@bingyanglin bingyanglin force-pushed the feat/grpc-transaction-filter branch 4 times, most recently from 0a5ec53 to ebbe1d4 Compare September 24, 2025 13:50
@bingyanglin bingyanglin changed the title feat(gRPC): Add subscription to transaction including filtering feat(gRPC): Add transaction and API services for internal usage Sep 24, 2025
@bingyanglin bingyanglin force-pushed the feat/grpc-transaction-filter branch 6 times, most recently from c62698b to 707e542 Compare September 26, 2025 04:40
@bingyanglin bingyanglin changed the title feat(gRPC): Add transaction and API services for internal usage feat(gRPC): Add transaction and node services for internal usage Sep 26, 2025
@bingyanglin bingyanglin force-pushed the feat/grpc-transaction-filter branch 2 times, most recently from b314d54 to d6053fd Compare September 26, 2025 13:09
@bingyanglin bingyanglin changed the title feat(gRPC): Add transaction and node services for internal usage feat(gRPC): Add transaction and read/write services for internal usage Sep 28, 2025
@bingyanglin bingyanglin force-pushed the feat/grpc-transaction-filter branch 2 times, most recently from 52aa127 to 89e7a56 Compare September 29, 2025 14:44
@bingyanglin bingyanglin force-pushed the feat/grpc-transaction-filter branch from 726181b to 83033fe Compare September 29, 2025 17:03
@bingyanglin bingyanglin marked this pull request as ready for review September 30, 2025 07:44
@bingyanglin bingyanglin requested a review from a team as a code owner September 30, 2025 07:44
@bingyanglin bingyanglin requested review from a team as code owners September 30, 2025 07:44
@bingyanglin bingyanglin force-pushed the feat/grpc-transaction-filter branch from 3050afb to 8d40b0b Compare September 30, 2025 10:17
Copy link
Contributor

@semenov-vladyslav semenov-vladyslav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good. There are a few nits to improve.

fn indexes(&self) -> Option<&dyn RestIndexes>;

/// Enable downcasting to concrete types for enhanced functionality
fn as_any(&self) -> &dyn std::any::Any;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A weird method for a trait. Should RestStateReader be extended with pub fn authority_state(&self) -> Arc<AuthorityState> and pub fn load_epoch_store_one_call_per_task(&self) -> Arc<AuthorityPerEpochStore> methods instead?

Comment on lines +384 to +392
/// Get access to the underlying AuthorityState
pub fn authority_state(&self) -> &Arc<AuthorityState> {
&self.state
}

/// Load epoch store for transaction processing
pub fn load_epoch_store_one_call_per_task(&self) -> Arc<AuthorityPerEpochStore> {
self.state.load_epoch_store_one_call_per_task().clone()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not move these methods and make them a part of RestStateReader trait?

pub fn subscribe_events(
&self,
filter: EventFilter,
) -> Box<dyn futures::Stream<Item = IotaEvent> + Send + Unpin> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be BoxStream<'_, IotaEvent>? Or is Unpin important here?

&self,
filter: EventFilter,
) -> Box<dyn futures::Stream<Item = IotaEvent> + Send + Unpin> {
Box::new(Box::pin(self.event_streamer.subscribe(filter)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double Box? Doesn't look right. With BoxStream we can just use one Box::pin.

Comment on lines +125 to +126
) -> Box<dyn futures::Stream<Item = IotaTransactionBlockEffects> + Send + Unpin> {
Box::new(Box::pin(self.transaction_streamer.subscribe(filter)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

impl CheckpointService for CheckpointGrpcService {
type StreamCheckpointsStream =
Pin<Box<dyn futures::Stream<Item = Result<crate::checkpoint::Checkpoint, Status>> + Send>>;
Pin<Box<dyn futures::Stream<Item = Result<Checkpoint, Status>> + Send>>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Pin<Box<dyn futures::Stream<Item = Result<Checkpoint, Status>> + Send>>;
futures::BoxStream<Result<Checkpoint, Status>>;

&self,
request: Request<GetLatestCheckpointRequest>,
) -> Result<Response<Checkpoint>, Status> {
debug!("get_latest_checkpoint called");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
debug!("get_latest_checkpoint called");

request: Request<GetObjectRequest>,
) -> Result<Response<GetObjectResponse>, Status> {
let req = request.into_inner();
debug!("get_object called");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
debug!("get_object called");

#[tonic::async_trait]
impl TransactionService for TransactionGrpcService {
type StreamTransactionsStream =
std::pin::Pin<Box<dyn futures::Stream<Item = Result<Transaction, Status>> + Send>>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::pin::Pin<Box<dyn futures::Stream<Item = Result<Transaction, Status>> + Send>>;
futures::BoxStream<Result<Transaction, Status>>;

// Downcast to RestReadStore for enhanced functionality
self.state_reader
.as_any()
.downcast_ref::<RestReadStore>()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This downcast suggests that the only type for the dyn object state_reader is RestReadStore, all other types are "fallback" or mock.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ci Issues related to our CI pipeline core-protocol node Issues related to the Core Node team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

gRPC: Replace all REST endpoints used in the tests with gRPC ones
4 participants