Logo
Nuevos usuarios de RPC: 35% de descuento el primer mesVer oferta
OnFinality Learn
Guías de red y protocolo12 min de lectura

Substrate state_getMetadata y versiones de runtime: consulta de metadatos de cadena en cualquier bloque

Aprende a consultar los metadatos del runtime de Substrate en cualquier bloque, comprende las versiones de metadatos y evita fallos de decodificación en las actualizaciones del runtime.

TL;DR

Las cadenas basadas en Substrate, como Polkadot, exponen un runtime actualizable cuya superficie de API se describe mediante metadatos versionados. La RPC state_getMetadata devuelve estos metadatos para el mejor bloque actual o para un hash de bloque específico, lo que permite decodificar correctamente extrínsecos y almacenamiento históricos. Debes fijar los metadatos al bloque que estás consultando y comparar spec_version o hashes de metadatos para detectar actualizaciones que de otro modo romperían la lógica de decodificación de tu cliente.

Respuesta directa: los metadatos son el contrato de API de la cadena y cambian

Si te integras con una cadena basada en Substrate como Polkadot, los metadatos del runtime son la descripción autoritativa de la API de la cadena: cada pallet, extrínseco invocable, elemento de almacenamiento, evento, error y constante. Estos metadatos tienen versiones (actualmente v14 y v15 son comunes) y cambian cuando el runtime se actualiza en la cadena. El método RPC state_getMetadata devuelve estos metadatos, y puedes pasar un hash de bloque opcional para recuperar los metadatos tal como existían en ese bloque exacto. No fijar los metadatos a tu bloque objetivo es la causa raíz de fallos silenciosos de decodificación después de una actualización del runtime.

La regla práctica: consulta siempre los metadatos para el bloque que estás decodificando y almacénalos en caché con la versión del runtime (spec_version) como clave. Compara el spec_version o el hash de los metadatos entre solicitudes para detectar una actualización. Este artículo explica el mecanismo, muestra cómo consultar metadatos en cualquier bloque y proporciona una lista de verificación para solucionar problemas.

Cómo funcionan los metadatos del runtime: esquemas versionados para un runtime actualizable

El runtime de una cadena Substrate (FRAME) es un blob de WebAssembly almacenado en la cadena y es actualizable mediante gobernanza o sudo. Cada actualización del runtime puede cambiar el conjunto de pallets, extrínsecos, claves de almacenamiento, eventos y errores. Los metadatos del runtime son una descripción legible por máquina de esa superficie de API, codificada con el códec SCALE. El formato de metadatos en sí está versionado: v14 es el formato actual ampliamente soportado, y v15 añade información de la API del runtime y soporte para la era de respaldo asíncrono. La versión está vinculada al spec_version, transaction_version y nombres de spec apex del runtime, que cambian en las actualizaciones.

Los clientes construidos con metadatos antiguos decodificarán incorrectamente extrínsecos o almacenamiento después de una actualización porque las definiciones de tipos y los índices pueden haber cambiado. Por ejemplo, un índice de llamada que apuntaba a Balances.transfer podría ahora apuntar a un extrínseco diferente. La documentación de Polkadot-SDK y polkadot.js.org son las fuentes primarias autoritativas para los formatos de metadatos y el versionado del runtime.

La superficie RPC incluye state_getMetadata (con hash de bloque at opcional), state_call para invocar APIs del runtime como Metadata_metadata_at_version, y state_runtimeVersion (o chain_getRuntimeVersion) para obtener el spec_version actual. La disponibilidad de estos métodos depende de la compilación del nodo y la versión del runtime, según lo distribuido por el estado del runtime de la cadena.

Consultar metadatos en un bloque específico: el flujo de trabajo

Para decodificar un extrínseco o valor de almacenamiento histórico, necesitas los metadatos que eran válidos en el bloque donde se incluyó ese extrínseco. El flujo de trabajo es: 1) Obtén el hash del bloque de interés (por ejemplo, de una transacción o número de bloque). 2) Llama a state_getMetadata con ese hash como parámetro at. 3) Decodifica los metadatos devueltos codificados en SCALE para determinar su versión (v14, v15, etc.) y extrae el registro de tipos. 4) Usa ese registro para decodificar el extrínseco o la clave de almacenamiento.

