Como implementar independentemente (Prova de Existência) em 2 etapas

Olá pessoal! Meu nome é Ararat e trabalho na QuantNet, que realiza concursos de estratégias algorítmicas. Recentemente, uma tarefa importante surgiu diante de mim - fornecer garantias para a inviolabilidade das datas dos usuários (isso é extremamente importante, pois, para verificar corretamente a eficácia das estratégias, é necessário usar dados dos mercados financeiros globais em tempo real).

Foi aí que me deparei com o conceito de PoE (Prova de Existência). Já foi escrito bastante sobre isso na Internet, mas as especificidades da plataforma me fizeram pensar um pouco. Portanto, decidi escrever este artigo e compartilhar minha experiência na arquitetura e implementação de PoE. Eu acho que será especialmente relevante para os caras da fintech.

Dividi meu artigo em 3 blocos principais:

  • O que é PoE e quando pode ser necessário
  • Algoritmo de implementação
  • A solução para o meu caso específico

Então, o que é Prova de Existência?


A prova de existência (literalmente, prova de existência) ajuda a provar que um documento, arquivo ou dado foi criado em uma data e hora específicas. O maior pedido é o registro de patentes. Mas pelo que vi, na maioria das vezes é aplicado em áreas na interseção entre finanças e TI.

Um exemplo da minha área de negociação algorítmica: você tem um algoritmo que fornece cerca de 70% das previsões corretas de ações para as próximas 2 semanas. Você decide vender suas previsões para outros participantes do mercado. A questão é pequena: convencer o comprador de que suas previsões estão corretas e foram feitas antes dos resultados da licitação, ou seja, garantir sua implementação em um horário específico.

Como isso pode ser garantido? Certo, implemente o PoE.

Algoritmo de implementação de PoE


Primeiro você precisa:

  1. Prepare o arquivo que você deseja patentear. (Fiz o PDF, mas você pode usar qualquer outro contêiner).
  2. Obtenha o hash do arquivo fornecido (usei o formato sha256).

Apenas no caso, um hash é uma “impressão digital” individual de um arquivo, garantindo (quase completa) ausência de coincidência com o hash de outro arquivo. Ao receber o hash do arquivo, você precisará gerar apenas uma transação na rede blockchain especificando o hash do documento no corpo da transação.

Só isso. Com o prólogo terminado. Agora passamos ao mais interessante.

(Para maior clareza, criei um código especial (apenas para demonstração). Você pode ver o exemplo do serviço de demonstração aqui .)

Vamos dar uma olhada em como a demo funciona.

Proponho dividir a implementação em 2 partes:

  1. Preparação de um contrato inteligente e uma carteira de éter.
  2. Geração de transação no código Node.js e chave privada.

Vamos em ordem:

Parte 1: Preparando um contrato e uma carteira Ethereum Smart

O próprio PoE foi primeiro associado ao blockchain Bitcoin. Mas eu escolhi o blockchain do éter e os contratos inteligentes para implementação. Contratos inteligentes nos dão flexibilidade, modularidade e escalabilidade no futuro, agindo como um armazenamento para hashes na blockchain.

Eu escolhi um contrato inteligente simples que pode aceitar um hash com uma data apropriada, o formato hash => data, também seria ótimo ter um método que retorne a data do hash quando chamado. Além disso, seria bom garantir que apenas o proprietário do contrato pudesse adicionar novos hashes.

Código do contrato inteligente:

``` pragma solidity 0.5.9; /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". */ contract Ownable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ constructor () internal { _owner = msg.sender; emit OwnershipTransferred(address(0), _owner); } /** * @return the address of the owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner()); _; } /** * @return true if `msg.sender` is the owner of the contract. */ function isOwner() public view returns (bool) { return msg.sender == _owner; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0)); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } /** * @title HashStore * @dev The contract store the hashes and returns date by hash * Only the owner can add new hashes */ contract HashStore is Ownable { mapping(bytes32 => uint256) private _hashes; event HashAdded(bytes32 hash); function addHash(bytes32 rootHash) external onlyOwner { require(_hashes[rootHash] == 0, "addHash: this hash was already deployed"); _hashes[rootHash] = block.timestamp; emit HashAdded(rootHash); } function getHashTimestamp(bytes32 rootHash) external view returns (uint256) { return _hashes[rootHash]; } } ``` 

