web3.py库学习笔记
python与以太坊区块链交互的库,通过web3.py可以构建去中心化应用、智能合约交互等。pip install web3安装
一、配置
web3库需要依托以太坊节点建立连接,将这类连接统称为Providers,并且存在多种配置方式。安装web3.py后,就需要配置Provider和要用到的中间件。
(一)Provider
- Test Provider
测试用的Provider:eth-tester,用于入门和快速开发。内置存有以太币的测试账户,并会将每一笔交易即时纳入区块中。fromweb3importWeb3,EthereumTesterProvider w3=Web3(EthereumTesterProvider())w3.is_connected()输出TrueEthereumTesterProvider需要通过
pip install web3[tester]安装 - Local Provider
与以太坊进行交互最安全的方式,是在自有硬件设备上运行以太坊客户端。对于本地运行的节点,IPC 连接是安全性最高的选择,同时也支持 HTTP 与 WebSocket 配置。主流客户端 Geth 默认开放 8545 端口用于处理 HTTP 请求,8546 端口用于处理 WebSocket 请求。可按照下述方式连接本地节点:fromweb3importWeb3,AsyncWeb3# IPC 连接w3=Web3(Web3.IPCProvider("./path/to/filename.ipc"))w3.is_connected()# 输出True# HTTP 连接w3=Web3(Web3.HTTPProvider("http://127.0.0.1:8545"))w3.is_connected()# 输出True# Async HTTP 连接w3=AsyncWeb3(Web3.AsyncHTTPProvider("http://127.0.0.1:8545"))awaitw3.is_connected()# 输出True# WebSocket 连接w3=awaitAsyncWeb3(AsyncWeb3.WebSocketProvider("ws://127.0.0.1:8546"))awaitw3.is_connected()# 输出True# Async IPC 连接w3=AsyncWeb3(AsyncWeb3.AsyncIPCProvider("./path/to/filename.ipc"))awaitw3.is_connected()# 输出True - Remote Provider
可以通过指定端点来连接远程节点,和本地节点的操作方式一致:fromweb3importWeb3,AsyncWeb3# HTTP 连接w3=Web3(Web3.HTTPProvider("https://<your-provider-url>"))w3=AsyncWeb3(AsyncWeb3.AsyncHTTPProvider('https://<your-provider-url>'))w3=awaitAsyncWeb3(AsyncWeb3.WebSocketProvider('wss://<your-provider-url>'))
web3库自带以下内置Provider:
- HTTPProvider:用于连接基于HTTP与HTTPS协议的JSON-RPC服务器。
- IPCProvider:用于连接基于IPC套接字的JSON-RPC服务器。
- AsyncHTTPProvider:以异步方式连接基于HTTP与HTTPS协议的JSON-RPC服务器。
- AsyncIPCProvider:通过持久连接,以异步方式连接基于IPC套接字的JSON-RPC服务器。
- WebSocketProvider:通过持久连接,以异步方式连接基于WebSocket的JSON-RPC服务器。
(二)中间件
web3.py中间件采用洋葱模型,每一层中间件作用于provider的incoming request和outgoing response。默认内置了多款中间件,可以对中间件进行新增、注入、替换操作,也可以移除、停用任意一款中间件:
- gas_price_strategy
- ens_name_to_address
- attrdict
- validation
- gas_estimate
默认配置定义在web3/manager.py文件的get_default_middleware()方法中。
- AttributeDict:用于将JSON-RPC响应转换为Python属性字典,方便后续操作。
class web3.middleware.AttributeDictMiddleware - ENS Name to Address Resolution:用于将将以太坊域名服务(ENS)域名解析为其指向的地址。例如,w3.eth.send_transaction 函数支持在发送方(from)与接收方(to)字段中使用后缀为.eth的域名。
class web3.middleware.ENSNameToAddressMiddleware - Gas Price Strategy:若已设置gas price策略且条件适用,系统会为交易附加gasPrice参数。
class web3.middleware.GasPriceStrategyMiddleware - Buffered Gas Estimate:若交易参数中未设置gas参数,本中间件会补充gas预估数值。设定规则为:
min(w3.eth.estimate_gas + gas_buffer, gas_limit),其中gas_buffer默认数值为100000。classweb3.middleware.BufferedGasEstimateMiddleware - Validation:用于验证交易参数是否符合要求。
class web3.middleware.ValidationMiddleware
使用示例:
# Anvil 默认使用 POA 共识,注入 POA 中间件以正确解析区块w3.middleware_onion.inject(ExtraDataToPOAMiddleware,layer=0)# 注入到中间件栈的 最外层 (最先执行)。中间件是"洋葱"结构,layer 越小越靠外以太坊客户端geth在开发模式与Goerli测试网中采用了PoA原型机制,该原型机制与以太坊黄皮书规范存在偏差。黄皮书规定每个区块内的额外数据字段长度上限为32字节,而geth的PoA机制使用的数据长度超出了该限制,因此此中间件会在返回区块数据前对其做小幅修改。
二、API接口
(一)基础API
Web3类内置了诸多便捷的工具函数:
编解码工具
- Web3.is_encodable()
- Web3.to_bytes()
- Web3.to_hex()
- Web3.to_int()
- Web3.to_json()
- Web3.to_text()
地址工具
- Web3.is_address()
- Web3.is_checksum_address()
- Web3.to_checksum_address()
货币单位转换
- Web3.from_wei()
- Web3.to_wei()
密码哈希运算
- Web3.keccak()
- Web3.solidity_keccak()
(二)web3.eth 接口
与以太坊交互最常用的接口均收纳在web3.eth命名空间下。
数据获取:
查询账户余额(get_balance)、交易信息(get_transaction)以及区块数据(get_block)是web3.py最基础的常用操作。接口列表:
- web3.eth.get_balance()
- web3.eth.get_block()
- web3.eth.get_block_transaction_count()
- web3.eth.get_code()
- web3.eth.get_proof()
- web3.eth.get_storage_at()
- web3.eth.get_transaction()
- web3.eth.get_transaction_by_block()
- web3.eth.get_transaction_count()
- web3.eth.get_uncle_by_block()
- web3.eth.get_uncle_count()
交易发送:
绝大多数常规场景可使用send_transaction接口,或是sign_transaction和 send_raw_transaction组合。接口列表:
- web3.eth.send_transaction()
- web3.eth.sign_transaction()
- web3.eth.send_raw_transaction()
- web3.eth.replace_transaction()
- web3.eth.modify_transaction()
- web3.eth.wait_for_transaction_receipt()
- web3.eth.get_transaction_receipt()
- web3.eth.sign()
- web3.eth.sign_typed_data()
- web3.eth.estimate_gas()
- web3.eth.generate_gas_price()
- web3.eth.set_gas_price_strategy()
三、合约
web3.py 能够协助部署已发布的智能合约、读取合约数据,或是调用合约中的函数。部署合约的前提是合约已完成编译,且能够获取对应的字节码与应用二进制接口(ABI)。编译工作可在Remix平台完成,也可借助Ape等各类合约开发框架实现。
- 合约对象实例化完成后,调用constructor中的transact方法,即可部署合约实例:
ExampleContract=w3.eth.contract(abi=abi,bytecode=bytecode)tx_hash=ExampleContract.constructor().transact()tx_receipt=w3.eth.wait_for_transaction_receipt(tx_hash)tx_receipt.contractAddress'0x8a22225eD7eD460D7ee3842bce2402B9deaD23D3' - 将已部署合约加载至
Contract对象后,便可通过functions命名空间调用该合约内置函数:deployed_contract=w3.eth.contract(address=tx_receipt.contractAddress,abi=abi)deployed_contract.functions.myFunction(42).transact() - 若需读取合约数据(或是在本地预览交易执行结果,无需在区块链网络上实际执行交易),可以使用
ContractFunction.call调用方法,也可选用更为简洁的ContractCaller语法:# Using ContractFunction.calldeployed_contract.functions.getMyValue().call()42# Using ContractCallerdeployed_contract.caller().getMyValue()42 - API列表
- web3.eth.contract()
- Contract.address
- Contract.abi
- Contract.bytecode
- Contract.bytecode_runtime
- Contract.functions
- Contract.events
- Contract.fallback
- Contract.constructor()
- Contract.encode_abi()
- web3.contract.ContractFunction
- web3.contract.ContractEvents
四、事件、日志、过滤器
如果想要对新挖出的区块或是合约触发的特定事件做出响应,可以使用get_logs, subscriptions, 或者filters。
- API列表:
- web3.eth.subscribe()
- web3.eth.filter()
- web3.eth.get_filter_changes()
- web3.eth.get_filter_logs()
- web3.eth.uninstall_filter()
- web3.eth.get_logs()
- Contract.events.your_event_name.create_filter()
- Contract.events.your_event_name.build_filter()
- Filter.get_new_entries()
- Filter.get_all_entries()
- Filter.get_all_entries()
- Filter.format_entry()
- Filter.is_valid_entry()
五、网路API
可从web3.net对象中获取一些基本的网路属性
- web3.net.listening
- web3.net.peer_count
- web3.net.version
六、其他
ERC20 是以太坊上的代币标准 (Ethereum Request for Comments #20),定义了一组所有代币必须实现的函数接口。常见的 ERC20 代币:USDT、USDC、UNI、LINK 等。
ERC20 规定的核心函数包括:- balanceOf(address) 查询某地址的代币余额
- transfer(address, uint256) 转账
- approve(address, uint256) 授权他人使用你的代币
- transferFrom(address, address, uint256) 被授权人代为转账
ERC20 代币本身就是一个智能合约 ,部署在以太坊上,有自己的合约地址。代币余额不是存在你的钱包里,而是记录在代币合约的存储中。
abi (Application Binary Interface,应用二进制接口)
ABI是合约的"函数说明书" ——告诉外部程序如何调用合约的函数。它描述了:
- 函数类型type: 定义函数的类型,如"function"、“constructor”、“fallback”、“receive”(接收以太币)等。
- 函数名称name: 帮助识别函数。
- 函数参数inputs: 数组对象,每个对象包括参数名称、参数类型、components(如果是tuple类型)。
- 返回类型outputs: 指定函数调用返回的数据类型,类似inputs。
- stateMutability: 定义函数是否会修改合约状态(如"nonpayable"、“payable”、“view”、"pure"等)。
- 合约存储槽
合约的存储槽(storage slots)是合约状态变量的存储位置。每个合约都有一个存储槽,每个状态变量都有一个对应的存储槽,合约的状态变量按声明顺序依次占用槽位。