Para el último bloque, puedes omitir el parámetro at, pero ten en cuenta que el nodo devuelve metadatos para su mejor bloque actual, que puede cambiar entre solicitudes. Para detectar una actualización entre dos solicitudes, compara el spec_version de state_runtimeVersion o el hash de los metadatos (por ejemplo, usando state_call a Metadata_metadata_at_version y aplicando hash).

polkadot.js expone metadatos y registro conscientes de la versión: la API @polkadot/api consulta automáticamente los metadatos y actualiza su registro cuando detecta una actualización del runtime (a través de api.runtimeVersion). Sin embargo, para la decodificación histórica, debes crear manualmente una instancia de Api con un hash de bloque específico o usar bibliotecas de bajo nivel para decodificar con los metadatos correctos.

Ejemplo ejecutable: obtener y comparar metadatos en el último bloque y en bloques históricos

El siguiente script bash usa curl para consultar un endpoint RPC de Polkadot (reemplázalo con tu propio endpoint, por ejemplo, del servicio de API de OnFinality). Obtiene el hash del último bloque, luego llama a state_getMetadata para el último bloque y para un bloque anterior específico (puedes reemplazarlo con un hash histórico conocido). Extrae la versión de metadatos y el spec_version usando state_call a Metadata_metadata_at_version y state_runtimeVersion.

La salida esperada muestra la versión de metadatos y el spec_version para ambos bloques. Si difieren, ocurrió una actualización del runtime entre esos bloques. Completa la tabla de resultados a continuación con tus propias mediciones.

#!/bin/bash
# Reemplaza con tu endpoint
ENDPOINT="https://rpc.polkadot.io"
# Obtén el hash del último bloque
LATEST_HASH=$(curl -s -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"chain_getBlockHash","params":[],"id":1}' $ENDPOINT | jq -r '.result')
echo "Hash del último bloque: $LATEST_HASH"
# Obtén metadatos en el último bloque
curl -s -H "Content-Type: application/json" -d "{\"jsonrpc\":\"2.0\",\"method\":\"state_getMetadata\",\"params\":[\"$LATEST_HASH\"],\"id\":2}" $ENDPOINT | jq -r '.result' | xxd -r -p | head -c 10 | od -An -t u1
echo ""
# Obtén la versión del runtime en el último bloque
curl -s -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"state_getRuntimeVersion","params":[],"id":3}' $ENDPOINT | jq '.result.specVersion'
# Reemplaza con un hash de bloque anterior (por ejemplo, de un número de bloque conocido)
OLD_HASH="0x..."
# Obtén metadatos en el bloque anterior
curl -s -H "Content-Type: application/json" -d "{\"jsonrpc\":\"2.0\",\"method\":\"state_getMetadata\",\"params\":[\"$OLD_HASH\"],\"id\":4}" $ENDPOINT | jq -r '.result' | xxd -r -p | head -c 10 | od -An -t u1
echo ""
# Obtén la versión del runtime en el bloque anterior (usando state_call)
curl -s -H "Content-Type: application/json" -d "{\"jsonrpc\":\"2.0\",\"method\":\"state_call\",\"params\":[\"Core_version\",\"0x\",\"$OLD_HASH\"],\"id\":5}" $ENDPOINT | jq '.result'

Tabla de resultados: completa tus mediciones

Ejecuta el script anterior y registra la versión de metadatos y el spec_version para cada bloque. La versión de metadatos es el primer byte de los metadatos codificados en SCALE (por ejemplo, 14 para v14, 15 para v15). El spec_version es un número devuelto por la llamada de versión del runtime.

  • Hash del último bloque: [completar]
  • Versión de metadatos en el último bloque: [completar]
  • Spec_version en el último bloque: [completar]
  • Hash del bloque anterior: [completar]
  • Versión de metadatos en el bloque anterior: [completar]
  • Spec_version en el bloque anterior: [completar]
  • ¿Cambió el spec_version? [sí/no]

