Como configurar uma rede privada Ethereum na DigitalOcean
Tags: blockchain, cloud, ethereum, web3
Published: 2022-03-28 11:35:21

Ethereum é um software executado em uma rede de computadores que garante que dados e pequenos programas de computador, chamados contratos inteligentes, sejam replicados e processados ​​em todos os computadores da rede, sem um coordenador central. Seu objetivo é criar um computador mundial descentralizado e autossustentável, resistente à censura e imparável [1].

**Blockchain Ethereum**
Assim como o Bitcoin, o Ethereum possui uma blockchain, que contém blocos de dados (transações e contratos inteligentes). Os blocos são criados ou minerados por alguns participantes e distribuídos para outros participantes que os validam [1].

Um minerador, ao validar um novo bloco, é recompensado com uma certa quantia de valor por fazer esse trabalho. Qual é esse valor? A blockchain Ethereum usa um token digital intrínseco chamado "Ether" [2].

**Protocolo Ethereum**
Ethereum também é um protocolo, e isso significa que podem existir várias redes independentes em conformidade com esse protocolo mas que não interagem entre si. Com isso, uma rede privada é uma rede completamente isolada da rede principal Ethereum [3].

Normalmente, as redes privadas são criadas por organizações para armazenar dados que não devem ser visíveis fora da mesma. Além disso, elas podem ser usadas para o desenvolvimento e testes de aplicativos descentralizados (dApps) e smart contracts antes de um lançamento na rede principal.

**O que faremos a seguir:**

- Configuraremos uma rede privada;
- Configuraremos full nodes;
- Mineraremos alguns novos blocos;
- Por fim, criaremos uma transação enviando tokens ganhos como recompensa pela mineração de novos blocos;

**Contexto**

Criaremos uma rede privada com 2 full nodes. O primeiro será responsável por inicializar a blockchain e ser o primeiro signatário, enquanto o segundo será adicionado a rede em um estágio posterior.

Um full node é responsável por validar as transações e blocos e, em seguida, por retransmiti-los para outros participantes da rede [4].

**1ª etapa: Criação de uma instância Ubuntu**

A [Digital Ocean](https://www.digitalocean.com/), provedora de infraestrutura em nuvem, permite criar máquinas virtuais por meio de um de seus produtos: https://www.digitalocean.com/products/droplets

Para publicação desse guia, foram utilizadas instâncias Ubuntu da Digital Ocean com as seguintes especificações:

- Ubuntu 20.04 (LTS) x64
- 1 GB / 1 CPU;
- 25 GB SSD Disk;
- 1000 GB Transfer;
- Datacenter Region: New York 1 (nyc1);
- VPC Network: default-nyc1 (DEFAULT);

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vc1rburax81h0rr7ok9a.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qb1sa1rw93st00jvta67.png)

**2ª etapa: Instalação do Geth no Ubuntu via PPAs**

Go-ethereum (geth) é a interface de linha de comando implementada em Go para executar um full node Ethereum. 

Uma das maneiras de instalar o geth em distribuições Ubuntu é através de PPAs (Personal Package Archives).

Para instalá-lo, execute os seguintes comandos:

```
sudo add-apt-repository -y ppa:ethereum/ethereum 
sudo apt-get update 
sudo apt-get install ethereum
```

**3ª etapa: Criação do bloco Genesis**

O primeiro bloco de uma blockchain, chamado de bloco Genesis, pode ser configurado a partir de um arquivo .json.

Abra uma interface de linha de comando e crie um diretório para armazenar os dados da nova blockchain privada e navegue até ele:

```
cd ~ && mkdir private-blockchain && cd private-blockchain
```

Com um editor de texto de sua preferência, crie o arquivo genesis.json com as seguintes informações:

