Python与以太坊的桥梁:如何用Python调用以太坊网络**
以太坊作为全球领先的智能合约平台,其生态系统日益庞大,吸引了无数开发者和企业,而Python,凭借其简洁的语法、丰富的库支持和强大的社区,成为了与区块链技术交互的热门选择,本文将详细介绍如何使用Python调用以太坊网络,包括连接节点、读取数据、发送交易以及与智能合约交互等核心操作。
准备工作:环境搭建与依赖安装
在开始之前,我们需要准备以下几样东西:
-
以太坊节点:Python脚本需要通过一个以太坊节点来与以太坊网络通信,你可以选择:
- 本地节点:使用Geth或OpenEthereum等客户端在自己电脑上运行一个全节点或轻节点,这对硬件有一定要求。
- Infura或Alchemy等第三方服务:这是更便捷的选择,它们提供远程的以太坊节点接口,你只需要注册获取一个HTTP或WebSocket的URL即可,对于开发和小型应用来说,免费套餐通常足够。
- 本地测试网节点:在开发测试阶段,强烈建议在本地运行一个测试网节点(如Ropsten, Goerli, Sepolia),或者使用Infura/Alchemy提供的测试网端点,避免消耗真实的ETH。
-
Python环境:确保你的系统已安装Python 3.6或更高版本。
-
安装Web3.py库:Web3.py是以太坊官方Python库,提供了与以太坊节点交互的完整API,它是Python调用以太坊事实上的标准。
pip install web3
-
钱包与私钥(可选,用于发送交易):如果你需要发送交易或部署合约,你需要一个以太坊钱包(如MetaMask)和对应的私钥。请务必妥善保管私钥,切勿泄露!
连接到以太坊节点
使用Web3.py连接到以太坊节点是第一步,以连接到Infura的HTTP节点为例:
from web3 import Web3
infura_url = "https://mainnet.infura.io/v3/YOUR_PROJECT_ID"
w3 = Web3(Web3.HTTPProvider(infura_url))
# 检查连接是否成功
print(f"是否连接成功: {w3.is_connected()}")
# 获取当前区块号
print(f"当前区块号: {w3.eth.block_number}")
如果你使用的是本地节点(如Geth默认端口8545),URL可以是 http://127.0.0.1:8545。
读取以太坊数据
连接成功后,我们可以轻松读取以太坊上的数据。
- 获取账户余额:
# 替换成你想查询的以太坊地址 address = "0x742d35Cc6634C0532925a3b844Bc454e4438f44e"
确保地址是校验过的格式
checksum_address = w3.to_checksum_address(address)
balance_wei = w3.eth.get_balance(checksum_address) balance_eth = w3.from_wei(balance_wei, 'ether')
print(f"地址 {checksum_address} 的余额是: {balance_eth} ETH")
2. **获取交易详情**:
```python
# 替换成你想查询的交易哈希
tx_hash = "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060"
tx_details = w3.eth.get_transaction(tx_hash)
print(f"交易详情: {tx_details}")
- 获取合约事件日志:这将在后续智能合约交互部分详细说明。
发送交易(转账)
发送交易比读取数据复杂,因为它需要签名和支付Gas费。
-
准备私钥和地址:
# 替换成你的私钥(请勿在代码中硬编码私钥,使用环境变量或配置文件管理!) private_key = "YOUR_PRIVATE_KEY" sender_address = w3.eth.account.from_key(private_key).address checksum_sender_address = w3.to_checksum_address(sender_address)
-
获取Nonce:Nonce是账户发送的交易序号,必须按顺序递增。
nonce = w3.eth.get_transaction_count(checksum_sender_address)
-
构建交易:
# 接收方地址 receiver_address = w3.to_checksum_address("0x1234567890123456789012345678901234567890") # 转账金额(以Wei为单位) value = w3.to_wei(0.01, 'ether') # Gas价格(Gwei) gas_price = w3.eth.gas_price # Gas限制 gas_limit = 21000 # 转账ETH的典型Gas限制 transaction = { 'to': receiver_address, 'value': value, 'gas': gas_limit, 'gasPrice': gas_price, 'nonce': nonce, 'chainId': 1 # 主网chainId,测试网请使用对应的chainId,如Goerli是5 } -
签名交易:
signed_tx = w3.eth.account.sign_transaction(transaction, private_key)
-
发送交易并等待确认:
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) print(f"交易已发送,哈希: {tx_hash.hex()}") # 等待交易被打包 tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash) print(f"交易收据: {tx_receipt}")
与智能合约交互
这是Python调用以太坊最强大的功能之一,你需要合约的ABI(Application Binary Interface)和地址。
-
获取合约ABI和地址:
- ABI:是合约的接口描述,通常在编译Solidity合约时生成(JSON格式)。
- 地址:已部署的合约地址。
-
加载合约:
# 假设我们有一个简单的ERC20代币合约的ABI(简化示例) # 实际使用时请替换为你的完整ABI token_abi = """ [ {"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"type":"function"}, {"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"type":"function"}, {"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"type":"function"}, {"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"type":"function"} ] """ # 替换成你的合约地址 contract_address = w3.to_checksum_address("0xYourContractAddressHere") # 加载合约 contract = w3.eth.contract(address=contract_address, abi=token_abi) -
调用合约的纯函数(读取数据,不修改状态):
# 获取代币名称 token_name = contract.func
tions.name().call() print(f"代币名称: {token_name}") # 查询某个地址的代币余额 address_to_check = "0x742d35Cc6634C0532925a3b844Bc454e4438f44e" token_balance = contract.functions.balanceOf(address_to_check).call() print(f"地址 {address_to_check} 的代币余额: {token_balance}")
-
调用合约的修改函数(发送交易,修改状态): 这与发送ETH转账类似,需要构建交易、签名并发送。
# 假设我们要调用transfer函数进行代币转账 receiver_address = w3.to_checksum_address("0x1234567890123456789012345678901234567890") amount_to_transfer = 1000 * 10**18 # 假设代币精度是18位小数 # 获取nonce nonce = w3.eth.get_transaction_count(checksum_sender_address) # 构建调用合约的交易 build_tx = contract.functions.transfer( receiver_address, amount_to_transfer ).build_transaction({ 'from': checksum_sender_address, 'nonce': nonce, 'gas': 200000, # Gas限制根据合约方法复杂度调整 '