ZYCORD docs
Português
ZycordDocumentaçãoExecutando um nó

Executando um nó

O guia do operador para o zycordd. O protocolo que ele fala é a especificação de fio; esta página é sobre rodá-lo.

A versão de uma linha#

zycordd --devnet --dir ./devnet

Isso é um nó completo: ele valida cada bloco desde a gênese, serve pares, e responde a um RPC somente leitura em 127.0.0.1:9420. Para entrar na rede que está de fato rodando, veja Testnet pública — e note que ela precisa do binário -randomx.

O que o nó não tem#

Não há material de chave no processo do nó, jamais. Ele não aceita seed, nem frase secreta, nem arquivo de chave. A assinatura acontece no zcd, e o único endpoint de escrita do nó — /submit — não concede autoridade alguma: um certificado submetido é validado exatamente como um que chegasse de um desconhecido.

Também não há endpoint privilegiado, porque não há nada a privilegiar. Nenhuma chave pode pausar, atualizar, censurar ou emitir, então não há chamada a expor.

Se você puser a RPC atrás de um proxy, limite a taxa no proxy

O limitador se baseia no par de transporte e nunca no X-Forwarded-For: um limitador que confia em um cabeçalho que o cliente define é um limitador que o cliente desliga. Atrás de um proxy, toda requisição portanto chega com o endereço do proxy, então o limite por cliente deixa de ser por cliente e se torna um único balde compartilhado de 600 por minuto para todos ao mesmo tempo — e um único chamador pode esvaziá-lo para todos eles. Isso é discutivelmente pior que nenhum limite, e nada na resposta diz isso: os chamadores recebem um 429 simples quer tenham causado o problema, quer tenha sido outro.

A superfície somente leitura#

Qualquer coisa que observe a cadeia de fora — um explorador, um monitor, um indexador — a lê aqui. O nó entrega bytes e nunca interpretação.

EndpointResponde
/status, /headIdentidade do topo, altura, raiz de estado
/block?height=N ou ?id=0x…Um bloco em JSON, com canonical, orphaned e confirmations
/block?…&format=sszO mesmo bloco como bytes SSZ canônicos, application/octet-stream
/paramsO conjunto de parâmetros ativo e sua raiz de consenso
/cell, /balanceEstado do topo
/feesTaxas base, e os tetos elásticos em vigor
/mempoolContadores do pool; ?limit=N acrescenta até 1000 ids pendentes, do menor primeiro
/network, /metricsFormato das conexões e contadores
/submitA única escrita, e ela não concede nada
Os tetos não são parâmetros

O §8.1 do whitepaper faz os tetos de bytes, de gas e de certificados do bloco funções de T, o alvo sequencial, e T é estado de consenso que o controlador de época move. O /params portanto carrega apenas os valores de gênese — block_byte_limit_genesis e afins — que são onde T começa e o piso ao qual ele pode decair de volta, nunca o limite em vigor. Esses números permanecem reais para sempre, então ler um deles como "o limite de tamanho do bloco" é errado silenciosamente, e por até a distância entre o valor de gênese de 2,5 MB e o teto de capacidade de 8 MB. O /fees serve o T ao vivo e os quatro tetos derivados dele, para que a derivação possa ser verificada em vez de presumida.

Por que os bytes importam#

O blake3("zcd/block/v1" ‖ header_bytes) é o id do bloco, então um observador que rederiva ids a partir do que lhe foi servido ou concorda com a rede ou descobre imediatamente. É também como os resultados por certificado são obtidos: se um certificado foi aplicado, sofreu omissão e foi cobrado, ou foi descartado é computado dentro do fold e nunca persistido, porque uma linha por certificado para sempre, em um armazenamento que vive em memória, não é algo que se possa pedir a um nó que carregue. Um observador que queira os resultados faz o fold do bloco ele mesmo.

O que não está aqui, e não estará#

  • Nenhuma iteração arbitrária de estado. Sem lista de endereços, sem varredura por prefixo, sem lista de ricos.
  • Nenhum estado histórico. /cell e /balance leem o topo; "saldo na altura H" implica um histórico retido que o nó não guarda.
  • Nenhuma chamada de administração, reindexação ou depuração, porque não há nada a privilegiar.

A agregação pertence a quem quer que esteja observando, computada uma vez na ingestão para seu próprio banco de dados.

Códigos de status#

As leituras respondem a GET e HEAD e recusam todo outro verbo com 405. Uma pergunta bem formada com resposta negativa — uma altura que a cadeia não alcançou, um id desconhecido, o corpo de um bloco que perdeu uma reorganização — é 404; apenas uma requisição malformada é 400. Um registro que o nó escreveu e não consegue mais ler de volta é 500, não 400: a falha é do disco do nó, e dizer a um chamador que sua requisição era malformada o convida a parar de retentar uma requisição que sempre foi bem formada. Um poller nunca deveria ter que ler prosa para distinguir ausência de erro, ou o próprio bug do bug do nó.

Reorganizações#

A busca por altura responde apenas para a cadeia canônica. Um bloco que perde uma reorganização mantém seu cabeçalho e perde seu corpo, então seu id ainda resolve, volta marcado como orphaned, e ainda carrega o vínculo com o pai de volta ao ponto de bifurcação — o que faz da busca por id o único caminho seguro contra reorganizações.

Alcançabilidade, e por que importa mais do que parece#

