Construindo um Blockchain: The Gray Paper

Background

O trem de excitação do blockchain está em um alto histórico! Existem inúmeros artigos e notícias que o chamam de maior invenção desde a internet. Por outro lado, há um acampamento igualmente grande dizendo que, embora a tecnologia seja ótima, não existe um caso de uso real .

Até recentemente, estive em algum lugar do meio. Intrigado por blockchain comecei a pesquisá-lo. Depois de ler vários artigos e white papers, senti-me confortável com alguns dos termos e conceitos. No entanto, eu ainda não tinha esse momento “aha” O conteúdo que eu estava lendo era um nível muito alto e não transmitia claramente o poder eo potencial de construção de aplicativos distribuídos e descentralizados.

Há duas semanas Blockchain Academy TLV iniciou sua sessão inaugural. A premissa da Academia Blockchain é promover uma discussão técnica ativa e produtiva sobre blocos.

Meu objetivo é explicar o que eu aprendi até agora na minha jornada de blocos de bloco, e acompanhar você através de uma implementação de bloqueio inspirado Ethereum, eu tenho trabalhado nas últimas 2 semanas.

O que não posso criar, não entendo

Durante o primeiro encontro do Blockchain TLV, Leonid Beder discutiu os conceitos básicos do blockchain, e codificou uma implementação de bloqueio básico em formato simples. A implementação incluiu a seguinte funcionalidade:

Blockchain: uma lista crescentemente crescente de registros , denominados blocos , que são vinculados e protegidos usando criptografia . Cada bloco geralmente contém um ponteiro hash como um link para um bloco anterior, um carimbo de data e hora e dados de transação. Definimos uma classe inicial com a seguinte interface:

  • Nós armazenamos todos os blocos na cadeia de blocos.
  • Nós armazenamos o conjunto de todas as transações que esperam ser processadas.
  • Método para criar novos blocos
  • Método para envio de novas transações no pool.

Blocos: Todo bloco da nossa cadeia conterá

  • Número do bloco (ou seja, “3º bloco na cadeia”)
  • transações
  • Timestamp – tempo de criação do bloco
  • Número não-arbitrário que só pode ser usado uma vez
  • O hash do bloco anterior – usando o hash anterior, tornamos a cadeia de blocos imutável

Transações: definimos uma classe de transações que continha

  • O endereço público do remetente
  • O endereço público do destinatário
  • O valor da transação.

Enviar um nó : um bloco é um banco de dados distribuído e descentralizado, onde cada nó da rede possui uma cópia completa do histórico de transações Uma vez que estamos desenvolvendo uma cadeia de bloqueio sem permissões, todos podem participar. Este método nos permite adicionar nós à rede.

Enviar uma transação : um bloco de cadeias serve como registro do histórico de transações. Embora uma transação possa ser definida de forma ampla, o caso de uso mais popular é uma transferência de fundos do usuário A para o usuário B. Esse método nos permite criar transações, esperando ser minado.

Mine a Block : as transações não são refletidas na rede imediatamente. Precisamos investir o poder computacional na validação de transações. Isso é chamado de Prova de Trabalho. Minar um bloco é a ação de executar “Prova de Trabalho” em todas as transações que foram recentemente emitidas, mas ainda não foram validadas. Não há almoços gratuitos em criptografia;)

Consenso : Consenso é o processo de todos os nós que chegam a acordo sobre o estado atual da rede. Escolhemos a abordagem da “Cadeia mais longa” (Greedy Maior Observado Subtree). Esta abordagem afirma que todos os nós aceitarão o bloqueio do nó com a maioria dos blocos. O raciocínio por trás disso, é que a cadeia de blocos mais longa possui o poder mais computacional investido nele (lembre-se, exigimos que os blocos sejam validados via PoW) e, portanto, é o mais confiável / credível.

Confira o código fonte das oficinas aqui.

