跳转到内容

交易筛选

随着 Indexer gRPC v2 的发布,我们引入了交易筛选功能。 交易筛选使你可以根据特定条件,有选择地处理 Aptos 区块链交易。 当构建仅需处理所有交易子集的 Indexer 或服务时,这尤其有用,例如:

  • 跟踪特定智能合约交互
  • 监控特定地址的钱包活动
  • 为特定模块中的事件建立索引
  • 仅处理成功交易

源代码位于 aptos-core

通过在交易流的 gRPC 请求中包含交易筛选器来应用筛选。

筛选系统定义于 aptos/indexer/v1/filter.proto

message BooleanTransactionFilter {
oneof filter {
APIFilter api_filter = 1;
LogicalAndFilters logical_and = 2;
LogicalOrFilters logical_or = 3;
BooleanTransactionFilter logical_not = 4;
}
}
message APIFilter {
oneof filter {
TransactionRootFilter transaction_root_filter = 1;
UserTransactionFilter user_transaction_filter = 2;
EventFilter event_filter = 3;
}
}

GetTransactionsRequest 消息中,筛选器作为可选参数提供:

message GetTransactionsRequest {
// Required; start version of current stream.
optional uint64 starting_version = 1;
// Optional; number of transactions to return in current stream.
optional uint64 transactions_count = 2;
// Optional; number of transactions in each response batch.
optional uint64 batch_size = 3;
// Optional; if provided, only transactions matching the filter are included.
optional BooleanTransactionFilter transaction_filter = 4;
}

示例:

可以利用交易筛选器,从 Geomi 的 gRPC 端点获取所有用户交易:

Terminal window
grpcurl \
-d '{"transaction_filter":{"api_filter":{"transaction_root_filter":{"transaction_type":"TRANSACTION_TYPE_USER"}}}}' \
-max-msg-sz 30000000 \
-H "authorization:Bearer <api_key>" \
grpc.mainnet.aptoslabs.com:443 \
aptos.indexer.v1.RawData/GetTransactions

要点:

  • transaction_filter 字段是可选的,省略它即可流式传输所有交易
  • 提供筛选器时,只返回符合筛选条件的交易
  • 筛选器在服务端应用,可降低客户端的带宽和处理开销
  • 筛选器会在应用前验证;无效筛选器将产生错误响应

交易筛选系统采用声明式方法:指定要使用筛选器匹配的内容,再使用布尔逻辑(AND、OR、NOT)组合它们。 可在以下位置定义筛选器:

  • 使用构建器模式的 Rust 代码
  • 用于 API 配置的 JSON
  • 用于配置文件的 YAML

可使用三种主要筛选器类型:

根据顶层交易属性筛选交易。

可用字段:

  • success(布尔值):交易成功或失败
  • txn_type(枚举):交易类型(User、Genesis、BlockMetadata、StateCheckpoint、Validator、BlockEpilogue)

示例:

{
"type": "TransactionRootFilter",
"txn_type": "User",
"success": true
}

根据发送者和入口函数详细信息筛选用户提交的交易。

可用字段:

  • sender(字符串):提交交易的账户地址
  • payload:筛选被调用的入口函数
    • function:入口函数详细信息
      • address(字符串):合约地址
      • module(字符串):模块名称
      • function(字符串):函数名称

示例:

{
"type": "UserTransactionFilter",
"sender": "0x1",
"payload": {
"function": {
"address": "0x1",
"module": "coin",
"function": "transfer"
}
}
}

根据交易发出的事件筛选交易。

可用字段:

  • struct_type:按事件的 Move 结构体类型筛选
    • address(字符串):合约地址
    • module(字符串):模块名称
    • name(字符串):结构体名称
  • data_substring_filter(字符串):按事件数据中的子字符串筛选事件

示例 1:按结构体类型筛选:

{
"type": "EventFilter",
"struct_type": {
"address": "0x1",
"module": "coin",
"name": "CoinDeposit"
}
}

示例 2:按数据子字符串筛选:

{
"type": "EventFilter",
"data_substring_filter": "transfer"
}

示例 3:组合结构体类型和数据子字符串:

{
"type": "EventFilter",
"struct_type": {
"address": "0x1",
"module": "coin"
},
"data_substring_filter": "0xabc123"
}

可使用逻辑运算符组合筛选器,以创建复杂查询:

匹配满足指定全部筛选器的交易。

{
"and": [
{
"type": "TransactionRootFilter",
"success": true
},
{
"type": "EventFilter",
"struct_type": {
"address": "0x1",
"module": "coin",
"name": "CoinDeposit"
}
}
]
}

匹配满足指定筛选器中任意一个的交易。

{
"or": [
{
"type": "UserTransactionFilter",
"sender": "0xabc..."
},
{
"type": "UserTransactionFilter",
"sender": "0xdef..."
}
]
}

匹配满足指定筛选器的交易。

