Uma introdução ao Ethereum para desenvolvedores Python, parte 1
Então, você já ouviu falar de Ethereum e está pronto para entrar na toca do coelho? Este artigo abordará rapidamente alguns conceitos básicos de blockchain e, em seguida, fará com que você interaja com um nó Ethereum simulado – lendo dados de blocos, verificando saldos de contas e enviando transações. Ao longo do caminho, destacaremos as diferenças entre as formas tradicionais de criar aplicativos e este novo paradigma descentralizado.
(Pré-requisitos flexíveis)
Este artigo pretende ser acessível a uma vasta gama de desenvolvedores. Ferramentas Python serão usadas, mas elas são apenas um veículo para as ideias – não há problema se você não for um desenvolvedor Python. No entanto, farei apenas algumas suposições sobre o que você já sabe, para que possamos avançar rapidamente para os pontos específicos do Ethereum.
Suposições:
- Você sabe usar um terminal,
- Você já escreveu algumas linhas de código Python,
- A versão 3.6 ou superior do Python está instalada em sua máquina (o uso de um ambiente virtual (opens in a new tab) é fortemente incentivado), e
- você já usou o
pip, o instalador de pacotes do Python. Novamente, se algum desses pontos não for verdadeiro, ou se você não planeja reproduzir o código neste artigo, provavelmente ainda conseguirá acompanhar sem problemas.
Blockchains, resumidamente
Existem muitas maneiras de descrever o Ethereum, mas em sua essência, ele é uma blockchain. As blockchains são compostas por uma série de blocos, então vamos começar por aí. Em termos mais simples, cada bloco na blockchain Ethereum é apenas um conjunto de metadados e uma lista de transações. No formato JSON, se parece com algo assim:
1{2 "number": 1234567,3 "hash": "0xabc123...",4 "parentHash": "0xdef456...",5 ...,6 "transactions": [...]7}Cada bloco tem uma referência ao bloco que veio antes dele; o parentHash é simplesmente o hash do bloco anterior.
Uma blockchain é essencialmente uma lista encadeada; cada bloco tem uma referência ao bloco anterior.
Essa estrutura de dados não é nova, mas as regras (ou seja, protocolos ponto a ponto) que governam a rede, sim. Não há autoridade central; a rede de pares deve colaborar para sustentar a rede e competir para decidir quais transações incluir no próximo bloco. Então, quando você quiser enviar dinheiro para um amigo, precisará transmitir essa transação para a rede e esperar que ela seja incluída em um bloco futuro.
A única maneira de a blockchain verificar se o dinheiro foi realmente enviado de um usuário para outro é usar uma moeda nativa daquela blockchain (ou seja, criada e governada por ela). No Ethereum, essa moeda é chamada ether, e a blockchain Ethereum contém o único registro oficial de saldos de contas.
Um novo paradigma
Essa nova pilha de tecnologia descentralizada gerou novas ferramentas para desenvolvedores. Essas ferramentas existem em muitas linguagens de programação, mas nós as veremos pela ótica do Python. Reiterando: mesmo que Python não seja sua linguagem de escolha, não deve ser muito difícil acompanhar.
Desenvolvedores Python que desejam interagir com o Ethereum provavelmente usarão o Web3.py (opens in a new tab). Web3.py é uma biblioteca que simplifica muito a maneira como você se conecta a um nó Ethereum e, em seguida, envia e recebe dados dele.
Clientes Ethereum podem ser configurados para serem acessíveis por IPC (opens in a new tab), HTTP ou Websockets, então o Web3.py precisará espelhar essa configuração. O Web3.py se refere a essas opções de conexão como provedores. Você precisará escolher um dos três provedores para vincular a instância do Web3.py com seu nó.
Configure o nó Ethereum e o Web3.py para se comunicarem através do mesmo protocolo, por exemplo, IPC neste diagrama.
Uma vez que o Web3.py esteja configurado corretamente, você pode começar a interagir com a blockchain. Aqui estão alguns exemplos de uso do Web3.py como uma prévia do que está por vir:
1# ler dados de bloco:2w3.eth.get_block('latest')34# enviar uma transação:5w3.eth.send_transaction({'from': ..., 'to': ..., 'value': ...})Instalação
Neste passo a passo, trabalharemos apenas dentro de um interpretador Python. Não criaremos nenhum diretório, arquivo, classe ou função.
$ devem ser executados no terminal. (Não digite o $, ele apenas significa o início da linha.)Primeiro, instale o IPython (opens in a new tab) para ter um ambiente amigável para explorar. O IPython oferece preenchimento com a tecla Tab, entre outros recursos, tornando muito mais fácil ver o que é possível dentro do Web3.py.
pip install ipythonO Web3.py é publicado com o nome web3. Instale-o da seguinte forma:
pip install web3Mais uma coisa – vamos simular uma blockchain mais tarde, o que requer mais algumas dependências. Você pode instalá-las via:
pip install 'web3[tester]'Está tudo pronto para começar!
Observação: o pacote web3[tester] funciona até o Python 3.10.xx
Iniciando um sandbox
Abra um novo ambiente Python executando ipython em seu terminal. Isso é comparável a executar python, mas vem com mais recursos extras.
ipythonIsso imprimirá algumas informações sobre as versões do Python e do IPython que você está executando, e então você verá um prompt aguardando a entrada:
1In [1]:Você está vendo um shell interativo do Python agora. Essencialmente, é um sandbox para experimentar. Se você chegou até aqui, é hora de importar o Web3.py:
1In [1]: from web3 import Web3Apresentando o módulo Web3
Além de ser um portal para o Ethereum, o módulo Web3 (opens in a new tab) oferece algumas funções de conveniência. Vamos explorar algumas delas.
Em um aplicativo Ethereum, você comumente precisará converter denominações de moeda. O módulo Web3 fornece alguns métodos auxiliares apenas para isso: from_wei (opens in a new tab) e to_wei (opens in a new tab).
Observação: computadores são conhecidos por não lidarem bem com matemática decimal. Para contornar isso, os desenvolvedores geralmente armazenam valores em dólares como centavos. Por exemplo, um item com o preço de US$ 5,99 pode ser armazenado no banco de dados como 599.
Um padrão semelhante é usado ao lidar com transações em ether. No entanto, em vez de duas casas decimais, o ether tem 18! A menor denominação do ether é chamada de wei, então esse é o valor especificado ao enviar transações.
1 ether = 1000000000000000000 wei
1 wei = 0,000000000000000001 ether
Tente converter alguns valores de e para wei. Observe que existem nomes para muitas das denominações (opens in a new tab) entre ether e wei. Um dos mais conhecidos entre eles é o gwei, pois é frequentemente como as taxas de transação são representadas.
1In [2]: Web3.to_wei(1, 'ether')2Out[2]: 100000000000000000034In [3]: Web3.from_wei(500000000, 'gwei')5Out[3]: Decimal('0.5')Outros métodos utilitários no módulo Web3 incluem conversores de formato de dados (por exemplo, toHex (opens in a new tab)), auxiliares de endereço (por exemplo, isAddress (opens in a new tab)) e funções de hash (por exemplo, keccak (opens in a new tab)). Muitos deles serão abordados mais adiante na série. Para ver todos os métodos e propriedades disponíveis, utilize o preenchimento automático do IPython digitando Web3. e pressionando a tecla Tab duas vezes após o ponto.
Conversando com a cadeia
Os métodos de conveniência são ótimos, mas vamos passar para a blockchain. O próximo passo é configurar o Web3.py para se comunicar com um nó Ethereum. Aqui, temos a opção de usar os provedores IPC, HTTP ou Websocket.
Não seguiremos por este caminho, mas um exemplo de um fluxo de trabalho completo usando o Provedor HTTP pode ser algo assim:
- Baixe um nó Ethereum, por exemplo, o Geth (opens in a new tab).
- Inicie o Geth em uma janela de terminal e espere que ele sincronize com a rede. A porta HTTP padrão é
8545, mas é configurável. - Diga ao Web3.py para se conectar ao nó via HTTP, em
localhost:8545.w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545')) - Use a instância
w3para interagir com o nó.
Embora esta seja uma maneira “real” de fazer isso, o processo de sincronização leva horas e é desnecessário se você só quer um ambiente de desenvolvimento. O Web3.py expõe um quarto provedor para este fim, o EthereumTesterProvider. Este provedor de teste se vincula a um nó Ethereum simulado com permissões flexíveis e moeda falsa para experimentar.
O EthereumTesterProvider se conecta a um nó simulado e é útil para ambientes de desenvolvimento rápidos.
Esse nó simulado é chamado eth-tester (opens in a new tab) e nós o instalamos como parte do comando pip install web3[tester]. Configurar o Web3.py para usar este provedor de teste é tão simples quanto:
1In [4]: w3 = Web3(Web3.EthereumTesterProvider())Agora você está pronto para surfar na cadeia! Isso não é algo que as pessoas dizem. Eu acabei de inventar isso. Vamos fazer um tour rápido.
O tour rápido
Primeiro, uma verificação:
1In [5]: w3.is_connected()2Out[5]: TrueComo estamos usando o provedor de teste, este não é um teste muito valioso, mas se ele falhar, é provável que você tenha digitado algo errado ao instanciar a variável w3. Verifique se você incluiu os parênteses internos, ou seja, Web3.EthereumTesterProvider().
Parada do tour nº 1: contas
Por conveniência, o provedor de teste criou algumas contas e as pré-carregou com ether de teste.
Primeiro, vamos ver uma lista dessas contas:
1In [6]: w3.eth.accounts2Out[6]: ['0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf',3 '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF',4 '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', ...]Se você executar este comando, verá uma lista de dez strings que começam com 0x. Cada um é um endereço público e é, de certa forma, análogo ao número de uma conta corrente. Você forneceria este endereço a alguém que quisesse lhe enviar ether.
Como mencionado, o provedor de teste pré-carregou cada uma dessas contas com um pouco de ether de teste. Vamos descobrir quanto há na primeira conta:
1In [7]: w3.eth.get_balance(w3.eth.accounts[0])2Out[7]: 1000000000000000000000000São muitos zeros! Antes de sair rindo até o banco falso, lembre-se da lição sobre denominações de moeda de antes. Os valores de Ether são representados na menor denominação, wei. Converta isso para ether:
1In [8]: w3.from_wei(1000000000000000000000000, 'ether')2Out[8]: Decimal('1000000')Um milhão de ether de teste — nada mal.
Parada do tour nº 2: dados do bloco
Vamos dar uma olhada no estado desta blockchain simulada:
1In [9]: w3.eth.get_block('latest')2Out[9]: AttributeDict({3 'number': 0,4 'hash': HexBytes('0x9469878...'),5 'parentHash': HexBytes('0x0000000...'),6 ...7 'transactions': []8})Muitas informações são retornadas sobre um bloco, mas há apenas algumas coisas a serem destacadas aqui:
- O número do bloco é zero — não importa há quanto tempo você configurou o provedor de teste. Ao contrário da rede Ethereum real, que adiciona um novo bloco a cada 12 segundos, esta simulação esperará até que você lhe dê algum trabalho a fazer.
transactionsé uma lista vazia, pelo mesmo motivo: ainda não fizemos nada. Este primeiro bloco é um bloco vazio, apenas para iniciar a cadeia.- Observe que o
parentHashé apenas um monte de bytes vazios. Isso significa que é o primeiro bloco da cadeia, também conhecido como bloco gênese.
Parada do tour nº 3: transações
Estamos presos no bloco zero até que haja uma transação pendente, então vamos criar uma. Envie alguns ether de teste de uma conta para outra:
1In [10]: tx_hash = w3.eth.send_transaction({2 'from': w3.eth.accounts[0],3 'to': w3.eth.accounts[1],4 'value': w3.to_wei(3, 'ether'),5 'gas': 210006})Este é geralmente o ponto em que você esperaria vários segundos para que sua transação fosse incluída em um novo bloco. O processo completo é mais ou menos assim:
- Envie uma transação e guarde o hash da transação. Até que o bloco contendo a transação seja criado e transmitido, a transação fica “pendente”.
tx_hash = w3.eth.send_transaction({ … }) - Aguarde a transação ser incluída em um bloco:
w3.eth.wait_for_transaction_receipt(tx_hash) - Continue a lógica do aplicativo. Para ver a transação bem-sucedida:
w3.eth.get_transaction(tx_hash)
Nosso ambiente simulado adicionará a transação a um novo bloco instantaneamente, para que possamos ver a transação imediatamente:
1In [11]: w3.eth.get_transaction(tx_hash)2Out[11]: AttributeDict({3 'hash': HexBytes('0x15e9fb95dc39...'),4 'blockNumber': 1,5 'transactionIndex': 0,6 'from': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf',7 'to': '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF',8 'value': 3000000000000000000,9 ...10})Exibir tudoVocê verá alguns detalhes familiares aqui: os campos from, to e value devem corresponder às entradas de nossa chamada send_transaction. O outro detalhe reconfortante é que esta transação foi incluída como a primeira transação ('transactionIndex': 0) no bloco número 1.
Também podemos verificar facilmente o sucesso desta transação, verificando os saldos das duas contas envolvidas. Três ether deveriam ter sido movidos de uma para outra.
1In [12]: w3.eth.get_balance(w3.eth.accounts[0])2Out[12]: 99999699997900000000000034In [13]: w3.eth.get_balance(w3.eth.accounts[1])5Out[13]: 1000003000000000000000000O último parece bom! O saldo passou de 1.000.000 para 1.000.003 ether. Mas o que aconteceu com a primeira conta? Parece ter perdido um pouco mais de três ether. Infelizmente, nada na vida é de graça, e usar a rede pública Ethereum exige que você compense seus pares por seu papel de apoio. Uma pequena taxa de transação foi deduzida da conta que enviou a transação - essa taxa é a quantidade de gás queimado (21.000 unidades de gás para uma transferência de ETH) multiplicada por uma taxa base que varia de acordo com a atividade da rede, mais uma gorjeta que vai para o validador que inclui a transação em um bloco.
Mais sobre gás
E respire
Já estamos nisso há um tempo, então este parece ser um bom lugar para fazer uma pausa. A descoberta continua, e vamos continuar explorando na parte dois desta série. Alguns conceitos futuros: conectar a um nó real, contratos inteligentes e tokens. Tem mais alguma pergunta? Queremos saber! Seu feedback influenciará para onde vamos a partir daqui. Pedidos são bem-vindos via Twitter (opens in a new tab).
Última atualização da página: 6 de fevereiro de 2025


