NOVO: Helius adquire a Light Protocol
Como lidar com erros de blockhash na Solana
Blog/Desenvolvimento

Como lidar com erros de blockhash na Solana

Engenheiro de Experiência do DesenvolvedorOwen Venter no XOwen Venter no LinkedIn
7 min de leitura

O que é um blockhash?

Para entender o que é um blockhash, você precisa entender o que são slots e blocos.

  • Um slot é um período no qual um validador pode produzir um bloco 
  • Um bloco é um conjunto de transações + metadados processado por um validador. Os metadados de cada bloco o conectam ao bloco anterior, criando uma cadeia.

É importante entender que os slots duram entre 400 e 600 ms e que, em cada slot, um validador pode propor um novo bloco. Se nenhum bloco for criado, o slot será incrementado e outro validador tentará criar um novo bloco. Isso significa que nem todos os slots terão blocos associados, mas todos os blocos têm slots associados nos quais foram propostos.

Certo, então o que é um blockhash? Um blockhash é um valor de hash exclusivo de todos os registros do ledger da blockchain criados durante um slot. Ele é calculado a partir do ID do último registro do bloco. Cada bloco produzido resulta na criação de um blockhash exclusivo. Esses blockhashes são usados como marcas temporais.

Quais são os níveis de compromisso da Solana?

Outro conceito importante são os níveis de compromisso. Esses níveis de compromisso medem a confirmação da rede para um bloco específico. As três opções são processed, confirmed e finalized.

Quando um validador envia um bloco para a cadeia, o bloco fica no estado processed. Depois que o número necessário de validadores (66% dos validadores)  vota pela inclusão do bloco, ele é adicionado à cadeia e o nível de compromisso muda para confirmed. Após outros 31 blocos serem criados sobre esse bloco, o nível de compromisso muda para finalized.

Por que ocorrem erros de blockhash?

Todas as transações incluem um blockhash recente que funciona como uma marca temporal, e a transação expira quando esse blockhash deixa de ser considerado recente o suficiente. Os validadores que processam transações verificam a “BlockhashQueue” (uma lista dos últimos 300 blockhashes) para conferir se o blockhash da transação é recente o suficiente. Se o blockhash não estiver na lista, a transação será rejeitada. Como os slots geralmente duram entre 400 ms e 600 ms, um blockhash permanece válido por 60 a 90 segundos.

Blockhash não encontrado (falha na simulação da transação: blockhash não encontrado)

Erros de “blockhash não encontrado” ocorrem quando o blockhash incluído em uma transação não é considerado válido no momento em que um validador processa a transação. Isso pode acontecer porque ele é antigo demais ou, em alguns casos, recente demais. 

A causa mais comum desse erro é o blockhash incluído em uma transação não estar presente na fila dos últimos 300 blockhashes usada pelo validador para comparação. Isso causa o erro de blockhash não encontrado. As transações podem expirar no intervalo entre sua criação e seu processamento dentro do período exigido. Isso pode acontecer quando um usuário demora muito para assinar uma transação. Também pode haver situações em que uma transação válida é enviada, mas não é incluída no bloco atual e, quando pode ser incluída em um bloco posterior, o blockhash da transação já está muito antigo.

Em situações como essa, nas quais a transação efetivamente expirou, é comum encontrar erros de altura de bloco excedida (TransactionExpiredBlock heightExceededError). Para entender melhor esse erro, é necessário saber o que significa altura do bloco. A altura do bloco representa o número de blocos abaixo do bloco atual. Se o bloco atual for o bloco 1000, a altura do bloco será 1000. Quando uma transação é criada, a altura máxima do bloco até a qual essa transação será válida é registrada. Se, durante o processamento da transação, a altura atual do bloco for maior que a altura máxima válida do bloco da transação, o erro será gerado.