Como você já percebeu, usamos 2 contratos separados: Próprio e HashStore.
O contrato HashStore é responsável por armazenar hashes e emitir a data do hash, mediante solicitação. O contrato de Propriedade é responsável por verificar se o novo hash foi adicionado exclusivamente pelo proprietário do contrato.

Para adicionar um hash, você precisa chamar o método addHash, passando o valor sha256 como argumento para o nosso arquivo. Se os hashes dentro do contrato corresponderem, a transação será rejeitada. Isso filtra a duplicação indesejada de valores com datas diferentes. É verificado aqui:

 require(_hashes[rootHash] == 0, "addHash: this hash was already deployed"); 

Podemos obter a data da transação do hash usando o método getHashTimestamp, passando o hash com a data da transação desejada como argumento. O método getHashTimestamp retorna a hora no formato UNIX. Você pode traduzir para qualquer formato mais legível.

Então, descobrimos o contrato, agora você precisa implantá-lo na rede. Para fazer isso, precisamos de duas coisas:

  1. éter para interagir com o blockchain
  2. algum éter para chamar métodos e implantar contratos.

Para não desperdiçar éter nos testes, podemos usar a rede de testes de ropsten. Saiba mais aqui. Esse endereço é o proprietário do contrato, pois foi o iniciador da implantação e pode adicionar novos hashes no futuro. Depois disso, você precisa salvar este endereço em um local seguro, bem como a chave privada da sua carteira e o endereço do contrato. Todos nós precisaremos disso no futuro.

Parte 2: Geração de transação no Node.js e chave privada

Portanto, neste ponto, já temos uma carteira de éter, sua chave secreta, um contrato na rede de teste e um hash de dados. Resta configurar a interação com o blockchain.

Para fazer isso, usaremos a biblioteca web3.js e criaremos um token para nosso nó. Criei o meu usando o serviço infura.io e ele se parece com isso:

 ropsten.infura.io/v3/YOUR_TOKEN_HERE 

Para hash, use o pacote sha256. O formato dos dados pode ser qualquer um, mas no exemplo usamos os dados em JSON.

Como resolvi meu caso usando PoE?


Além de ter PoE, era importante para mim não sobrecarregar os usuários com blockchain e taxa de transação, por exemplo, chamar o método addHash (bytes32 rootHash) custa 0,2 finney (0,0002 ETH ou US $ 0,06 à taxa de junho de 2019).



Cerca de 30 conclusões da posição estratégica saiam por dia, ou seja, custa US $ 2,1. Se o número de usuários aumentar 100 vezes e a taxa de Éter aumentar, o custo, é claro, aumentará.

Decidi manter um hash na blockchain por um dia. Esse hash será gerado a partir de hashes de saídas diárias da estratégia e seus identificadores internos.



Temos uma solução que não tem funcionalidade inferior, porém, muito mais barata. Não vemos problemas com escalabilidade, no entanto, você sempre pode dividir a saída de uma posição estratégica em vários blocos e salvar vários hashes na rede blockchain. E um participante pode facilmente verificar um hash separado usando outros hashes vizinhos.

No final


Para verificação, criamos um modelo especial, disponível como um notebook Jupyter. A qualquer momento, o usuário pode baixar o modelo, regenerar tudo e verificar se todas as posições são realmente aquelas que foram criadas e salvas no passado.

 ```   : 1.    API       1.     2.    API  ,         3.          ,              .          . ``` 

Source: https://habr.com/ru/post/pt459046/


All Articles