Ethereum & Python - Future of Web3 V1
Harnessing the Power of Ethereum and Python for Blockchain Innovation
Table of contents
In this article, we will delve into Web3 development, focusing on the combination of Ethereum and Python. We will explore how this powerful duo can shape the future of blockchain technology and revolutionize various industries. Through practical code examples, we will demonstrate the seamless integration of Ethereum's decentralized network and Python's extensive capabilities, focusing on Account Access and Transactions. The next few articles will be concentrated on the same topic only. This article is not an introduction to BlockChain or Ethereum, those topics are pre-requisites, more information can be found here
Let's Get Going...
Configuration
Step1 Libraries
Configure venv using
python -m venv venv
Activate venv using
source <path>/venv/bin/activate
Install Necessary Libraries
pip install web3
Step2 Account Setup
This account is needed for demonstration, as well as deployment of smart contracts. For privacy, this account number will not be visible throughout the article, rather I will be either using a masked Testnet account or some transaction details from etherscan
Get API Endpoint from Alchemy I chose Polygon Mumbai (For Contract Deployment) and Ethereum Mainnet (For Account and Block Analysis) for this experiment
Add network Manually
Open Metamask. Click on the network dropdown menu (set to Ethereum Mainnet by default) and click the Add Network button. You need to create a free account to get your private API key from one of these providers to put into the dedicated RPC endpoint URL below.
Add network Manually
Network: Polygon Mumbai Testnet
RPC URL (public endpoint):
https://rpc-mumbai.maticvigil.com
.
RPC URL (dedicated endpoint):
https://polygonmumbai.g.alchemy.com/v2/<your-api-key
>
Chain ID: 80001
Currency Symbol: MATIC
Block Explorer URL:
https://mumbai.polygonscan.com/
Go ahead and click Save
Copy your wallet address from MetaMask by clicking over your account name
Head over to Faucet and request test MATIC - you will need this to pay for gas on the Polygon network. You can also add sepolia eth to the Eth mainnet account. This step is discussed further in detail
- Infura API for EthMainnet
- Create API Key
- Add Suitable Name
- Copy Ethereum Endpoint. Polygon Pos can also be activated from here
API looks like https://sepolia.infura.io/v3/<your API Key> (If you use mainnet like me, it seems like https://mainnet.infura.io/v3/<your API Key> )and can be added to metamask too as described in 2nd step. I had this as well as Polygon API configured with my metamask
Adding money to Test Account
Copy the Wallet Number or Account hex
Change a Testnet Network of choice (Sepolia (Eth) or Mumbai (Polygon)), I am using Polygon TestNet (Mumbai) for this experiment.
Add money
Go on to https://mumbaifaucet.com/ or https://sepoliafaucet.com/ to get test tokens
Login to Alchemy, enter the copied wallet address and click Send me MATIC.
Check Transaction
Copy this Transaction hash or click here to check details on etherscan.
Etherscan explore
Details of Transaction Hash and To Address (Your testnet Address) can also be accessed here. We will access all these details, and more using Python.
The Primary Reason to use Testnet is the availability of these free tokens for development and educational purposes, but for real projects, the network can be changed to Mainnet, real transactions can be made, and for those too, details can be fetched using transaction hash.
Finally, let's get coding.
Code
In all the examples shown below, I have shorted the hex outputs to '0x<>'. The primary reason is to make output clear for readers. It is also a good practice here to observe the keys-value pairs in output, same can be accessed using dictname['keyname'] and can be used, instead of the entire output.
- Import the libraries
import os
from web3 import Web3
from eth_account import Account
- Connect to Mainnet or Testnet Server
# Connect to Infura Mainnet - Etherium Node
w3 = Web3(Web3.HTTPProvider('https://mainnet.infura.io/v3/<API>'))
- Check Gas Fee, Latest Block & Chain ID
#Check Chain ID
chain_id = w3.eth.chain_id
print('Chain ID:', chain_id)
# Get the latest block number
latest_block_number = w3.eth.block_number
print('Latest block number:', latest_block_number)
#Check gas Price
gas_price = w3.eth.gas_price
print('Gas price in WEI:', gas_price)
Output
Chain ID: 1
Latest block number: 17259477
Gas price in WEI: 55219615922
# Eth Chain ID is 1
chain_id
: This variable retrieves the Chain ID of the connected Ethereum network. The Chain ID uniquely identifies a specific blockchain network, such as the mainnet, testnets, or private networks.gas_price
: This variable retrieves the current gas price on the network, which represents the cost of executing a transaction or contract function in terms of Ether.block_number
: In blockchain technology, a block number refers to a unique identifier assigned to each block in a blockchain network. Each block contains a collection of transactions or other data, and these blocks are linked together in chronological order to form the blockchain.
- Check the Balance of an Address on this network.
#Get Balance of an address
address = '0x<>'
balance = w3.eth.get_balance(address, block_identifier=latest_block_number)
print('Balance of address:', balance)
# Address can be accessed from Metamask, copy and paste in code
Output:
Balance of address: 0
- Get Storage & Transaction Count
#Get storage at
storage = w3.eth.get_storage_at(address, 0)
print('Storage:', storage)
#Get transaction count
transaction_count = w3.eth.get_transaction_count(address)
print('Transaction count:', transaction_count)
Output
Storage: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Transaction count: 0
transaction_count
: This retrieves the total number of transactions sent from a specific Ethereum address. Thestorage
: Storage refers to the persistent data storage associated with each smart contract deployed on the blockchain. Smart contracts are self-executing contracts with the terms of the agreement directly written into code. They have their own storage space where they can store and retrieve data.- Access Transaction by Hash & receipts
As discussed, the transaction's hash can be got from https://etherscan.io/
#Get transaction by hash
transaction_hash = '0x<>'
transaction = w3.eth.get_transaction(transaction_hash)
print('Transaction:', transaction)
#Get transaction receipt
transaction_receipt = w3.eth.get_transaction_receipt(transaction_hash)
print('Transaction receipt:', transaction_receipt)
Output
Transaction: AttributeDict({'accessList': [], 'blockHash': HexBytes('0x<>'), 'blockNumber': 17234057, 'chainId': 1, 'from': '0x<>', 'gas': 22111, 'gasPrice': 64968650009, 'hash': HexBytes('0x<>'), 'input': '0x', 'maxFeePerGas': 64968650009, 'maxPriorityFeePerGas': 0, 'nonce': 81604, 'r': HexBytes('0x<>'), 's': HexBytes('0x<>'), 'to': '0x<>', 'transactionIndex': 140, 'type': 2, 'v': 0, 'value': 201717279656681044})
Transaction receipt: AttributeDict({'blockHash': HexBytes('0x<>'), 'blockNumber': 17234057, 'contractAddress': None, 'cumulativeGasUsed': 13740891, 'effectiveGasPrice': 64968650009, 'from': '0x<>', 'gasUsed': 22111, 'logs': [AttributeDict({'address': '0x<>', 'blockHash': HexBytes('0x<>'), 'blockNumber': 17234057, 'data': HexBytes('0x<>'), 'logIndex': 386, 'removed': False, 'topics': [HexBytes('0x<>')], 'transactionHash': HexBytes('0x<>'), 'transactionIndex': 140})], 'logsBloom': HexBytes('0x<>'), 'status': 1, 'to': '0x<>', 'transactionHash': HexBytes('0x<>'), 'transactionIndex': 140, 'type': 2})
Access Transaction by Block
#Get transaction by block transaction_by_block = w3.eth.get_transaction_by_block(block_number, 0) print('Transaction by block:', transaction_by_block)
Output:
Transaction by block: AttributeDict({'accessList': [AttributeDict({'address': '0xc<>', 'storageKeys': ['0x<>', '0x<>', '0x<>', '0x<>', '0x<>', '0x<>', '0x<>', '0x<>', '0x<>']}), AttributeDict({'address': '0x<>', 'storageKeys': ['0x<>', '0x<>', '0x<>', '0x<>']}), AttributeDict({'address': '0x<>', 'storageKeys': ['0x<>', '0x<>', '0x7<>']}), AttributeDict({'address': '0x<>', 'storageKeys': ['0x<>', '0x<>', '0x<>', '0x<>']}), AttributeDict({'address': '0x<>', 'storageKeys': ['0x<>', '0x<>']})], 'blockHash': HexBytes('0x<>'), 'blockNumber': 17259477, 'chainId': 1, 'from': '0x<>', 'gas': 5000000, 'gasPrice': 55131255922, 'hash': HexBytes('0x<>'), 'input': '0x<>', 'maxFeePerGas': 55131259222, 'maxPriorityFeePerGas': 0, 'nonce': 492, 'r': HexBytes('0x<>'), 's': HexBytes('0x<>'), 'to': '0x<>', 'transactionIndex': 0, 'type': 2, 'v': 0, 'value': 17259477})
- Get Proof
#Get Proof
proof = w3.eth.get_proof(address, [0])
print('Proof:', proof)
Output
Proof: AttributeDict({'accountProof': [HexBytes('0x<>'), HexBytes('0x<>'), HexBytes('0x<>'), HexBytes('0x<>'), HexBytes('0x<>'), HexBytes('0x<>'), HexBytes('0xf<>')], 'address': '0x<>', 'balance': 0, 'codeHash': HexBytes('0x<>'), 'nonce': 0, 'storageHash': HexBytes('0x<>'), 'storageProof': [AttributeDict({'key': HexBytes('0x00'), 'proof': [], 'value': HexBytes('0x<>')})]})
#OUTPUT BREAKDOWN
Proof: AttributeDict({
'accountProof': [HexBytes('0x<>'), HexBytes('0x<>'), HexBytes('0x<>'), HexBytes('0x<>'), HexBytes('0x<>'), HexBytes('0x<>'), HexBytes('0xf<>')],
'address': '0x<>',
'balance': 0,
'codeHash': HexBytes('0x<>'),
'nonce': 0,
'storageHash': HexBytes('0x<>'),
'storageProof': [AttributeDict({
'key': HexBytes('0x00'),
'proof': [],
'value': HexBytes('0x<>')
})]
})
account proof
- The account proof may include cryptographic proofs or evidence related to the account's existence, history, or state.balance
- It specifies the balance of the address, represented as an integer. In this case, the balance is 0, indicating that the address has no Ether balance.codeHash
: This field contains the code hash of the smart contract associated with the address. The code hash is a unique identifier derived from the bytecode of the contract.storageHash
: This field contains the storage hash of the smart contract associated with the address. The storage hash represents the current state of the contract's storage.storageProof
: It appears to be a list containing a singleAttributeDict
object. This object represents a proof related to a specific storage keynonce
: It represents the nonce value associated with the address. The nonce is a transaction count or sequence number that helps to prevent replay attacks.address
: This field contains the Ethereum address associated with the proof.
Conclusion
In conclusion, the combination of Ethereum and Python presents a powerful duo that has the potential to shape the future of blockchain technology and revolutionize various industries. This article has explored the seamless integration of Ethereum's decentralized network and Python's extensive capabilities for Web3 development. By demonstrating practical code examples, the article has covered key aspects such as account access, transaction handling, chain ID, gas price, block numbers, storage, and transaction proofs. Through the utilization of libraries like web3 and MetaMask, developers can leverage the vast possibilities of Ethereum and Python to build innovative decentralized applications. With the availability of testnets and APIs like Infura, developers can experiment, test, and deploy their applications securely.
What's Next
In the next article, we will delve into the deployment of smart contracts on the Ethereum blockchain and explore how to access and interact with them using Python. We will cover the process of compiling and deploying smart contracts, including contract initialization. Additionally, we will demonstrate how to interact with deployed contracts using Python, including calling contract functions, reading contract states, and handling events. By combining Ethereum's powerful smart contract capabilities with Python's versatility, we can unlock endless possibilities for building decentralized applications. Stay tuned for the next article as we dive deeper into the world of smart contract deployment and Python integration in Ethereum development.