Skip to content

Commit

Permalink
Simpler Transaction Filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
CapCap committed May 31, 2024
1 parent b412cc8 commit 236b94d
Show file tree
Hide file tree
Showing 14 changed files with 786 additions and 5 deletions.
41 changes: 37 additions & 4 deletions rust/Cargo.lock

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

3 changes: 2 additions & 1 deletion rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[workspace]
resolver = "2"

members = ["indexer-metrics", "moving-average", "processor", "server-framework"]
members = ["indexer-metrics", "moving-average", "processor", "server-framework", "transaction-filter"]

[workspace.package]
authors = ["Aptos Labs <[email protected]>"]
Expand Down Expand Up @@ -86,6 +86,7 @@ sha2 = "0.9.3"
sha3 = "0.9.1"
strum = { version = "0.24.1", features = ["derive"] }
tempfile = "3.3.0"
thiserror = "1.0.61"
toml = "0.7.4"
tracing-subscriber = { version = "0.3.17", features = ["json", "env-filter"] }
tokio = { version = "1.35.1", features = ["full"] }
Expand Down
29 changes: 29 additions & 0 deletions rust/transaction-filter/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[package]
name = "transaction-filter"
version = "0.1.0"

# Workspace inherited keys
authors = { workspace = true }
edition = { workspace = true }
homepage = { workspace = true }
license = { workspace = true }
publish = { workspace = true }
repository = { workspace = true }
rust-version = { workspace = true }
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
anyhow = { workspace = true }
aptos-protos = { workspace = true }

prost = { workspace = true }

serde = { workspace = true }
serde_json = { workspace = true }

thiserror = { workspace = true }

[dev-dependencies]
# we only decompress the fixture protos in tests
lz4 = "1.24.0"

Binary file not shown.
Binary file not shown.
Binary file not shown.
39 changes: 39 additions & 0 deletions rust/transaction-filter/src/filters/event_filter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use crate::{filters::MoveStructTagFilter, traits::Filterable};
use anyhow::Error;
use aptos_protos::transaction::v1::{move_type::Content, Event};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct EventFilter {
// Only for events that have a struct as their generic
#[serde(skip_serializing_if = "Option::is_none")]
pub struct_type: Option<MoveStructTagFilter>,
}

impl Filterable<Event> for EventFilter {
fn is_valid(&self) -> Result<(), Error> {
if self.struct_type.is_none() {
return Err(Error::msg("At least one of struct_type must be set"));
};

self.struct_type.is_valid()?;
Ok(())
}

fn is_allowed(&self, item: &Event) -> bool {
if let Some(struct_type_filter) = &self.struct_type {
if let Some(Content::Struct(struct_tag)) =
&item.r#type.as_ref().and_then(|t| t.content.as_ref())
{
if !struct_type_filter.is_allowed(struct_tag) {
return false;
}
} else {
return false;
}
}

true
}
}
12 changes: 12 additions & 0 deletions rust/transaction-filter/src/filters/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
pub mod event_filter;
pub mod move_module;
pub mod transaction_root;
pub mod user_transaction_request;
pub mod write_set_change_filter;

// Re-export for easier use
pub use event_filter::EventFilter;
pub use move_module::{MoveModuleFilter, MoveStructTagFilter};
pub use transaction_root::TransactionRootFilter;
pub use user_transaction_request::{UserTransactionPayloadFilter, UserTransactionRequestFilter};
pub use write_set_change_filter::WriteSetChangeFilter;
54 changes: 54 additions & 0 deletions rust/transaction-filter/src/filters/move_module.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use crate::traits::Filterable;
use anyhow::{anyhow, Error};
use aptos_protos::transaction::v1::{MoveModuleId, MoveStructTag};
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct MoveModuleFilter {
#[serde(skip_serializing_if = "Option::is_none")]
pub address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
}

impl Filterable<MoveModuleId> for MoveModuleFilter {
fn is_valid(&self) -> Result<(), Error> {
if self.address.is_none() && self.name.is_none() {
return Err(anyhow!("At least one of address or name must be set"));
};
Ok(())
}

fn is_allowed(&self, module_id: &MoveModuleId) -> bool {
self.address.is_allowed(&module_id.address) && self.name.is_allowed(&module_id.name)
}
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct MoveStructTagFilter {
#[serde(skip_serializing_if = "Option::is_none")]
pub address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub module: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
}

impl Filterable<MoveStructTag> for MoveStructTagFilter {
fn is_valid(&self) -> Result<(), Error> {
if self.address.is_none() && self.module.is_none() && self.name.is_none() {
return Err(anyhow!(
"At least one of address, module or name must be set"
));
};
Ok(())
}

fn is_allowed(&self, struct_tag: &MoveStructTag) -> bool {
self.address.is_allowed(&struct_tag.address)
&& self.module.is_allowed(&struct_tag.module)
&& self.name.is_allowed(&struct_tag.name)
}
}
43 changes: 43 additions & 0 deletions rust/transaction-filter/src/filters/transaction_root.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use crate::traits::Filterable;
use anyhow::Error;
use aptos_protos::transaction::v1::{transaction::TransactionType, Transaction};
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct TransactionRootFilter {
#[serde(skip_serializing_if = "Option::is_none")]
pub success: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub txn_type: Option<TransactionType>,
}

impl Filterable<Transaction> for TransactionRootFilter {
fn is_valid(&self) -> Result<(), Error> {
if self.success.is_none() && self.txn_type.is_none() {
return Err(Error::msg(
"At least one of success or txn_types must be set",
));
};
Ok(())
}

fn is_allowed(&self, item: &Transaction) -> bool {
if !self
.success
.is_allowed_opt(&item.info.as_ref().map(|i| i.success))
{
return false;
}

if let Some(txn_type) = &self.txn_type {
if txn_type
!= &TransactionType::try_from(item.r#type).expect("Invalid transaction type")
{
return false;
}
}

true
}
}
Loading

0 comments on commit 236b94d

Please sign in to comment.