Lista de verificación para solucionar problemas: fallos comunes y correcciones

Al consultar metadatos en un bloque, puedes encontrar varios problemas. Usa esta lista de verificación para diagnosticarlos y corregirlos.

Si obtienes un error 'Cannot convert' o deriva de definiciones de tipos, probablemente estás usando los metadatos más recientes para decodificar un extrínseco histórico. Corrección: obtén los metadatos en el bloque objetivo y usa ese registro.

Si las claves de almacenamiento no coinciden después de una actualización, los prefijos de pallet o los hashers pueden haber cambiado. Corrección: compara los metadatos en los dos bloques para identificar los cambios.

Si un nodo de archivo no puede exponer metadatos para bloques profundamente podados, puede ser porque el nodo no es un nodo de archivo o el estado del runtime no está disponible. Corrección: usa un nodo de archivo dedicado (consulta Consultar el estado histórico de Polkadot a través de RPC).

Si state_getMetadata devuelve un error para un bloque antiguo, el bloque podría ser anterior a la introducción de la versión de metadatos o el nodo no tiene ese estado. Corrección: verifica que el bloque esté dentro de la ventana de poda del nodo o usa un endpoint de archivo.

Si ves una discrepancia entre state_getMetadata y state_runtimeVersion, recuerda que este último devuelve la versión actual del runtime, no necesariamente la del bloque que estás consultando. Siempre pasa el hash de bloque a ambos métodos si está disponible.

Limitaciones y compensaciones de las consultas de metadatos en bloque

Consultar metadatos en un bloque específico es potente pero tiene limitaciones. Primero, no todos los nodos son nodos de archivo; un nodo completo puede podar el estado histórico, haciendo que los metadatos de bloques antiguos no estén disponibles. Segundo, el formato de metadatos en sí evoluciona, por lo que debes manejar múltiples versiones (v14, v15, futuras) en tu decodificador. Tercero, la disponibilidad de métodos RPC varía según la compilación del nodo y la versión del runtime; por ejemplo, state_call a Metadata_metadata_at_version puede no estar presente en runtimes antiguos.

En cuanto al rendimiento, obtener metadatos para cada bloque es ineficiente. En su lugar, almacena en caché los metadatos por versión del runtime y actualiza solo cuando cambie el spec_version. Así es como polkadot.js maneja las actualizaciones del runtime: escucha los cambios de spec_version y actualiza su registro de forma diferida.

Finalmente, los metadatos describen la API del runtime, pero no incluyen la lógica real. Para errores de decodificación, es posible que necesites combinar los metadatos con la versión del runtime y la versión del formato del extrínseco (por ejemplo, extensiones firmadas).

Próximos pasos: profundiza en tu conocimiento de integración con Substrate

Ahora que comprendes los metadatos y las versiones del runtime, explora temas relacionados para fortalecer tu integración. Para una visión general más amplia de los métodos RPC de Polkadot, consulta la Guía RPC de Polkadot. Para entender cómo la finalidad afecta la disponibilidad de bloques, lee sobre la finalidad de Polkadot y la cabeza finalizada.

Si trabajas con datos históricos, la guía sobre Consultar el estado histórico de Polkadot a través de RPC es esencial. Para manejar errores en extrínsecos, consulta Decodificación de errores de despacho de extrínsecos de Polkadot. Y para datos en tiempo real eficientes, revisa la Guía RPC WebSocket de Polkadot en profundidad.

Para uso en producción, considera usar un proveedor RPC confiable como el servicio de API de OnFinality con precios de RPC que se adapten a tus necesidades. Siempre prueba tu manejo de metadatos contra una testnet antes de implementar en mainnet.

Nunca te preocupes por la infraestructura nuevamente

OnFinality elimina la carga pesada de DevOps para que puedas construir de forma más inteligente y rápida.

Comenzar