Ir al contenido principal

Relleno de datos en la cadena de bloques: Streams

Actualizado el
20 de julio de 2026

El «backfilling» es el proceso de recuperar datos históricos de la cadena de bloques para alimentar bases de datos, analizar tendencias pasadas o auditar transacciones. Tanto si necesitas indexar una cadena completa desde el bloque Génesis como si solo quieres ponerte al día con la actividad de las últimas 24 horas, la recuperación eficiente de datos históricos supone un reto fundamental para la infraestructura.

Streams facilitan el rellenado de datos históricos gracias a plantillas de un solo clic, filtrado del lado del servidor, opciones de procesamiento por lotes y compresión, y entrega garantizada a tu destino preferido. En lugar de escribir scripts complejos para sondear puntos finales RPC, basta con configurar un Stream, establecer el rango de bloques y, si se desea, aplicar filtros para extraer solo los datos que necesitas; así, Streams los datos a tu destino (por ejemplo, Webhook, S3, PostgreSQL, Azure Storage, etc.) de forma fiable y a gran escala.

¿Por qué utilizar Streams el relleno?

Streams los aspectos relacionados con la infraestructura, como los reintentos, la ordenación de bloques y la gestión de errores, lo que te permite centrarte exclusivamente en la lógica de datos de tu aplicación.

CaracterísticaDescripción
FiltrosPuedes procesar y transformar los datos en el servidor antes de su envío mediante filtros. Utiliza decodificar recibos EVM para la decodificación hexadecimal, la creación de cargas útiles personalizadas y la depuración con console.log().
Agrupación y compresiónPuedes configurar tamaño_del_lote_del_conjunto_de_datos (p. ej., 10-100) para agrupar varios bloques por solicitud. También puedes activar compresión: «gzip» en configuración de destino.
Almacén de clave-valorPuedes guardar listas de seguimiento, ABI, o valores de configuración, y acceder a ellos en los filtros mediante qnLib métodos. También puedes gestionar los valores a través de la API REST.
API RESTPuedes crear, actualizar, pausar y eliminar Streams mediante programación Streams la API REST.
MulticadenaCada «Stream» está destinado a una cadena o red concreta. Puedes ejecutar varios Streams paralelo para realizar rellenos en múltiples cadenas. Consulta «Cadenas compatibles».
Transición en tiempo realPuedes omitir fin_rango para continuar con la transmisión una vez finalizada la recuperación de datos. Puedes utilizar elastic_batch_enabled para reducir automáticamente el tamaño del lote en la punta y mantener_distancia_respecto_a_la_punta para reducir reorganización frecuencia.

Estimación de los costes de relleno

La recuperación de datos históricos de la cadena de bloques consume créditos de API en función del número de bloques procesados, aplicando los multiplicadores del conjunto de datos de red. Streams el mismo fondo común de créditos de API que RPC.

Utiliza la calculadora de créditos de la API para calcular los costes de relleno antes de empezar. La calculadora muestra:


  • Total de créditos API necesarios para completar los bloques históricos disponibles
  • Créditos por bloque en función del conjunto de datos y la red seleccionados
  • ¿Qué redes admiten el «backfilling»? (Solana , por ejemplo, no admiten actualmente el «backfilling»).

Cómo rellenar datos


  1. Selecciona tu cadena y tu red. Consulta las cadenas compatibles con Streams.

  2. Define el rango de bloques. Puedes elegir si quieres empezar desde el bloque Génesis o desde una altura de bloque concreta. En cuanto al bloque final, puedes establecerlo en una altura concreta o elegir la transmisión continua para seguir recibiendo nuevos bloques.

  3. Selecciona tu conjunto de datos. Streams diferentes conjuntos de datos, como «Block», «Block con recibos», «Transacciones», «Registros», etc. Elige el que mejor se adapte a tu caso de uso. Consulta la sección «Datos retrospectivos por ecosistema» más abajo para ver los conjuntos de datos específicos de cada cadena.

  4. Aplica filtros (opcional). Utiliza el filtrado del lado del servidor para limitar los datos que deseas recibir.

  5. Elige tu destino. Configura dónde quieres que se envíen los datos, como Webhooks, S3, PostgreSQL, etc. Consulta la documentación sobre destinos para obtener más detalles.

  6. Comprueba la conexión y envía una carga de prueba en la página de configuración de Stream para asegurarte de que todo está configurado correctamente.

  7. Inicia la retransmisión.

¿No sabes qué ajustes elegir?

Consulta nuestros «Consejos para el relleno» a continuación para obtener recomendaciones sobre la preparación de lotes, la compresión y la optimización del rendimiento.