```
{
  "config": {
    "chainId": <insira um valor inteiro positivo arbitrário>,
    "homesteadBlock": 0,
    "eip150Block": 0,
    "eip155Block": 0,
    "eip158Block": 0,
    "byzantiumBlock": 0,
    "constantinopleBlock": 0,
    "petersburgBlock": 0,
    "istanbulBlock": 0,
    "berlinBlock": 0,
    "londonBlock": 0,
    "ethash": {}
  },
  "difficulty": "1",
  "gasLimit": "8000000",
  "alloc": {}
}
```

**chainId**

Parâmetro que identifica a cadeia atual e é usado para proteção contra ataques de repetição. Você deve configurá-lo com um valor inteiro positivo arbitrário.

Existe um site dedicado ao registro das chains da EVM (Ethereum Virtual Machine) e seus IDs correspondentes: https://chainlist.org/

**homesteadBlock, eip150Block, eip155Block, etc**

São parâmetros relacionados à bifurcação da cadeia e versionamento dela. 

À medida que o desenvolvimento do protocolo Ethereum avança, novos recursos Ethereum ficam disponíveis. Para habilitar esses recursos em sua rede privada, você deve agendar um hard fork.

No nosso caso, vamos deixá-los com valor 0, já que estamos iniciando uma nova blockchain.

**ethash**

Ethash é um algoritmo de consenso por prova de trabalho (PoW / Proof of Work). Como ele é o algoritmo de consenso padrão, nenhum parâmetro adicional precisa ser configurado para usá-lo.

**difficulty**

Corresponde ao nível de dificuldade para minerar um novo bloco. Definir esse valor baixo é útil em uma blockchain privada, pois permite minerar novos blocos rapidamente.

**gasLimit**

Esse valor afeta o quanto de computação da EVM (Ethereum Virtual Machine) pode acontecer em um único bloco. Com uma dificuldade de mineração baixa, os blocos se moverão muito rápido. Você pode definir um valor alto para evitar atingir o limite e desacelerar sua rede. Com isso, uma maior quantidade de transações poderão ser processadas por bloco.

**alloc**

Permite definir uma lista de carteiras com uma pré-alocação de tokens ao iniciar a blockchain. Como poderemos minerar tokens rapidamente, não será necessário usar essa opção.

Para inicializar o bloco de genesis a partir dos parâmetros definidos no arquivo genesis.json, execute o seguinte comando:

```
geth --datadir . init genesis.json 
```

Observe o resultado da execução do comando e verifique que na última linha do resultado é exibido algo como: `"INFO [03-19|21:43:14.533] Successfully wrote genesis state.."`. Essa mensagem significa que a inicialização da blockchain privada foi feita com sucesso.

**4ª etapa: Inicialização de um full node Ethereum**

Para iniciar um full node e ter acesso ao Geth JavaScript Console, execute o seguinte comando:

```
geth --datadir . --networkid <Use o mesmo valor que você definiu como sendo o chainId> --nodiscover --http --http.corsdomain "*" --http.api "eth,net,web3,personal,miner,admin" --allow-insecure-unlock console 2>> eth.log
```

- **--datadir**: configura a localização do diretório onde os dados da blockchain serão armazenados;
- **--networkid**: As redes Ethereum têm dois identificadores, um ID de rede e um ID de cadeia. Embora muitas vezes tenham o mesmo valor, eles têm usos diferentes. A comunicação ponto a ponto entre os nós usa o ID da rede, enquanto o processo de assinatura da transação usa o ID da cadeia. No nosso caso, iremos usar o mesmo valor que foi definido como chainId, pois não queremos usar o mesmo ID da rede principal [9].
- **--nodiscover**: desativa o mecanismo de descoberta de novos nós (para que a adição de um novo nó como signatário seja feita de forma manual);
- **--http**: habilita o servidor HTTP-RPC. O geth aceita, por padrão,  conexões na interface de loopback (127.0.0.1) na porta 8545;
- **--http.corsdomain**: Como o servidor HTTP pode ser acessado de qualquer aplicativo local, uma proteção adicional é incorporada ao servidor para evitar o uso indevido da API por páginas web. Como estamos em um ambiente de testes, podemos habilitar o acesso de qualquer origem utilizando "*";
- **--http.api**: permite que os módulos listados sejam usados ​​em chamadas HTTP;
- **--allow-insecure-unlock**: é usado para permitir o desbloqueio de conta de forma insegura ao usar a API HTTP-RPC. Como estamos em um ambiente de testes, usaremos essa flag para ser possível enviar transações através do console geth;
- **console**: Inicia o console JavaScript interativo geth;

