本文作者:一个程序猿[1]
如果你想让 Web3.py 来定制一些基础功能之外的工作,最少有这几个选择:中间件、自定义方法、外部模块和自定义 provider。这篇文章将逐个介绍这些分别是什么,什么时候会涉及到,以及如何开始。
1. 中间件
What
中间件[2]允许你在发出请求之前或收到结果之后向现有方法添加一些行为。
When
如果你希望每次执行某个 RPC 调用或一组调用时都发生某些事情,如记录日志、数据可视化、数据转换等,请使用中间件。
How
Web3.py 有一组标配的默认中间件[3],还有很多可选中间件[4]。但是,如果你需要编写一些自定义中间件,有几个语法选择:使用函数或类[5]。对于一些简单的情况,使用函数语法是很典型的。
代码语言:javascript复制def example_middleware(make_request, w3):
# do one-time setup operations here
def middleware(method, params):
# 在这里做前置预处理
# perform the RPC request, getting the response
response = make_request(method, params)
# 在这里做后置处理
# finally return the response
return response
return middleware
- 使用函数语法的中间件模板 -
中间件是按特定顺序层次执行的,API[6]允许将新的中间件添加(add
)到列表的末尾,也可以插入(inject
),替换( replace
)或者 移除(remove
)一层, 或者清除clear
整个中间件堆栈。
2. 自定义方法
What
可以将任意 RPC 方法添加到现有模块中。
When
如果你正在使用具有非标准 RPC 命令的客户端或在分叉客户端中测试某些自定义功能,那么注册自定义方法会很方便。
如果你想应用自己的请求或结果格式化程序,自定义方法也可用于覆盖现有方法。
How
attach_methods
函数在每个模块上都可用,并接受带有方法名称和对应Method
的字典:
from web3.method import Method
w3.eth.attach_methods({"create_access_list": Method("eth_createAccessList")})
w3.eth.create_access_list(...)
你可以选择性的包含自定义输入处理方法、请求和结果格式化程序
代码语言:javascript复制from web3.method import Method
w3.eth.attach_methods({
"example": Method(
"eth_example",
mungers=[...],
request_formatters=[...],
result_formatters=[...],
is_property=False,
),
})
w3.eth.example()
- 向Eth
模块添加自定义eth_example
方法 -
如果你想使用属性而不用函数方法,可以将is_property
设置为True
来添加属性。
3. 外部模块
What
外部模块[7]允许在一个主题下导入一组 API ,从而提供更大的灵活性。回想一下:插件。
When
在引入一整个 L2 API 或者一个客户端支持的多个非标准 RPC 方法时,外部模块可能会很有用。如Erigon[8]的特定方法像erigon_getHeaderByHash
, erigon_getHeaderByNumber
等。
How
模块只需要是类并且可以引用父 Web3 实例。在Web3
实例化时使用关键字external_modules
参数或在任何时候通过attach_modules
方法配置你的外部模块:
# add modules at instantiation:
w3 = Web3(
HTTPProvider(...),
external_modules={"example": ExampleModule}
)
# add modules after instantiation:
w3.attach_modules({"example": ExampleModule})
# invoking external modules:
w3.example.example_method()
更多上下文,包括嵌套模块示例,可在这里[9]获得。
4. 自定义 Provider
What
provider[10] 的核心是定义如何执行请求。
When
构建自定义 provider[11] 仅适用于插入自定义测试框架或类似的极少数情况。如果你只是想连接到另一个 EVM 区块链、侧链或 rollup,通常只需配置一个现有选项:HTTPProvider[12], IPCProvider[13], 或 WebsocketProvider[14].
How
Provider 只需要两个方法,make_request
和isConnected
,以及一个自定义middlewares
.
from web3.providers.base import BaseProvider
class CustomProvider(BaseProvider):
middlewares = ()
def make_request(self, method, params):
return {"result": {"welp": "lol"}}
def isConnected(self):
print(True)
w3 = Web3(CustomProvider())
w3.eth.get_block("latest")
# AttributeDict({"welp": "lol"})
总结
上面的选项粗略的按灵活性从小到大排序。在实践中,我认为中间件和外部模块能够发挥最大的作用,特别是当受信任的外部模块变成司空见惯的事。
还有一个monkey 补丁[15]没有包括在这篇文章中。如果你走上了那条路……一切都好吗?说真的,如果你的定制需要用到 monkey 补丁的另一个向量,请在这里[16]创建 Issue。
原文链接:https://snakecharmers.ethereum.org/web3-py-patterns-customizations/
参考资料
[1]
一个程序猿: https://learnblockchain.cn/people/9
[2]
中间件: https://web3py.readthedocs.io/en/stable/middleware.html
[3]
默认中间件: https://web3py.readthedocs.io/en/stable/middleware.html#default-middleware
[4]
可选中间件: https://web3py.readthedocs.io/en/stable/middleware.html#optional-middleware
[5]
函数或类: https://web3py.readthedocs.io/en/stable/internals.html#middlewares
[6]
API: https://web3py.readthedocs.io/en/stable/middleware.html#middleware-stack-api
[7]
外部模块: https://learnblockchain.cn/article/4053
[8]
Erigon: https://github.com/ledgerwatch/erigon
[9]
这里: https://snakecharmers.ethereum.org/web3-py-patterns-external-modules/
[10]
provider: https://web3py.readthedocs.io/en/latest/providers.html
[11]
自定义provider: https://web3py.readthedocs.io/en/latest/internals.html#providers
[12]
HTTPProvider: https://web3py.readthedocs.io/en/latest/providers.html#httpprovider
[13]
IPCProvider: https://web3py.readthedocs.io/en/latest/providers.html#ipcprovider
[14]
WebsocketProvider: https://web3py.readthedocs.io/en/latest/providers.html#websocketprovider
[15]
monkey 补丁: https://en.wikipedia.org/wiki/Monkey_patch
[16]
这里: https://github.com/ethereum/web3.py/issues