后端

Python与以太坊交互实战:Web3.py库的使用指南

TRAE AI 编程助手

Python与以太坊交互实战:Web3.py库的使用指南

引言

以太坊作为最流行的智能合约平台之一,为开发者提供了构建去中心化应用(DApps)的强大能力。Web3.py是Python生态系统中与以太坊交互的核心库,它封装了JSON-RPC接口,提供了简洁易用的API用于连接节点、发送交易、部署和调用智能合约等操作。本文将带你从零开始,全面掌握Web3.py的使用方法。

1. 环境准备与基础配置

1.1 安装Web3.py

首先需要安装Web3.py库及其相关依赖:

# 安装Web3.py核心库
pip install web3
 
# 安装Solidity编译器(用于编译智能合约)
pip install py-solc-x
 
# 安装Infura SDK(可选,用于便捷连接Infura节点)
pip install infura-sdk

1.2 连接以太坊节点

要与以太坊网络交互,必须连接到一个以太坊节点。常见的选择包括:

  • 本地节点(如Geth、Nethermind、Erigon)
  • 第三方节点服务(如Infura、Alchemy、QuickNode)

以下是使用Infura连接以太坊主网的示例:

from web3 import Web3
 
# Infura项目ID(需注册获取)
INFURA_PROJECT_ID = "your-project-id-here"
 
# 连接以太坊主网
infura_url = f"https://mainnet.infura.io/v3/{INFURA_PROJECT_ID}"
web3 = Web3(Web3.HTTPProvider(infura_url))
 
# 验证连接状态
if web3.is_connected():
    print("✅ 已成功连接到以太坊主网")
else:
    print("❌ 连接失败")

1.3 网络配置

不同的以太坊网络有不同的配置参数:

网络Chain ID测试网 faucet
主网1-
Goerli测试网5https://goerlifaucet.com/
Sepolia测试网11155111https://www.infura.io/faucet/sepolia

连接测试网示例:

# 连接Sepolia测试网
sepolia_url = f"https://sepolia.infura.io/v3/{INFURA_PROJECT_ID}"
web3_sepolia = Web3(Web3.HTTPProvider(sepolia_url))
 
print(f"Sepolia网络连接状态:{web3_sepolia.is_connected()}")

2. 核心区块链操作

2.1 获取区块链基础信息

# 获取当前块号
block_number = web3.eth.block_number
print(f"当前块号:{block_number}")
 
# 获取最新块详细信息
latest_block = web3.eth.get_block("latest")
print(f"最新块哈希:{latest_block.hash.hex()}")
print(f"块包含交易数:{len(latest_block.transactions)}")
print(f"块时间戳:{latest_block.timestamp}")
 
# 获取指定块信息
block_10000000 = web3.eth.get_block(10000000)
print(f"第10000000块矿工:{block_10000000.miner}")

2.2 账户与地址操作

# 创建新账户
new_account = web3.eth.account.create()
print(f"新账户地址:{new_account.address}")
print(f"新账户私钥:{new_account.key.hex()}")
 
# 从私钥加载账户
private_key = "0xYourPrivateKeyHere"
account = web3.eth.account.from_key(private_key)
print(f"加载的账户地址:{account.address}")
 
# 验证地址格式
address = "0xEthereumAddressHere"
is_valid = web3.is_address(address)
print(f"地址格式是否有效:{is_valid}")
 
# 转换为校验和地址
checksum_address = web3.to_checksum_address(address)
print(f"校验和地址:{checksum_address}")

2.3 ETH余额查询

# 查询账户余额
address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"  # Vitalik Buterin地址
balance_wei = web3.eth.get_balance(address)
balance_eth = web3.from_wei(balance_wei, "ether")
print(f"账户余额:{balance_eth} ETH")

3. 交易操作

3.1 构建并发送ETH交易

# 定义发送者、接收者和私钥
sender_address = "0xSenderAddressHere"
receiver_address = "0xReceiverAddressHere"
private_key = "0xSenderPrivateKeyHere"
 
