O que é Ethereum e a Ethereum Virtual Machine?
Neste artigo focaremos em explicar o que é Ethereum e como funciona a Ethereum por trás das cortinas ao explicar o que é a Ethereum Virtual Machine.
Em qualquer momento durante o artigo, não se preocupe caso você se depare com algum termo desconhecido; basta conferir nosso glossário de termos da blockchain a fim de conseguir desfrutar de todo o material. Aqui é o link do artigo-glossário.
O que é Ethereum?
Para você não esquecer e para revisarmos rapidamente: A Ethereum é uma das blockchains mais famosas atualmente. É um computador global formado por uma rede distribuída de computadores que utilizam de seu poder computacional para manter ou alterar o estado do computador global.
Todas as alterações ocorrem no formato de transações, utilizando-se de uma criptomoeda chamada ETH. A característica principal da rede Ethereum é que as transações de criptomoedas e dados não estão limitadas entre duas pessoas.
Na verdade, uma pessoa pode interagir com uma aplicação salva nesta rede distribuída a fim de executar as tarefas que lhe interessa. O nome dessa aplicação é DApp (Aplicações Descentralizadas) e estas são criadas por meio de um código de programação. Ao código de programação que cria as DApps, damos o nome de smart contracts. Logo, a Ethereum é uma rede distribuída na qual aplicações estão rodando e pessoas podem interagir com as mesmas e entre si por meio de transações.
Introdução
Agora que relembramos o que é Ethereum, vamos ver como ela realmente funciona. Para isso, precisaremos entender o que é e como funciona a Ethereum Virtual Machine (EVM).

Representação Visual da Blockchain da Ethereum. (Source: https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)
A figura acima mostra como existe um estado global da rede Ethereum. Este estado global é determinado pelo estado de todas as contas da rede. Sendo assim, qualquer alteração do estado de uma conta individual altera o estado global, fazendo com que todos os nós (link do glossário) tenham a necessidade de receber e validar aquela transação a fim de que o novo estado seja o mesmo em todos os nós.
Todos terão a mesma blockchain caso o estado de todas as contas seja o mesmo em todos os nós. Existem dois tipos de contas: as contas externas e as contas de contrato. As contas contratos são as contas que representam os smart contracts. As contas externas são aquelas com o objetivo de uso individual. Representam um indivíduo — um indivíduo pode ter várias contas externas diferentes para armazenar seus tokens e fazer transações.