Embora fosse um monte de material novo para processar em uma hora, fiquei preso 🙂 Para o final da oficina, Leonid anunciou uma surpresa!

                                                            Eu gosto de surpresas

Haveria uma competição para ver quem poderia fazer o pedido de atração mais criativo e “incrível” para o bloco de bloco básico que acabamos de construir.

Meu trabalho nas últimas 2 semanas

Eu estava com vontade de aprender mais sobre blockchain, e acredito que construir um é a melhor maneira de fazer isso. Comecei a criar uma cadeia de blocos inspirada na implementação Ethereum com as seguintes características:

  • Sistema de contabilidade – os usuários poderão registrar contas (contas externas) com um saldo e iniciar transferências de fundos. Além disso, os usuários podem registrar contas de contrato e implantar contratos inteligentes em toda a rede
  • Máquina de estado baseada em transações
  • Transações garantidas e validadas e transições de estados
  • Permita que os usuários escrevam contratos inteligentes e aplicativos descentralizados onde eles podem criar suas próprias regras arbitrárias para propriedade, formatos de transação e funções de transição do estado.

Contas

O estado compartilhado global de nós na rede é composto por contas. As contas detêm informações importantes, como

  • endereço: isso servirá como o nome da conta, semelhante ao que fizemos na oficina.
  • saldo: montante dos fundos de propriedade da conta
  • nonce : se a conta é uma conta de propriedade externa, esse número representa o número de transações enviadas pelo endereço da conta.

Minha implementação de bloqueio tem dois tipos diferentes de contas:

  • Contas externas, que são controladas por chaves privadas (via criptografia RSA)
  • Contas contratuais, que são controladas pelo código do contrato.

Estado compartilhado único em toda a rede

As contas são públicas, e você pode ver qualquer conta, dado seu endereço, e o nó foi registrado. Eu criei contas “globais” informando todos os nós da criação de uma conta na rede. Então, quando as transações da conta são despachadas para um nó, eu propagar essa transação para todos os nós na rede. Desta forma, o bloco é verdadeiramente descentralizado, e não dependemos de nós simples para informações valiosas, como existência de conta ou saldos de contas. Essencialmente, criamos um singular “estado compartilhado” entre os nós.

Registramos cada conta em cada nó, de modo que seja “global”

Diferenças entre contas externas e de contrato

A principal diferença entre os dois tipos de contas está enraizada na forma como eles podem se comunicar com outras contas na rede. Uma conta externa pode se comunicar de duas maneiras

  1. Mensagens de outras contas externas (ou seja, uma transação que move fundos da conta A para B).
  2. Invocando a execução do método em contas contratuais. Esses métodos variam, pois dependem apenas do autor do contrato e do contrato que ele / ela criou.

É importante esclarecer que as contas do contrato, em contraste com as contas externas, não podem enviar despachos explícitos para a rede. Em vez disso, as contas de contrato só podem emitir transações em resposta a outras transações que receberam.

Contas Externas

A autenticação de contas é feita via criptografia RSA. Após a inicialização da conta, um par privado de chave pública é criado e gravado no disco.

Teclas criadas no construtor ExternalAccounts. À direita, vemos a chave pública

Essas chaves são usadas para assinar digitalmente pedidos de transações de saída com as credenciais da conta. Uma implementação mais robusta sempre pede uma conta, quer ele quer ou não assinar o pedido antes de enviá-lo. Você pode ver uma implementação rudimentar deste em requestAuthForTransaction.sh.

requestAuthForTransaction.sh

Um pressuposto que fiz para esta implementação é que todas as contas concordam em assinar todos os pedidos de transações com suas credenciais.

Contas de Contrato

As contas do contrato são controladas pelo seu código. Eles simplesmente executam um código específico quando invocados e têm controle direto sobre o equilíbrio.