Outra situação que pode causar um “erro de blockhash não encontrado” ocorre quando o blockhash de uma transação é mais recente que o blockhash usado para verificar a expiração dessa transação. Isso pode parecer confuso, então vejamos um exemplo: você cria uma transação e inclui o blockhash de um bloco específico, digamos o bloco 1000, e a envia imediatamente para um RPC. O RPC pode obter o blockhash do bloco anterior, que, nesse caso, poderia ser o bloco 999 (porque o RPC usa um nível de compromisso mais alto ou porque o nó RPC está atrasado em relação à rede). Como resultado, o blockhash da transação não será encontrado. Essa é uma situação incomum, mas pode ocorrer em dois cenários:

1. Níveis de compromisso incompatíveis

Ao criar a transação, o nível de compromisso confirmed é usado, mas, quando o RPC calcula sua validade, ele usa o nível finalized por padrão.

Isso pode fazer com que o blockhash usado na verificação seja mais antigo que o blockhash da transação, pois os blocos finalized estão 31 blocos “atrás” do bloco mais recente.

Se o nível de compromisso processed for usado para obter o blockhash de uma transação em uma bifurcação minoritária que acaba sendo descartada, o blockhash será inválido e não será encontrado durante o processamento.

2. RPCs incompatíveis

Se dois RPCs diferentes forem usados para obter o blockhash e enviar a transação, qualquer atraso no RPC que envia a transação poderá fazer com que o bloco usado para verificar a validade seja mais antigo que o bloco usado na criação da transação.

Como corrigir erros de blockhash

Existem algumas medidas que você pode tomar para lidar com cada uma das situações mencionadas acima.

1. Garanta que a transação seja enviada com um blockhash que não seja antigo demais:

Use o nível de compromisso confirmed ao obter o blockhash de uma transação, pois isso garante a inclusão de um blockhash mais recente em comparação com o nível de compromisso finalized.

Você também pode usar o nível de compromisso processed para obter um blockhash um pouco mais recente, mas cerca de 5% dos blocos processados não são finalizados pelo cluster. Isso significa que o blockhash da transação pertencerá a uma bifurcação descartada e não será mais válido.

2. Garanta que o blockhash de uma transação não seja mais recente que o blockhash usado para verificar a validade da transação:

Sempre defina preflightCommitment (mesmo ao usar skipPreflight) com o mesmo nível de compromisso usado para obter o blockhash da transação. Isso evita que o blockhash da transação seja mais recente que o blockhash usado para verificar a validade da transação.

Para lidar com nós RPC atrasados ao enviar transações, você deve continuar reenviando as transações ao RPC. Isso pode ser feito em intervalos definidos para que, se um RPC estiver atrasado, ele eventualmente alcance a rede e detecte a expiração da transação.

Se a solicitação simulateTransaction for usada, o parâmetro replaceRecentBlockhash deverá ser definido. Esse sinalizador instrui o RPC a substituir o blockhash da transação simulada por um blockhash que sempre será válido para a simulação.

3. Continue tentando enviar a transação enquanto o blockhash for válido:

Quando uma transação for criada e o blockhash mais recente for obtido, você deverá registrar o lastValidBlockHeight desse blockhash. Depois, poderá continuar tentando enviar a transação com esse blockhash até que a altura atual do bloco ultrapasse a altura válida do bloco da transação. A chamada RPC getBlockHeight pode ser usada para verificar continuamente se a transação ainda é válida. Quando a altura atual do bloco for maior que a altura lastValidBlock da transação, um novo blockhash deverá ser obtido e usado.

Espero que este artigo ajude você a entender melhor os erros de blockhash e a reduzir a frequência com que eles ocorrem. Se tiver outras dúvidas, participe da nossa comunidade no Discord ou envie uma mensagem direta para nós no X.

Recursos adicionais:

‍

Assine a Helius

Acompanhe as novidades mais recentes do desenvolvimento Solana e receba atualizações quando publicarmos

Imagem ampliada