**Acesso ao console Geth**

Você pode iniciar o full node de mineração como um console ou executar o console separadamente e anexá-lo à um full node de mineração, com o comando attach:

```
geth --datadir . attach ipc:geth.ipc
```

Para monitorar a execução do geth, execute os seguintes comandos em uma outra interface de linha de comando:

```
cd ~/private-blockchain && tail -f eth.log
```

**5ª etapa: Criação de uma nova conta**

Esse etapa considera que você esteja dentro do Geth JavaScript console.

Para criar uma nova conta, execute o seguinte comando passando como parâmetro uma senha segura que será usada para encriptar sua nova conta:

```
personal.newAccount("<secure password>")
```

O resultado do comando anterior será o endereço da conta criada. 

Um endereço como:

`"0xd55859a0125c8f248905419e68b1fd603a9e7328"`

O atributo "coinbase" representa o endereço da conta para onde as recompensas de mineração irão ser transferidas. Como nenhuma conta havia sido considerada como coinbase até o momento, o endereço da primeira conta criada foi definida como coinbase.

Com isso, os seguintes comandos retornarão o mesmo endereço:

```
eth.accounts[0]
```

```
eth.coinbase
```

Para consultar a quantidade de tokens em sua conta, execute o seguinte comando no console Geth:

```
web3.fromWei(eth.getBalance(eth.coinbase), "ether")
```

**6ª etapa: Inicializar mineração**

Para começar o processo de mineração de CPU usando um número determinado de threads (nesse caso, estamos passando como parâmetro o valor 1), execute o seguinte comando:
 
```
miner.start(1)
```

A partir de uma interface de linha de comando, você poderá executar os seguintes comandos para monitorar o andamento do processo de mineração:

```
cd ~/private-blockchain
tail -f eth.log
```

E perceberá que a seguinte mensagem será exibida como informativo:

`Generating DAG in progress...`

A saída mostra o DAG (directed acyclic graph) sendo criado. Esse processo é parte do configuração inicial do algoritmo de consenso ethash.

Considerando as especificações das instâncias Ubuntu utilizadas nesta publicação, o processo de geração do DAG durou aproximadamente 30 minutos.

Quando o processo de geração do DAG é concluído, a seguinte mensagem é exibida como informativo:

`Generated ethash verification cache...`

Após o DAG ser gerado, a mineração de novos blocos é iniciada.

Quando um bloco é extraído, são adicionados tokens ao saldo da sua conta como recompensa. Este é um bom indicador se o processo de mineração foi bem-sucedido ou não.

Ao minerar um novo bloco, será exibido algo como:

`INFO [03-19|22:21:08.660] Successfully sealed new block            number=1 sealhash=976c5d..862079 hash=f58c06..f22756 elapsed=30m49.597s
INFO [03-19|22:21:08.714] 🔨 mined potential block                  number=1 hash=f58c06..f22756`

Se continuarmos a mineração, o saldo de sua conta continuará aumentando à medida que novos blocos são minerados.

**7ª etapa: Repita as etapas 2-5 em uma segunda instância para configurar seu segundo full node Ethereum**

Certifique-se de que o mesmo arquivo genesis.json seja usado ao iniciar o blockchain no segundo full node.

Não inicie a mineração (6ª Etapa) na segunda instância, pois queremos que o segundo full node esteja na mesma rede / blockchain que o do primeiro. Faremos esse processo através de uma etapa de pareamento.

