在以太坊开发中,web3.py 库提供了多种灵活的方法来发送交易。本文将详细介绍三种主流方式,并指导你根据实际需求选择最适合的方案。
核心方法概览
web3.py 提供了 send_transaction() 和 send_raw_transaction() 两种基础方法,适用于不同场景:
send_transaction():适合快速开发,可与中间件配合实现自动签名send_raw_transaction():提供更高控制权,支持离线签名和预签名交易
对于智能合约交互,你还可以使用:
transact()方法:简化合约函数调用build_transaction()+ 签名 +send_raw_transaction():完整控制交易流程
👉 查看实时交易工具
方法一:使用 eth-tester 快速测试
许多教程使用 eth-tester(通过 EthereumTesterProvider)来快速验证想法和构建概念证明。测试账户发送的交易会自动签名,无需手动处理。
from web3 import Web3, EthereumTesterProvider
w3 = Web3(EthereumTesterProvider())
acct1 = w3.eth.accounts[0] # eth-tester 生成的测试账户
some_address = "0x0000000000000000000000000000000000000000"
# eth-tester 会自动签名并发送交易
tx_hash = w3.eth.send_transaction({
"from": acct1,
"to": some_address,
"value": 123123123123123
})
tx = w3.eth.get_transaction(tx_hash)
assert tx["from"] == acct1这种方法适合学习和原型开发,但不适合生产环境。
方法二:使用中间件自动签名
当你从测试环境过渡到实际应用时,可以使用 web3.py 中间件为特定账户自动签名交易。
from web3.middleware import SignAndSendRawMiddlewareBuilder
import os
# 重要:切勿在代码中直接硬编码私钥!使用环境变量
pk = os.environ.get('PRIVATE_KEY')
acct2 = w3.eth.account.from_key(pk)
# 添加 acct2 作为自动签名器
w3.middleware_onion.inject(SignAndSendRawMiddlewareBuilder.build(acct2), layer=0)
# 中间件会自动为来自 acct2 的交易签名
tx_hash = w3.eth.send_transaction({
"from": acct2.address,
"value": 3333333333,
"to": some_address
})
tx = w3.eth.get_transaction(tx_hash)
assert tx["from"] == acct2.address你还可以设置默认账户,这样在省略 "from" 字段时会自动使用该账户。
方法三:手动构建和发送原始交易
如果不使用中间件,你需要手动完成交易的构建、签名和发送全过程。
# 1. 构建交易
transaction = {
'from': acct2.address,
'to': some_address,
'value': 1000000000,
'nonce': w3.eth.get_transaction_count(acct2.address),
'gas': 200000,
'maxFeePerGas': 2000000000,
'maxPriorityFeePerGas': 1000000000,
}
# 2. 使用私钥签名交易
signed = w3.eth.account.sign_transaction(transaction, pk)
# 3. 发送已签名的交易
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
tx = w3.eth.get_transaction(tx_hash)
assert tx["from"] == acct2.address这种方法提供了最大程度的控制权,适合需要精细管理交易流程的场景。
智能合约交易处理
智能合约交互同样遵循上述原理,主要通过两种方式实现:
使用 transact() 方法
# 部署合约
tx_hash = Billboard.constructor("gm").transact({"from": acct2.address})
receipt = w3.eth.get_transaction_receipt(tx_hash)
deployed_addr = receipt["contractAddress"]
# 引用已部署的合约
billboard = w3.eth.contract(address=deployed_addr, abi=abi)手动构建合约交易
# 构建未发送的交易
unsent_billboard_tx = billboard.functions.writeBillboard("gn").build_transaction({
"from": acct2.address,
"nonce": w3.eth.get_transaction_count(acct2.address),
})
# 签名并发送
signed_tx = w3.eth.account.sign_transaction(unsent_billboard_tx, private_key=acct2.key)
tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
w3.eth.wait_for_transaction_receipt(tx_hash)👉 获取进阶交易策略
常见问题
我应该选择哪种交易发送方式?
如果你追求开发效率且主要使用同一账户,推荐使用中间件配合 send_transaction()。如果需要更高控制权或离线签名,则应选择 send_raw_transaction()。
如何安全地管理私钥?
永远不要在代码中硬编码私钥。使用环境变量或专业的密钥管理服务,并确保私钥不会提交到版本控制系统。
交易发送失败有哪些常见原因?
常见原因包括:余额不足、gas 设置过低、nonce 值不正确、或是网络拥堵。发送前务必检查这些参数。
如何估算合理的 gas 费用?
可以使用 w3.eth.estimate_gas() 方法估算交易所需的 gas 量,并参考当前网络状况设置适当的 gas 价格。
智能合约交易与普通交易有何不同?
合约交易需要包含调用数据(data),而普通交易只需指定接收地址和金额。合约交易通常需要更多 gas。
如何确认交易是否成功?
使用 w3.eth.wait_for_transaction_receipt(tx_hash) 等待交易确认,并检查返回的收据中的状态字段。
选择合适的方法取决于你的具体需求:测试开发、生产环境自动化还是精细控制。无论哪种方式,web3.py 都提供了强大的工具来满足你的以太坊交易需求。