Why am I sharing my travel stories?
Founder & CEO of TruStory. I have a passion for understanding things at a fundamental level and sharing it as clearly as possible.
Há chances de que você tenha ouvido falar sobre a blockchain Ethereum, quer você saiba ou não o que é. Está incluído nas notícias muito recentemente, incluindo a capa de algumas grandes revistas, mas ler esses artigos pode ser como gibberish se você não tiver uma base para o que é exatamente o Ethereum. O que é, então? Essencialmente, um banco de dados público que mantém um registro permanente de transações digitais. Importante, esse banco de dados não precisa de nenhuma autoridade central para mantê-lo. Em vez disso, opera como um sistema transacional "sem confiança" - um framework no qual os indivíduos podem fazer transações peer-to-peer sem precisar confiar uns nos outros por terceiros.
Ainda confuso? É aí que este correio entra. Meu objetivo é explicar como o Ethereum funciona em um nível técnico, sem fórmulas complexas de matemática ou de aparência assustadora. Mesmo se você não é um programador, espero que você vá embora com ao menos uma melhor compreensão da tecnologia. Se algumas partes são muito técnicas e difíceis de cavar, isso está tudo bem! Realmente não há necessidade de entender todos os pequenos detalhes. Recomendo que nos concentremos apenas no entendimento a um nível mais alargado.
Muitos dos tópicos abordados nesta publicação são um detalhamento dos conceitos discutidos no papel amarelo. Adicionei minhas próprias explicações e diagramas para facilitar a compreensão do Ethereum. Aqueles bravos o suficiente para aceitar o desafio técnico também podem ler o papel amarelo do Ethereum.
Vamos começar!
Uma blockchain é uma "máquina de singleton transacional criptográficamente segura com estado compartilhado." [1] ****Isso é surdo, né?
Vamos quebrá-lo.
O Ethereum implementa este paradigma da blockchain.
A blockchain Ethereum é essencialmente uma base em transações máquina de estado.Na ciência da computação, uma máquina de estado refere-se a algo que vai ler uma série de entradas e, com base nessas entradas, será a transição para um novo estado.
Com a máquina de estado da Ethereum, começamos com um "estado genésico". Isso é análogo a uma tela em branco, antes que quaisquer transações tenham acontecido na rede. Quando as transações são executadas, esta transição de estado genesis para algum estado final. Em qualquer momento, este estado final representa o estado atual do Ethereum.
O estado do Ethereum possui milhões de transações. Estas transações estão agrupadas em "blocos". Um bloco contém uma série de transações e cada bloco está encadeado com seu bloco anterior.
Para causar uma transição de um estado para o próximo, uma transação deve ser válida. Para que uma transação seja considerada válida, ela deve passar por um processo de validação conhecido como mineração. /0> Mineração é quando um grupo de nós (ou seja, computadores) gasta seus recursos de computação para criar um bloco de transações válidas.
Qualquer nó da rede que se declara como um mineiro pode tentar criar e validar um bloco. Muitos mineiros de todo o mundo tentam criar e validar blocos ao mesmo tempo. Cada mineiro fornece uma "prova" matemática ao enviar um bloco para o blockchain, e esta prova atua como uma garantia: se a prova existe, o bloco deve ser válido.
Para que um bloco seja adicionado ao blockchain principal, o minerador deve provar isso mais rápido do que qualquer outro minerador concorrente. O processo de validação de cada bloco tendo um mineiro fornece uma prova matemática é conhecido como um “prova de trabalho.
Um mineiro que valida um novo bloco é recompensado com uma certa quantidade de valor para fazer este trabalho. Qual é esse valor? A blockchain Ethereum usa um token digital intrínseco chamado "Ether".
Toda vez que um minerador prova um bloco, novos tokens Ether são gerados e premiados. Você pode se perguntar: que garantias de que todos mantêm uma única cadeia de blocos?
Como podemos ter certeza de que não existe um subconjunto de mineiros que decidirão criar sua própria cadeia de blocos?
Anteriormente, definimos uma blockchain como uma máquina singleton transacional com estado. Com esta definição, podemos compreender que o estado actual correcto seja uma verdade global única, que todos têm de aceitar. Ter múltiplos estados (ou cadeias) arruinaria todo o sistema, porque seria impossível chegar a acordo sobre qual estado era o correto. Se as correntes divergissem, você poderia possuir 10 moedas numa cadeia, 20 por outra e 40 por outra.
Nesse cenário, não haveria como determinar qual cadeia era mais "válida". Sempre que vários caminhos são gerados, um "fork" ocorre. Nós normalmente queremos evitar os forks, porque eles perturbam o sistema e forçam as pessoas a escolher em que cadeia elas "acreditam".
Para determinar qual caminho é mais válido e evitar várias cadeias, a Ethereum usa um mecanismo chamado “protocolo GHOST.
“GHOST” = “Sub-árvore Heviça Mais Observada”
Em termos simples, o protocolo GHOST diz que devemos escolher o caminho que mais computou tem sido feito no seu. Uma maneira de determinar esse caminho é usar o número de bloco do bloco mais recente (o "bloco de folha"), que representa o número total de blocos no caminho atual (não contando o bloco genesis). Quanto maior o número do bloco, maior o caminho e maior o esforço de mineração que deve ter chegado à folha. A utilização deste raciocínio permite-nos chegar a acordo sobre a versão canônica do estado actual.
Agora que você tem a visão geral de 10.000 pés do que é uma blockchain. Vamos nos aprofundar nos principais componentes dos quais o sistema Ethereum é com:
Uma nota antes de começar: sempre que digo “hash” de X, refiro-me ao KECCAK-256 hash, usado pela Ethereum.
O "estado-compartilhado" global da Ethereum é composto por muitos objetos pequenos ("contas") que são capazes de interagir uns com os outros através de um framework de transmissão de mensagens. Cada conta tem um estado associado a ele e um endereço. Um endereço na Ethereum é um identificador de 160 bits que é usado para identificar qualquer conta.
Existem dois tipos de contas:
É importante entender uma diferença fundamental entre contas de propriedade externa e contas de contratos. Uma conta de propriedade externa pode enviar mensagens para outras contas de propriedade externa OU para outras contas de contrato criando e assinando uma transação usando sua chave privada. /0> Uma mensagem entre duas contas de propriedade externa é simplesmente uma transferência de valor. Mas uma mensagem de uma conta de propriedade externa para uma conta de contrato ativa o código da conta de contrato, permitindo-lhe executar várias ações (e.. tokens de transferência, escreva para o armazenamento interno, cunhar novos tokens, realizar alguns cálculos, criar novos contratos, etc.).
Ao contrário das contas de propriedade externa, as contas de contrato não podem iniciar novas transações por conta própria. Em vez disso, /0> contas de contrato só podem processar transações em resposta a outras transações que elas receberam (de uma conta de propriedade externa ou de outra conta de contrato). Nós aprenderemos mais sobre chamadas contratadas na seção "Transações e Mensagens".
Portanto, qualquer ação que ocorra na blockchain Ethereum é sempre definida em movimento por transações disparadas de contas controladas externamente.
A conta state consiste de quatro componentes, que estão presentes independentemente do tipo da conta:
Ok, então sabemos que o estado global da Ethereum consiste em um mapeamento entre os endereços das contas e os estados da conta. Este mapeamento é armazenado em uma estrutura de dados conhecida como Patricia Merkle .
Uma árvore de Merkle (ou também chamada de “Trilha de Merkle”) é um tipo de árvore binária composta por um conjunto de nós com:
Os dados na parte inferior da árvore são gerados dividindo os dados que queremos armazenar em chunks, em seguida dividindo os pedaços em baldes, e, em seguida, pegar o hash de cada balde e repetir o mesmo processo até que o número total de hashes remanescentes se torne apenas um: o hash raiz. /1>
Esta árvore é necessária para ter uma chave para cada valor armazenado dentro dela. A partir do nó raiz da árvore, a chave deve dizer qual nó filho seguir para obter o valor correspondente, que é armazenado nos nós de folhas. No caso da Ethereum, o mapeamento de chave/valor para a árvore de estado está entre os endereços e as suas contas associadas, incluindo o saldo, nonce, codeHash, e storageRoot para cada conta (onde o storageRoot é em si mesmo uma árvore).
Fonte: whitepaper Ethereum Essa mesma estrutura de trie é usada também para armazenar transações e recibos. Mais especificamente, cada bloco tem um "cabeçalho" que armazena o hash do nó raiz de três estruturas diferentes do trie do Merkle, incluindo:
A capacidade de armazenar todas essas informações de forma eficiente em tentativas de Merkle é incrivelmente útil na Ethereum para o que chamamos de "clientes ligeiros" ou "nós ligeiros. Lembre-se de que uma blockchain é mantida por vários nós. Em termos gerais, existem dois tipos de nós: nós completos e nós de luz.
Um nó completo de arquivo sincroniza o blockchain baixando a cadeia completa, do bloco gênesis ao atual bloco head, executando todas as transações contidas nele. /0> Normalmente, os mineradores armazenam o nó completo do arquivo, porque eles devem fazê-lo para o processo de mineração. Também é possível baixar um nó completo sem executar cada transação. Independentemente disso, qualquer nó completo contém a cadeia inteira.
Mas a menos que um nó precise executar cada transação ou facilmente consultar dados históricos, não há realmente necessidade de armazenar a cadeia inteira. É aqui que entra o conceito de nó leve. Em vez de baixar e armazenar a cadeia completa e executar todas as transações, nós de luz baixam apenas a cadeia de cabeçalhos, do bloco gênesis para a cabeça atual, sem executar nenhuma transação ou recuperar nenhum estado associado. /0> Porque nós de luz tem acesso a cabeçalhos de bloco, que contêm hashes de três tentativas, eles ainda podem gerar e receber facilmente respostas verificáveis sobre transações, eventos, saldos, etc.
A razão pela qual isto funciona é porque os hashes na árvore de Merkle propagam para cima - se um usuário malicioso tentar trocar uma transação falsa no final de uma árvore de Merkle, essa mudança causará uma mudança no hash do nó acima, que mudará o hash do nó acima, e assim por diante, até que eventualmente mude a raiz da árvore.
Qualquer nó que queira verificar uma peça de dados pode usar algo chamado de "Prova de Merkle" para fazer isso. Uma prova de Merkle consiste de:
Qualquer um que esteja lendo a prova pode verificar se a hashing para esse branch é consistente ao longo da árvore, e, por conseguinte, que a parte interessada se encontra efectivamente nessa posição da árvore.
Em resumo, o benefício de usar uma árvore de Patricia Merkle é que o nó raiz desta estrutura depende criptograficamente dos dados armazenados na árvore, e então o hash do nó raiz pode ser usado como uma identidade segura para esses dados. Uma vez que o cabeçalho do bloco inclui o hash raiz do estado, transações e recibos de árvores, qualquer nó pode validar uma pequena parte do estado da Ethereum sem precisar armazenar o estado inteiro, que pode ser potencialmente ilimitado em tamanho. /0>
Um conceito muito importante no Ethereum é o conceito de taxas.
Todo cálculo que ocorre como resultado de uma transação na rede Ethereum cobra uma taxa — não há almoço grátis! /0> Esta taxa é paga em um valor denominado “gás. Gas é a unidade usada para medir as taxas necessárias para um cálculo específico.
Preço do gás é a quantidade de Ether que você está disposto a gastar em cada unidade de gás e é medida em “gwei. "Wei" é a menor unidade de Ether, onde 1├^\\├Wei representa 1 Ether. Uma gwei é 1.000.000.000 Wei. A cada transação, o remetente define o limite de gás e o preço do gás . O produto de preço do gás e limite do gás representa o valor máximo de Wei que o remetente está disposto a pagar pela execução de uma transação.
Por exemplo, digamos que o remetente define o limite de gás para 50.000 e um preço de gás para 20 gwei. Isso implica que o remetente está disposto a gastar no máximo 50.000 x 20 gwei = 1.000.000.000.000 Wei = 0,001 Ether para executar essa transação.
Lembre-se de que o limite de gás representa o gás máximo no qual o remetente está disposto a gastar dinheiro. Se eles tiverem Ether suficiente no saldo da sua conta para cobrir esse máximo, estão dispostos a ir. O remetente é reembolsado por qualquer gás não utilizado no final da transação, trocado à taxa original.
No caso de o remetente não fornecer o gás necessário para executar a transação, a transação corre "sem gasolina" e é considerada inválida. Neste caso, o processamento de transação aborta e quaisquer alterações de estado que ocorreram são revertidas, tal que acabamos no estado da Ethereum antes da transação. Além disso, um registro de falha da transação é registrado, mostrando que transação foi tentada e onde ela falhou. E já que a máquina já gastou esforços para executar os cálculos antes de ficar sem gasolina, logicamente, nenhum gás é reembolsado ao remetente. /0>
Para onde exatamente esse dinheiro de gás vai? Todo o dinheiro gasto em gás pelo remetente é enviado para o endereço "beneficiário", que é tipicamente o endereço do minerador. /0> Como os mineradores estão gastando o esforço para executar cálculos e validar transações, os mineradores recebem a taxa de gás como recompensa.
Normalmente, quanto maior o preço do gás que o remetente está disposto a pagar, maior o valor que o minerador deriva da transação. Assim, os mineradores mais prováveis serão selecioná-los. Desta forma, os mineradores são livres para escolher quais transações querem validar ou ignorar. Para orientar os remetentes sobre qual preço do gás deve ser definido, Os mineiros têm a opção de publicitar o preço mínimo de gás para o qual irão executar as operações.
Não só o gás é usado para pagar etapas de computação, como também é usado para pagar pelo uso de armazenamento. /0> A taxa total de armazenamento é proporcional ao menor múltiplo de 32 bytes utilizados. As taxas de armazenamento têm alguns aspectos matizados.
Por exemplo, uma vez que o aumento do armazenamento aumenta o tamanho do banco de dados do estado da Ethereum em todos os nós , há um incentivo para manter a quantidade de dados armazenados pequenos. Por este motivo, se uma transação tem um passo que limpa uma entrada no armazenamento, a taxa pela execução da operação é perdida e um reembolso é dado para liberar espaço de armazenamento.
Um aspecto importante do modo como o Ethereum funciona é que cada operação executada pela rede é simultaneamente executada por cada nó completo. /0>, no entanto, os passos computacionais na Máquina Virtual Ethereum são muito caros. Portanto, os contratos inteligentes da Ethereum são mais usados para tarefas simples, como executar uma lógica de negócios simples ou verificar assinaturas e outros objetos criptográficos, ao invés de usos mais complexos, como armazenamento, e-mail, ou aprendizado de máquina, o que pode colocar uma pressão na rede. Taxas de impressão impedem que os usuários sobrecarregem a rede.
A Ethereum é uma linguagem completa de Turing. (Em resumo, uma máquina de Turing é uma máquina que pode simular qualquer algoritmo de computador (para aqueles que não estão familiarizados com as máquinas de Turing, confira este e esse). Isso permite laços e torna o Ethereum suscetível ao problema de paragem, um problema no qual você não pode determinar se um programa será executado infinitamente. Se não houvesse taxas, um ator malicioso poderia facilmente interromper a rede executando um loop infinito em uma transação, sem repercussões. Assim, as taxas protegem a rede de ataques deliberados.
Você poderia estar pensando, "por que também temos que pagar pelo armazenamento? Bem, tal como a computação, o armazenamento na rede Ethereum é um custo do qual toda a rede terá de suportar o fardo.
Notamos anteriormente que a Ethereum é uma máquina de estado com base em transações . /0> Em outras palavras, transações ocorrendo entre contas diferentes são o que move o estado global do Ethereum de um estado para o outro.
No sentido mais básico, uma transação é uma peça de instrução assinada criptograficamente que é gerada por uma conta de propriedade externa, serializado e então enviado para a blockchain. /0> Existem dois tipos de transações: chamadas de mensagens e criação de contratos (ou seja, transações que criam novos contratos Ethereum).
Todas as transações contêm os seguintes componentes, independentemente de seu tipo:
Por exemplo, se um contrato inteligente serve como um serviço de registro de domínio, uma chamada para esse contrato pode esperar campos de entrada, como o domínio e o endereço Ip. Por exemplo, se um contrato inteligente serve como um serviço de registro de domínio, uma chamada para esse contrato pode esperar campos de entrada, como o domínio e o endereço Ip.
Outra maneira de pensar sobre isso é que transações são o que ponte o mundo externo para o estado interno do Ethereum. Mas isso não significa que os contratos não possam falar com outros contratos. Os contratos que existem no escopo global do estado da Ethereum podem conversar com outros contratos dentro desse mesmo escopo. Em vez disso, são geradas por contratos. Eles são objetos virtuais que, ao contrário das transações, não são serializados e existem apenas no ambiente de execução do Ethereum.
Quando um contrato envia uma transação interna para outro contrato, o código associado que existe na conta de contrato do destinatário é executado.
Uma coisa importante a notar é que transações ou mensagens internas não contêm um gasLimit. Isso acontece porque o limite de gás é determinado pelo criador externo da transação original (ou seja, alguma conta de propriedade externa). O limite de gás que os conjuntos de contas de propriedade externa têm de ser suficientemente alto para realizar a transação. incluindo quaisquer sub-execuções que ocorrem como resultado dessa transação, como mensagens contratual a contrato. Se, na cadeia de transações e mensagens, uma execução de mensagem em particular ficar sem gasolina, então a execução da mensagem será revertida, juntamente com quaisquer mensagens subsequentes disparadas pela execução. No entanto, a execução pai não precisa reverter.
Todas as transações são agrupadas em "blocos". Um blockchain contém uma série de blocos que são encadeados.
Na Ethereum, um bloco consiste de:
O que diabos é um "ommer?" An ommer é um bloco cujo pai é igual ao pai do bloco atual. Vamos mergulhar rapidamente no que os ômeros são usados e por que um bloco contém os cabeçalhos dos blocos para os ômeros.
Por causa da maneira como a Ethereum é construída, os tempos de blocos são muito inferiores (~15 segundos) às de outras blockchains, como o Bitcoin (~10 minutos). Isto permite processamento de transação mais rápido. No entanto, uma das desvantagens dos blocos mais curtos é o facto de os mineiros encontrarem soluções em blocos mais concorrentes. Esses blocos concorrentes também são referidos como "blocos órfãos" (ou seja, blocos minerados não fazem parte da cadeia principal).
O propósito dos ômeros é ajudar a recompensar mineiros por incluir estes blocos órfãos. Os ombros que os mineradores incluem devem ser "válidos", ou seja, dentro da sexta geração ou menor do bloco atual. Depois de seis crianças, os blocos órfãos obsoletos já não podem ser referenciados (porque incluir transações mais antigas iria complicar um pouco as coisas).
Blocos Ommer recebem uma recompensa menor que um bloco cheio. No entanto, ainda há algum incentivo para os mineradores incluírem esses blocos órfãos e colherem uma recompensa.
Vamos voltar aos blocos por um momento. Nós mencionamos anteriormente que cada bloco tem um bloco "cabeçalho", mas o que é exatamente isso? Um cabeçalho de bloco é uma parte do bloco que consiste de:
Observe como cada cabeçalho de blocos contém três estruturas de triagem para:
Estas estruturas de triagem não são nada além da Patricia Merkle tentar que discutimos anteriormente. Além disso, existem alguns termos da descrição acima que merecem ser clarificados. Vamos dar uma olhada.
O Ethereum permite logs que permitem rastrear várias transações e mensagens. Um contrato pode gerar explicitamente um log definindo "eventos" que ele quer registrar.
Uma entrada de log contém:
Os logs são armazenados de forma eficiente em um filtro de flores, que armazena os dados infinitos de registros de forma eficiente.
Os registros armazenados no cabeçalho vêm das informações de log contidas no recibo da transação. Assim como você recebe um recibo quando compra algo em uma loja, o Ethereum gera um recibo para cada transação. Como você esperaria, cada recibo contém certas informações sobre a transação. Esse recibo inclui itens como:
A "dificuldade" de um bloco é usada para impor a consistência no tempo que leva para validar blocos. O bloco genesis tem uma dificuldade de 131,072, e uma fórmula especial é usada para calcular a dificuldade de cada bloco depois. Se um determinado bloco for validado mais rapidamente do que o bloco anterior, o protocolo Ethereum aumenta a dificuldade do bloco. A dificuldade do bloco afeta a nonce,, que é um hash que deve ser calculado ao minerar um bloco, usando o algoritmo de prova de trabalho.
A relação entre o bloco dificuldade e nonce é matematicamente formalizada como:
onde Hd é a dificuldade.
A única maneira de encontrar um nonce que atenda a um limite de dificuldade é usar o algoritmo de prova de trabalho para enumerar todas as possibilidades. O tempo esperado para encontrar uma solução é proporcional à dificuldade — quanto maior a dificuldade, mais difícil se torna achar o nonce, e assim mais difícil é validar o bloco, o que, por sua vez, aumenta o tempo necessário para validar um novo bloco. Então, ajustando a dificuldade de um bloco, o protocolo pode ajustar quanto tempo leva para validar um bloco. /0> Se, por outro lado, o tempo de validação está ficando mais lento, o protocolo diminui a dificuldade.
Dessa forma, o tempo de validação se ajusta para manter uma taxa constante — em média, um bloco a cada 15 segundos.
Nós chegamos a uma das partes mais complexas do protocolo Ethereum: a execução de uma transação. Diga que você envia uma transação para a rede Ethereum para ser processada. O que acontece com a transição no estado do Ethereum para incluir a sua transação?
Em primeiro lugar, todas as transacções devem cumprir um conjunto inicial de requisitos para serem executadas.
Estas incluem:
Se a transação atende a todos os requisitos acima para a validade, então passamos para o próximo passo.
Primeiro, deduzimos do saldo do remetente o custo inicial da execução e aumente o nonce da conta do remetente por 1 para responder pela transação atual. Neste ponto, podemos calcular o gás restante como o limite total de gás para a transação menos o gás usado intrínseco.
Em seguida, a transação começa a executar. Ao longo da execução de uma transação, o Ethereum mantém o controle da "substância. Esta substância é uma maneira de registrar informações acumuladas durante a transação, que serão necessárias imediatamente após a conclusão da transação.
Especificamente, contém:
Em seguida, os vários cálculos necessários pela transação são processados.
Uma vez que todos os passos necessários pela transação tenham sido processados e assumindo que não há um estado inválido, o estado é finalizado determinando a quantidade de gás não usado a ser reembolsado para o remetente. Além do gás não utilizado, o remetente também é reembolsado de alguma dedução do "saldo do reembolso" que descrevemos acima.
Uma vez que o remetente é reembolsado:
Finalmente, ficamos com o novo estado e um conjunto de logs criados pela transação.
Agora que abordamos os conceitos básicos de execução de transação, vamos analisar algumas das diferenças entre transações geradoras de contratos e chamadas de mensagens.
Lembre que, na Ethereum, existem dois tipos de contas: contas de contrato e contas de propriedade externa. Quando dizemos que uma transação é "criar contrato", queremos dizer que o propósito da transação é criar uma nova conta contratada.
Para criar uma conta de novo contrato, primeiramente declaramos o endereço da nova conta usando uma fórmula especial. Em seguida, inicializamos a nova conta por:
Uma vez inicializada a conta, podemos criar a conta usando o código de init enviado com a transação (veja a seção "Transação e mensagens" para uma atualização no código de init). O que acontece durante a execução deste código de inicialização é variado. Dependendo do construtor do contrato, ele pode atualizar o armazenamento da conta, criar outras contas de contrato, fazer outras chamadas de mensagens, etc. À medida que o código para inicializar um contrato é executado, ele usa gás. A transação não pode usar mais gás que o gás restante. Se o fizer, a execução atingirá uma excepção e saída extravagantes. Se a transação se sai devido a uma exceção de gás desgaste, então o estado é revertido para o ponto imediatamente antes da transação. O remetente é não devolveu o gás que foi gasto antes de acabar.
Boo hoo.
No entanto, se o remetente enviou qualquer valor Ether com a transação, o valor Ether será reembolsado mesmo se a criação do contrato falhar. Ufa!
Se o código de inicialização for executado com sucesso, será pago um custo final de criação de contrato. Este é um custo de armazenamento, e é proporcional ao tamanho do código do contrato criado (novamente, não há almoço grátis! Se não há gás suficiente restante para pagar este custo final, então a transação declara novamente uma exceção fora de gás e aborta.
Se tudo corre bem e nós chegamos até aqui sem exceções, então qualquer gás não utilizado restante é reembolsado ao remetente original da transação, e o estado alterado pode agora persistir!
Viva!
A execução de um pedido de mensagem é semelhante à de um contrato criado, com algumas diferenças.
A execução de chamadas de mensagem não inclui nenhum código de entrada, uma vez que nenhuma conta será criada. Entretanto, ele pode conter dados de entrada, se esses dados foram fornecidos pelo remetente da transação. Uma vez executada, chamadas de mensagem também têm um componente extra contendo os dados de saída, que é usado se uma execução subsequente precisar destes dados.
Como é verdadeiro no caso da criação do contrato, se uma mensagem para a execução de chamada sair porque ele fica sem gasolina ou porque a transação é inválida (e.. overflow, destino de salto inválido, ou instrução inválida), nenhum gás usado é reembolsado para o chamador original. Em vez disso, todo o gás não utilizado restante é consumido, e o estado é reposto imediatamente antes da transferência do equilíbrio.
Até a atualização mais recente do Ethereum, não havia nenhuma maneira de parar ou reverter a execução de uma transação sem ter o sistema consumir todo o gás que você forneceu. Por exemplo, digamos que você criou um contrato que emitiu um erro quando um chamador não foi autorizado a executar alguma transação. Em versões anteriores do Ethereum, o gás restante ainda seria consumido e nenhum gás seria reembolsado para o remetente. Mas a atualização de Bizâncio inclui um novo código "reverter" que permite que um contrato pare a execução e reverta as alterações de estado sem consumir gás restante e com a capacidade de retornar um motivo para a transação fracassada. /0> Se uma transação for encerrada devido a um reverso, o gás não utilizado será devolvido ao remetente.
Até agora, aprendemos sobre a série de etapas que precisam acontecer para que uma transação seja executada do início ao fim. Agora, vamos ver como a transação é executada dentro da VM.
A parte do protocolo que realmente lida com o processamento das transações é a máquina virtual da Ethereum, conhecida como a Máquina Virtual da Ethereum (EVM). /0> O EVM é uma máquina virtual completa de giração, como definida anteriormente.
A única limitação que o EVM tem que uma típica máquina completa de Turing não é que o EVM está intrinsecamente ligado por gás. Assim, o montante total de computação que pode ser feito é intrinsecamente limitado pela quantidade de gás fornecido.
Source: CMU Moreover, the EVM has a stack-based architecture. A stack machine is a computer that uses a last-in, first-out stack to hold temporary values.
The size of each stack item in the EVM is 256-bit, and the stack has a maximum size of 1024.
The EVM has memory, where items are stored as word-addressed byte arrays. Memory is volatile, meaning it is not permanent.
The EVM also has storage. Unlike memory, storage is non-volatile and is maintained as part of the system state. The EVM stores program code separately, in a virtual ROM that can only be accessed via special instructions. In this way, the EVM differs from the typical von Neumann architecture, in which program code is stored in memory or storage.
The EVM also has its own language: “EVM bytecode.” When a programmer like you or me writes smart contracts that operate on Ethereum, we typically write code in a higher-level language such as Solidity. We can then compile that down to EVM bytecode that the EVM can understand.
Okay, now on to execution.
Before executing a particular computation, the processor makes sure that the following information is available and valid:
At the start of execution, memory and stack are empty and the program counter is zero.
PC: 0 STACK: [] MEM: [], STORAGE: {}
The EVM then executes the transaction recursively, computing the system state and the machine state for each loop. The system state is simply Ethereum’s global state. The machine state is comprised of:
Stack items are added or removed from the leftmost portion of the series.
On each cycle, the appropriate gas amount is reduced from the remaining gas, and the program counter increments.
At the end of each loop, there are three possibilities:
Assuming the execution doesn’t hit an exceptional state and reaches a “controlled” or normal halt, the machine generates the resultant state, the remaining gas after this execution, the accrued substate, and the resultant output.
Phew. We got through one of the most complex parts of Ethereum. Even if you didn’t fully comprehend this part, that’s okay. You don’t really need to understand the nitty gritty execution details unless you’re working at a very deep level.
Finally, let’s look at how a block of many transactions gets finalized.
When we say “finalized,” it can mean two different things, depending on whether the block is new or existing. If it’s a new block, we’re referring to the process required for mining this block. Se for um bloco existente, estamos falando sobre o processo de validação do bloco. Em ambos os casos, há quatro requisitos para um bloco ser “finalizado”:
1) Validar (ou, se minerar, determine) ommers
Cada bloco de ômero dentro do cabeçalho do bloco deve ser um cabeçalho válido e estar dentro da sexta geração do bloco presente.
2) Validar (ou, se estiver minerando, determine) transações
O número de gasUsado no bloco deve ser igual ao gás cumulativo utilizado pelas transações listadas no bloco. (Lembre que ao executar uma transação, mantemos o controle do contador de gás de bloco, que mantém controle do gás total usado por todas as transações no bloco).
3) Aplique recompensas (somente se minerar)
O endereço do beneficiário recebe 5 tempo por minerar o bloco. (Sob a proposta Ethereum EIP-649, esta recompensa de 5 ETH em breve será reduzida para 3 ETH). Além disso, para cada somador, o beneficiário do bloco atual recebe um adicional de 1/32 da recompensa em bloco. Por último, o beneficiário do(s) bloco(s) de ômero(s) também é premiado com uma certa quantia (há uma fórmula especial para como isto é calculado).
4) Verificar (ou, se estiver minerando, calcular um estado válido) e não Certifique-se de que todas as transações e as mudanças de estado resultantes sejam aplicadas, e então defina o novo bloco como o estado depois que a recompensa de bloco for aplicada ao estado final da transação resultante. A verificação ocorre verificando este estado final contra a tentativa de estado armazenada no cabeçalho.
A seção “Blocos” abordou brevemente o conceito de dificuldade do bloco. O algoritmo que dá significado à dificuldade de bloco é chamado de Proof of Work (PoW). O algoritmo de prova de trabalho da Ethereum é chamado de "Ethash" (anteriormente conhecido como Dagger-Hashimoto).
O algoritmo está formalmente definido como:
on m é o mixHash, n é o nonce, Hn é o cabeçalho do novo bloco (excluindo o nonce e mixHash componentes, que devem ser calculados), Hn é o nonce do cabeçalho do bloco, and d é o DAG*, que é um conjunto de dados grande. 0> Na seção “Blocos*”, falamos sobre os vários itens que existem em um cabeçalho de blocos.
Dois desses componentes foram chamados de mixHash e de nonce. Como você pode se lembrar:
nonce: um hash que, quando combinado com o mixHash, prova que este bloco levou a cabo computação suficiente. Como exatamente as mixHash e nonce são calculadas usando a função PoW é algo complexa, e algo que possamos nos esforçar mais profundamente em um post separado.
Mas em um nível alto, funciona assim: Uma "semente" é calculada para cada bloco. Essa semente é diferente para cada "poch", onde cada época tem 30.000 blocos de comprimento. Para a primeira época, a Seed é o hash de uma série de 32 bytes de zeros. Para cada período subsequente, é o hash do hash de semente anterior.
Usando esta semente, um nó pode calcular um "cache" pseudo-aleatório. Este cache é incrivelmente útil porque permite o conceito de "nós leve", que discutimos anteriormente nesta publicação. O propósito dos nós leves é dar-se ao luxo de certos nós a capacidade de verificar uma transação eficientemente sem o encargo de armazenar todo o conjunto de dados do blockchain. Um nó leve pode verificar a validade de uma transação baseada apenas neste cache, porque o cache pode regenerar o bloco específico que ele precisa verificar.
Usando o cache, um nó pode gerar o "conjunto de dados" DAG, onde cada item no conjunto de dados depende de um pequeno número de itens pseudo-selecionados aleatoriamente do cache. Para ser um minerador, você deve gerar este conjunto de dados completo; todos os clientes e mineradores completos armazenam este conjunto de dados, e o conjunto de dados cresce linearmente com o tempo.
Os mineradores podem então pegar fatias aleatórias do conjunto de dados e colocá-los através de uma função matemática para codificá-los em uma "mixHash. /0>" Um minerador irá gerar repetidamente um mixHash até que a saída esteja abaixo do alvo desejado nonce. Quando a saída atende a este requisito, este nonce é considerado válido e o bloco pode ser adicionado à cadeia.
no geral, o objetivo dos PoW é provar, de forma criptográfica segura que uma determinada quantidade de computação foi gasta para gerar alguma saída (i.. A nonce). Isto é porque não há uma maneira melhor de encontrar um nonce que está abaixo do limite necessário, além de enumerar todas as possibilidades. /0> Os resultados da aplicação recorrente da função hash têm uma distribuição uniforme e, portanto, podemos ter a certeza de que Em média, o tempo necessário para encontrar tal nonce depende do limite de dificuldade. /0> Quanto maior a dificuldade, mais tempo leva para se resolver para a nonce. Desta forma, o algoritmo PoW dá significado ao conceito de dificuldade, usado para impor a segurança da blockchain.
O que queremos dizer com segurança blockchain? É simples: queremos criar uma blockchain em que TODOS confiam. Como discutimos anteriormente nesta publicação, se houvesse mais de uma cadeia, usuários perderiam confiança, porque eles seriam incapazes de determinar razoavelmente qual cadeia era a cadeia "válida". Para que um grupo de usuários aceite o estado subjacente que é armazenado em uma blockchain, precisamos de um único blockchain canônico em que um grupo de pessoas acredita.
Isto é exatamente o que o algoritmo PoW faz: garante que um determinado blockchain permaneça canônico no futuro, tornando incrivelmente difícil para um invasor criar novos blocos que substituam uma determinada parte do histórico (e.. por apagar transações ou criar transações falsas) ou manter um fork. /0> Para que seu bloco seja validado primeiro, um invasor precisaria resolver consistentemente o nonce mais rápido que qualquer um na rede que a rede acredita que sua cadeia é a mais pesada (baseado nos princípios do protocolo GHOST que mencionamos anteriormente). Isso seria impossível a menos que o atacante tivesse mais de metade do poder de mineração da rede, um cenário conhecido como a maioria 51% de ataque.
Além de fornecer uma blockchain segura, PoW também é uma maneira de distribuir riqueza para aqueles que gastam sua computação para fornecer essa segurança. Lembrar que um mineiro recebe uma recompensa por minerar um bloco, incluindo:
A fim de garantir que o uso do mecanismo de consenso PoW para a distribuição de segurança e riqueza seja sustentável a longo prazo, O Ethereum se esforça para consagrar essas duas propriedades:
Na rede blockchain do Bitcoin um problema que surge em relação às duas propriedades acima é que o algoritmo PoW é uma função hash SHA256. A fraqueza deste tipo de função é que ela pode ser resolvida de forma muito mais eficiente usando hardware especializado, também conhecido como ASICs. Para mitigar esta questão, a Ethereum optou por tornar o seu algoritmo PoW (Ethhash) sequencialmente difícil de memória. Isso significa que o algoritmo é projetado para que calcular o nonce exija muita memória e largura de banda. Os grandes requisitos de memória tornam difícil para um computador usar sua memória em paralelo para descobrir várias nonces simultaneamente, e os requisitos de largura de banda elevada tornam difícil até mesmo para um computador super rápido descobrir múltiplos nonce simultaneamente. Isto reduz o risco de centralização e cria condições de concorrência mais equitativas para os nós que estamos a verificar.
Uma coisa a notar é que a Ethereum está transicionando de um mecanismo de consenso PoW para algo chamado "proof-of-stake". Este é um tópico bestial que podemos explorar em um futuro post.
☺️
…Ufa! Você chegou até o fim. Eu espero?
Há muito a digerir neste cargo, eu sei. Se você precisar de várias leituras para entender totalmente o que está acontecendo, tudo bem. Li pessoalmente o jornal amarelo do Ethereum e várias partes do código muitas vezes antes de brincar com o que se estava a passar.
No entanto, espero que tenham achado esta panorâmica útil. Se você encontrar algum erro ou erro, eu adoraria que você escrevesse uma nota privada ou publicasse diretamente nos comentários. Eu olho para tudo de "em, eu prometo ;)
E lembre-se, eu sou humano (yep, é verdade) e eu cometo erros. Eu tomei tempo para escrever este cargo para o benefício da comunidade, gratuitamente. Por isso, por favor, seja construtivo no seu feedback, sem ferimentos desnecessários.
☺️
[1] https://github.com/ethereum/yellowpaper
Founder & CEO of TruStory. I have a passion for understanding things at a fundamental level and sharing it as clearly as possible.