Use esta página para executar o seu próprio rand-node na testnet, que também é a forma recomendada de usar uma carteira com privacidade: um nó que você mesmo executa não fica sabendo de ninguém além de você qual folha você está prestes a gastar. Um observador sincroniza, reverifica cada prova e serve o JSON-RPC; um validador faz o mesmo e participa do consenso assim que a sua chave entra no conjunto de uma época.
Compilação
Requisitos: Rust 1.98.1 (fixado em rust-toolchain.toml; o rustup o instala), um compilador C++ e cmake para o RocksDB. O crate do zkVM tem dependências por caminho para um checkout vizinho circuits/ do repositório do sistema de provas (randprotocol/zkp-circuits), que deve ficar ao lado de fullnode/, no commit a partir do qual a release foi incorporada: a linha circuits: de crates/randprotocol-zkvm/guests-compiled/PROVENANCE.md (aeacf31 para a v0.6.8, como para a v0.6.7). A primeira compilação leva de 10 a 20 minutos.
git clone https://github.com/randprotocol/fullnode
cargo build --release # target/release/rand-node, target/release/rand, target/release/rand-prover
Execute a v0.6.8 (git checkout v0.6.8, commit c9c9bd3c, é a release que a frota executa; rand_getVersion informa o sha de um nó). Sua release no GitHub traz rand-node, rand, rand-prover e SHA256SUMS, compilados em um único host da frota e sem assinatura. A chain 20 a exige: seu gênesis traz campos que nenhuma compilação anterior lê (testnet, binding_domain, proof_window_blocks, program_state, os grupos rotation e fees da bridge, os tetos de gas e a admissão de staking por voto), e a v0.6.8 traz mudanças de consenso que um nó mais antigo não executa. As provas continuam sendo geradas sob o conjunto de restrições 8, como nas chains 18 e 19, e cada pacote continua levando uma prova de autorização ao lado da prova do pacote (autorização separada, desde a chain 17); por isso o gênesis fixa os mesmos dois guests: o guest de pacote v3 (hc_bundle 60af094a…) e o guest de autorização (hc_auth 1e4e347f…). O gênesis traz também uma seção gas, hardening_v6 e envelope_bytes. Uma compilação v0.6.8 recusa o gênesis das chains 14, 15, 16 e 17 em run e em verify, pelo hash; ela ainda consegue executar o da chain 19. Todo nó executa a compilação da frota.
Chain 20: um hard fork com parada total
A chain 20 entrou no ar em 2026-10-01 às 06:17 UTC. Ela foi cortada a partir de um snapshot da chain 19 e migrada com parada total e início total: todo nó da chain 19 parou na altura 7.700, e todo nó iniciou na chain 20 com a v0.6.8. Não foi uma atualização gradual, por dois motivos. A chain 20 é um novo gênesis, de modo que nenhum bloco é compartilhado com a chain 19. E a v0.6.8 traz mudanças de consenso da auditoria v6 que jamais devem ser aplicadas nó a nó: CON-4 remove a liberação automática do bloqueio de um validador, e CH-1 adiciona um pacemaker com certificado de timeout. Todos os 26 validadores, suas chaves, ids de peer e bootstraps foram mantidos; o quórum continua sendo de 18 de 26. As chains 19 e 18 foram aposentadas.
Portanto, migrar um nó da chain 19 para a chain 20 exige o novo binário, o novo arquivo de gênesis e um diretório de dados novo, como abaixo. As carteiras precisam da v0.6.8 para enviar na chain 20: seu gênesis vincula cada prova e cada mensagem assinada ao seu hash (binding_domain: 1), o que uma carteira mais antiga não faz.
Chaves
rand-node keygen --out node.key.json # prints the address
rand-node address --key node.key.json # address, public key, libp2p peer id
O arquivo é { "seed", "address", "public_key" }, com modo 0600; somente a seed é secreta. Um observador também precisa de uma chave: ela é a identidade p2p. Uma chave de nó não é uma chave de carteira: use rand keygen para uma carteira.
Gere a sua própria chave e mantenha-a fora do checkout. O repositório do fullnode não rastreia mais nenhuma chave (auditoria v3, OPS-1): os arquivos deploy/node-*.key.json e deploy/payout/*.key.json que foram commitados para as chains 8 a 13 são seeds publicadas e não devem ser usados. As chaves de validador da chain 20 foram geradas fora do repositório e nunca estiveram nele: seus 26 validadores de gênesis são as dezoito chaves geradas para a chain 14 e as oito vinculadas na chain 15, mantidas em todos os cortes desde então.
Desde a v0.6.8, rand-node keygen recusa um arquivo --out que já exista; a v0.6.7 o sobrescrevia sem perguntar. O arquivo é a única cópia da seed. Faça backup dele antes que um bond dependa dele.
Inicializar a partir do gênesis
Todo nó de uma chain precisa do arquivo de gênesis idêntico byte a byte; rand-node init o copia para o diretório de dados e imprime o seu hash, que deve ser 6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135 para a chain 20. O arquivo é deploy/genesis-chain20.json (sha256 0020247a…3a21). Ele foi commitado na main do fullnode com o registro de lançamento (commit 74cfaca0), depois da tag, de modo que um checkout de v0.6.8 não o contém: obtenha-o da main.
git -C fullnode show origin/main:deploy/genesis-chain20.json > genesis-chain20.json
rand-node init --datadir ./data-6210cf07 --genesis genesis-chain20.json
Isso cria <datadir>/db (RocksDB) com o bloco 0, as nove notas de gênesis como as primeiras folhas da árvore (sete notas RAND com 5.184,243719258 RAND de carteiras de operadores vindas da chain 19, e duas notas zUSD de 10 e 89 zUSD, os 99 zUSD bloqueados na custódia da bridge) e o registro de validadores. Executar de novo com o mesmo gênesis não faz nada; um gênesis diferente é recusado (already initialized with a different genesis significa que o datadir pertence a outra chain). Dê ao diretório de dados o nome formado pelos oito primeiros caracteres do hash do gênesis, como a frota faz (data-<name>-6210cf07), para que nunca colida com o da chain 19 (-a3defc93).
A estrutura do arquivo de gênesis:
{
"chain_id": 20,
"timestamp_ms": 1790835251661,
"validators": [ { "public_key": "<hex>", "stake": 1000000000000, "payout": "rand1…" } ],
"alloc": [ { "cm": "<64 hex>", "envelope": { "kem_ct": "…", "to_receiver": "…", "to_sender": "…", "body": "…" }, "amount": 1000000000000,
"opening": { "pk": "<64 hex>", "time": 0, "r": "<64 hex>" } },
{ "cm": "…", "envelope": { … }, "amount": 1000000000,
"opening": { "pk": "<64 hex>", "time": 0, "r": "<64 hex>", "asset": 1 } } ],
"faucet": true,
"confidential": true,
"fri_profile": "production",
"hc_bundle": "60af094acfe65d85fdb18fb3d06cf9085dcf28c96e59e87f1ee527226e6e3fce",
"bridge": { "emitter": "<64 hex>", "guardians": [ "<40 hex>" ], "emitters": { "2": "<64 hex>", "3": "…", "4": "…", "5": "…" },
"pq_guardians": [ "<hex>" ], "pause_key": "<hex>",
"rules_v2": { "global_mint_cap_per_window": 400000000000, "cap_window_secs": 86400 },
"guardian_set_index": 1, "burn_sequence": 13,
"min_inbound_sequence": { "2": 3, "3": 3, "4": 3, "5": 7 },
"rotation": { "delay_secs": 86400, "needs_possession": true },
"fees": { "mint_bps": 10, "burn_bps": 10, "recipient": "rand1…" } },
"tokens": { "registration_fee": 1000000000, "mint_cap_per_day": 10000000000000,
"tokens": [ { "name": "Shielded USD", "symbol": "zUSD", "salt": "<64 hex>",
"backings": [ { "chain": 2, "token": "<64 hex>", "decimals": 6 }, … ] } ],
"max_tokens": 4096, "burn_registration_fee": true, "bound_note_value": true },
"consensus_domain": 1,
"staking": { "faucet_budget_per_epoch": "10000000000000", "bond_activation_epochs": 2,
"max_weight_bps": 3333, "registration_v2": true,
"faucet_recipients": [ "rand1…" ], "faucet_minters": [ "<validator address>" ],
"max_stake_entry_bps_per_epoch": 2500, "admission_by_vote": true },
"epoch_blocks": 1000,
"max_program_words": 65535,
"max_proof_bytes": 4194304,
"max_block_bytes": 20971520,
"max_call_envelope_bytes": 65536,
"max_program_public_words": 32768,
"envelope_bytes": 1860,
"hardening_v6": true,
"hc_auth": "1e4e347f44cf86750b30a9a4bdf9ec9256efe353d4ff8017451eca7d195639c1",
"gas": { "gas_price": "100", "byte_price": "800", "bundle_gas_limit": 20479, "metering": "circuit",
"dynamic": { "target_block_bytes": 10485760, "target_block_gas": 262144,
"adjust_bps": 1250, "min_gas_price": "100", "min_byte_price": "800",
"max_gas_price": "10000", "max_byte_price": "80000", "byte_load": "paying" } },
"testnet": true,
"binding_domain": 1,
"proof_window_blocks": 1024,
"program_state": { "cell_fee": 10000000 }
}
Todo campo está no hash do gênesis. hc_bundle fixa o guest de pacote contra o qual cada prova de pacote é verificada, e hc_auth o guest de autorização contra o qual cada prova de autorização é verificada; um nó cuja compilação monte um guest diferente se recusa a iniciar e informa os dois digests. Os cinco campos max_* são opcionais e só entram no hash quando presentes; a chain 20 define os cinco. max_proof_bytes é de 4 MiB, onde as chains 13 a 16 tinham 8 MiB: desde a chain 17 uma transação pode carregar três provas (pacote, autorização, chamada), e um gênesis com hc_auth deve ter max_block_bytes de pelo menos três vezes max_proof_bytes mais 1 MiB. Cada nota de alloc traz o seu opening (pk, time, r e, para uma nota de token, asset), de modo que o dono e o valor de uma nota de gênesis são públicos por design. A chain 20 tem:
- uma seção
bridge: o conjunto de guardiões 1 no índice 1 com oito guardiões, emissores para as chains de origem 2, 3, 4 e 5 (os da chain 19), oitopq_guardiansDilithium2, umapause_key,burn_sequence13, umamin_inbound_sequencede 3 para as chains de origem 2, 3 e 4 e de 7 para a chain de origem 5, erules_v2(um teto global de emissão de 4.000 zUSD por janela de 24 h). Novos na chain 20:rotation, pela qual a rotação de um PQ-guardian ou da pause-key exige prova de posse pelas novas chaves e entra em vigor 86.400 s depois de confirmada; efees, pela qual a chain retém 10 bps de cada depósito e 10 bps de cada burn como uma nota zUSD para um endereço de tesouraria, de modo que um depósito credita o valor bruto menos a taxa e um burn libera o seu valor menos a taxa; - uma seção
tokens: uma taxa de registro de 1 RAND, queimada em vez de paga ao proponente; ummint_cap_per_dayde 100.000 tokens por lastro com oito casas decimais; um limite de registro de 4.096 tokens; o limite de 2^63 para o valor de uma nota; e zUSD listado no gênesis com seus sete lastros, 99 zUSD bloqueados (Ethereum USDT 22, BSC USDT 22, Tron USDT 30, Solana USDT 25) contra as duas notas zUSD de gênesis; consensus_domain: 1: toda assinatura de consenso está vinculada a este gênesis (Consenso);- uma seção
staking: o faucet limitado por lista de permissão a 16 carteiras e a 18 chaves de validadores emissores, com um orçamento de 10.000 RAND por época, um atraso de bond de duas épocas, um teto de peso de 3.333 bps e registros v2, como na chain 19; novos na chain 20,admission_by_vote(uma nova chave de validador só se registra depois que o conjunto de validadores a vota para entrar) e um orçamento de entrada de 2.500 bps do peso ativo por fronteira de época, onde a chain 19 tinha 10.000 RAND fixos (Staking). Não háslashing; - uma seção
gas: uma chamada paga pelo limite de gas que a sua prova declara e pelos seus bytes, a preços que começam em 100 unidades por gas e 800 unidades por KiB e se movem após cada bloco conforme o seu preenchimento em relação a uma meta de 10.485.760 bytes e 262.144 de gas, em no máximo 1.250 bps por bloco, nunca abaixo dos preços iniciais e, novidade da chain 20, nunca acima de 10.000 e 80.000. Somente os bytes que pagam um preço por byte, a prova de uma chamada e o seu envelope de entrada, contam para a carga do preço por byte (byte_load: "paying"). Toda prova de pacote declara o mesmo limite, 20.479 (Taxas); envelope_bytes: 1860: todo envelope de nota tem exatamente 1.860 bytes e traz um campo de memo criptografado;hardening_v6: true, a chave de endurecimento da v0.6, definida por toda chain desde a chain 16;testnet: true, a marca que permite que um faucet conviva com uma seção de bridge;binding_domain: 1: as provas de cada transação e cada mensagem de ação assinada incluem o hash do gênesis, de modo que nada provado ou assinado para uma chain é verificado em outra;proof_window_blocks: 1024: a âncora de um pacote pode ser uma das últimas 1.024 raízes de fim de bloco e o seutimepode estar até 1.024 blocos atrás da altura (256 na chain 19), o que dá a um prover lento ou delegado cerca de vinte minutos;program_state, RPL-2: células de programa, cofres de programa e a açãoInvoke, com uma taxa de célula de 0,1 RAND por célula que um invoke cria (JSON-RPC traz os limites).
Ele não tem seção aggregation, e a compilação se recusa a iniciar com um gênesis que traga uma.
timestamp_ms é o instante zero do relógio da cadeia. Ao gerar um genesis próprio, defina-o próximo do horário real de lançamento e nunca à frente dele. Se estiver muito no passado, o tempo de bloco fica atrás do relógio de parede até que o limite de 60 s por passo de bloco permita que o alcance. Se estiver mais de 15 segundos no futuro, o bloco 1 não é sequer confirmado: todo voto, inclusive o do líder, fica retido até que o horário de parede alcance o timestamp do genesis. Confira-o com o relógio da máquina que lança a frota, não com o da que gerou o arquivo.
Execução
rand-node run --datadir ./data --key node.key.json \
--listen /ip4/0.0.0.0/tcp/30303 --rpc 127.0.0.1:8545 --no-mdns \
--bootstrap /ip4/164.90.239.200/tcp/30303/p2p/12D3KooWEQEbUwZRgqhDPXhW7vNBmcRcnhUDGUADe81VFdv3ALYe \
--bootstrap /ip4/165.245.173.74/tcp/30303/p2p/12D3KooWJyc5oDHggAr89e9QrRFBy9Tg8TxXh18yzrb1SM6KKLYw \
--bootstrap /ip4/188.166.235.187/tcp/30303/p2p/12D3KooWSyX84P1DAbWByLHpRBMLRWD53r3Jj4aqVt6tHoF8B2ZQ
| argumento | padrão | significado |
|---|---|---|
--datadir | obrigatório | o diretório de dados inicializado |
--key | obrigatório | arquivo de chave: identidade de validator, identidade p2p, destinatário das taxas |
--listen | /ip4/0.0.0.0/tcp/30303 | multiaddr de escuta do libp2p, repetível |
--bootstrap | nenhum | peer a contatar na inicialização e a cada 30 s enquanto estiver desconectado, repetível |
--rpc | 127.0.0.1:8545 | o listener JSON-RPC e WebSocket do operador: todos os métodos, e ele confia no loopback. Mantenha-o no loopback e nunca encaminhe um endpoint público para ele |
--public-rpc <ADDR> | desativado | v0.6.8: um segundo listener, público, para um proxy reverso ou um encaminhamento SSH apontar: um conjunto fixo de métodos sem os métodos de chave de visualização, rand_mint ou rand_getPeers, sem lotes, sem WebSocket, um único medidor para todos os chamadores (JSON-RPC) |
--rpc-viewing-token-file <PATH> | desativado | v0.6.8: exige um bearer token (a primeira linha do arquivo, com 32 caracteres ou mais) nos métodos de chave de visualização de --rpc |
--reserved-peer <PEER_ID> | nenhum | v0.6.8, repetível: um peer admitido além do limite de conexões de entrada; veja Peers reservados |
--strict-gossip | desativado | v0.6.8: aceita apenas gossip com assinatura de autor, número de sequência e origem válidos; a adoção é feita nó a nó |
--validator | desativado | este nó mantém uma chave de validator e participa do consenso quando sua chave está no conjunto atual |
--no-mdns | desativado | desativa a descoberta na LAN; recomendado em servidores |
--block-interval-ms | 1000 | espaçamento mínimo entre propostas |
--view-timeout-ms | 3000 | timeout base de view, dobrando a cada timeout consecutivo até 8× |
--verify-chain | quick | verificação de integridade na inicialização: off, quick (estrutura e reexecução do ledger), full (também cada assinatura e QC) |
--keep-raw-proofs | desativado | modo de arquivo para a agregação de blocos; sem efeito na chain 20 |
--prune-history | desativado (mantém tudo) | mantém o ledger e apenas esta quantidade de histórico de blocos: <n>m, <n>h ou <n>d, no mínimo 1h. Os validators da testnet usam 24h, exceto os dois arquivos; veja Poda do histórico |
--min-free-disk-mb | 1024 | recusa-se a iniciar com menos espaço livre no sistema de arquivos do diretório de dados; rand_getHealth responde disk_low abaixo de quatro vezes esse valor. 0 desativa a proteção |
--prover <ADDR> | desativado | hospeda um prover delegado neste endereço, um listener próprio e nunca o RPC; veja abaixo |
--gas-price, --byte-price | 100, 800 | o piso de preço do pool para uma chamada em uma cadeia sem seção gas. O genesis da chain 20 define seus próprios preços, então o nó ignora ambas as flags ali e registra um aviso |
--prover-accept-spend-key foi descontinuado: um nó v0.6.8 que o receba se recusa a iniciar, portanto remova-o de qualquer arquivo de unit herdado da v0.6.7.
Os três bootstraps acima são os validators C, D e E, inalterados desde a chain 19. A chain 20 roda com as chaves de validator geradas para a chain 14, de modo que seus peer ids são os mesmos que a chain 14 usou; uma identidade p2p é derivada da chave de validator. A maioria dos validators mantém apenas um dia de blocos, portanto um nó que sincroniza a partir do genesis, ou que está mais de um dia atrasado, também precisa de um peer com histórico completo. Adicione um dos dois arquivos:
--bootstrap /ip4/168.144.46.203/tcp/30303/p2p/12D3KooWS5usdMPvsbaWSaT2xtKndHvDYurwmueoNvaRRarb2wRf # obs1
--bootstrap /ip4/206.81.29.236/tcp/30303/p2p/12D3KooWPocyZGcNB9Vp68VSfgVvNXhSzBBoJa4h9R1yMkp71XHh # rand-archive-2
Omita --validator para executar um observador. Inicialização: abrir o armazenamento, conferir os guests desta build com hc_bundle e hc_auth do genesis, executar a verificação de integridade (truncando uma cauda danificada e preservando o estado de segurança de votos), retomar o consenso a partir do head persistido, iniciar a rede e o RPC e, em seguida, sincronizar a partir de qualquer peer que esteja à frente. RUST_LOG assume por padrão info,libp2p=warn,libp2p_mdns=off; Ctrl-C ou SIGTERM, o sinal de parada do systemd, encerra de forma limpa. Reiniciar a partir do mesmo --datadir retoma a partir do head persistido.
Regras de topologia do fullnode: nós atrás de NAT discam para nós com endereços públicos; abra a TCP 30303 de entrada nos nós públicos; vincule o RPC a 127.0.0.1, a menos que haja firewall — ele aceita transações de qualquer um que consiga alcançá-lo e, depois que uma chave de visualização é importada nele, trate a porta como portadora de chaves. Mantenha --block-interval-ms em 1000 ou mais lento: a prova de um bundle leva cerca de dois minutos e seu anchor é válido por 1.024 blocos na chain 20 (256 na chain 19).
Um validator precisa de um relógio sincronizado. Desde a chain 14, o horário de parede faz parte do consenso (reforço da ponte B2). Um bloco cujo timestamp esteja mais de 60 s além do de seu pai é inválido, e um validator retém seu voto em um bloco cujo timestamp esteja mais de 15 s à frente do seu próprio relógio. Um validator com o relógio atrasado, portanto, deixa de votar sem registrar nenhuma falha, e dezoito de vinte e seis precisam votar para confirmar na chain 20. Execute NTP em todo validator e confira-o antes de iniciar o nó:
timedatectl # want "System clock synchronized: yes" and "NTP service: active"
chronyc tracking
apt-get install -y chrony && systemctl enable --now chrony # if it is not synchronised
Peers reservados
Desde a v0.6.8, um nó aceita no máximo 256 conexões de entrada estabelecidas e 64 semiabertas, e uma identidade libp2p não custa nada para ser criada, de modo que desconhecidos poderiam ocupar todas as vagas. Três tipos de peer são reservados, admitidos além do limite e atendidos a partir da parcela do orçamento de sincronização destinada aos validators: todo peer de --bootstrap, todo --reserved-peer e toda identidade de validator conhecida a partir de uma vinculação de peer assinada. Cada nó --validator assina sua identidade libp2p com sua chave de validator e a dissemina por gossip; um nó que conhece a chave a partir de um conjunto de validators reserva esse peer e mantém o registro entre reinicializações. O armazenamento de uma cadeia recém-gerada não contém vinculações, portanto, até que cheguem os primeiros anúncios, apenas os dois primeiros tipos são reservados: ao gerar uma cadeia, passe os peer ids dos validators da frota com --reserved-peer ou mantenha-os na lista de bootstrap (rand-node address --key <file> imprime o peer id de uma chave). rand_status.reserved_peers os contabiliza; em um nó da frota, deve chegar ao número de validators em até um minuto após a inicialização.
Verificação
rand-node status # rand_status verbatim
rand --rpc http://127.0.0.1:8545 status
rand peers
rand_status informa height, view, syncing, sync_target, peer_count, connected_peers, reserved_peers, mempool_size, is_validator, active_validator, faucet, confidential, testnet, fri_profile, programs, notes, nullifiers, tree_root, hc_bundle, hc_auth, binding_domain, gas_prices, o address e o peer_id do nó, os diagnósticos de sincronização (sync_inflight_age_ms, sync_failures, sync_late_batches), o disco (disk_free_bytes, disk_low) e o piso de retenção (prune_floor, 0 em um nó que mantém tudo; prune_history_secs, null quando não definido). Na chain 20, espere hc_bundle 60af094a…, hc_auth 1e4e347f…, faucet true, confidential true, testnet true, binding_domain 1, fri_profile "production" e gas_prices entre 100 e 10.000 por gas e entre 800 e 80.000 por KiB. rand_getGenesisHash deve responder 6210cf07…5135 e rand_getVersion, 0.6.8.
rand_getHealth responde disk_low (com free_bytes) antes de ok, syncing ou behind quando o espaço livre está abaixo de quatro vezes --min-free-disk-mb.
Poda do histórico
Um nó iniciado com --prune-history 24h mantém o ledger (notes, nullifiers, anchors, o registro de validators, programas) íntegro e apaga blocos mais antigos, seus certificados, transações e recibos. Uma passagem ocorre a cada 16º bloco confirmado e apaga até 512 blocos mais antigos que o timestamp do head menos a janela; o genesis, o head e seu pai nunca são apagados, e o piso só sobe. O espaço em disco é recuperado depois que o RocksDB executa a compactação. Na chain 20, assim como na chain 19, 24 dos 26 validators usam 24h e mantêm cerca de um dia de blocos. Quando a poda foi ativada para a chain 14 (2026-09-25), as tabelas de blocos de cada validator caíram de 19 GB para 3,3–4,4 GB depois que o backlog foi drenado; os outros dois, obs1 e rand-archive-2, validators também desde 2026-09-27, rodam sem a flag e mantêm tudo. Um nó da mainnet-beta nunca passa a flag.
Em um nó com poda, uma consulta endereçada por altura abaixo do piso (rand_getBlockByHeight, rand_getFinality por altura, um intervalo de rand_getBlocks ou rand_getCompactBlocks que o alcance) responde com o erro -32010 com data.floor: consulte um arquivo. Uma consulta endereçada por hash responde null para um bloco que o nó não mantém mais, como para um que nunca existiu. A varredura da carteira não é afetada, pois notes e nullifiers nunca são podados.
A verificação de inicialização de um nó com poda é estrutural (o bloco 0 e os blocos retidos, seus QCs, vínculos com o pai e líderes), não uma reexecução a partir do genesis, e não se repara sozinha: se falhar, sincronize novamente a partir de um arquivo. Não abra um diretório de dados com poda com uma build anterior à v0.5.7, a menos que ela rode com --verify-chain off: sua verificação padrão reexecuta a partir do genesis, constata a ausência do bloco 1 e trunca o ledger até o genesis.
Hospedagem de um prover
Na chain 20, uma carteira gera duas provas para cada bundle, e a maior exige cerca de 6 GB de memória. Uma carteira que não consegue comportá-la pode entregar essa prova a um prover delegado ao qual esteja pareada: o binário separado rand-prover ou o mesmo serviço hospedado por um nó.
rand-prover --home /root/prover keygen
rand-prover --home /root/prover pair --name laptop --url https://prover.example.net
rand-node run --datadir ./data --key node.key.json --prover 127.0.0.1:8600 --prover-home /root/prover
pair imprime um link randprover:. A carteira o recebe com rand prover pair <link> e depois gera provas por meio dele com a opção global --prover. O listener do prover é próprio, nunca um método do RPC: um endereço igual a --rpc é recusado. Com --prover, o nó se recusa a iniciar a menos que <prover-home>/prover.key.json exista (padrão <datadir>/prover) e haja 5.74 GB por slot de prova, mais 1 GiB de memória, disponíveis; --prover-max-parallel define os slots, um por padrão.
Na chain 20, o prover recebe a viewing key da carteira e um salt novo, não a spend key. A carteira produz ela mesma a prova de autorização sobre a spend key, de modo que um prover pareado pode ler todo o histórico dessa carteira e não pode gastar. Mantenha o listener em loopback, a menos que um proxy com terminação TLS fique à frente dele, e não o hospede em uma máquina que sirva um RPC público. Uma parada espera a prova em andamento, portanto defina TimeoutStopSec=180 em uma unit do systemd.
Verificar e reparar
rand-node verify --datadir ./data # full: hashes, QCs, signatures, proofs, ledger replay, the supply counters
rand-node verify --datadir ./data --mode quick # structure and ledger replay
rand-node verify --datadir ./data --repair # truncate a damaged tail; peers resync the rest
Pare o nó primeiro. O código de saída é 0 se estiver consistente e 2 se um problema foi encontrado e --repair não foi informado. O replay reverifica a prova de cada bundle, de modo que um build cujo conjunto de restrições difere do que produziu a chain para no primeiro bundle.
Tornar-se validator
Um validator entra em uma chain em execução por bonding, não por um novo genesis: inicie o nó com --validator, imprima um registro com rand-node register --key node.key.json --payout <rand1…> --v2 (a chain 20 recusa um registro v1), faça uma carteira dar bond de pelo menos 1,000 RAND com rand bond <address> 1000 --registration <hex>, e o nó passa a propor quando o bond é ativado: na chain 20, no mínimo três limites de época de 1,000 blocos após o bond. Na chain 20, o bond vem em segundo lugar. O genesis dela define staking.admission_by_vote, de modo que um bond que registra uma nova chave é recusado até que validators que detenham mais de dois terços do peso de votação tenham votado a favor da chave: cada um assina com rand-node admit sign --candidate <key or registration> --key <validator key> --genesis-hash 6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135, e um deles envia os votos com rand-node admit submit (Linha de comando). rand_getAdmitted lista as chaves votadas e ainda não registradas. No máximo 2,500 bps do peso ativo se tornam peso novo em um mesmo limite de época. Staking percorre o processo. Para uma chain de teste privada, rand-node genesis gera uma:
rand-node genesis --chain-id 88 \
--validator a.key.json,1000,rand1<a's payout address> \
--validator <hex public key of b>,1000,rand1<b's payout address> \
--alloc rand1<address>=1000 \
--epoch-blocks 1000 --faucet --fri-profile production \
--out genesis.json
e scripts/local-testnet.sh executa dois validators em uma máquina, com RPC em 8545 e 8546. Sem outras flags, o genesis não tem hc_auth, nem seção gas, nem memo. A chain 20 foi gerada com --hardening-v6 --bundle-guest v3 --auth-guest --gas-price 100 --byte-price 800 --bundle-gas-limit 20479 --gas-dynamic 10485760,262144,1250 --max-gas-price 10000 --max-byte-price 80000 --gas-byte-load paying --envelope-bytes 1860 --testnet --binding-domain 1 --proof-window-blocks 1024 --program-state-cell-fee 10000000 por cima (as chains 18 e 19 tinham as flags até --envelope-bytes), e suas seções bridge e staking e o consensus_domain foram inseridos pelo script de geração. Uma nova chain própria deve passar --binding-domain 1: uma carteira v0.6.8 gera a prova na forma vinculada ao genesis em todo chain id fora de 14 a 19.
Implantar em um servidor
O diretório deploy/ do repositório contém os scripts que a frota usa: deploy/push-to-vps.sh <ip> <letter> "<bootstraps>" [validator|observer] provisiona um servidor Linux (rsync do código-fonte, build, instalação de /usr/local/bin/{rand-node,rand}, inicialização de um datadir identificado pelo hash do genesis, instalação de um serviço systemd rand-node), e deploy/rebuild-vps.sh <ip> refaz o build a cada novo commit e reinicia mantendo os dados. Dois cuidados. O script de provisionamento inicializa a partir de deploy/genesis.json, que não é o arquivo da chain 20, portanto um nó para a testnet é configurado manualmente a partir de deploy/genesis-chain20.json (em main, veja acima). E os dois scripts fazem rsync de /root/fullnode com --delete, de modo que uma chave mantida dentro dessa árvore é apagada pelo próximo rebuild: mantenha-a em /root/keys, como a frota faz e como o script de provisionamento da v0.6.8 agora faz por padrão (o da v0.6.7 gravava a chave em /root/fullnode/deploy/). O gerenciamento do serviço é systemctl status rand-node, journalctl -u rand-node -f. O servidor precisa de build-essential clang cmake pkg-config libssl-dev e de uma toolchain Rust. Um servidor de 1 vCPU e 2 GB não consegue compilar os binários; compile em outro lugar e copie-os. Executar um validator e um aggregator traz os tamanhos e a configuração passo a passo.
O explorer
randscan.org roda ao lado do validator E e indexa a chain 20; sua API REST e seu feed WebSocket são a forma mais fácil de ler a chain sem um nó (API do explorer). O explorer é de código aberto (randprotocol/randscan) e seu indexador precisa apenas do JSON-RPC rand_* de um nó e de um banco de dados PostgreSQL, de modo que pode ser executado contra o seu próprio nó.