Datos de relleno por ecosistema

Streams utilizar para completar datos de cualquier ecosistema, incluidos Ethereum, Bitcoin, Solana y otros. Dado que tienen estructuras y formatos de datos diferentes, selecciona tu ecosistema a continuación para ver conjuntos de datos específicos de cada cadena, filtros de ejemplo y respuestas.


Ethereum las cadenas EVM

Streams numerosas cadenas EVM, entre las que se incluyen Ethereum, Base, Arbitrum y BNB Smart Chain. Todas las cadenas EVM comparten una arquitectura y una estructura de datos similares, por lo que los filtros y los formatos de carga útil suelen ser los mismos en todas las cadenas, aunque pueden existir algunas diferencias específicas de cada cadena.

Descodificación de datos del EVM

Al trabajar con cadenas compatibles con EVM, puedes verificar y analizar los datos más fácilmente utilizando el decodificar recibos EVM función. Esta utilidad transforma datos hexadecimales sin procesar en formatos legibles para el usuario, utilizando como entradas los recibos de transacción sin procesar y las ABI de tus contratos.

El proceso de decodificación realiza automáticamente lo siguiente:


  • Compara las firmas de eventos de los registros de transacciones con las ABI facilitadas.
  • Decodifica los parámetros según su tipo (direcciones, números enteros, cadenas, etc.).
  • Devuelve datos estructurados con parámetros con nombre en un registros descodificados objeto.

Más información sobre esta función: Decodificación de datos EVM

Fuentes de datos disponibles

En el caso de cadenas EVM como Ethereum, Base, Arbitrum y BNB Smart Chain, puedes utilizar los siguientes conjuntos de datos para completar los datos históricos.

Para consultar la especificación JSON completa y los detalles de cada conjunto de datos, consulta la documentación sobre fuentes de datos.

Fuente de datosDescripción
BloqueUna matriz de objetos de bloque, tal y como la devuelve la función eth_getBlockByNumber
Bloc de recibosUna matriz de objetos que contiene un conjunto de datos compuesto por bloques y recibos, tal y como los devuelven las funciones `eth_getBlockByNumber` y `eth_getBlockReceipts`.
TransaccionesUna matriz de matrices de objetos de transacción, tal y como aparecen en la matriz de transacciones de los datos del bloque
RegistrosUna matriz de matrices de objetos de registro, tal y como aparecen dentro de la matriz «logs» en los recibos de transacciones.
RecibosUna matriz de matrices, cada una de las cuales contiene objetos de recibo tal y como los devuelve la función `eth_getBlockReceipts`.
Rastros (debug_trace)Una matriz de matrices de datos de seguimiento, tal y como los devuelve la función `debug_traceBlock`.
Trazas (trace_block)Una matriz de matrices de datos de seguimiento, tal y como los devuelve la función `trace_block`
Bloque con recibos + debug_traceUna matriz de objetos que contiene un conjunto de datos compuesto por bloques, recibos y trazas de `debug_traceBlock`
Bloque con recibos + trace_blockUna matriz de objetos que contiene un conjunto de datos compuesto por bloques, recibos y trazas procedentes de trace_block
nota

La disponibilidad de las fuentes de datos varía según la cadena. Es posible que algunos conjuntos de datos (concretamente, Traces) no sean compatibles con todas las redes EVM. Consulta la página «Fuentes de datos» para ver la matriz de compatibilidad actual.

Ejemplo: Transferencias de tokens ERC-20

La función de ejemplo que se muestra a continuación filtra un bloque de transacciones para identificar y descodificar las transferencias de tokens ERC-20 estándar, comprobando los datos de entrada en busca de los transferencia firma del método.


// Chain: Ethereum
// Dataset: Transactions
// Test with block: 23977403

type Payload struct {
Data [][]Tx `json:"data"`
Metadata map[string]interface{} `json:"metadata"`
}
type Tx struct {
Hash string `json:"hash"`
From string `json:"from"`
To string `json:"to"`
Input string `json:"input"`
BlockNumber string `json:"blockNumber"`
}

