
A rede Ethereum, amplamente conhecida em um círculo restrito de desenvolvedores de blockchain, já se estabeleceu como uma plataforma conveniente e estável para o desenvolvimento de contratos inteligentes. Tentamos disponibilizar contratos inteligentes para usuários despreparados, oferecendo contratos simples, mas praticamente úteis. Recentemente, desenvolvemos um contrato inteligente de disputa Bet Me. O contrato é baseado em uma aposta (disputa) entre dois oponentes. Eles reforçam a justiça própria com uma taxa monetária. O perdedor perde dinheiro e o vencedor leva tudo. Vou falar mais sobre isso neste artigo.
Por que a blockchain está aqui?
Para começar, a pergunta que os autores de artigos sobre o blockchain raramente fazem é: o blockchain é necessário nessa situação? Quais tarefas são difíceis de resolver com um contrato oral ou contrato legal, mas simplesmente com uma blockchain?
Se duas pessoas discutiram verbalmente, isso geralmente se traduz em um novo julgamento. "Eu não quis dizer isso", "As circunstâncias externas influenciaram o resultado, caso contrário, eu teria razão", "Sim, eu não discuti seriamente com você, mas você pensou nisso consigo mesmo" e outras possíveis desculpas fazem uma argumentação oral para muitas pessoas conhecidas taxas razoavelmente baixas. Com apostas sérias e um conhecido relativamente distante, é mais promissor concluir um contrato por escrito e anotar em detalhes a essência da disputa, apostas, critérios de decisão e quaisquer outras condições que as partes considerem importantes.
Essa abordagem tem várias desvantagens.
- Na maioria das vezes, é necessário atrair um advogado, ou até dois, um de cada lado; caso contrário, você poderá esquecer um ponto importante, o que levará a perdas financeiras.
- Freqüentemente, apenas as obrigações das partes são prescritas no contrato, mas a responsabilidade pela violação dessas obrigações não é. Como resultado, é muito fácil para um lado não pagar e, para o outro, é extremamente difícil e caro obter seu dinheiro nos tribunais.
- Ou pode ser que ambas as partes insistem em sua inocência, e mesmo ir a tribunal não garante que o vencedor receba o dinheiro.
- Pode acontecer que o lado perdedor simplesmente não tenha dinheiro, e mesmo uma decisão judicial não o forçará a pagar suas dívidas, apesar de todas as obrigações.
A blockchain (e a rede Ethereum em particular) permite que você trabalhe com dinheiro (nós chamaremos de éter dinheiro; isso não é totalmente correto, mas é conveniente e reflete suficientemente o verdadeiro estado das coisas, pois éter é muito fácil trocar por dinheiro fiduciário e vice-versa). Ao mesmo tempo, no Ethereum, você pode reduzir os contratos a um conjunto de regras específicas, simplesmente não é possível não cumpri-las. Portanto, nosso contrato inteligente aceita dinheiro de cada lado e o bloqueia até que eventos específicos ocorram. Um conjunto de regras predefinidas do programa permitirá ao vencedor sacar dinheiro. Isto é exatamente o que você precisa.
Implementação
Um conjunto de regras que regem uma disputa pode ser implementado de várias maneiras. A seguir, falaremos sobre o que fizemos para os usuários da plataforma Smartz.
A disputa envolve duas partes. Quem cria a cópia do contrato na rede Ethereum é chamado de proprietário do contrato (Proprietário), e seu oponente é chamado de oponente (Oponente). O proprietário do contrato configura uma declaração textual que ele considera verdadeira. O oponente está apostando que a afirmação é falsa. A decisão sobre o resultado da disputa é tomada por um árbitro independente (Árbitro), cuja candidatura é aprovada pelo proprietário e pelo oponente. O árbitro recebe uma comissão na forma de uma porcentagem do valor da disputa.
O trabalho do contrato é dividido em várias etapas sucessivas.
- As negociações . O proprietário e o oponente, mesmo antes da criação do contrato, podem negociar de qualquer maneira conveniente. Depois de decidirem em conjunto quem será o árbitro, eles enviam ao candidato um convite para julgar sua disputa. Ao receber o convite, o árbitro verá todas as condições e o Estado correspondente. Mais sobre isso abaixo, mas por enquanto é importante entender que o futuro árbitro deve transferir esse número para o contrato para mostrar em que condições ele está pronto para julgar os debatedores. Se o proprietário estabeleceu um valor diferente de zero do depósito de segurança (ArbiterPenaltyAmount), então, de acordo com os termos, o árbitro deve transferir a quantidade indicada de tempo de antena para o contrato, após o qual é bloqueado até que o árbitro decida os debatedores ou até o prazo final para a solução da disputa. Neste último caso, o árbitro perde a oportunidade de retirar o depósito de segurança, e esse valor é distribuído igualmente entre as partes na disputa.
- Inicialização . O proprietário do contrato cria uma instância do contrato e define seus parâmetros: objeto de disputa; a data em que o árbitro deve decidir (Prazo); porcentagem da comissão de arbitragem (número fracionário ≥ 0 e <100); o valor da fiança (pode ser zero), que o árbitro deve dar como garantia de que ele se compromete a decidir a disputa na redação existente na hora certa. O proprietário também define o endereço Ethereum do árbitro em quem ele confia. Somente o proprietário deste endereço poderá se tornar um árbitro posteriormente.
- Taxa do proprietário Após a configuração, o titular do contrato faz uma aposta. Para fazer isso, ele envia qualquer quantidade de éter ao contrato. Esse valor é a taxa, ele é bloqueado no endereço do contrato.
- O consentimento do árbitro . O lance do proprietário corrige os termos da disputa. Agora, o árbitro vê os termos completos da transação: a redação da disputa, o tempo antes do qual uma decisão precisa ser tomada e, o mais importante, ele pode entender quanto éter receberá como recompensa. Se o árbitro estiver satisfeito com tudo, ele confirma sua participação e, ao mesmo tempo, transfere o depósito do seguro.
- Procure um oponente . Após o consentimento do árbitro, começa a busca pelo oponente. O proprietário define o endereço do oponente com antecedência, se ele estiver pronto para discutir apenas com alguém específico ou deixar o endereço vazio e, em seguida, o proprietário de qualquer endereço na rede (exceto o árbitro e o proprietário) poderá se tornar o oponente. O oponente confirma a participação na disputa chamando um método separado do contrato, para o qual ele transmite o número da versão atual dos dados e transmite - tanto quanto o proprietário definiu. A partir deste momento, a aposta é considerada concluída. Agora, o contrato aguarda a decisão do árbitro ou a data-limite.
- O resultado da disputa . O árbitro pode julgar a disputa de três maneiras.
- Reconheça a afirmação como verdadeira. Nesse caso, o proprietário do contrato pode retirar toda a quantidade de éter, exceto a comissão do árbitro e o depósito de segurança (se houver): o dinheiro é retirado pelo árbitro e o oponente não recebe nada.
- Reconheça a declaração como falsa. Nesse caso, o árbitro pode retirar o éter no valor da comissão devido a ele e no valor da promessa. O oponente fica com o resto, mas o dono não recebe nada.
- declarar a disputa insolúvel. Por exemplo, o proprietário criou uma disputa com a afirmação "A partida de futebol entre as equipes A e B, marcada para o próximo domingo, terminará com uma pontuação de 2: 1 a favor de A". Se a partida for cancelada, o árbitro não resolverá a disputa, mas ele poderá receber sua promessa, porque o problema não foi causado por sua falta. Nesse caso, cada uma das partes poderá solicitar a transferência de ar no valor de sua própria oferta do endereço do contrato para sua carteira. - Retirar fundos . Quando o árbitro tomar uma decisão ou a data do prazo chegar, cada uma das partes poderá solicitar uma conclusão no ar. Quanto éter produzir, o próprio contrato calculará, concentrando-se nos resultados da disputa.
- Destruição do contrato . O proprietário pode enviar um comando de autodestruição ao contrato. Isso pode ser feito antes da conclusão da transação (se o árbitro não foi encontrado) ou após a sua conclusão (se todas as partes retiraram os fundos devidos a elas). Essa oportunidade será útil se, de uma maneira mágica, mais ar do que o recebido for recebido no endereço do contrato. A probabilidade de tal evento é muito baixa, mas ainda no Ethereum é impossível bloquear completamente a transferência da transmissão para o endereço de um contrato arbitrário, e jogar dinheiro congelado é bobagem.
Agora, um pouco sobre por que o número da versão do estado é necessário. Esse é o número que aumenta a cada alteração nas condições significativas da disputa, como a redação da disputa, o tamanho das comissões ou multas do árbitro. Quando alguém concorda com os termos da disputa, 1) vê o estado atual dos dados; 2) envia uma chamada para o método de contrato, que registra a aceitação dos termos. Se entre esses dois eventos uma das partes (provavelmente o proprietário) alterar o parâmetro do contrato, você concordará com a outra versão dos dados. Por exemplo, um candidato a árbitro entra na interface do contrato no smartz.io e vê que ele está sendo oferecido para julgar uma disputa no 10 Ether (hoje são cerca de US $ 3.000) por uma comissão de 1% (cerca de US $ 30). O candidato concorda e envia a transação de confirmação para a rede. O proprietário desonesto vê no pool de mineração a transação bruta do árbitro e envia a sua: muda a remuneração do árbitro em 0%. Um fraudador coloca o preço do gás acima da média e, com alguma probabilidade, os mineradores podem processar sua transação mais cedo. Tal ataque é chamado de ataque frontal. O Número da versão do estado protege contra ele. Se a transação do proprietário-praga for processada anteriormente, o número da versão dos dados no contrato será alterado. O árbitro em sua transação enviou o número da versão dos dados um a menos. Portanto, o contrato se recusará a concluir a transação, ocorrerá uma reversão. O árbitro revisará as novas condições e se recusará a participar ou concordar enviando o número da versão atual dos dados.
Ao desenvolver um contrato de éter, você precisa pensar muito em cenários ruins. O que acontecerá se o proprietário do contrato decidir privar o árbitro? E se o árbitro fosse desonesto? E se o oponente for realmente um hacker? Ou os três estão ansiosos para se enganar, porque os riscos na disputa são altos o suficiente? Além disso, é necessário levar em consideração possíveis violações do curso normal da disputa, quando a transmissão será bloqueada no contrato e até o proprietário não terá acesso a ela. Por exemplo, a opção de declarar a disputa insolúvel já surgiu durante a implementação. Pelo mesmo motivo, a sequência de etapas da disputa é a seguinte: taxa do proprietário -> escolha do árbitro -> taxa do oponente. Pode acontecer que o oponente não tenha confirmado sua participação, e o prazo final seja definido no futuro. Para não se tornar um investidor de longo prazo, o árbitro pode se recusar a participar, mas apenas até que o oponente tenha feito uma aposta. E há muitas dessas nuances no contrato. A boa notícia é que isso precisa ser programado uma vez e usado. Se a disputa fosse formalizada como um contrato em papel, no caso de tais situações de fronteira, muitas pessoas teriam que entrar em cada item repetidamente e concordar entre si como interpretá-lo. O blockchain permite que você fixe as condições, como no contrato, mas atribua a interpretação das condições à máquina virtual e sempre tenha um e apenas um resultado de sua execução.
Não se pode ignorar o problema de um árbitro interessado. Em nosso contrato, o árbitro toma a decisão sozinho. Para situações simples, isso é suficiente, mas às vezes o risco de interesse pessoal do árbitro é inaceitável. Uma saída é introduzir na lógica do contrato a capacidade de adicionar vários árbitros e tomar uma decisão votando. Essa é uma lógica bastante complicada, especialmente se você deseja torná-la universal para todas as disputas possíveis e seus participantes. No entanto, a boa notícia é que toda a lógica da arbitragem coletiva complexa pode ser movida para um contrato inteligente separado. O endereço do contrato que o proprietário da disputa registrará como árbitro. Do ponto de vista da interface, esse contrato deve poder chamar vários métodos do contrato de disputa: consentimento para julgar a disputa, recusa de tal consentimento, três versões da decisão e um método de transmissão. Dentro do contrato de arbitragem, a lógica de decisão da maioria dos árbitros pode ser usada, semelhante à maneira como é feita no contrato da Carteira de várias assinaturas, também disponível no Smartz.io como construtor.
Para parte das disputas, é possível substituir o grupo de árbitros por um contrato usando um ou mais oráculos. Ou invente outra maneira, por exemplo, transforme o argumento em roleta com uma solução aleatória. E tudo isso - sem alterar o código do contrato da disputa e sem complicar a lógica do seu trabalho.
Teste
Eu quero dizer algumas palavras sobre o teste. Todo mundo sabe que a automação de teste é boa. Muitos, na verdade, escrevem testes para seu código. Algumas pessoas usam a abordagem TDD no desenvolvimento - o longo e bem conhecido Test Driven Development. A principal diferença entre TDD e teste simples é que os testes são escritos antes do código. Isso permite que você observe o código do contrato de fora, sinta os possíveis problemas e resolva-os com antecedência. Além disso, o TDD, quando usado corretamente, permite alterar significativamente a lógica do trabalho, se necessário de repente. O uso adequado vem com a experiência. O TDD não é uma bala de prata, como você pode pensar, lendo vários materiais sobre esse tópico. Ao mesmo tempo, é preocupante que os guias de desenvolvimento no Truffle e no Node.js. não demonstrem o uso do TDD para o desenvolvimento do Solidity. Desenvolvedores iniciantes adquirem maus hábitos e acabam sofrendo muito.
TDD implica que existem muitos testes no projeto. Por exemplo, o código do contrato de disputa tem 325 linhas e o código de teste deste contrato tem 2144 linhas. Em algum momento, os testes se tornaram grandes o suficiente para que o teste de trufas levasse mais de um minuto. O ciclo de desenvolvimento no TDD envolve testes frequentes após pequenas alterações no código. Para que o desenvolvimento não se tornasse um tormento, tive que ensinar o Truffle a executar apenas parte dos testes que correspondiam à expressão regular transmitida.
Sob o capô, o Truffle usa a estrutura Mocha para testes. O Mocha pode filtrar o início dos testes por intervalos regulares, mas o Truffle não consegue passar o parâmetro --grep correspondente na linha de comando que está fora da caixa. Aproveitando o fato de que a configuração do Truffle é um código JavaScript normal, inseri nele uma análise dos argumentos da linha de comando e a formação de parâmetros para o Mocha. A configuração que obtive como resultado está disponível no projeto GitHub. A implementação não é muito bonita, mas funciona e economiza muito tempo.
Sumário
O contrato de disputa foi concebido como uma funcionalidade muito simples, mas graças ao TDD e à análise de possíveis vetores de ataque, ele evoluiu para uma implementação de restrições um pouco mais rica. As deficiências óbvias do contrato estão relacionadas à decisão exclusiva do árbitro; no entanto, elas podem ser eliminadas sem modificação do código do contrato de disputa, se o sistema de votação de vários árbitros for implementado em um contrato inteligente separado. O uso de oráculos para disputas em que isso é possível é realizado da mesma maneira.
O contrato de disputa do BetMe pode ser testado e executado usando um modelo predefinido na plataforma Smartz . Isso exigirá uma extensão Metamask para o navegador da área de trabalho ou a Trust Wallet para dispositivos móveis. Além disso, o código-fonte do próprio contrato é publicado no GitHub.
Vale a pena reconhecer que hoje o uso de tecnologias blockchain se resume principalmente a criptomoedas e à emissão de tokens para ICOs. Organizações Autônomas Descentralizadas (DAOs) ainda não se tornaram realidade. Mas se você imaginar como os sistemas de contrato de disputa se desenvolverão ainda mais, você pode imaginar uma lista de árbitros com uma classificação, por exemplo, com base no Registro Curadoria de Token. Após a conclusão das disputas, seus participantes podem votar a favor ou contra os árbitros com que lidam, mudando de posição no ranking.
Por um lado, o contrato de disputa da BetMe é um elemento auto-suficiente praticamente aplicável. Mas, por outro lado, pode muito bem se tornar um dos tijolos a partir dos quais, com o tempo, o ecossistema de organizações descentralizadas se formará.
Ligações