diff --git a/ecosystem/indexer-grpc/transaction-filter/README.md b/ecosystem/indexer-grpc/transaction-filter/README.md index 6cb3fdf73baf8..492c8923f56e1 100644 --- a/ecosystem/indexer-grpc/transaction-filter/README.md +++ b/ecosystem/indexer-grpc/transaction-filter/README.md @@ -33,62 +33,62 @@ The `TransactionFilterBuilder` is a more ergonomic way to build a filter, and is performance, assuming this is being done infrequently. ``` - use transaction_filter::filters::EventFilterBuilder; - - let ef = EventFilterBuilder::default() - .data("spins") - .struct_type( - MoveStructTagFilterBuilder::default() - .address("0x0077") - .module("roulette") - .name("spin") - .build()?, - ) - .build()?; +use transaction_filter::filters::EventFilterBuilder; + +let ef = EventFilterBuilder::default() + .data("spins") + .struct_type( + MoveStructTagFilterBuilder::default() + .address("0x0077") + .module("roulette") + .name("spin") + .build()?, + ) + .build()?; ``` The `TransactionFilter` struct is also available, but requires direct construction of the structs. ``` - use transaction_filter::filters::EventFilter; - - let ef = EventFilter { - data: Some("spins".into()), - struct_type: Some(MoveStructTagFilter { - address: Some("0x0077".into()), - module: Some("roulette".into()), - name: Some("spin".into()), - }), - }; +use transaction_filter::filters::EventFilter; + +let ef = EventFilter { + data: Some("spins".into()), + struct_type: Some(MoveStructTagFilter { + address: Some("0x0077".into()), + module: Some("roulette".into()), + name: Some("spin".into()), + }), +}; ``` Once you have some filters built, you can combine them with the boolean operators `and`, `or`, and `not`. ``` - let trf = TransactionRootFilterBuilder::default() - .success(true).build()?; - - let utf = UserTransactionFilterBuilder::default() - .sender("0x0011".into()).build()?; - - let ef = EventFilterBuilder::default() - .struct_type( - MoveStructTagFilterBuilder::default() - .address("0x0077") - .module("roulette") - .name("spin") - .build()?, - ) - .build()?; - - // Combine filters using logical operators! - // (trf OR utf) - let trf_or_utf = BooleanTransactionFilter::from(trf).or(utf); - // ((trf OR utf) AND ef) - let query = trf_or_utf.and(ef); - - let transactions: Vec = transaction_stream.next().await; - let filtered_transactions = query.filter_vec(transactions); +let trf = TransactionRootFilterBuilder::default() + .success(true).build()?; + +let utf = UserTransactionFilterBuilder::default() + .sender("0x0011".into()).build()?; + +let ef = EventFilterBuilder::default() + .struct_type( + MoveStructTagFilterBuilder::default() + .address("0x0077") + .module("roulette") + .name("spin") + .build()?, + ) + .build()?; + +// Combine filters using logical operators! +// (trf OR utf) +let trf_or_utf = BooleanTransactionFilter::from(trf).or(utf); +// ((trf OR utf) AND ef) +let query = trf_or_utf.and(ef); + +let transactions: Vec = transaction_stream.next().await; +let filtered_transactions = query.filter_vec(transactions); ``` ## API & Serialization diff --git a/ecosystem/indexer-grpc/transaction-filter/src/boolean_transaction_filter.rs b/ecosystem/indexer-grpc/transaction-filter/src/boolean_transaction_filter.rs index 59cc21ad3ba95..d5bc5ac196fa1 100644 --- a/ecosystem/indexer-grpc/transaction-filter/src/boolean_transaction_filter.rs +++ b/ecosystem/indexer-grpc/transaction-filter/src/boolean_transaction_filter.rs @@ -335,7 +335,7 @@ mod test { let query = trf_or_utf.and(ef); println!( - "JSON RESULT: \n {}", + "JSON RESULT (QUERY 1):\n {}", serde_json::to_string_pretty(&query).unwrap() ); @@ -380,7 +380,7 @@ mod test { let query = BooleanTransactionFilter::from(ef_econia).or(ef_aries); println!( - "JSON RESULT: \n {}", + "JSON RESULT (QUERY 2):\n {}", serde_json::to_string_pretty(&query).unwrap() ); } diff --git a/ecosystem/indexer-grpc/transaction-filter/src/filters/event.rs b/ecosystem/indexer-grpc/transaction-filter/src/filters/event.rs index 07724b5677a39..8dcbca5ab45a9 100644 --- a/ecosystem/indexer-grpc/transaction-filter/src/filters/event.rs +++ b/ecosystem/indexer-grpc/transaction-filter/src/filters/event.rs @@ -6,6 +6,21 @@ use anyhow::Error; use aptos_protos::transaction::v1::{move_type::Content, Event}; use serde::{Deserialize, Serialize}; +/// Example: +/// ``` +/// use aptos_transaction_filter::{EventFilterBuilder, MoveStructTagFilterBuilder}; +/// +/// let move_struct_tag_filter = MoveStructTagFilterBuilder::default() +/// .address("0x0077") +/// .module("roulette") +/// .name("spin") +/// .build() +/// .unwrap(); +/// let filter = EventFilterBuilder::default() +/// .struct_type(move_struct_tag_filter) +/// .build() +/// .unwrap(); +/// ``` #[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] #[serde(deny_unknown_fields)] #[derive(derive_builder::Builder)] diff --git a/ecosystem/indexer-grpc/transaction-filter/src/filters/mod.rs b/ecosystem/indexer-grpc/transaction-filter/src/filters/mod.rs index 00aad253dfdc2..289a629c65c79 100644 --- a/ecosystem/indexer-grpc/transaction-filter/src/filters/mod.rs +++ b/ecosystem/indexer-grpc/transaction-filter/src/filters/mod.rs @@ -13,6 +13,7 @@ pub use event::EventFilterBuilder; pub use move_module::{MoveStructTagFilter, MoveStructTagFilterBuilder}; pub use transaction_root::{TransactionRootFilter, TransactionRootFilterBuilder}; pub use user_transaction::{ - UserTransactionFilter, UserTransactionFilterBuilder, UserTransactionPayloadFilter, + EntryFunctionFilter, EntryFunctionFilterBuilder, UserTransactionFilter, + UserTransactionFilterBuilder, UserTransactionPayloadFilter, UserTransactionPayloadFilterBuilder, }; diff --git a/ecosystem/indexer-grpc/transaction-filter/src/filters/move_module.rs b/ecosystem/indexer-grpc/transaction-filter/src/filters/move_module.rs index 7cd3de0ea2712..c78fb5da1e6af 100644 --- a/ecosystem/indexer-grpc/transaction-filter/src/filters/move_module.rs +++ b/ecosystem/indexer-grpc/transaction-filter/src/filters/move_module.rs @@ -6,6 +6,17 @@ use anyhow::anyhow; use aptos_protos::transaction::v1::MoveStructTag; use serde::{Deserialize, Serialize}; +/// Example: +/// ``` +/// use aptos_transaction_filter::MoveStructTagFilterBuilder; +/// +/// let filter = MoveStructTagFilterBuilder::default() +/// .address("0x0000000000000000000000000000000000000000000000000000000000000004") +/// .module("aptos_token") +/// .name("Token") +/// .build() +/// .unwrap(); +/// ``` #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] #[derive(derive_builder::Builder)] diff --git a/ecosystem/indexer-grpc/transaction-filter/src/filters/transaction_root.rs b/ecosystem/indexer-grpc/transaction-filter/src/filters/transaction_root.rs index 60b5ae5e00aa2..8cc684d13f4b7 100644 --- a/ecosystem/indexer-grpc/transaction-filter/src/filters/transaction_root.rs +++ b/ecosystem/indexer-grpc/transaction-filter/src/filters/transaction_root.rs @@ -6,6 +6,15 @@ use anyhow::Error; use aptos_protos::transaction::v1::{transaction::TransactionType, Transaction}; use serde::{Deserialize, Serialize}; +/// Example: +/// ``` +/// use aptos_transaction_filter::TransactionRootFilterBuilder; +/// +/// let filter = TransactionRootFilterBuilder::default() +/// .success(true) +/// .build() +/// .unwrap(); +/// ``` #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] #[derive(derive_builder::Builder)] diff --git a/ecosystem/indexer-grpc/transaction-filter/src/filters/user_transaction.rs b/ecosystem/indexer-grpc/transaction-filter/src/filters/user_transaction.rs index 19bcfb6a76e71..6c4207bc39691 100644 --- a/ecosystem/indexer-grpc/transaction-filter/src/filters/user_transaction.rs +++ b/ecosystem/indexer-grpc/transaction-filter/src/filters/user_transaction.rs @@ -11,6 +11,14 @@ use serde::{Deserialize, Serialize}; /// We use this for UserTransactions. /// We support UserPayload and MultisigPayload +/// +/// Example: +/// ``` +/// use aptos_transaction_filter::UserTransactionFilterBuilder; +/// +/// let address = "0x806b27f3d7824a1d78c4291b6d0371aa693437f9eb3393c6440519c0ffaa627f"; +/// let filter = UserTransactionFilterBuilder::default().sender(address).build().unwrap(); +/// ``` #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] #[derive(derive_builder::Builder)] @@ -69,6 +77,17 @@ impl Filterable for UserTransactionFilter { } } +/// Example: +/// ``` +/// use aptos_transaction_filter::EntryFunctionFilterBuilder; +/// +/// let filter = EntryFunctionFilterBuilder::default() +/// .address("0x0000000000000000000000000000000000000000000000000000000000000001") +/// .module("coin") +/// .function("transfer") +/// .build() +/// .unwrap(); +/// ``` #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] #[derive(derive_builder::Builder)] @@ -113,6 +132,21 @@ impl Filterable for EntryFunctionFilter { } } +/// Example: +/// ``` +/// use aptos_transaction_filter::{EntryFunctionFilterBuilder, UserTransactionPayloadFilterBuilder}; +/// +/// let entry_function_filter = EntryFunctionFilterBuilder::default() +/// .address("0x0000000000000000000000000000000000000000000000000000000000000001") +/// .module("coin") +/// .function("transfer") +/// .build() +/// .unwrap(); +/// let filter = UserTransactionPayloadFilterBuilder::default() +/// .function(entry_function_filter) +/// .build() +/// .unwrap(); +/// ``` #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] #[derive(derive_builder::Builder)] diff --git a/ecosystem/indexer-grpc/transaction-filter/src/lib.rs b/ecosystem/indexer-grpc/transaction-filter/src/lib.rs index ed01c2ec4da2f..fecb7e30dacc6 100644 --- a/ecosystem/indexer-grpc/transaction-filter/src/lib.rs +++ b/ecosystem/indexer-grpc/transaction-filter/src/lib.rs @@ -6,8 +6,9 @@ pub mod errors; pub mod filters; pub mod traits; -// re-export for convenience +// Re-exports for convenience. pub use boolean_transaction_filter::BooleanTransactionFilter; +pub use filters::*; pub use traits::Filterable; #[cfg(test)] diff --git a/ecosystem/indexer-grpc/transaction-filter/src/test_lib/mod.rs b/ecosystem/indexer-grpc/transaction-filter/src/test_lib/mod.rs index 5d11a99e50649..76c44c07b625b 100644 --- a/ecosystem/indexer-grpc/transaction-filter/src/test_lib/mod.rs +++ b/ecosystem/indexer-grpc/transaction-filter/src/test_lib/mod.rs @@ -30,7 +30,6 @@ pub fn load_random_april_3mb_fixture() -> TransactionsInStorage { decompress_fixture(data) } -#[allow(dead_code)] pub fn load_graffio_fixture() -> TransactionsInStorage { let data = include_bytes!( "../../fixtures/compressed_files_lz4_f3d880d9700c70d71fefe71aa9218aa9_301616000.pb.lz4" diff --git a/ecosystem/indexer-grpc/transaction-filter/src/traits.rs b/ecosystem/indexer-grpc/transaction-filter/src/traits.rs index 9024b1e04ad4b..e259201a12c80 100644 --- a/ecosystem/indexer-grpc/transaction-filter/src/traits.rs +++ b/ecosystem/indexer-grpc/transaction-filter/src/traits.rs @@ -15,18 +15,17 @@ where /// The actual public API is via `is_valid` which will call `validate_state` and return an error if it fails, but annotated with the filter type/path fn validate_state(&self) -> Result<(), FilterError>; - /** - * This is a convenience method to allow for the error to be annotated with the filter type/path at each level - * This is the public API for checking the validity of a filter! - * Example output looks like: - * ```text - * FilterError: This is a test error!. - * Trace Path: - * transaction_filter::traits::test::InnerStruct: {"a":"test"} - * core::option::Option: {"a":"test"} - * transaction_filter::traits::test::OuterStruct: {"inner":{"a":"test"}} - * ``` - **/ + /// This is a convenience method to allow for the error to be annotated with the filter type/path at each level + /// This is the public API for checking the validity of a filter! + /// Example output looks like: + /// ```text + /// FilterError: This is a test error!. + /// Trace Path: + /// transaction_filter::traits::test::InnerStruct: {"a":"test"} + /// core::option::Option: {"a":"test"} + /// transaction_filter::traits::test::OuterStruct: {"inner":{"a":"test"}} + /// ``` + /// #[inline] fn is_valid(&self) -> Result<(), FilterError> { // T @@ -76,7 +75,7 @@ where } } -/// This allows for Option to always return true: i.e if the filter is None, then all items are allowed. +/// This allows for `Option` to always return true: i.e if the filter is None, then all items are allowed. impl Filterable for Option where F: Filterable,