func Filter(qn *qn.QNContext, payload Payload) interface{} {
// The standard ERC-20 transfer(address,uint256) method signature
const transferMethodID = "0xa9059cbb"

var filteredTransactions []map[string]interface{}

// Loop through all blocks in the batch (data is [][]tx: outer = block, inner = txs)
for _, transactions := range payload.Data {
for _, tx := range transactions {
// Ensure the input carries a full transfer(address,uint256) call:
// "0x" + 4-byte selector + two 32-byte words = 138 hex chars.
if !strings.HasPrefix(tx.Input, transferMethodID) || len(tx.Input) < 138 {
continue
}

// Decode the 'to' address (skip selector + left-padding)
toAddress := "0x" + tx.Input[34:74]
// Decode the 'value' (amount) from the trailing 32-byte word.
// uint256 can exceed int64, so convert hex → decimal without math/big.
amount := hexToDecimal(tx.Input[74:])

filteredTransactions = append(filteredTransactions, map[string]interface{}{
"txHash": tx.Hash,
"fromAddress": tx.From,
"toAddress": toAddress,
"amount": amount,
"tokenContract": tx.To,
"blockNumber": tx.BlockNumber,
})
}
}

// Return nil if no transfers were found — skips delivery to your destination
// (API credits are still consumed based on blocks processed).
if len(filteredTransactions) == 0 {
return nil
}
return map[string]interface{}{"transactions": filteredTransactions}
}

// hexToDecimal converts an arbitrary-length hex string (with or without a "0x"
// prefix) to its decimal string form, safe for full uint256 values.
func hexToDecimal(hexStr string) string {
hexStr = strings.TrimPrefix(strings.ToLower(hexStr), "0x")
hexStr = strings.TrimLeft(hexStr, "0")
if hexStr == "" {
return "0"
}

// digits holds the decimal value little-endian (least-significant first).
digits := []int{0}
for _, c := range hexStr {
v, err := strconv.ParseInt(string(c), 16, 32)
if err != nil {
return "0"
}
carry := int(v)
for i := 0; i < len(digits); i++ {
cur := digits[i]*16 + carry
digits[i] = cur % 10
carry = cur / 10
}
for carry > 0 {
digits = append(digits, carry%10)
carry /= 10
}
}

var sb strings.Builder
for i := len(digits) - 1; i >= 0; i-- {
sb.WriteByte(byte('0' + digits[i]))
}
return sb.String()
}

Recursos adicionales

Consejos para el relleno

Organización por lotes para un relleno más rápido

De forma predeterminada, Streams un bloque cada vez. En el caso de las actualizaciones retrospectivas, aumentar el tamaño del lote (por ejemplo, 10 o 100 bloques por envío) reduce la sobrecarga y acelera la ingesta. Ajusta esta configuración en los parámetros de Stream en función de la capacidad de tu destino.

Si vas a seguir con la transmisión en tiempo real, te recomendamos que utilices Elastic Batch para ajustar automáticamente el tamaño de los lotes.

Optimización del rendimiento

La combinación del filtrado (para transmitir únicamente los datos que se desean) con la compresión (para optimizar la transferencia de datos) mejora el rendimiento durante las recargas a gran escala.


consejo

Si tu filtro devuelve null, no se envían datos a tu destino (lo que reduce las cargas útiles innecesarias). Nota: Streams créditos de API en función de los bloques procesados, independientemente del filtrado.

Filtros de depuración

Registra la información de tu función de filtro para depurar durante el desarrollo. Los registros aparecen en la pestaña «Registros», junto a la pestaña «Resultados», en el Editor de filtros de flujo.

En JavaScript, utiliza console.log(). En Go, utiliza fmt.Println — su salida se recoge en el Registros La pestaña «tab» funciona como un registro de nivel informativo y formatea automáticamente los objetos (mapas, segmentos, estructuras) en una cadena de caracteres, lo que te permite registrar la carga útil directamente.

El ejemplo de Go que aparece a continuación parte de la base de que Carga útil La estructura se declara en tu filtro (véanse los ejemplos anteriores). Al hacer referencia a un tipo no definido en el Filtro La firma hace que el intérprete genere un mensaje engañoso bucle de definición de constantes error, así que asegúrate de que la estructura esté definida.


func Filter(qn *qn.QNContext, payload Payload) interface{} {
fmt.Println("Data:", payload.Data)
fmt.Println("Metadata:", payload.Metadata)

// ... rest of your filter
}

Pruebas con datos sin procesar

Al crear un nuevo filtro, puedes descargar los datos sin procesar de un bloque de prueba concreto desde la interfaz de usuario de configuración de Stream. Esto te ayuda a comprender la estructura exacta de la carga útil antes de escribir la lógica del filtro.

Seguridad y autenticación

Streams un token de seguridad con cada entrega que puedes utilizar para verificar las solicitudes procedentes de Quicknode. También puedes configurar encabezados personalizados en los ajustes de tu destino. Para los destinos de webhook, consulta «Cómo validar los mensajes Streams entrantes Streams » para obtener más detalles sobre la implementación.