Tipos de Conta na Ethereum. (Adaptado de https://www.preethikasireddy.com/post/how-does-ethereum-work-anyway)
Cada tipo de conta possui alguns atributos como mostrado acima. Vamos analisar cada um deles:
nonce: no caso de uma conta externa, é a quantidade de transações feitas pela conta. No caso de uma conta contrato, é a quantidade de contratos criados a partir desta conta.
balance: a quantidade de Wei nesta conta. Wei é uma unidade de medida que equivale a 10^-18 ETH.
codeHash: código em formato de hash numérico que contém as funcionalidades do contrato e que é executado pela EVM.
storageRoot: o hash superior da Merkle Patricia Tree que representa os conteúdos de um contrato salvos na blockchain.
Dessa forma, quando eu baixo a blockchain da Ethereum no meu computador, todas as contas na rede da Ethereum devem ter o mesmo atributo quando comparado ao que está armazenado nos outros nós espalhados ao redor do mundo, de forma que a blockchain seja íntegra. Caso isso não aconteça, seria como eu ter um banco nacional onde cada filial mostra que um determinado cliente tem um saldo bancário diferente. Seria muito estranho, não é mesmo?! Isso daria um problemão. Dessa forma, a blockchain precisa ser a mesma em todos os nós para que continue funcionando bem.
Entrei no Etherscan.io e cliquei numa conta externa aleatória para mostrar os atributos dela:

Conta Externa Aleatória
Clique aqui para você ver um exemplo de conta contrato e encontrar os atributos dela.
Como foi? Se não encontrou todos, não tem problema, vamos ajudar você mais a frente.
Pronto! Agora você sabe o que é um estado de uma conta e como dar uma olhada nos atributos básicos no Etherscan. Ter a blockchain da Ethereum no seu computador é ter o estado atual de todas as contas no seu computador e o histórico das transações que elas fizeram desde o início da rede. Você já deve ter percebido que isso requer muito espaço. Abaixo você pode ver o tamanho da blockchain no momento em que estou escrevendo. Mais de 1TB — e subindo!

Mas e se uma conta mudar de estado? Vamos supor que eu fiz uma transação agora transferindo 15 ETH para uma conta de uma outra pessoa. O que todos nós teremos que fazer para que todos recebam essa atualização? É aí que entra a Ethereum Virtual Machine, responsável por executar esse processo de atualização à medida que novas transações são feitas.
O que é Ethereum Virtual Machine?
Vamos entender agora qual o processo que acontece para que uma transação seja feita.
Quando uma transferência como a que usei de exemplo acontece, os atributos balance e nonce das duas contas externas são atualizados. Quando há qualquer alteração em um determinado contrato — mudando o valor de uma variável, por exemplo — o que é atualizado é o storage do contrato. Consequentemente o estado global da blockchain também — como mostrado abaixo — pois ele é o estado de todas as contas juntos.

Atualização do Estado Global da Rede Ethereum (https://takenobu-hs.github.io/downloads/ethereum_evm_illustrated.pdf)
Vamos mergulhar mais no que aconteceu nessa transação. A figura abaixo mostra a arquitetura de uma EVM. Existem várias. Você mesmo pode criar a sua. Basta seguir a arquitetura abaixo. Aqui você pode ver as principais implementações da EVM feitas até agora. Vamos usar o GETH daqui em diante.

Para entender o processo do que acontece numa transação, vamos usar o contrato simples abaixo:

Ao ir para o GETH, criar uma rede local e fazer o deploy deste contrato (link para artigo), obtemos o seu bytecode:

eth.getCode(contract address) function
Pronto! Esta é a linguagem que o GETH e qualquer outra EVM entende: uma linguagem numérica chamada de bytecode do contrato que expressa as funcionalidades do contrato.
Lembrando que o endereço que usei ali entre parênteses é o endereço do seu contrato depois de feito o deploy — que vai ser, obviamente, diferente do meu.
Agora, o GETH lerá esses números e entenderá o que nosso contrato quer fazer. Você percebe que declaramos algumas variáveis memory, que são os argumentos das funções. O valor destas variáveis será armazenado temporariamente na memória da EVM e carregada no stack quando necessário.
O stack é onde tudo acontece. Os comandos de nosso código são colocados em uma pilha (stack) e cada um é executado, do último até o primeiro que foi colocado.
Usando o exemplo do contrato anterior, o argumento new_message1 será colocado na memória usando o comando (opcode) MSTORE no stack. Quando a função setMessage for executada no stack, o valor new_message1 virá como argumento da função por meio do opcode MLOAD.

Funcionamento da EVM
O mesmo vale para a variável new_message2 e todas as outras informações dentro do contrato. No final, o valor que realmente nos interessa no contrato — que será armazenado na storage — são as variáveis message1 e message2.
Esse é o processo que acontece por trás das cortinas quando, por exemplo, trocamos o valor de message1 ali no Remix. Recapitulando: a implementação da EVM — no exemplo, Geth — lê o bytecode do contrato, importa as variáveis que não nos interessam permanentemente, armazenando-as na memory, usadas pelos códigos (opcodes) que entram e saem do stack e o resultado final é salvo no storage do contrato.
Claro que este foi um exemplo usando só dois opcodes. Mas existem vários e o stack suporta até 1024 opcodes de uma vez. Uma lista de vários opcodes pode ser encontrada aqui.
Vitalik teve que pensar em como tornar este processo seguro. Como todos terão que executar as transações em seus computadores, o que aconteceria se alguém colocasse um contrato com um loop infinito na blockchain? O processo descrito acima seria feito infinitamente por todos os computadores na rede, gastando os recursos computacionais de todos e parando a rede toda naquele mesmo estágio, sem mais transações futuras, criação de novas contas e, consequentemente, um fracasso da rede. Este é um ataque Denial of Service (DoS).
Como solução para este problema, existe o gás! O gás é uma unidade que mede o poder computacional consumido durante a execução de uma transação. Quantos mais opcodes forem executados no stack, mais valores forem armazenados no storage e mais variáveis memory forem guardadas temporariamente, mais recurso computacional é requerido dos mineradores e validadores das transações. Por exemplo, para o opcode SSTORE — que armazena um valor no storage do contrato — o custo do gás é de 20000 wei.

Tabela de Custo em Gas Por Opcode (Tabela Completa em: https://ethereum.github.io/yellowpaper/paper.pdf, página 27)
O valor em gás corresponde à quantidade de wei que será descontado de uma conta e dado ao minerador da transação. Quando fazemos uma transação, o gás deve ser pago baseado na quantidade de opcodes usados e memória consumida. Assim, caso alguém use um loop infinito, gás será consumido até que a conta não tenha mais ETH disponível. Logo, o dono do contrato do loop infinito pagará muito dinheiro aos mineradores e estes serão pagos por usar seus recursos por determinado tempo. Dessa forma, Vitalik conseguiu tornar segura a Ethereum Virtual Machine.
À medida que o gas é descontado enquanto a transação procede e caso a conta externa fique sem gas para continuar a executar os opcodes e fazer a transação, a mesma é revertida — ou seja, não acontece — e o gas que teria sido usado é devolvido ao dono como se nada tivesse acontecido. O Program Counter conta cada ciclo que acontece na EVM.

Ciclo da EVM para execução de uma transação. (Source [1])
Arquitetura da Blockchain Ethereum
Agora que já vimos como uma transação ocorre na EVM, vamos ver como esse processo se encaixa na Ethereum como um todo.
O estado global da rede Ethereum, portanto, se dá por uma relação de mapping entre os endereços das contas e os estados das contas. Estes dados estão dispostos na rede usando a infraestrutura de uma Merkle Patricia Tree modificada.

Representação de Uma Merkle Patricia Tree
O algoritmo usado para criptografar cada uma das informações nas árvores armazenadas na rede é chamado de Keccak-256. Uma representação de como cada bloco depende do bloco anterior e como os estados também são interdependentes é mostrado abaixo.

Visualmente, é assim que a rede é disposta. Os blocos estão numa sequência linear, sendo que cada bloco possui algumas informações. Ao conjunto de informações de um determinado bloco, damos o nome de block header. Já o estado de todas as contas — determinado pelos atributos: balance, nonce, codeHash e storageRoot — está contido no stateRoot. O stateRoot é um hash.

Ora, como é que todos os estados de todas as contas da rede estão contidos em um hash de tamanho tão limitado? Simples, basta representar cada estado por meio de um hash e uni-los todos em um único hash! Na verdade, estamos quase lá!
De cada conta é feito um hash que representa a conta e seu estado. Dois hashes adjacentes são colocados em um único hash, que é colocado com os hashes dos hashes adjacentes, em uma formato de árvore até que resulte em um hash final, o stateRoot hash.
Dessa forma, qualquer alteração em qualquer um dos atributos de uma conta terá um impacto — mesmo que mínimo — no hash final do stateRoot. Quando comparado ao hash encontrado em todos os outros nós, ficará evidente que há uma alteração em algum lugar da blockchain em algum atributo de uma conta. Assim, é possível eu mentir na minha blockchain dizendo que tenho 1000 ETH mesmo sem tê-los.
Mas quando confrontado com todos os outros nós, a mentira será pública, invalidando minha blockchain. Esse é o trabalho dos mineradores e validadores — fazer com a blockchain permaneça única e íntegra.
O mais legal ainda é que não só os estados das contas são armazenados na forma de uma Merkle Patricia Tree, mas também todas as transações e todos os recibos de todas as transações.

(Source: Ethereum Yellow Paper)
Além disso, o próprio storageRoot, é uma Merkle Patricia Tree, representando em uma árvore todas as informações importantes do contrato que foram salvas depois que o processo de se fazer uma transação acontece na EVM. Isso mostra o porquê a Ethereum é tão segura. Qualquer alteração mínima em qualquer variável de um contrato, por exemplo, leva a alteração do hash final do storageRoot, que leva a alteração final do hash representando o stateRoot.
Resumindo
Ufa! Parabéns para você que chegou até aqui. O principal objetivo deste artigo é deixar bem claro para você que a Ethereum funciona de forma distribuída em nós, sendo que cada um deles executa algum client diferente — Geth, pro exemplo — que é uma implementação real da infraestrutura e regras da Ethereum Virtual Machine especificada no documento oficial Ethereum Yellow Paper.
As implementações da EVM usam algoritmos a fim de criptografar informações — como transações, recibos e estados das contas — e armazená-los em uma estrutura de dados em forma de árvore, chamada modified Merkle Patricia tree, o que garante segurança à rede contra falsificações, ataques de Denial of Service (DoS) ou quebra da rede por algum agente malicioso.
Este artigo demonstrou o funcionamento da Ethereum 1.0. Logo mais teremos um artigo mostrando as atualizações feitas nesse processo para entender a Ethereum 2.0!
Se você se interessou mais sobre o assunto veja mais sobre introdução ao bitcoin e blockchain.
Siga a gente em nossas rede sociais que estão no rodapé do site, e compartilhe conhecimento 🙂