{
"not": {
"type": "TransactionRootFilter",
"success": false
}
}

匹配所有成功的代币转账交易:

{
"and": [
{
"type": "TransactionRootFilter",
"success": true
},
{
"type": "UserTransactionFilter",
"payload": {
"function": {
"address": "0x1",
"module": "coin",
"function": "transfer"
}
}
}
]
}

跟踪特定钱包的所有交易:

{
"type": "UserTransactionFilter",
"sender": "0x806b27f3d7824a1d78c4291b6d0371aa693437f9eb3393c6440519c0ffaa627f"
}

跟踪多个钱包的交易:

{
"or": [
{
"type": "UserTransactionFilter",
"sender": "0xabc..."
},
{
"type": "UserTransactionFilter",
"sender": "0xdef..."
}
]
}

跟踪来自特定集合的 NFT 铸造事件:

{
"type": "EventFilter",
"struct_type": {
"address": "0x4",
"module": "aptos_token",
"name": "MintTokenEvent"
}
}

跟踪与特定智能合约模块的全部交互:

{
"type": "EventFilter",
"struct_type": {
"address": "0x123abc...",
"module": "my_defi_module"
}
}

跟踪来自多个 DEX 协议的成功兑换事件:

{
"and": [
{
"type": "TransactionRootFilter",
"success": true
},
{
"or": [
{
"type": "EventFilter",
"struct_type": {
"address": "0xdex1",
"module": "swap",
"name": "SwapEvent"
}
},
{
"type": "EventFilter",
"struct_type": {
"address": "0xdex2",
"module": "pool",
"name": "TradeEvent"
}
}
]
}
]
}

获取除失败交易外的所有用户交易:

{
"and": [
{
"type": "UserTransactionFilter",
"sender": "0xabc..."
},
{
"type": "TransactionRootFilter",
"success": true
}
]
}

筛选器也可用 YAML 格式表示,该格式通常更适合配置文件阅读:

and:
- or:
- type: TransactionRootFilter
success: true
- type: UserTransactionFilter
sender: '0x1'
- type: EventFilter
struct_type:
address: '0x1'
module: coin
name: CoinDeposit

如果使用 Rust 构建,可以配合构建器模式使用 aptos-transaction-filter crate:

use aptos_transaction_filter::{TransactionRootFilterBuilder, BooleanTransactionFilter};
// Create a filter for successful transactions
let filter = TransactionRootFilterBuilder::default()
.success(true)
.build()
.unwrap();
let boolean_filter = BooleanTransactionFilter::from(filter);
use aptos_transaction_filter::{EventFilterBuilder, MoveStructTagFilterBuilder};
let filter = EventFilterBuilder::default()
.struct_type(
MoveStructTagFilterBuilder::default()
.address("0x1")
.module("coin")
.name("CoinDeposit")
.build()
.unwrap()
)
.build()
.unwrap();
use aptos_transaction_filter::{UserTransactionFilterBuilder, EntryFunctionFilterBuilder, UserTransactionPayloadFilterBuilder};
let filter = UserTransactionFilterBuilder::default()
.sender("0x1")
.payload(
UserTransactionPayloadFilterBuilder::default()
.function(
EntryFunctionFilterBuilder::default()
.address("0x1")
.module("coin")
.function("transfer")
.build()
.unwrap()
)
.build()
.unwrap()
)
.build()
.unwrap();
use aptos_transaction_filter::BooleanTransactionFilter;
// Create individual filters
let success_filter = TransactionRootFilterBuilder::default()
.success(true)
.build()
.unwrap();
let sender_filter = UserTransactionFilterBuilder::default()
.sender("0x1")
.build()
.unwrap();
let event_filter = EventFilterBuilder::default()
.struct_type(
MoveStructTagFilterBuilder::default()
.address("0x1")
.module("coin")
.build()
.unwrap()
)
.build()
.unwrap();
// Combine with logical operators
let combined = BooleanTransactionFilter::from(success_filter)
.or(sender_filter)
.and(event_filter);
// Use the filter
if combined.matches(&transaction) {
// Process transaction
}
// Serialize to JSON
let json = serde_json::to_string_pretty(&filter).unwrap();
// Serialize to YAML
let yaml = serde_yaml::to_string(&filter).unwrap();
// Deserialize from JSON
let filter: BooleanTransactionFilter = serde_json::from_str(&json).unwrap();

交易筛选系统针对高吞吐处理进行了优化:

  1. 单次遍历:筛选器仅处理每笔交易一次
  2. 最少分配:筛选器避免 clone 和不必要的复制
  3. 提前退出:一旦发现不匹配,筛选器便短路退出
  4. 地址缓存:缓存地址标准化结果以提升性能

为获得最佳性能:

  • 尽可能使用特定筛选器(例如按地址筛选,而不是筛选所有交易)
  • 在 AND 操作中先放置限制更严格的筛选器
  • 设计筛选器时考虑 mainnet 上的交易量