Certa manhã, me deparei com um artigo sobre na blockchain da Waves platform.
O quadro geral estava claro, mas o método de implementação específico não. Quais códigos, assinaturas, o que, para onde, por quê?
Após várias consultas com o autor do oráculo, consegui unir a lógica do sorteio (implementada em PHP) com o algoritmo de geração de números aleatórios.
- No início do torneio/rodada, pedimos ao oráculo a primeira parte do código (R-code).
Nesse momento, não há informações sobre o número de jogadores, nem sobre a quantidade de prêmios, nem sobre o valor das recompensas e até mesmo sobre a existência da loteria. O oráculo emite um código aleatório pessoal através de uma transação, que poderá ser utilizado apenas uma vez e somente por quem o solicitou. A propósito, o R-code pode ser "adquirido" (entenda-se o custo da transação de solicitação + compensação ao oráculo pela transação de resposta, que soma cerca de $0.015 com a taxa atual, e o código em si é fornecido gratuitamente) com antecedência, em quantidades múltiplas, para não precisar esperar pela transação de resposta. Eu criei um pequeno buffer regularmente atualizado no banco de dados.
- O torneio normalmente dura 60 blocos na blockchain da Waves platform, o que atualmente equivale a aproximadamente 1 hora. O torneio é considerado realizado e fechado se, após 60 blocos, houver pelo menos dois ingressos, caso contrário, o tempo de atividade do torneio é estendido por mais 60 blocos.
- Imediatamente após o fechamento do torneio, formamos e enviamos a transação de dados (também pagamos uma taxa por isso, de aproximadamente $0.005), se necessário — várias transações, nas quais estão fixadas todas as condições do sorteio e uma lista ordenada de jogadores (ingressos) de onde precisamos selecionar os vencedores.
- Neste estágio, já temos a primeira parte do código (R-code) e o ID da transação de dados (TXID). Nós os enviamos para assinatura ao oráculo na forma de concatenação (R-code + TXID), novamente pagando a taxa e a compensação. O oráculo verifica os dados recebidos quanto à exclusividade e propriedade, e em resposta nos envia a segunda parte do código (S-code) no formato sha256, que se torna o ponto de partida para o gerador de números aleatórios.
- Para obter um número aleatório que indicará o número do bilhete vencedor, transformamos o S-code de dados binários sha256 em uma representação hexadecimal (HEX). Em seguida, a partir da string HEX resultante, obtemos um número. Calculamos o resto da divisão do número obtido pelo número de bilhetes (all_tickets) e adicionamos 1 ao resultado (para obter um número de 1 até all_tickets). No final, obtemos o número do vencedor.
- Se, de acordo com as condições do sorteio, houver vários vencedores, repetimos as operações anteriores na quantidade correspondente ao número de prêmios. Cada vez, removemos da lista o bilhete que já ganhou e diminuímos all_tickets em 1, enquanto substituímos o S-code pelo número anteriormente obtido.
Vamos analisar um exemplo real, torneio nº 119:
Um total de 7 bilhetes (all_tickets)
Custo do bilhete 50 moedas (Bet)
Taxa de jogo 10% (Fee)
De acordo com as regras da loteria, 30% vão para os prêmios, ou seja, neste caso, 2 bilhetes devem receber um prêmio, cujo valor é calculado pela fórmula (Bet*all_tickets-Fee)/2.
1. Recebemos o R-code:
2. Após o fechamento do torneio, temos uma lista de bilhetes na forma de pares: número + endereço (endereço da carteira de onde foi feito o pagamento da participação no torneio). Note que os endereços podem se repetir, isso significa que um participante comprou vários bilhetes em um único torneio, o que não é proibido pelas regras.
Enviamos a data da transação:
3. Solicitamos o S-code: com o comentário (R-code + TXID):
RdbAiAhKhveAtR4eyTKq75noMxdcEoxbE6BvojJjM13VE 82JTMzhHM5xEA2fQ9Qscd5QAJU3DAd8nShLjdVHTer5S
4. Recebemos o S-code:
5. Determinamos os vencedores.
6.
Como resultado, temos no blockchain um registro passo a passo do procedimento de sorteio de prêmios, com a possibilidade de verificá-lo a qualquer momento. Manipular os resultados por parte do organizador é praticamente impossível, ao menos que seja de forma imperceptível.
determinar o vencedor nº 1
Todos_ticket:
Índice: 1 Bilhete:139
Índice: 2 Bilhete:141
Índice: 3 Bilhete:143
Índice: 4 Bilhete:145
Índice: 5 Bilhete:147
Índice: 6 Bilhete:149
Índice: 7 Bilhete:151
1. bin -> hex (bin2hex(sha256(S-code))): Ri89jHB4UXZDXY6gT1m4LBDXGMTaYzHozMk4nxiuqVXdC -> 0xdaf5802953dcb27f89972e38e8900b898733f6a613e6e1c6c5491362c1832596
2. hex -> número gmp: 0xdaf5802953dcb27f89972e38e8900b898733f6a613e6e1c6c5491362c1832596 -> 99037963059744689166154019807924045947962565922868104113173478160267437352342
3. gmp -> módulo (mod=7): 99037963059744689166154019807924045947962565922868104113173478160267437352342 -> 4
4. módulo -> bilhete: 4 -> 145
determinar o vencedor nº 2
Todos_ticket:
Índice: 1 Bilhete:139
Índice: 2 Bilhete:141
Índice: 3 Bilhete:143
Índice: 4 Bilhete:147
Índice: 5 Bilhete:149
Índice: 6 Bilhete:151
1. bin -> hex (bin2hex(sha256(hex anterior))): daf5802953dcb27f89972e38e8900b898733f6a613e6e1c6c5491362c1832596 -> 0x9560e77525e9ea2db92cdb8484dc52046ccafac7c719b8859ff55f0eb92834a0
2. hex -> número gmp: 0x9560e77525e9ea2db92cdb8484dc52046ccafac7c719b8859ff55f0eb92834a0 -> 67565829218838067182838043983962684143266386786567427968312120473742580659360
3. gmp -> módulo (mod=6): 67565829218838067182838043983962684143266386786567427968312120473742580659360 -> 1
4. módulo -> bilhete: 1 -> 139
Fim.Fonte: habr.com