# 获取当前gas价格
gas_price = web3.eth.gas_price
print(f"当前gas价格:{web3.from_wei(gas_price, 'gwei')} Gwei")
 
# 获取发送者的nonce(交易次数)
nonce = web3.eth.get_transaction_count(sender_address)
 
# 构建交易对象
transaction = {
    "to": receiver_address,
    "value": web3.to_wei(0.01, "ether"),  # 发送0.01 ETH
    "gas": 21000,  # 普通ETH转账的固定gas限制
    "gasPrice": gas_price,
    "nonce": nonce,
    "chainId": 1  # 主网Chain ID
}
 
# 签名交易
signed_transaction = web3.eth.account.sign_transaction(transaction, private_key)
print(f"已签名交易:{signed_transaction}")
 
# 发送交易
tx_hash = web3.eth.send_raw_transaction(signed_transaction.rawTransaction)
print(f"交易哈希:{web3.to_hex(tx_hash)}")
 
# 等待交易确认
tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash)
print(f"交易确认状态:{'成功' if tx_receipt.status == 1 else '失败'}")
print(f"交易包含在块:{tx_receipt.blockNumber}")

3.2 交易状态查询

# 根据哈希查询交易
tx_hash = "0xTransactionHashHere"
transaction = web3.eth.get_transaction(tx_hash)
print(f"交易发送者:{transaction['from']}")
print(f"交易接收者:{transaction['to']}")
print(f"交易价值:{web3.from_wei(transaction['value'], 'ether')} ETH")
print(f"交易gas价格:{web3.from_wei(transaction['gasPrice'], 'gwei')} Gwei")

4. 智能合约交互

4.1 编译智能合约

from solcx import compile_source, install_solc
 
# 安装指定版本的Solidity编译器
install_solc("0.8.20")
 
# 智能合约源代码
contract_source = """
pragma solidity ^0.8.20;
 
contract SimpleStorage {
    uint256 private _value;
 
    event ValueStored(uint256 value);
    event ValueUpdated(uint256 oldValue, uint256 newValue);
 
    function store(uint256 value) public {
        _value = value;
        emit ValueStored(value);
    }
 
    function update(uint256 newValue) public {
        uint256 oldValue = _value;
        _value = newValue;
        emit ValueUpdated(oldValue, newValue);
    }
 
    function retrieve() public view returns (uint256) {
        return _value;
    }
}
"""
 
# 编译合约
compiled_contract = compile_source(contract_source, output_values=["abi", "bin"])
contract_interface = compiled_contract["<stdin>:SimpleStorage"]
 
print(f"合约ABI:{contract_interface['abi']}")
print(f"合约字节码:{contract_interface['bin']}")

4.2 部署智能合约

# 构建合约实例
SimpleStorage = web3.eth.contract(abi=contract_interface["abi"], bytecode=contract_interface["bin"])
 
# 构建部署交易
deploy_transaction = SimpleStorage.constructor().build_transaction(
    {
        "from": sender_address,
        "nonce": nonce,
        "gas": 1000000,  # 部署合约需要更多gas
        "gasPrice": gas_price,
        "chainId": 1
    }
)
 
# 签名并发送部署交易
signed_deploy = web3.eth.account.sign_transaction(deploy_transaction, private_key)
deploy_tx_hash = web3.eth.send_raw_transaction(signed_deploy.rawTransaction)
 
# 等待部署完成
deploy_receipt = web3.eth.wait_for_transaction_receipt(deploy_tx_hash)
print(f"✅ 合约部署成功!")
print(f"合约地址:{deploy_receipt.contractAddress}")
print(f"部署交易哈希:{deploy_receipt.transactionHash.hex()}")

4.3 调用智能合约方法

# 加载合约实例
contract_address = deploy_receipt.contractAddress
simple_storage = web3.eth.contract(address=contract_address, abi=contract_interface["abi"])
 
# 调用view/pure方法(无需交易,免费)
current_value = simple_storage.functions.retrieve().call()
print(f"合约当前存储值:{current_value}")
 
