Substrate: del runtime al consenso propio
Artículo 5 de 20
25%
completado al llegar aquí
Sistemas distribuidosNota de investigación16 min de lectura
Tu primer nodo local: templates, omni-node y chain spec
Tres caminos para levantar una cadena Substrate local: polkadot-omni-node con chain spec, un template o el nodo kitchensink, y qué guarda el génesis.
Ruta Substrate: 0/20
Prerequisitos recomendados
Si alguno de estos conceptos todavía está medio nebuloso, empieza por aquí. Te ahorra tropiezos y un par de cejas fruncidas.
El runtime en Wasm: nodo y runtime hablan por dos puertas
Dónde vive el runtime de Substrate (la clave :code del estado) y cómo conversa con el nodo: host functions de sp_io y runtime APIs de sp_api.
Blockchain15 min de lectura→FRAME: pallets que se ensamblan en un runtime
Cómo FRAME arma un runtime de Substrate con pallets: Config, storage, llamadas, eventos y errores unidos con construct_runtime, y en qué difiere de un contrato.
Blockchain14 min de lectura→
La cooperativa del capítulo anterior ya tiene un runtime con su pallet de reservas. Ahora quiere verlo funcionar: crear una cuenta, reservar una sala y ver el evento en un bloque. Nadie en el equipo quiere escribir todavía código de nodo ni elegir un algoritmo de consenso. Necesitan una cadena local, desechable, que produzca bloques en segundos. Este capítulo muestra tres caminos para tenerla y explica la pieza que los une a todos: el chain spec.
Los tres caminos son: el binario polkadot-omni-node con un runtime y un chain spec, un template del SDK (minimal, solochain o parachain) que trae su propio nodo, o el nodo de demostración kitchensink del repositorio. Cada uno cambia cuánto controlas y cuánto código mantienes.
Brújula de lectura
Actor, evidencia y estado
Actor
Quien opera el nodo localCompila el runtime, genera el chain spec y arranca el binario con un estado temporal.
Evidencia
Hash del génesisDepende de la raíz de estado inicial: dos nodos con génesis distinto son cadenas distintas.
Estado
Génesis desde un presetCuentas con fondos, claves de prueba y el propio :code, todo definido en el chain spec.
Preguntas guía
- ¿Qué es un nodo "omni" y qué cadenas puede ejecutar?
- ¿Qué contiene un chain spec y por qué todos los nodos deben usar el mismo génesis?
- ¿Qué diferencia hay entre los formatos full, patch y raw del génesis?
- ¿Qué es el sellado manual y por qué sirve para desarrollar pero no para producción?
- ¿Cuándo necesitas tu propio nodo en lugar del omni-node?
Conexiones dentro de la serie
- Antes: El runtime en Wasm explica que el runtime vive en
:code; FRAME: pallets que se ensamblan en un runtime muestra cómo se arma. - Contraste: Foundry, Anvil y Cast: taller local para Ethereum es el equivalente de una cadena local desechable del lado de Ethereum, y JSON-RPC: hablar con Ethereum sin magia explica qué expone un nodo por RPC y en qué confiar.
- Después: la ruta sigue con extrinsics, estado y pesos antes de llegar a la producción de bloques con slots y Aura.
Nodo y runtime se encuentran: tres caminos
Recordemos la división: el runtime es la STF y el nodo es todo lo demás. La documentación del omni-node lo repite: el nodo contiene base de datos, red, servidor RPC y consenso, y es un binario nativo compilado desde Rust. [1] Durante años, cada runtime venía con su propio nodo, porque ambos estaban fuertemente acoplados; por eso todos los templates traen una carpeta node y otra runtime.
El primer camino rompe ese acoplamiento. polkadot-omni-node es un binario blanco publicado con el SDK, capaz de cubrir las necesidades de la mayoría de las parachains, y también de ejecutar el Wasm de una parachain en local para pruebas. [1] No necesita código propio: se configura con un chain spec externo. La documentación de Polkadot lo describe como capaz de ejecutar "most parachains that do not require custom node-level logic or extensions". [2]
El segundo camino son los templates que se mantienen en el propio repositorio del SDK. [3] El minimal template tiene lo mínimo para ser una cadena funcional y sirve para aprender. El solochain template, antes llamado substrate-node-template, es una cadena independiente con un consenso básico y algunos pallets. El parachain template está listo para conectarse a una relay chain. Si abres el service.rs del nodo solochain, verás que usa Aura para producir bloques y GRANDPA para la finalidad, dos motores con capítulo propio más adelante. [4]
El tercer camino es el nodo kitchensink (substrate-node), que incluye todas las funciones de nodo y runtime del SDK. Su runtime reúne todos los módulos de FRAME, y la documentación avisa que "is only used for testing and demonstration". [5] Sirve para explorar, no como base de un proyecto.
¿Con qué nodo empiezo?
La documentación del omni-node lo resume en tres opciones para quien construye una parachain: usar polkadot-omni-node, que "can run almost any runtime with --dev-block-time"; usar su librería para tener algo más de control; o usar los nodos tradicionales, la mejor opción para quien quiere control total, "such as changing the consensus engine, altering the transaction pool, and so on". [1] Esta ruta termina conectando un consenso propio, así que más adelante vas a necesitar el tercer camino.
El chain spec: génesis más propiedades de red
Un chain spec (especificación de cadena) es el archivo que le dice a un nodo de qué cadena forma parte. La documentación lo define así: "A chain specification file defines the set of properties that are required to run the node as part of the chain." [6] Tiene dos partes: el estado inicial del runtime y las propiedades de red, de las cuales la más importante es la lista de bootnodes, los nodos conocidos a los que conectarse al arrancar.
El estado inicial se llama génesis. Todos los nodos de una red deben construir sobre exactamente el mismo bloque génesis, y como la cabecera de ese bloque incluye la raíz de estado, cualquier diferencia en el estado inicial produce otra cadena. [7] El génesis puede incluir cuentas con fondos, la cuenta administradora (sudo) y el conjunto inicial de autoridades del consenso. Y como el runtime vive en el estado, el Wasm inicial también va en el chain spec, bajo :code.
El génesis admite tres formatos. [7]
- full: un JSON con todas las claves de la configuración de génesis del runtime; no se usan valores por defecto.
- patch: solo las claves que cambian respecto del valor por defecto que provee el runtime. La regla es
full = default + patch, con la advertencia de que el valor por defecto puede no funcionar solo. - raw: pares clave-valor del almacenamiento ya calculados. El código del runtime es uno de esos pares.
Para pasar de full o patch a raw, el nodo le entrega el JSON al runtime por la runtime API GenesisBuilder::build_state, y el runtime lo convierte en entradas de storage. [7] Por eso el runtime debe implementar esa API. Para cadenas de producción o de larga vida se recomienda raw: es el único formato que garantiza que la raíz de estado no cambie cuando cambia la estructura de la configuración de génesis en una actualización de software.
Del runtime compilado a bloques locales
Cómo leer esta figura
Fila superior de izquierda a derecha: una caja verde crate del runtime, FRAME y Rust; una flecha 1, cargo build, lleva a una caja violeta runtime.wasm compilado; una flecha 2, chain-spec-builder, con el rótulo inferior preset development, lleva a una caja ocre chain_spec.json, génesis más red. De esta baja una flecha 3, guion guion chain, a una caja azul polkadot-omni-node con guion guion dev-block-time 1000. Una flecha azul 4, sella, va hacia la izquierda a la caja un bloque por segundo, manual seal, sin consenso. Desde la caja del runtime baja una flecha roja discontinua rotulada otra ruta: control total hacia una caja roja nodo propio, template solochain, Aura y GRANDPA. Fila inferior con el título sección genesis del chain spec: tres cajas, full: todas las claves; patch: default más cambios; raw: pares clave-valor. Una línea discontinua une full y patch, y una flecha build_state, en el runtime, va de patch a raw.
Presets de génesis: desarrollo frente a red de pruebas
Escribir un génesis a mano es propenso a errores. Por eso los runtimes exponen presets: configuraciones de génesis con nombre, ya preparadas. La documentación los describe como variantes útiles para redes de prueba predefinidas, desarrollo local o pruebas de integración, con cuentas con fondos, autoridades de consenso y clave sudo ya cargadas. [6] Un preset es, en realidad, un patch que se combina con el valor por defecto.
El SDK recomienda que todo runtime exponga al menos dos presets: development, pensado para probar con un solo nodo, y local_testnet, pensado para varios nodos locales. [9] La decisión práctica es simple: development para iterar sobre la lógica en tu máquina; local_testnet cuando quieres ver varios nodos, por ejemplo con herramientas como zombienet; y un chain spec raw, revisado y versionado, para cualquier red que deba durar.
Una advertencia de la documentación ahorra horas de depuración: si construyes un preset a mano en JSON y escribes mal una clave, la deserialización puede ignorarla en silencio. La recomendación es usar la macro build_struct_json_patch y probar cada preset convirtiéndolo a almacenamiento raw. [6]
Sellado manual y la secuencia de la guía oficial
La guía "Your first Node" ejecuta un runtime sin código de consenso. Ese runtime "can only be executed with a node that also expects no consensus", es decir, con sellado manual, y la opción --dev-block-time del omni-node hace precisamente eso. [8] El sellado manual (manual seal) es un motor que, según su código, "listens for rpc calls to seal blocks and create forks" y está pensado para entornos de prueba. [10] Con --dev-block-time, en vez de esperar una llamada RPC, sella un bloque a intervalos fijos.
Flujo visual
Secuencia de la guía oficial (omni-node en modo desarrollo)
Los comandos de la guía son estos. Se reproducen como referencia: no se ejecutaron para este capítulo, y las versiones deben fijarse según la versión del SDK que uses. [8]
# Fuente: docs/sdk/src/guides/your_first_node.rs (paritytech/polkadot-sdk). Referencia, no verificado aquí.
cargo install polkadot-omni-node
cargo install staging-chain-spec-builder
chain-spec-builder -c <ruta-de-salida> create \
--relay-chain dontcare \
--runtime polkadot_sdk_docs_first_runtime.wasm \
named-preset development
polkadot-omni-node --tmp --dev-block-time 1000 --chain <chain_spec>.jsonTres detalles del bloque anterior. El crate se llama staging-chain-spec-builder porque el nombre chain-spec-builder en crates.io ya estaba tomado por otra persona. El omni-node está hecho para parachains, así que el chain spec debe llevar los campos para_id y relay_chain; por eso aparece --relay-chain dontcare. Y --tmp guarda el estado en una carpeta temporal, para reiniciar sin purgar la cadena. [8]
Queda una tensión que conviene nombrar. La documentación del omni-node dice que, por ahora, las solochains no están soportadas por los OmniNodes, pero también que --dev-block-time puede ejecutar cualquier runtime con sellado manual, sin restricciones sobre el consenso del runtime. [1] La lectura prudente: --dev-block-time es un modo de desarrollo para probar lógica, no una forma de operar una solochain. Probarlo con el runtime de la cooperativa antes de escribir el laboratorio de esta ruta queda a validar.
Qué cambia respecto de Ethereum
Si usaste Anvil, la idea es conocida: una cadena local que mina bloques al instante o a intervalos, con cuentas de prueba precargadas, para iterar sin red pública. --dev-block-time con el preset development cumple el mismo papel. La diferencia es qué estás probando. Con Anvil pruebas contratos sobre reglas de Ethereum fijas. Con el omni-node pruebas las reglas mismas: tu runtime es la STF de esa cadena local.
Otra diferencia es el génesis. En Ethereum, el génesis de mainnet está fijado y tus pruebas locales imitan esa cadena. En Substrate, el génesis forma parte de tu diseño: decides cuentas iniciales, autoridades y el Wasm inicial, y lo distribuyes como chain spec. Dos equipos con el mismo runtime pero distinto chain spec operan cadenas distintas.
Por último, el acceso. Como en JSON-RPC de Ethereum, el nodo expone un servidor RPC para clientes; la confianza que depositas en sus respuestas depende de si el nodo es tuyo o de un tercero. En tu máquina, con --tmp, el nodo es tuyo y desechable.
Qué llevarte de este capítulo
Para ver un runtime funcionando no necesitas escribir un nodo: compilas el runtime, generas un chain spec con chain-spec-builder y un preset, y arrancas polkadot-omni-node con --dev-block-time, que sella bloques sin consenso. El chain spec junta génesis y propiedades de red; el formato raw es el que conviene para redes duraderas. Si necesitas cambiar el consenso o el pool de transacciones, el camino es un nodo propio desde un template, y esa es la dirección que tomará esta ruta.
Bibliografía académica
- [1]
Parity Technologies, "(Omni) Node," polkadot_sdk_docs, paritytech/polkadot-sdk, docs/sdk/src/reference_docs/omni_node.rs. [Online]. Available: https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/docs/sdk/src/reference_docs/omni_node.rs (consultado 2026-11-13).
Tipos de nodo, alcance del omni-node, --dev-block-time y consenso compartido entre nodo y runtime.
- [2]
Polkadot Developers, "Polkadot Omni Node," polkadot-developers/polkadot-docs, docs/reference/tools/omninode.md. [Online]. Available: https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/docs/reference/tools/omninode.md (consultado 2026-11-13).
El omni-node se configura con un chain spec externo.
- [3]
Parity Technologies, "Templates," polkadot_sdk_docs, paritytech/polkadot-sdk, docs/sdk/src/polkadot_sdk/templates.rs. [Online]. Available: https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/docs/sdk/src/polkadot_sdk/templates.rs (consultado 2026-11-13).
Templates minimal, solochain (antes substrate-node-template) y parachain.
- [4]
Parity Technologies, "Solochain template: node service," paritytech/polkadot-sdk, templates/solochain/node/src/service.rs. [Online]. Available: https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/templates/solochain/node/src/service.rs (consultado 2026-11-13).
El nodo del template solochain conecta sc_consensus_aura (import queue) y sc_consensus_grandpa (block import).
- [5]
Parity Technologies, "Polkadot SDK," polkadot_sdk_docs, paritytech/polkadot-sdk, docs/sdk/src/polkadot_sdk/mod.rs. [Online]. Available: https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/docs/sdk/src/polkadot_sdk/mod.rs (consultado 2026-11-13).
Componentes del Polkadot SDK: Substrate, FRAME, Cumulus, XCM y binarios.
- [6]
Parity Technologies, "Chain Spec Genesis," polkadot_sdk_docs, paritytech/polkadot-sdk, docs/sdk/src/reference_docs/chain_spec_genesis.rs. [Online]. Available: https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/docs/sdk/src/reference_docs/chain_spec_genesis.rs (consultado 2026-11-13).
Qué es un chain spec, GenesisConfig, presets y formatos de génesis.
- [7]
Parity Technologies, "sc-chain-spec," paritytech/polkadot-sdk, substrate/client/chain-spec/src/lib.rs. [Online]. Available: https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/substrate/client/chain-spec/src/lib.rs (consultado 2026-11-13).
Campos del chain spec y formatos full, patch y raw.
- [8]
Parity Technologies, "Your first Node," polkadot_sdk_docs, paritytech/polkadot-sdk, docs/sdk/src/guides/your_first_node.rs. [Online]. Available: https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/docs/sdk/src/guides/your_first_node.rs (consultado 2026-11-13).
Pasos: instalar omni-node y chain-spec-builder, compilar runtime, crear chain spec y ejecutar.
- [9]
Parity Technologies, "sp-genesis-builder," paritytech/polkadot-sdk, substrate/primitives/genesis-builder/src/lib.rs. [Online]. Available: https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/substrate/primitives/genesis-builder/src/lib.rs (consultado 2026-11-13).
Presets development (un nodo) y local_testnet (varios nodos locales).
- [10]
Parity Technologies, "sc-consensus-manual-seal," paritytech/polkadot-sdk, substrate/client/consensus/manual-seal/src/lib.rs. [Online]. Available: https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/substrate/client/consensus/manual-seal/src/lib.rs (consultado 2026-11-13).
Motor de sellado manual para entornos de prueba.
Rutas vecinas
Si este tema te abrió hambre, sigue por aquí.
Series y labs que comparten área o dependen de esta ruta. Pocas opciones, para no convertir la curiosidad en menú infinito.
Series relacionadas
HotStuff: de cero a estado del arte
Ruta progresiva para entender consenso BFT moderno: quórums, sincronía parcial, locks, taxonomía one/two/three-chain, QC/highQC, multipipeline, view-change, responsiveness, AggQC, Fast-HotStuff, sync y frontera DAG-BFT.
Ethereum: de historia a labs
Serie progresiva para entender Ethereum desde el whitepaper, forks y The Merge hasta EVM, Solidity, proof-of-stake, rollups, account abstraction, DeFi, observabilidad y laboratorios reproducibles.
Ruta práctica: activos digitales en la operación
Nueve módulos, de menor a mayor dependencia, para decidir cómo usar custodia, wallets, llaves, firmas multifirma y MPC, AML/KYT y stablecoins con Fireblocks, BitGo, Kaleido, Circle y Tether.
Labs para convertir lectura en práctica
Prueba de trabajo y reajuste de dificultad
Laboratorio determinista para medir el costo de la prueba de trabajo y ver cómo el reajuste por altura de bloque estabiliza el tiempo entre bloques.
Consensus benchmark
Banco reproducible para comparar consenso BFT y documentar los trade-offs de HotStuff-2.
Ethereum local: Anvil, wallet y primera transacción
Laboratorio base para levantar una red local, crear cuentas, firmar transacciones y observar receipts sin gastar ETH real.
RPC y Cast: leer Ethereum con lupa
Ejercicios con JSON-RPC y Cast para consultar bloques, nonces, gas, receipts, logs y errores reproducibles.
Sigue leyendo
Ideas conectadas con este artículo
Una ruta corta para continuar sin abrir veinte pestañas y perder el hilo.
Qué es Substrate hoy: el Polkadot SDK por dentro
Substrate ya no es un repositorio aparte: es el framework base del Polkadot SDK. Un mapa de nombres, piezas y crates para empezar sin perderse.
La cadena como función de transición de estado
El modelo mental que sostiene toda la ruta: una función determinista toma el estado y un bloque y devuelve el estado siguiente. En Substrate esa función se llama runtime.
El runtime en Wasm: nodo y runtime hablan por dos puertas
El runtime es un blob Wasm guardado en el estado bajo la clave :code. El nodo lo llama por runtime APIs y el runtime pide ayuda al nodo por host functions. Por qué la segunda puerta casi nunca se ensancha.
FRAME: pallets que se ensamblan en un runtime
Un pallet encapsula una responsabilidad; el runtime es la suma de pallets configurados. Anatomía de un pallet, cómo se ensamblan y por qué un pallet no es un contrato inteligente.