Um dos desafios aqui foi descobrir como suportar isso em uma maneira dinâmica, distribuída, descentralizada e de confiança. O Ethereum usa uma máquina virtual acessível a nível mundial (dado um ponteiro para o código de byte do contrato) para executar o código do contrato. Mas JS não tem uma VM globalmente acessível fora da caixa para todos os nós a serem consultados. Inicialmente, tentei implantar um contrato para todos os nós na rede como um objeto JSON com stringência, de modo que a execução do contrato poderia ser invocada de forma independente em cada nó, analisando o objeto recebido. Infelizmente, o JSON.stringify ignora métodos e funções, portanto, eliminando contratos inteligentes de suas funcionalidades em gravações. A minha solução alternativa para o envio de contratos de forma dinâmica (não codificada em cada instância de nó) em toda a rede foi a seguinte:

Implantando um Contrato

  1. Escreva um contrato inteligente como um objeto JS simples.

2. Envolva-o com parênteses para torná-lo uma string e remova todas as novas linhas para que possa ser processado através do método JS eval incorporado quando outros nós a recebem.

3. Envie a string como dados para todos os nós na rede.

Implantando um contrato em toda a rede

Isso permite que os nós criem contratos on-line e os implante na rede. Agora, um nó pode receber um contrato que não conheceu antes e executar seu código! 😀😀😀

Escrevendo atualizações do contrato

Inicialmente, podemos analisar o contrato stringificado usando o método JS eval incorporado, que leva uma seqüência de caracteres e o avalia como uma declaração JS.

Depois de executar um método que altera o estado do contrato (ou seja, altera o saldo do contrato), queremos armazenar o contrato na íntegra, sem perder o acesso aos nossos métodos.

Portanto, usaremos o método de stringis JSON e passamos uma função “substituição” personalizada , instruindo-o sobre como seqüenciar as funções.

No futuro, para ler a versão especialmente rigorosa do contrato, passaremos um “reviver” personalizado para o método JSON.parse.

Emitir transações através da execução do contrato

Algumas mutações contratuais só podem atualizar o estado interno do contrato. Outras execuções de contrato podem “emitir” transações que efetuam o estado da rede. Por exemplo, um contrato que detém fundos (os contratos regem seus próprios fundos) pode enviá-los a um usuário específico após uma determinada condição ser cumprida. Essas transações emitidas são ouvidas e colocadas na fila de mineração, de forma semelhante a outras transações na rede. Eles devem ser validados antes de serem gravados no bloco. O fluxo parece assim:

Uma transação emitida por meio de um pedido de mutação do contrato, anexado ao mempool

Contratos inteligentes com permissões

Chamar um contrato inteligente simplesmente invoca um método que resulta em uma emissão de transação. Os contratos são implantados globalmente e gostaríamos de uma maneira fácil de controlar quem pode invocar métodos de contrato. Gostaríamos de permitir que os usuários criem contratos que suportem permissões de usuários. Por exemplo, em uma eleição, nós só queremos que os usuários elegíveis possam votar (podemos determinar a elegibilidade, no entanto, achamos adequado). Como todas as transações solicitadas são assinadas digitalmente via criptografia RSA pelo solicitante, podemos verificar com segurança o usuário que solicitou a execução do contrato e decidir se ele está ou não autorizado a fazê-lo.

Exemplo DAOVotingContract.ts com permissões

Validação de transação

Durante a primeira oficina, implementamos uma versão bruta das transações. Porque não tínhamos contas, nenhuma forma de identificação e nenhum saldo para atualizar, não tinham significado. Depois de implementar o acima, agora podemos verificar a legalidade, ou “correção” de uma transação solicitada

Função de transição estatal

O white paper da Ethereum descreve um cronograma de cryptocurrency como um sistema de transição do estado, onde o estado é composto pelo status de propriedade da moeda dentro do sistema. Na minha implementação, cada nó possui contas que possuem um saldo específico. Mas como o estado (equilíbrio) muda ao longo do tempo? Ethereum especifica uma Função de Transição de Estado da seguinte forma:

Ilustração do Livro Branco Ethereum

