ZYCORD documentación
Español
ZycordDocumentaciónEjecutar un nodo

Ejecutar un nodo

La guía del operador de zycordd. El protocolo que habla es la especificación de red; esta página trata de ejecutarlo.

La versión de una línea#

zycordd --devnet --dir ./devnet

Eso es un nodo completo: valida cada bloque desde la génesis, sirve a los pares y responde a un RPC de solo lectura en 127.0.0.1:9420. Para unirte a la red que está funcionando de verdad, véase Testnet pública — y ten en cuenta que necesita el binario -randomx.

Lo que el nodo no tiene#

No hay material de clave en el proceso del nodo, jamás. No acepta semilla, ni frase de paso, ni archivo de clave. La firma ocurre en zcd, y el único endpoint de escritura del nodo — /submit — no concede autoridad alguna: un certificado enviado se valida exactamente igual que uno que llegue de un desconocido.

Tampoco hay ningún endpoint privilegiado, porque no hay nada que privilegiar. Ninguna clave puede pausar, actualizar, censurar ni acuñar, así que no hay llamada que exponer.

Si pones el RPC detrás de un proxy, limita la tasa en el proxy

El limitador se indexa por el par de transporte y nunca por X-Forwarded-For: un limitador que confía en una cabecera que fija el cliente es un limitador que el cliente apaga. Detrás de un proxy, por tanto, cada petición llega con la dirección del proxy, así que el límite por cliente deja de ser por cliente y se convierte en un único cubo compartido de 600 por minuto para todos a la vez — y una sola persona que llame puede vaciarlo para todas las demás. Eso es discutiblemente peor que no tener límite alguno, y nada en la respuesta lo dice: quien llama recibe un 429 corriente tanto si lo causó él como si fue otro.

La superficie de solo lectura#

Cualquier cosa que observe la cadena desde fuera — un explorador, un monitor, un indexador — la lee aquí. El nodo entrega bytes y nunca interpretación.

Punto de accesoResponde
/status, /headIdentidad de la punta, altura, raíz de estado
/block?height=N o ?id=0x…Un bloque en JSON, con canonical, orphaned y confirmations
/block?…&format=sszEl mismo bloque como bytes SSZ canónicos, application/octet-stream
/paramsEl conjunto de parámetros activo y su raíz de consenso
/cell, /balanceEstado en la punta
/feesComisiones base, y los techos elásticos en vigor
/mempoolContadores de la reserva; ?limit=N añade hasta 1000 ids pendientes, de menor a mayor
/network, /metricsForma de las conexiones y contadores
/submitLa única escritura, y no concede nada
Los techos no son parámetros

El §8.1 del whitepaper hace que los techos de bytes, de gas y de certificados del bloque sean funciones de T, el objetivo secuencial, y T es estado de consenso que mueve el controlador de época. Por eso /params lleva solo los valores de la génesis — block_byte_limit_genesis y compañía — que son donde T empieza y el suelo al que puede decaer, nunca el límite en vigor. Esos números siguen siendo reales para siempre, así que leer uno como "el límite de tamaño de bloque" es un error silencioso, y de hasta la distancia entre el valor de génesis de 2,5 MB y el muro de capacidad de 8 MB. /fees sirve la T en vigor y los cuatro techos derivados de ella, de modo que la derivación pueda comprobarse en vez de confiarse.

Por qué importan los bytes#

blake3("zcd/block/v1" ‖ header_bytes) es el id del bloque, así que un observador que vuelve a derivar los ids de lo que se le sirvió o coincide con la red o se entera de inmediato. Es también como se obtienen los desenlaces por certificado: si un certificado se aplicó, se omitió y se cobró, o se descartó, se calcula dentro del fold y nunca se persiste, porque una fila por certificado para siempre, en un almacén que vive en memoria, no es algo que se le pueda pedir a un nodo que cargue. Un observador que quiera los desenlaces hace él mismo el fold del bloque.

Lo que no está aquí, y no estará#

  • Sin iteración arbitraria del estado. Sin lista de direcciones, sin barrido por prefijo, sin lista de ricos.
  • Sin estado histórico. /cell y /balance leen la punta; "saldo a la altura H" implica una historia retenida que el nodo no guarda.
  • Sin llamada de administración, reindexado ni depuración, porque no hay nada que privilegiar.

La agregación pertenece a lo que sea que esté observando, calculada una sola vez en la ingesta hacia su propia base de datos.

Códigos de estado#

Las lecturas responden a GET y HEAD y rechazan cualquier otro verbo con 405. Una pregunta bien formada con respuesta negativa — una altura que la cadena no ha alcanzado, un id desconocido, el cuerpo de un bloque que perdió una reorganización — es 404; solo una petición malformada es 400. Un registro que el nodo escribió y ya no puede releer es 500, no 400: la culpa es del disco del nodo, y decirle a quien llama que su petición estaba malformada le invita a dejar de reintentar una petición que siempre estuvo bien formada. Quien consulta nunca debería tener que leer prosa para distinguir la ausencia del error, o su propio fallo del del nodo.

Reorganizaciones#

La búsqueda por altura responde solo por la cadena canónica. Un bloque que pierde una reorganización conserva su cabecera y pierde su cuerpo, así que su id sigue resolviéndose, vuelve marcado como orphaned, y sigue llevando el enlace al padre hasta el punto de bifurcación — lo que hace de la búsqueda por id la única vía segura ante reorganizaciones.

Alcanzabilidad, y por qué importa más de lo que parece#

Zycord no hace travesía de NAT. Un nodo con --listen en un puerto alcanzable es un sitio desde el que otros pueden arrancar, y la proporción de nodos así es la condición falsable sobre la que descansa toda la decisión de no hacer travesía.

