Filtrado de Transacciones
Descripción General
Sección titulada «Descripción General»Con el lanzamiento de Indexer gRPC v2, introducimos la función de filtrado de transacciones. El filtrado de transacciones te permite procesar selectivamente transacciones de la blockchain de Aptos basándote en criterios específicos. Esto es particularmente útil cuando construyes indexadores o servicios que solo necesitan procesar un subconjunto de todas las transacciones, como:
- Rastrear interacciones específicas de contratos inteligentes
- Monitorear actividad de billeteras para ciertas direcciones
- Indexar eventos de módulos particulares
- Procesar solo transacciones exitosas
El código fuente se puede encontrar en aptos-core.
Definiciones de Protocol Buffers (Proto)
Sección titulada «Definiciones de Protocol Buffers (Proto)»Los filtros de transacciones se aplican incluyéndolos en la solicitud gRPC al stream de transacciones.
Estructura Proto del Filtro
Sección titulada «Estructura Proto del Filtro»El sistema de filtrado está definido en 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; }}Integración con Solicitud gRPC
Sección titulada «Integración con Solicitud gRPC»Los filtros se proporcionan como un parámetro opcional en el mensaje GetTransactionsRequest:
message GetTransactionsRequest { // Requerido; versión inicial del stream actual. optional uint64 starting_version = 1;
// Opcional; número de transacciones a retornar en el stream actual. optional uint64 transactions_count = 2;
// Opcional; número de transacciones en cada lote de respuesta. optional uint64 batch_size = 3;
// Opcional; si se proporciona, solo se incluyen las transacciones que coincidan con el filtro. optional BooleanTransactionFilter transaction_filter = 4;}Ejemplo:
Podemos utilizar el filtro de transacciones para obtener todas las transacciones de usuario desde el endpoint gRPC de Geomi:
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/GetTransactionsPuntos Clave:
- El campo
transaction_filteres opcional - puedes transmitir todas las transacciones omitiéndolo - Cuando se proporciona, solo se retornarán las transacciones que coincidan con los criterios del filtro
- El filtro se aplica del lado del servidor, reduciendo el ancho de banda y la sobrecarga de procesamiento para los clientes
- Los filtros se validan antes de aplicarse; los filtros inválidos resultarán en una respuesta de error
Cómo Funciona
Sección titulada «Cómo Funciona»El sistema de filtros de transacciones usa un enfoque declarativo donde especificas qué quieres coincidir usando filtros, y luego los combinas usando lógica booleana (AND, OR, NOT). Los filtros pueden definirse en:
- Código Rust usando patrones de construcción
- JSON para configuración basada en API
- YAML para archivos de configuración
Tipos de Filtros
Sección titulada «Tipos de Filtros»Hay tres tipos principales de filtros que puedes usar:
1. Filtro de Raíz de Transacción
Sección titulada «1. Filtro de Raíz de Transacción»Filtra transacciones basándose en propiedades de nivel superior de la transacción.
Campos Disponibles:
success(boolean): Si la transacción tuvo éxito o fallótxn_type(enum): El tipo de transacción (User, Genesis, BlockMetadata, StateCheckpoint, Validator, BlockEpilogue)
Ejemplo:
{ "type": "TransactionRootFilter", "txn_type": "User", "success": true}2. Filtro de Transacción de Usuario
Sección titulada «2. Filtro de Transacción de Usuario»Filtra transacciones enviadas por usuarios basándose en el remitente y detalles de la función de entrada.
Campos Disponibles:
sender(string): La dirección de cuenta que envió la transacciónpayload: Filtrar por la función de entrada que se llamafunction: Detalles de la función de entradaaddress(string): Dirección del contratomodule(string): Nombre del módulofunction(string): Nombre de la función
Ejemplo:
{ "type": "UserTransactionFilter", "sender": "0x1", "payload": { "function": { "address": "0x1", "module": "coin", "function": "transfer" } }}3. Filtro de Eventos
Sección titulada «3. Filtro de Eventos»Filtra transacciones basándose en los eventos que emiten.
Campos Disponibles:
struct_type: Filtrar por el tipo de struct Move del eventoaddress(string): Dirección del contratomodule(string): Nombre del móduloname(string): Nombre del struct
data_substring_filter(string): Filtrar eventos por una subcadena en sus datos
Ejemplo 1 - Filtrar por tipo de struct:
{ "type": "EventFilter", "struct_type": { "address": "0x1", "module": "coin", "name": "CoinDeposit" }}Ejemplo 2 - Filtrar por subcadena de datos:
{ "type": "EventFilter", "data_substring_filter": "transfer"}Ejemplo 3 - Combinar tipo de struct y subcadena de datos:
{ "type": "EventFilter", "struct_type": { "address": "0x1", "module": "coin" }, "data_substring_filter": "0xabc123"}Combinando Filtros con Lógica Booleana
Sección titulada «Combinando Filtros con Lógica Booleana»Los filtros pueden combinarse usando operadores lógicos para crear consultas complejas:
Operador AND
Sección titulada «Operador AND»Coincide con transacciones que satisfacen todos los filtros especificados.
{ "and": [ { "type": "TransactionRootFilter", "success": true }, { "type": "EventFilter", "struct_type": { "address": "0x1", "module": "coin", "name": "CoinDeposit" } } ]}Operador OR
Sección titulada «Operador OR»Coincide con transacciones que satisfacen cualquiera de los filtros especificados.
{ "or": [ { "type": "UserTransactionFilter", "sender": "0xabc..." }, { "type": "UserTransactionFilter", "sender": "0xdef..." } ]}Operador NOT
Sección titulada «Operador NOT»Coincide con transacciones que no satisfacen el filtro especificado.
{ "not": { "type": "TransactionRootFilter", "success": false }}Casos de Uso Comunes
Sección titulada «Casos de Uso Comunes»Filtrar Transacciones de Transferencia de Monedas
Sección titulada «Filtrar Transacciones de Transferencia de Monedas»Coincidir con todas las transacciones de transferencia de monedas exitosas:
{ "and": [ { "type": "TransactionRootFilter", "success": true }, { "type": "UserTransactionFilter", "payload": { "function": { "address": "0x1", "module": "coin", "function": "transfer" } } } ]}Filtrar por Remitente Específico
Sección titulada «Filtrar por Remitente Específico»Rastrear todas las transacciones de una billetera específica:
{ "type": "UserTransactionFilter", "sender": "0x806b27f3d7824a1d78c4291b6d0371aa693437f9eb3393c6440519c0ffaa627f"}Filtrar por Múltiples Remitentes
Sección titulada «Filtrar por Múltiples Remitentes»Rastrear transacciones de múltiples billeteras:
{ "or": [ { "type": "UserTransactionFilter", "sender": "0xabc..." }, { "type": "UserTransactionFilter", "sender": "0xdef..." } ]}Filtrar Eventos NFT
Sección titulada «Filtrar Eventos NFT»Rastrear eventos de acuñación de NFT de una colección específica:
{ "type": "EventFilter", "struct_type": { "address": "0x4", "module": "aptos_token", "name": "MintTokenEvent" }}Filtrar Interacciones con Contratos Inteligentes
Sección titulada «Filtrar Interacciones con Contratos Inteligentes»Rastrear todas las interacciones con un módulo de contrato inteligente específico:
{ "type": "EventFilter", "struct_type": { "address": "0x123abc...", "module": "my_defi_module" }}Filtro Complejo: Trading DEX
Sección titulada «Filtro Complejo: Trading DEX»Rastrear eventos de intercambio exitosos de múltiples protocolos 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" } } ] } ]}Excluir Transacciones Fallidas
Sección titulada «Excluir Transacciones Fallidas»Obtener todas las transacciones de usuario excepto las fallidas:
{ "and": [ { "type": "UserTransactionFilter", "sender": "0xabc..." }, { "type": "TransactionRootFilter", "success": true } ]}Formato YAML
Sección titulada «Formato YAML»Los filtros también pueden expresarse en formato YAML, que a menudo es más legible para archivos de configuración:
and: - or: - type: TransactionRootFilter success: true - type: UserTransactionFilter sender: '0x1' - type: EventFilter struct_type: address: '0x1' module: coin name: CoinDepositUsando Filtros en Rust
Sección titulada «Usando Filtros en Rust»Si estás construyendo con Rust, puedes usar el crate aptos-transaction-filter con patrones de construcción:
Filtro Básico
Sección titulada «Filtro Básico»use aptos_transaction_filter::{TransactionRootFilterBuilder, BooleanTransactionFilter};
// Crear un filtro para transacciones exitosaslet filter = TransactionRootFilterBuilder::default() .success(true) .build() .unwrap();
let boolean_filter = BooleanTransactionFilter::from(filter);Filtro de Eventos
Sección titulada «Filtro de Eventos»use aptos_transaction_filter::{EventFilterBuilder, MoveStructTagFilterBuilder};
let filter = EventFilterBuilder::default() .struct_type( MoveStructTagFilterBuilder::default() .address("0x1") .module("coin") .name("CoinDeposit") .build() .unwrap() ) .build() .unwrap();Filtro de Transacción de Usuario
Sección titulada «Filtro de Transacción de Usuario»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();Combinando Filtros
Sección titulada «Combinando Filtros»use aptos_transaction_filter::BooleanTransactionFilter;
// Crear filtros individualeslet 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();
// Combinar con operadores lógicoslet combined = BooleanTransactionFilter::from(success_filter) .or(sender_filter) .and(event_filter);
// Usar el filtroif combined.matches(&transaction) { // Procesar transacción}Serialización
Sección titulada «Serialización»// Serializar a JSONlet json = serde_json::to_string_pretty(&filter).unwrap();
// Serializar a YAMLlet yaml = serde_yaml::to_string(&filter).unwrap();
// Deserializar desde JSONlet filter: BooleanTransactionFilter = serde_json::from_str(&json).unwrap();Consideraciones de Rendimiento
Sección titulada «Consideraciones de Rendimiento»El sistema de filtros de transacciones está optimizado para procesamiento de alto rendimiento:
- Pasada Única: Los filtros procesan cada transacción solo una vez
- Mínimas Asignaciones: Los filtros evitan clones y copias innecesarias
- Salida Temprana: Los filtros hacen cortocircuito tan pronto como se encuentra una no-coincidencia
- Caché de Direcciones: La estandarización de direcciones se almacena en caché para mejorar el rendimiento
Para mejor rendimiento:
- Usa filtros específicos cuando sea posible (ej. filtrar por dirección en lugar de todas las transacciones)
- Coloca filtros más restrictivos primero en operaciones AND
- Considera el volumen de transacciones en mainnet al diseñar filtros