Em nossa implementação, tomaremos uma abordagem semelhante para validar transições de estado. Nós vamos:

  1. Verifique se uma transação adere à estrutura solicitada e possui todos os valores necessários.
  2. Todas as transações têm um SenderNodeId e um SenderAddress. Embora esta seja uma hipótese insegura, para a implementação atual e para a falta de um cliente de usuário apropriado, assumiremos que todas as contas concordam e assinam digitalmente todos os pedidos de transações de saída com suas credenciais. Antes de ser submetido à fila de mineração, verificaremos essa assinatura digital .
  3. Verifique se o nonce corresponde ao nonce na conta do remetente .
blockchain.ts

Depois de verificar a transação através do método stateTransitionValidation , podemos adicionar a transação para a fila de mineração e a minha. É importante notar que essas transações ainda não modificaram o estado da rede . Após o consenso, se essas transações pertencem à cadeia mais longa, e é uma transação que move fundos, validaremos que o remetente tenha um saldo de conta adequado. Um exemplo de filtragem de transações ilegais (o remetente A que envia mais fundos, ele possui) pode ser visto em apropriadoFunds.sh.

apropriadoFunds.sh

Para visualizar este processo:

Exemplo de Contratos

Agora que nosso bloco possui contas, transações validadas e uma maneira de criar e propagar contratos em toda a rede, podemos observar alguns contratos reais. Esses contratos são bastante legais e mostram a flexibilidade e o potencial de criar contratos inteligentes na cadeia de blocos.

Contra-contrato

Para começar as coisas, vejamos um contrato simples que atua como um contador. Toda vez que o método incrementValue do contrato é chamado, incrementaremos o contador. Observe que qualquer pessoa pode invocar este código de contrato.

const CounterContract = {
balance: 0,
counter: 0,
incrementValue: function() {
this.counter++;
},
id: 1,
fromAddress: Alice,
call: function() {
return {
getBalance: this.balance,
getFromAddress: this.fromAddress
};
},
send: function() {
return {
incrementValue: this.incrementValue
};
},
abi: function() {
return {
sendables: this.incrementValue.toString()
};
}
};

Invocamos o código do contrato enviando uma solicitação mutateContract /: CounterContract PUT . Este contrato tem seu próprio estado interno que governa. Quando o incrementValue é chamado, o estado do contrato emite uma transação, solicitando a mutação do estado do contrato. Depois de ser minado, a mutação é escrita na cadeia de blocos, de modo que tenhamos um registro de quem usou o contrato (iniciou o pedido de mutação) e como o contrato foi usado.

Este contrato pode ser executado através do cliente Postman ou executando o script counter_contract.sh no diretório shell-scripts.

Transferir fundos após a data arbitrária Contrato

Um cenário mais realista para um contrato inteligente é transferir fundos da conta A para a conta B. O contrato a seguir é baseado no cenário em que Bob quer transferir 400 moedas para Alice, após uma data arbitrária ter passado. Em vez de usar um serviço de terceiros, ou sistema de custódia, ele pode criar um contrato inteligente que verifica quando a data passou, e iniciar uma transferência de fundos.

const MoveFundsAfterDateContract = {
balance: 400,
expirationDate: new Date(October 13, 2016 11:13:00),
id: 2,
fromAddress: Bob,
call: function() {
return { getBalance: this.balance, getFromAddress: this.fromAddress };
},
send: function() {
return { changeBalance: this.changeBalance };
},
abi: function() {
return { callables: this.call(), sendables: this.send() };
},
moveFunds: function() {
var currentDate = new Date();
if (currentDate > this.expirationDate) {
return {
senderNodeId: B,
senderAddress: Bob,
recipientNodeId: A,
recipientAddress: Alice,
value: 20,
action: TRANSACTION_EXTERNAL_ACCOUNT
};
}
return null;
}
};

Quando o método moveFunds do contrato é invocado, ele verificará a data, verá que passou e transferiu fundos para Alice.