**8ª etapa: Pareamento dos full nodes**
Consideramos que nessa etapa você tenha dois full nodes em funcionamento, com as mesmas definições de bloco genesis, mas que apenas o primeiro esteja minerando novos blocos.

Antes de tudo, verifique que eles não estão pareados através do Geth console em ambas as instâncias:

```
admin.peers
```

O comando anterior deve retornar:

`[]`

Em seguida, precisaremos obter as informações sobre o primeiro full node para usá-las nas configurações de pareamento.

**node-01**
```
admin.nodeInfo.enode
```

O resultado do comando anterior será algo no seguinte formato:

`"enode://pubkey@ip:port?discport=0"`

Altere o valor do ip para o endereço IP privado do primeiro full node e adicione essa informação ao segundo full node com o seguinte comando:

**node-02**
```
admin.addPeer("enode://pubkey@ip:port")
```

Exemplo:

```
admin.addPeer("enode://2527461a25c9db1732e6105e1be50113e9203222381510a0e6a0139a78a4bfccecfeff962db192dcf32c8fc57cebe6209c1fa060ceb1b01432a22b57fb562833@10.136.0.2:30303")
```

Após a execução do comando anterior, os full nodes serão pareados.

Para verificar se o pareamento foi concluído, execute o comando `admin.peers` novamente em ambas a instâncias após alguns segundos:

**node-02**
```
admin.peers
```

O resultado será algo como:

```
[{
    caps: ["eth/66", "snap/1"],
    enode: "enode://2527461a25c9db1732e6105e1be50113e9203222381510a0e6a0139a78a4bfccecfeff962db192dcf32c8fc57cebe6209c1fa060ceb1b01432a22b57fb562833@10.136.0.2:30303?discport=0",
    id: "c27af002910cc0681dfb02df71a5c4e6c3f7d89a91dad1b957acf7014ac54903",
    name: "Geth/v1.10.16-stable-20356e57/linux-amd64/go1.17.5",
    network: {
      inbound: false,
      localAddress: "10.136.0.3:38204",
      remoteAddress: "10.136.0.2:30303",
      static: true,
      trusted: false
    },
    protocols: {
      eth: {
        difficulty: 131073,
        head: "0xe65d3192a9678e4eff3c117a30e9c1db3cf750e62c7410f8932ef3f7123b2690",
        version: 66
      },
      snap: {
        version: 1
      }
    }
}]
```

**9ª etapa: Transação entre contas**

Como os dois full nodes estão pareados, enviaremos alguns tokens entre as contas que criamos. Neste exemplo, enviaremos 1 ETH da conta criada no node-01 para a conta criada no node-02. Essa é uma maneira de verificar se toda configuração foi bem-sucedida.

**node-01** 

Para enviar uma transação, execute os seguintes comandos:

```
personal.unlockAccount(eth.coinbase)
```

```
eth.sendTransaction({from: eth.coinbase, to: "<endereço da conta de destino>", value: web3.toWei(1, "ether")})
```

Após um novo bloco ser minerado, fazendo com que sua transação seja confirmada, verifique que o saldo da conta criada a partir do node-02 será de valor 1. 

Com isso, concluímos a configuração de uma rede privada ethereum.

**Referências:**

1. https://bitsonblocks.net/2016/10/02/gentle-introduction-ethereum/
2. https://preethikasireddy.medium.com/how-does-ethereum-work-anyway-22d1df506369
3. https://ethereum.org/en/developers/docs/networks/
4. https://bitcoin.org/en/full-node
5. https://geth.ethereum.org/docs/install-and-build/installing-geth
6. https://ethereum.org/en/developers/docs/evm/
7. https://arvanaghi.com/blog/explaining-the-genesis-block-in-ethereum/
8. https://ethereum.stackexchange.com/questions/2376/what-does-each-genesis-json-parameter-mean
9. https://besu.hyperledger.org/en/stable/Concepts/NetworkID-And-ChainID/
10. https://web3js.readthedocs.io/
1. https://geth.ethereum.org/docs/