Como validar as apostas e sorteiosQualquer pessoa pode utilizar o seguinte script para validar tanto as apostas quanto o sorteio.
Talvez você já tenha python instalado em seu computador, pode verificar digitando python --version em um terminal. Outra alternativa é utilizar um site online, por exemplo
https://repl.it/languages/python3A seguir, o script:
from collections import namedtuple
import hashlib
import hmac
import sys
class Utils:
choices = 32
pick = 4
@staticmethod
def calculate_numbers(first_hash, second_hash, how_many=1, checksum=None):
if checksum:
calculated_checksum = hashlib.sha256(second_hash.encode()).hexdigest()
if calculated_checksum != checksum:
print("Provided checksum does not match. Please check it!!!")
return
else:
print("Checksum validation OK!")
raw_hash = hmac.new(first_hash.encode(), second_hash.encode(), digestmod=hashlib.sha256)
for n in range(how_many):
encoded_hash = raw_hash.hexdigest()
result = Utils.convert_hash_to_numbers(encoded_hash)
print(f"{n} - {encoded_hash} = {Utils.get_numbers([i.number for i in result])}")
Utils.print_formatted([str(i.segment) for i in result])
Utils.print_formatted([str(i.decimal) for i in result])
Utils.print_formatted([str(i.number) for i in result])
raw_hash.update(str(n).encode())
print()
@staticmethod
def print_formatted(value):
print("\t", end="")
for i in value:
print(f"{i:>3s} ", end="")
print("")
@staticmethod
def get_numbers(numbers):
result = []
for n in reversed(numbers):
if n not in result:
result.append(n)
if len(result) == Utils.pick:
return result
@staticmethod
def convert_hash_to_numbers(h):
Chunk = namedtuple('Chunk', ['segment', 'decimal', 'number'])
return [Chunk(i, int(i, 16), int(i, 16) % Utils.choices) for i in Utils.chunk_string(h, 2)]
@staticmethod
def chunk_string(string, length):
return (string[0+i:length+i] for i in range(0, len(string), length))
if __name__ == '__main__':
print_help = True
try:
if len(sys.argv) == 5:
if sys.argv[1] == 'draw':
print_help = False
print("Draw Validation")
Utils.calculate_numbers(first_hash=sys.argv[2], second_hash=sys.argv[3], checksum=sys.argv[4])
elif sys.argv[1] == 'ticket':
print_help = False
print("Ticket Validation")
Utils.calculate_numbers(first_hash=sys.argv[2], second_hash=sys.argv[3], how_many=int(sys.argv[4]))
else:
print("Incorrect number of parameters.")
except IndexError:
pass
finally:
if print_help:
print(f"Syntax:\n\t{sys.argv[0]} draw \n"
f"\t{sys.argv[0]} ticket ")
Para validar os tickets, é necessário fornecer o hash do bloco em que a transação foi incluída na blockchain, o hash da transação e o número de tickets a serem gerados (uma transação pode gerar mais de um ticket se for enviada uma quantidade múltipla do preço de um ticket)
De acordo com o exemplo dado acima, a transação
caf02fb319e38b7d6bceafcda0e6f8720ebf8dcd14a1f2632fcd7baddf85a1b1 foi incluída no bloco
608637, cujo hash é
000000000000000000054faed5985e33f3281604547ad22bd035785ca8ec20d8.
O valor enviado foi
0.002 e é o equivalente a dois tickets.
Rodando o script com esses parâmetros temos o seguinte resultado:
$ python validate_lottery.py ticket 000000000000000000054faed5985e33f3281604547ad22bd035785ca8ec20d8 caf02fb319e38b7d6bceafcda0e6f8720ebf8dcd14a1f2632fcd7baddf85a1b1 2
Ticket
0 - 5cc6992fc5006c21d788635354515682332e45cbaba6178bf61a8a0a5a88fd75 = [21, 29, 8, 26]
5c c6 99 2f c5 00 6c 21 d7 88 63 53 54 51 56 82 33 2e 45 cb ab a6 17 8b f6 1a 8a 0a 5a 88 fd 75
92 198 153 47 197 0 108 33 215 136 99 83 84 81 86 130 51 46 69 203 171 166 23 139 246 26 138 10 90 136 253 117
28 6 25 15 5 0 12 1 23 8 3 19 20 17 22 2 19 14 5 11 11 6 23 11 22 26 10 10 26 8 29 21
1 - b8940fbeee0c5140ab4663715eb93c8e2832ff7aa2391a9dc67b28e7bf4499ea = [10, 25, 4, 31]
b8 94 0f be ee 0c 51 40 ab 46 63 71 5e b9 3c 8e 28 32 ff 7a a2 39 1a 9d c6 7b 28 e7 bf 44 99 ea
184 148 15 190 238 12 81 64 171 70 99 113 94 185 60 142 40 50 255 122 162 57 26 157 198 123 40 231 191 68 153 234
24 20 15 30 14 12 17 0 11 6 3 17 30 25 28 14 8 18 31 26 2 25 26 29 6 27 8 7 31 4 25 10
As linha iniciando com "0 - " e "1 - " são o que realmente importa, elas indicam o número do ticket, o valor aleatório gerado para esse ticket e ao final, após o sinal de "=", os 4 números com os quais o ticket estará concorrendo.
O script fornecido anteriormente mostra em detalhe o processo de geração desses números, mas em linhas gerais:
- Os hashes do bloco e da transação são combinados utilizando sha256, essa sequência de caracteres possui 32 bytes (cada 2 caracteres aqui representam um número em hexadecimal - que varia de 00 a FF). Vvamos pegar o ticket 0 como exemplo:
5cc6992fc5006c21d788635354515682332e45cbaba6178bf61a8a0a5a88fd75
acima,
- A primeira linha após o ticket mostra essa divisão de 2 em 2 caracteres:
5c c6 99 2f c5 00 6c 21 d7 88 63 53 54 51 56 82 33 2e 45 cb ab a6 17 8b f6 1a 8a 0a 5a 88 fd 75
- A segunda linha apenas converteu os números de hexadecimal para decimal (aqui tem uma calculadora, assim como uma explicação para aqueles que tenham interesse:
https://calculareconverter.com.br/converter-hexadecimal-para-decimal/ )
92 198 153 47 197 0 108 33 215 136 99 83 84 81 86 130 51 46 69 203 171 166 23 139 246 26 138 10 90 136 253 117
- A terceira linha contém o resto da divisão de cada número por 32. Isso "normaliza" o resultado, fazendo com que tenhamos apenas números de 0 a 31. As chances de cada número aparecer são as mesmas porque 256 (o total de números válidos inicialmente) é múltiplo de 32:
28 6 25 15 5 0 12 1 23 8 3 19 20 17 22 2 19 14 5 11 11 6 23 11 22 26 10 10 26 8 29 21
Finalmente, começando do final da sequência anterior, pegamos os primeiros 4 números não repetidos, resultando nos números 21, 29, 8, 26
Para validar o sorteio, o processo é exatamente o mesmo, porém os parâmetros são o hash do bloco final, a sequência de caracteres e o hash informado no post inicial (esse hash será utilizado para confirmar que a sequência de caracteres não foi alterada. Vamos ao exemplo:
$ python validate_lottery.py draw 0000000000000000000465da70a3247e619e478ae45bf048e33a03a09a0f8dc2 eu-ainda-nao-sei-qual-a-palavra 95ec1d26f124c8d08323eaae796cd75f7ac13d93caab725ac6776f721af8f
Draw Validation
Provided checksum does not match. Please check it!!!
Veja que como eu ainda não sabia a sequência de caracteres, a validação falhou visto que o hash
95ec1d26f124c8d08323eaae796cd75f7ac13d93caab725ac6776f721af8f não corresponde ao que eu forneci ao script(
eu-ainda-nao-sei-qual-a-palavra). Neste caso nenhum detalhe foi gerado sobre os números sorteados.
Vamos agora tentar novamente com a sequência correta:
$ python validate_lottery.py draw 0000000000000000000465da70a3247e619e478ae45bf048e33a03a09a0f8dc2 4b95d84c-f41f-4eea-9f49-e7d147d4fb59 95ec1d26f124c8d08323eaae796cd75f7ac13d93caab725ac6776f721af8fea3
Draw Validation
Checksum validation OK!
0 - cc08162c81e682220e33e12cf55dfa0fa296500994fdd4c3e2e998f84cdc0a98 = [24, 10, 28, 12]
cc 08 16 2c 81 e6 82 22 0e 33 e1 2c f5 5d fa 0f a2 96 50 09 94 fd d4 c3 e2 e9 98 f8 4c dc 0a 98
204 8 22 44 129 230 130 34 14 51 225 44 245 93 250 15 162 150 80 9 148 253 212 195 226 233 152 248 76 220 10 152
12 8 22 12 1 6 2 2 14 19 1 12 21 29 26 15 2 22 16 9 20 29 20 3 2 9 24 24 12 28 10 24
Desta vez recebemos a mensagem que o checksum foi validado ok (Checksum validation OK!) e logo a seguir o resultado do sorteio (números 24, 10, 28 e 12) seguidos pelo detalhamento de como o número foi gerado, da mesma maneira que para a geração dos tickets (separação 2 a 2, conversão hexadecimal -> decimal, "normalização" dos números pegando o resto da divisão por 32 e finalmente pegando os 4 números não repetidos a partir do final)