Este contrato pode ser executado através do cliente Postman ou executando o script move_funds_after_data_contract.sh no diretório shell-scripts.

DAO Vote para o contrato de bônus

Este cenário envolve um DAO (organização autônoma descentralizada) que quer dar um bônus a um de seus funcionários. Como este DAO é uma organização completamente justa 😀😀😀, devemos votar em quem é merecedor do bônus.

Mas lembre-se, o blockchain é um livro público! Portanto, no momento em que carregamos para contratar a rede, qualquer pessoa pode vê-lo e fazer chamadas para o código do contrato. Nós gostaríamos de restringir a votação somente aos funcionários da DAO. Como mencionei anteriormente, cada solicitação com credenciais de contas, é assinada digitalmente por essa conta, com sua chave privada. Desta forma, é fácil verificar a verdadeira origem dos eleitores. Então, este contrato tem um campo “autorizadoVoters” que verificaremos contra, sempre que uma conta tentar votar.

const DAOVotingContract = {
balance: 400,
id: 3,
authorizedVoters: [
{ nodeId: A, address: Alice },
{ nodeId: B, address: Eve },
{ nodeId: A, address: Gal Gadot }
],
votes: [
{
nodeId: C,
address: Gal Gadot,
votes: 0
},
{
nodeId: C,
address: Ben Affleck,
votes: 0
}
],
fromAddress: Bob,
candidateA: {
nodeId: C,
address: Gal Gadot
},
candidateB: {
nodeId: A,
address: Selena Gomez
},
call: function() {
return {
getBalance: this.balance,
getFromAddress: this.fromAddress
};
},
send: function() {
return {
moveFunds: this.changeBalance
};
},
moveFunds: function(userData, vote) {
// Check if vote requester is authorized
const authorizedVoterIdx = this.authorizedVoters.findIndex(
user =>
user.nodeId === userData.nodeId && user.address === userData.address
);
if (authorizedVoterIdx === 1) return null;
// Check if candidate requester is voting for exists
const candidateIndex = this.votes.findIndex(
candidate => candidate.address === vote
);
if (candidateIndex === 1) return null;
// Cast Vote and verify users can’t vote twice
this.votes[candidateIndex].votes++;
this.authorizedVoters.splice(authorizedVoterIdx, 1);
// Users still need to cast vote
if (this.authorizedVoters.length > 0) return;
this.votes.sort((voteA, voteB) => voteB.votes voteA.votes);
return {
senderNodeId: B,
senderAddress: Bob,
recipientNodeId: this.votes[0].nodeId,
recipientAddress: this.votes[0].address,
value: 400,
action: TRANSACTION_EXTERNAL_ACCOUNT
};
}
};

Este contrato pode ser executado através do cliente Postman ou executando o script vote_permissions_contract.sh no diretório shell-scripts.

Estes são apenas vários exemplos de contratos inteligentes. A estrutura atual permite que qualquer pessoa faça o upload de qualquer contrato (desde que adira ao formato analisável que estou usando), implante-o na rede em sessão e comece a executá-lo. Podemos criar contratos para eleições, armazenamento de arquivos distribuídos e muito mais.

Conclusão

A programação dessa cadeia de bloqueio de prova de conceito foi um desafio! É apenas a ponta do iceberg em termos de formas de melhorar e garantir. Fui um excelente momento pesquisando os conceitos e aprendendo sobre implementações e mecanismos de cadeias de blocos.

Um grande agradecimento a Leonid Beder pela graciosa introdução do blockchain e aos colaboradores da Kin , Orbs e Samsung Next para organizar a Academia Blockchain .

Você pode verificar minha implementação completa aqui.

Se você quiser continuar a discussão do blockchain, sinta-se à vontade para alcançar o Linkedin .

Por último, se você chegou até aqui, obrigado por ficar com isso 🤗🤗🙌🙌🖖🏼

 

Fonte:  https://hackernoon.com/building-a-blockchain-the-grey-paper-5be456018040