# periphery: nothing to configure
zycordd --testnet --dir ./testnet

# core: bind a port, and make sure it is actually reachable
zycordd --testnet --dir ./testnet \
  --listen 0.0.0.0:9421 --advertise <public-address>:9421
Anuncia una dirección que responda, o ninguna

--advertise recurre a --listen, así que --listen 0.0.0.0:9421 sin --advertise publica 0.0.0.0:9421, que nadie puede marcar. Una dirección equivocada se propaga por el intercambio de pares y le cuesta una llamada a cada nodo que la intenta. Si no puedes abrir un puerto, deja --listen desactivado y sé periferia.

Comprobar si funcionó#

curl -s localhost:9420/network
{"enabled":true,"peers":8,"listening":true,"inbound":5,"outbound":3,"reachable":true}

listening: true con inbound: 0 después de que el nodo lleve unos minutos levantado significa que el puerto no es realmente alcanzable: el proceso está enlazado y esperando, y no llega nada. Eso parece sano en cualquier otra vista, que es por lo que este endpoint existe.

Direcciones de arranque desde un archivo#

zycordd --testnet --dir ./testnet --peers-file peers.txt

Una dirección por línea; los comentarios con # y las líneas en blanco se ignoran, y la lista se fusiona con las semillas incorporadas de la red. --peers toma lo mismo como argumento separado por comas, y --no-seeds descarta las incorporadas conservando ambas.

La interfaz del monedero, sobre un túnel ssh#

Un nodo no guarda ninguna clave y nunca la guardará. El monedero es un proceso aparte, y en un servidor es zcd ui:

zcd ui --key wallet.json --no-open

Eso imprime una URL y la sirve en 127.0.0.1:9430. Se enlaza a loopback y rechaza cualquier otra cosa, sin flag para anularlo. El proceso tras ese escuchador guarda una clave privada desbloqueada y se autentica con un token bearer en una URL, lo cual es adecuado para un socket que solo la máquina local puede abrir y no es adecuado para nada más. Alcanzarlo desde otro sitio es tarea de ssh, y ssh lo hace mejor de lo que lo haría esto:

# on your own machine
ssh -L 9430:127.0.0.1:9430 <host>

Luego abre la URL que imprimió el servidor. El token viaja en el fragmento de la URL, así que nunca llega al servidor, ni a un registro, ni a una cabecera Referer — trata la URL como el secreto que es. Es nueva en cada ejecución, y Ctrl-C borra la clave y deja de servir.

El extremo local del reenvío no tiene por qué ser el puerto 9430: la interfaz comprueba el nombre de host en la cabecera Host y deliberadamente no el puerto. El nombre de host es lo que importa — es lo que bloquea el rebinding de DNS, que es el ataque real contra un servidor en loopback, ya que cualquier página de tu navegador puede hacer peticiones a 127.0.0.1 y lo único que no puede falsificar es el nombre al que se navegó.

No pongas un proxy inverso delante de zcd ui

El consejo de arriba sobre el RPC del nodo trata de una superficie que no guarda ninguna clave y no concede ninguna autoridad. Esta guarda una clave. No hay ninguna versión de exponerla que sea buena idea, y el túnel cuesta un flag.

Otras dos formas que conviene conocer:

  • zcd ui --locked arranca sin pedir una contraseña en la terminal; la pide el navegador en su lugar. Útil cuando la terminal es compartida o queda registrada.
  • zcd ui --lock-after 5m acorta el bloqueo por inactividad, que borra la clave en su sitio — la semilla se sobrescribe, no se limita a dejar de referenciarse.

Identidad de par y anonimato#

El nodo genera una clave de par Ed25519 nueva en cada arranque y nunca la escribe en disco. No se deriva de nada — ni de tu monedero, ni de una semilla, ni de ninguna otra cosa de la máquina. Reiniciar la rota.

Si estás ejecutando un nodo de una forma que te importa, lo que te desanonimiza no es la clave. Es la dirección. Un nodo de arranque que ejecutes en infraestructura rastreable hasta ti es un vector de desanonimización que ninguna higiene de claves arregla.

Directorio de datos#

data/
  chain/       blocks, state, and the write-ahead log
  peers.json   the persisted peer store

El almacén de pares se persiste a propósito: un nodo que arranca en blanco tras cada reinicio le da al atacante una oportunidad nueva de llenarlo. Borrarlo es seguro pero desecha eso.

El nodo sobrevive a que lo maten en cualquier momento — para eso está el registro de escritura anticipada, y se prueba matando nodos al azar bajo caos de red. No sobrevive a que le editen el directorio de datos por debajo: al arrancar recalcula la raíz de estado y se niega a funcionar si la almacenada discrepa.

Elegir una red#

FlagRedChain idMotor
(ninguno)mainnet1randomx-v1
--testnettestnet pública2randomx-v1
--devnetdevnet local1337motor de desarrollo

Los parámetros están incrustados en el binario, no se leen de una ruta. Todo participante de una red pública tiene que llevar los mismos bytes o no están en una misma red, y un archivo pasado con --params es un archivo que se desvía. Una red distinta es una red distinta: las dos se desconectan en el saludo, y un directorio de datos que contenga la cadena equivocada se rechaza al arrancar en lugar de mezclarse en silencio.

Recuperar un directorio de datos dañado#

zycordd trae una vía de reparación para un directorio de datos contra el que un nodo se niega a arrancar. Detén el nodo primero — zycordd repair --dir ./data toma el cerrojo del directorio y se niega mientras lo tenga un nodo — y luego pregunta qué ha pasado con --dry-run antes de cambiar nada. Solo una clase de daño se repara en el sitio; para las demás el remedio es resincronizar, y la ejecución en seco es lo que te dice cuál tienes.