Python互动Eth智能合约全流程:从连接测试网到签名转账

·

所谓「纸上得来终觉浅」,在用 Truffle console 跑过几次合约后,我开始尝试用 Python 直接与智能合约对话。惊喜地发现:不仅语法更优雅,脚本可复用性也更高。下文把我踩过的坑和跑通的全部步骤梳理出来,供你 15 分钟就能在自己的电脑里跑出一套最小闭环。

核心关键词:Python、Web3py、智能合约、以太坊测试网、转账、签名交易、Ganache、ABI、合约交互


准备战场:安装依赖与启动测试链

开始前,确保环境就绪:

启动 Ganache,复制 HTTP RPC 地址备用(下文默认本地 7545 端口)。
👉 点击查看如何一键部署本地测试链,省去找节点的烦恼


率先出手:链接测试网络

from web3 import Web3

w3 = Web3(Web3.HTTPProvider("http://127.0.0.1:7545"))
print(w3.is_connected())        # True 即成功

若返回 True,说明 Web3py 已跟本地节点握手。除了 127.0.0.1 外,你也可以把节点换成 InfuraAlchemy 等第三方 RPC。


速查账户与余额

Ganache 的第一号账户即为挖矿地址(coinbase):

print(w3.eth.coinbase)
# 0x0374AD83DfEB8cfD94889631255AE43B2Aa93bbe

查询指定地址余额(Wei 转 Ether):

balance_wei = w3.eth.get_balance("0x0374AD83DfEB8cfD94889631255AE43B2Aa93bbe")
print(w3.from_wei(balance_wei, 'ether'))    # 100.0

快速热身:无须签名的简易转账

在本地私有链做实验,Ganache 会自动解锁账户,因此可以直接 send_transaction

from_addr = "0x0374AD83DfEB8cfD94889631255AE43B2Aa93bbe"
to_addr   = "0x13d2F0AB715924cdaF9623F155275CEdA55819EE"

tx_hash = w3.eth.send_transaction({
    'from':  from_addr,
    'to':    to_addr,
    'value': w3.to_wei(1, 'ether')
})
print(w3.to_hex(tx_hash))

区块一确认,print(w3.from_wei(w3.eth.get_balance(to_addr), 'ether')) 立即可见余额变动。

虽然便捷,但这只是「小白通道」。真正上主网时,每笔交易都必须经过私钥 数字签名,才能避免资产被任意转走。

进阶动作:附带签名的转账

线上环境与 Ganache 非解锁模式都要求交易附签名:

import os
from eth_account import Account
from web3 import Web3

w3 = Web3(Web3.HTTPProvider("http://127.0.0.1:7545"))

account1 = "0x0374AD83DfEB8cfD94889631255AE43B2Aa93bbe"
private_key = os.getenv("PRIVATE_KEY")   # 也可用 Ganache 返回的私钥
account2 = "0x13d2F0AB715924cdaF9623F155275CEdA55819EE"

nonce = w3.eth.get_transaction_count(account1)
tx = {
    'nonce':    nonce,
    'to':       account2,
    'value':    w3.to_wei(1, 'ether'),
    'gas':      21000,
    'gasPrice': w3.to_wei('50', 'gwei'),
    'chainId':  1337   # Ganache 默认为 1337
}
signed_tx = Account.sign_transaction(tx, private_key)
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
print("tx_hash", w3.to_hex(tx_hash))

错误私钥会立即抛出 ValueError: Invalid transaction v,r,s values,又是一道安全防线。


终极交互:读取并调用智能合约

1. 准备合约 ABI 与地址

假设你已用 Truffle 部署过 MetaCoin 合约到 Ganache:

from web3 import Web3
import json, os

w3 = Web3(Web3.HTTPProvider("http://127.0.0.1:7545"))
account = "0x0374AD83DfEB8cfD94889631255AE43B2Aa93bbe"
to_account = "0x13d2F0AB715924cdaF9623F155275CEdA55819EE"

with open("./build/contracts/MetaCoin.json") as f:
    artifact = json.load(f)

contract = w3.eth.contract(
    address="0x10BD02647FE442dA2E86D4b05a4aaEC24464314E",
    abi=artifact["abi"]
)

2. 读函数(不需要签名)

print("Sender Balance:", contract.functions.getBalance(account).call())
print("Receiver Balance:", contract.functions.getBalance(to_account).call())

3. 写函数(需要签名)

tx = contract.functions.sendCoin(to_account, 100).build_transaction({
    'from': account,
    'nonce': w3.eth.get_transaction_count(account),
    'gas': 70000,
    'gasPrice': w3.to_wei('50', 'gwei'),
    'chainId': 1337
})
signed = w3.eth.account.sign_transaction(tx, private_key)
tx_hash = w3.eth.send_raw_transaction(signed.rawTransaction)
print("transaction written:", w3.to_hex(tx_hash))

几分钟后在 Ganache 交易标签页即可看到这笔 内部交易 触发 Transfer 事件,MetaCoin 随之完成代币流转。


用例小结:一张图看懂链上流程

  1. 建立 HTTP 连接 → 读取状态(块高、余额)
  2. 构造 & 签名交易 → 广播到网络 → 等待区块确认
  3. 加载合约 ABI → 本地调用,解码 ABI 数据 → 验证合约事件

👉 一站式查看链上交易深度数据,别让手续费花冤枉钱


常见疑问 FAQ

Q1:本地测试链和主网的 gasPrice、chainId 有哪些差异?

Q2:为什么我用 w3.is_connected() 报 False?

Q3:如何把自己的私钥安全保存到环境变量?

Q4:MetaCoin 合约无返回值怎么办?

Q5:怎样监听合约事件?

Q6:我可以把这段脚本改成分布式签名吗?


写在最后

从舀一勺本地测试网的以太币,到用 Python 脚本签名、转账、调合约,整套流程不过几分钟,但背后囊括 区块链协议、密码学、节点通信 三大技术栈。
当你下次用 DApp 感觉「秒到」时,别忘了这是节点矿工、共识算法、以及你编写的每一行 Python 代码共同协作的结果。祝编码愉快,区块高度节节高升!