Uso e Melhores Práticas para o Gerador de Números Aleatórios ( Algorand )
Introdução
O gerador de números aleatórios da Algorand permite que contratos inteligentes acessem valores aleatórios. Este artigo explica como usar com segurança este gerador de números aleatórios. Ele complementa o artigo Aleatoriedade na Algorand que apresenta uma compreensão melhor de como o gerador funciona.
Alerta!
IMPORTANTE: Não seguir estas melhores práticas pode levar à perda total de fundos.
Visão geral do gerador de números aleatórios
O gerador de números aleatórios é composto por um serviço externo (oráculo) e um contrato inteligente de gerador de números aleatórios associado. Na TestNet, o contrato inteligente do gerador de números aleatórios tem a seguinte identificação de aplicativo: 110096026. Na MainNet, o contrato inteligente do gerador de números aleatórios tem o seguinte ID de aplicativo: 947957720.
O serviço gera provas Função Aleatória Verificável - VRF (ver Aleatoriedade na Algorand para cada rodada que é um múltipla de 8 e as submete ao contrato inteligente do gerador de números aleatórios, que verifica a correção dessas provas e armazena seus resultados em seu armazenamento global. O contrato inteligente pode armazenar até 189 saídas VRF, o que significa que ele armazena valores para 189 * 8 = 1512 rodadas passadas.
O contrato inteligente do gerador de números aleatórios usa essas saídas VRF para gerar valores pseudo-aleatórios para outros contratos inteligentes.
Utilização
Para que os contratos inteligentes tenham acesso à aleatoriedade, eles precisam consultar os contratos inteligentes do gerador de números aleatórios através dos seguintes métodos da ABI:
-
get(uint64,byte[])byte[]
: - Entrada:
-
round uint64
: a rodada da qual tiramos a saída VRF -
user_data byte[]
: dados opcionais do usuário a serem combinados com a saída do VRF - Saída:
get
um valor pseudo-aleatório de 32 bytes derivado da saída VRF armazenada correspondente a uma determinada rodada, a rodada e os dados do usuário. Caso a saída VRF não esteja disponível para a rodada, ela retorna uma matriz de bytes vazia. -
must_get(uint64,byte[])byte[]
: A lógicamust_get
é a mesma de get, mas entra em pane no caso de não haver valor a retornar.
As melhores práticas
Em resumo, um contrato inteligente que utilize o gerador de números aleatórios deve:
- Comprometer-se com a rodada na qual a aleatoriedade será acessada
- Assegurar um intervalo (em rodadas) entre a última entrada para os contratos inteligentes e a rodada compromissada (por exemplo, parar o registro do sorteio algumas rodadas antes da rodada compromissada para evitar a manipulação do resultado)
- Ler o valor aleatório somente após ele estar disponível (que pode levar até 11 rodadas em operação normal, mas muito mais em caso de serviço degradado. Veja abaixo para mais detalhes)
- Ler o valor aleatório antes que ele fique indisponível (1512 rodadas depois)
- Tratar cuidadosamente os casos em que o gerador de números aleatórios não fornece valores para um certo número de rodadas
- Tratar cuidadosamente os casos em que o gerador de números aleatórios é descontinuado, o que significa atualização do contrato inteligente ou pelo menos da identificação do aplicativo do contrato inteligente do gerador de números aleatórios. Os contratos inteligentes que não seguem as melhores práticas acima podem parar para sempre (e perder fundos) ou podem estar sujeitos a ataques à sua aleatoriedade. Os detalhes são fornecidos nas próximas subseções.
Se comprometendo com uma rodada futura
Um usuário ou contrato inteligente usando os métodos acima deve se comprometer publicamente em várias rodadas no futuro nas quais pretende usar os métodos. Quanto mais rodadas, melhor. O compromisso pode ser implícito ou explícito: contratos inteligentes usando aleatoriedade podem codificar as rodadas que eles estarão usando, "log", ou apenas defini-las implicitamente.
Além disso, deve haver rodadas suficientes entre a última entrada na qual a aleatoriedade pode ser aplicada e a rodada escolhida para a aleatoriedade. Novamente, quanto mais rodadas, melhor.
Por exemplo, um contrato inteligente de loteria que executa uma loteria a cada 10.000 rodadas pode usar sistematicamente a aleatoriedade em rodadas que são múltiplas de 10.000 (este é um compromisso implícito). Além disso, o contrato inteligente de loteria exigirá que todas as apostas de loteria sejam feitas em 200 rodadas (para uma loteria de grande valor) ou em 1 rodada (para uma loteria de pequeno valor) antes da rodada compromissada.
A chamada real para o contrato inteligente do gerador de números aleatórios só pode ser feita após a rodada comprometida ter passado e o serviço tiver enviado as provas VRF associadas.
Além disso, não devem ser feitas mais do que 1512 rodadas depois.
Lógica
Os valores pseudo-aleatórios para rodadas no passado já são conhecidos e não mais aleatórios! Se não houver compromisso com a rodada a ser escolhida, o usuário pode simplesmente esperar até encontrar uma rodada para a qual o valor pseudo-aleatório seja bom para ele (por exemplo, fazer com que eles vençam na loteria).
Além disso, é importante que a semente de bloco usada como entrada para o VRF no contrato inteligente de aleatoriedade seja imprevisível para o usuário. Quanto mais no futuro a rodada compromissada for, mais difícil será prever a semente do bloco, mesmo que o usuário tenha um controle significativo sobre a rede da Algorand.
Prazos de acesso ao valor aleatório
Qualquer contrato inteligente usando o gerador de números aleatórios precisa obter o valor aleatório para a rodada com a qual eles estão compromissados no momento certo (fazendo uma chamada get
or must_get
para o contrato inteligente do gerador de números aleatórios). Na maioria dos casos, isto requer o uso de um serviço externo para enviar na hora certa a transação certa (que então faz uma chamada get
ou must_get
para o contrato inteligente do gerador de números aleatórios).
Alerta!
Entretanto, é possível que em alguns casos o serviço VRF esteja atrasado e haja a necessidade de esperar por mais rodadas. Os contratos inteligentes precisam estar cientes de que podem precisar esperar mais do que o esperado para receber valores aleatórios e os serviços que chamam esses contratos inteligentes devem lidar com a situação de forma cordial.
Acesso ao valor aleatório em tempo hábil
Valores aleatórios só podem ser recuperados quando a saída VRF associada é armazenada no contrato inteligente do gerador de aleatoriedade. Na prática, isto significa que a chamada get
ou must_get
para o contrato inteligente do gerador de aleatoriedade deve ser realizada antes de 1512 rodadas após as rodadas compromissadas.
Caso isto não seja possível, os contratos inteligentes intermediários/proxy e serviços associados podem ser projetados para armazenar mais rodadas de valores aleatórios. O desenvolvedor do contrato inteligente é responsável pela execução desses serviços
Atualização e resiliência contra paralisações e descontinuidades
O gerador de números aleatórios pode enfrentar tempo de inatividade ou descontinuação total. Detalhes sobre riscos potenciais serão fornecidos no Anexo.
Do ponto de vista do desenvolvedor do contrato inteligente, isto significa que o contrato inteligente deve ser resistente a: * O valor aleatório para uma determinada rodada nunca estar disponível. * O contrato inteligente do gerador de números aleatórios deixar de funcionar completamente.
Um contrato inteligente não resiliente pode levar à perda completa de fundos. Por exemplo, uma loteria não resiliente exigindo o valor aleatório de 30.000 para distribuir os fundos ao vencedor perderia para sempre os fundos se o gerador de números aleatórios fosse descontinuado.
A solução mais simples para o problema é permitir a possibilidade de atualização do contrato inteligente.
Outra opção é usar um contrato inteligente por procuração atualizável entre o contrato inteligente real e o contrato inteligente por procuração. Este contrato inteligente proxy pode simplesmente chamar o contrato inteligente do gerador de números aleatórios. Mas devido a sua capacidade de atuaização, ele pode ser alterado para um contrato inteligente do gerador de números aleatórios diferente, caso o contrato original seja depreciado.
Outra solução é permitir que os participantes retirem seus fundos caso não haja maneira de obter o valor aleatório para a rodada compromissada, ou após uma quantidade fixa de blocos ter passado. Desta forma, o risco de ficar com os fundos bloqueados no contrato inteligente é reduzido.
Além disso, é importante que qualquer um possa acionar a chamada do contrato inteligente para obter o valor aleatório e não apenas o proprietário. Desta forma, o proprietário não pode bloquear a distribuição de ativos caso o resultado não esteja a seu favor.
Anexo: Detalhes sobre o tempo de parada e riscos de descontinuação
Devido ao fato de que o contrato inteligente de aleatoriedade depende de um serviço externo para apresentar provas de VRF, alguns riscos estão envolvidos:
O serviço está em baixa por algumas rodadas: se o serviço estiver em baixa por algumas rodadas, pode ocorrer um atraso na apresentação dos valores, o que significa que um usuário deve esperar mais tempo para obter a aleatoriedade.
O serviço está em baixa por mais de 1000 rodadas: como o contrato inteligente de aleatoriedade verifica cada prova VRF apresentada (com a ajuda do
vrf_verify
opcode, explicado neste artigo) e como as provas VRF são geradas a partir de sementes de bloco, somente as provas que foram geradas a partir de sementes de bloco das últimas 1000 rodadas podem ser verificadas. Caso o serviço esteja em baixa por mais de 1000 rodadas, algumas rodadas não terão valores aleatórios correspondentes a serem utilizados na chain. Assim, todo contrato inteligente que chama o contrato inteligente do gerador de números aleatórios deve ser projetado de tal forma que os fundos não sejam perdidos caso seja impossível obter aleatoriedade para a rodada compromissada, por exemplo, tendo uma ou mais rodadas de reserva ou permitindo que a comunidade vote na mudança da rodada.A chave privada VRF é destruída ou comprometida, ou mais geralmente, o serviço VRF está descontinuando as operações: o contrato inteligente do gerador de números aleatórios é imutável, o que significa que ele só verifica as provas VRF que foram geradas com a mesma chave privada. Caso esta chave não possa mais ser utilizada, o contrato inteligente do gerador de números aleatórios torna-se inutilizável (quer não possa aceitar mais provas de VRF ou o detentor da chave privada não seja confiável) e um novo contrato inteligente deve ser implantado com uma nova chave privada. Isto significa que um usuário deve ser resiliente a um caso em que o contrato inteligente do gerador de números aleatórios é trocado, por exemplo, chamando um contrato inteligente de proxy mutável.
Artigo escrito por Ori Shem-Tov e traduzido para o português por Rafael Ojeda
Você pode ler o artigo original em inglês aqui
Latest comments (0)