【学习笔记】web3库的基础使用

web3.py库学习笔记

python与以太坊区块链交互的库,通过web3.py可以构建去中心化应用、智能合约交互等。
pip install web3安装

一、配置

web3库需要依托以太坊节点建立连接,将这类连接统称为Providers,并且存在多种配置方式。安装web3.py后,就需要配置Provider和要用到的中间件。

(一)Provider

  1. Test Provider
    测试用的Provider:eth-tester,用于入门和快速开发。内置存有以太币的测试账户,并会将每一笔交易即时纳入区块中。
    fromweb3importWeb3,EthereumTesterProvider w3=Web3(EthereumTesterProvider())w3.is_connected()输出True

    EthereumTesterProvider需要通过pip install web3[tester]安装

  2. 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
  3. 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

六、其他

  1. 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 代币本身就是一个智能合约 ,部署在以太坊上,有自己的合约地址。代币余额不是存在你的钱包里,而是记录在代币合约的存储中。
  2. abi (Application Binary Interface,应用二进制接口)
    ABI是合约的"函数说明书" ——告诉外部程序如何调用合约的函数。它描述了:

  • 函数类型type: 定义函数的类型,如"function"、“constructor”、“fallback”、“receive”(接收以太币)等。
  • 函数名称name: 帮助识别函数。
  • 函数参数inputs: 数组对象,每个对象包括参数名称、参数类型、components(如果是tuple类型)。
  • 返回类型outputs: 指定函数调用返回的数据类型,类似inputs。
  • stateMutability: 定义函数是否会修改合约状态(如"nonpayable"、“payable”、“view”、"pure"等)。
  1. 合约存储槽
    合约的存储槽(storage slots)是合约状态变量的存储位置。每个合约都有一个存储槽,每个状态变量都有一个对应的存储槽,合约的状态变量按声明顺序依次占用槽位。