O Zycord não faz travessia de NAT. Um nó com --listen em uma porta alcançável é um lugar de onde outros podem fazer bootstrap, e a proporção de nós assim é a condição falseável sobre a qual repousa toda a decisão de não fazer travessia.

# 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
Anuncie um endereço que responda, ou nenhum

O --advertise recai sobre o --listen, então --listen 0.0.0.0:9421 sem --advertise publica 0.0.0.0:9421, que ninguém consegue discar. Um endereço errado se propaga pela troca de pares e custa a cada nó que o tenta uma discagem. Se você não conseguir encaminhar uma porta, deixe o --listen desligado e seja periferia.

Verificando se funcionou#

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

listening: true com inbound: 0 depois que o nó está no ar por alguns minutos significa que a porta não está de fato alcançável: o processo está vinculado e esperando, e nada está chegando. Isso parece saudável em qualquer outra visão, e é por isso que este endpoint existe.

Endereços de bootstrap a partir de um arquivo#

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

Um endereço por linha; comentários com # e linhas em branco são ignorados, e a lista é mesclada com os seeds embutidos da rede. O --peers recebe a mesma coisa como argumento separado por vírgulas, e o --no-seeds descarta os embutidos mantendo os dois.

A interface da carteira, por um túnel ssh#

Um nó não guarda chave alguma e nunca guardará. A carteira é um processo separado, e em um servidor ela é o zcd ui:

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

Isso imprime uma URL e a serve em 127.0.0.1:9430. Ela vincula ao loopback e recusa qualquer outra coisa, sem flag para sobrepor. O processo por trás desse listener guarda uma chave privada destrancada e autentica com um token portador em uma URL, o que é adequado para um socket que só a máquina local pode abrir e não é adequado para mais nada. Alcançá-lo de outro lugar é trabalho do ssh, e o ssh é melhor nisso do que isto seria:

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

Depois abra a URL que o servidor imprimiu. O token viaja no fragmento da URL, então ele nunca chega ao servidor, a um log, ou a um cabeçalho Referer — trate a URL como o segredo que ela é. Ela é nova a cada execução, e Ctrl-C apaga a chave e para de servir.

A ponta local do encaminhamento não precisa ser a porta 9430: a interface verifica o hostname no cabeçalho Host e deliberadamente não a porta. O hostname é o que importa — é ele que bloqueia o DNS rebinding, que é o ataque real contra um servidor em loopback, já que qualquer página no seu navegador pode fazer requisições a 127.0.0.1 e a única coisa que ela não pode forjar é o nome pelo qual foi acessada.

Não coloque um proxy reverso na frente do zcd ui

O conselho acima sobre o RPC do nó é sobre uma superfície que não guarda chave alguma e não concede autoridade alguma. Esta guarda uma chave. Não existe versão de expô-la que seja uma boa ideia, e o túnel custa uma flag.

Duas outras formas que vale conhecer:

  • zcd ui --locked inicia sem pedir uma frase secreta no terminal; o navegador pede em vez disso. Útil quando o terminal é compartilhado ou registrado em log.
  • zcd ui --lock-after 5m encurta o travamento por ociosidade, que apaga a chave no lugar — o seed é sobrescrito, não meramente desreferenciado.

Identidade de par e anonimato#

O nó gera uma chave de par Ed25519 nova a cada início e nunca a escreve em disco. Ela não é derivada de nada — nem da sua carteira, nem de uma seed, nem de qualquer outra coisa na máquina. Reiniciar a rotaciona.

Se você está rodando um nó de uma forma que lhe importa, o que o desanonimiza não é a chave. É o endereço. Um nó de bootstrap que você roda em infraestrutura rastreável até você é um vetor de desanonimização que nenhuma higiene de chaves conserta.

Diretório de dados#

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

O armazenamento de pares é persistido de propósito: um nó que começa do zero após cada reinício dá a um atacante uma nova chance de preenchê-lo. Apagá-lo é seguro mas joga isso fora.

O nó sobrevive a ser morto a qualquer momento — é para isso que serve o write-ahead log, e isso é testado matando nós aleatoriamente sob caos de rede. Ele não sobrevive a ter seu diretório de dados editado por baixo dele: ao iniciar ele recomputa a raiz de estado e se recusa a rodar se a armazenada divergir.

Escolhendo uma rede#

FlagRedeChain idEngine
(nenhuma)mainnet1randomx-v1
--testnettestnet pública2randomx-v1
--devnetdevnet local1337engine de desenvolvimento

Os parâmetros são embutidos no binário, não lidos de um caminho. Todo participante de uma rede pública precisa carregar os mesmos bytes ou eles não estão em uma mesma rede, e um arquivo passado por --params é um arquivo que deriva. Uma rede diferente é uma rede diferente: as duas se desconectam no handshake, e um diretório de dados contendo a cadeia errada é recusado na inicialização em vez de silenciosamente misturado.

Recuperando um diretório de dados danificado#

O zycordd traz um caminho de reparo para um diretório de dados contra o qual um nó se recusa a iniciar. Pare o nó primeiro — zycordd repair --dir ./data toma o cadeado do diretório e se recusa enquanto um nó o estiver segurando — e então pergunte o que aconteceu com --dry-run antes de mudar qualquer coisa. Só uma classe de dano é reparável no lugar; para as outras o remédio é ressincronizar, e é a execução a seco que diz qual delas você tem.