# 发送交易调用write方法
new_value = 42
update_transaction = simple_storage.functions.update(new_value).build_transaction(
    {
        "from": sender_address,
        "nonce": web3.eth.get_transaction_count(sender_address),
        "gas": 500000,
        "gasPrice": gas_price,
        "chainId": 1
    }
)
 
signed_update = web3.eth.account.sign_transaction(update_transaction, private_key)
update_tx_hash = web3.eth.send_raw_transaction(signed_update.rawTransaction)
web3.eth.wait_for_transaction_receipt(update_tx_hash)
 
# 再次读取值
updated_value = simple_storage.functions.retrieve().call()
print(f"合约更新后存储值:{updated_value}")

4.4 监听智能合约事件

# 创建事件过滤器(从最新块开始)
event_filter = simple_storage.events.ValueUpdated.create_filter(fromBlock="latest")
 
# 获取新事件
new_events = event_filter.get_new_entries()
for event in new_events:
    print(f"📅 事件类型:{event.event}")
    print(f"   旧值:{event.args.oldValue}")
    print(f"   新值:{event.args.newValue}")
    print(f"   交易哈希:{event.transactionHash.hex()}")
 
# 获取历史事件
history_events = simple_storage.events.ValueUpdated.get_logs(fromBlock=deploy_receipt.blockNumber)
print(f"历史事件总数:{len(history_events)}")

5. 高级功能与最佳实践

5.1 WebSocket实时监听

# 使用WebSocket连接
infura_ws_url = f"wss://mainnet.infura.io/ws/v3/{INFURA_PROJECT_ID}"
web3_ws = Web3(Web3.WebsocketProvider(infura_ws_url))
 
# 订阅新块事件
def handle_new_block(block_hash):
    block = web3_ws.eth.get_block(block_hash)
    print(f"🚀 新块:{block.number},包含交易:{len(block.transactions)}")
 
# 开始监听
web3_ws.eth.subscribe("newHeads", handle_new_block)
 
# 保持连接
import time
while True:
    time.sleep(1)

5.2 Gas优化

# 估算交易gas
estimated_gas = web3.eth.estimate_gas(transaction)
print(f"估算gas:{estimated_gas}")
 
# 使用EIP-1559交易(伦敦硬分叉后)
from web3.gas_strategies.time_based import fast_gas_price_strategy
 
# 设置gas策略
web3.eth.set_gas_price_strategy(fast_gas_price_strategy)
 
# 构建EIP-1559交易
transaction_eip1559 = {
    "to": receiver_address,
    "value": web3.to_wei(0.01, "ether"),
    "gas": 21000,
    "maxPriorityFeePerGas": web3.to_wei(2, "gwei"),  # 矿工小费
    "maxFeePerGas": web3.to_wei(50, "gwei"),  # 最大gas费
    "nonce": nonce,
    "chainId": 1
}

5.3 错误处理

try:
    tx_hash = web3.eth.send_raw_transaction(signed_transaction.rawTransaction)
    tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash)
except ValueError as e:
    print(f"交易失败:{e}")
except Exception as e:
    print(f"发生未知错误:{e}")

6. 常见问题与解决方案

6.1 连接失败

  • 检查网络连接和节点URL是否正确
  • 确保Infura项目ID有效
  • 对于本地节点,确保节点正在运行

6.2 交易失败

  • Out of gas:增加gas限制或检查交易是否有错误
  • Nonce too low:nonce值必须连续且唯一
  • Insufficient funds:确保账户有足够的ETH支付交易费用
  • Invalid address:确保地址格式正确(使用校验和地址)

6.3 合约交互错误

  • 确保ABI和合约地址正确
  • 检查函数参数类型和数量是否匹配
  • 确保合约已成功部署并确认

总结

Web3.py是Python开发者与以太坊交互的强大工具,支持从基础的ETH转账到复杂的智能合约开发。通过本文的学习,你应该已经掌握了Web3.py的核心功能和使用方法。

要深入了解Web3.py,可以参考:

现在,你可以开始构建自己的以太坊应用了!🚀

(此内容由 AI 辅助生成,仅供参考)