4个版本
0.1.1 | 2023年4月30日 |
---|---|
0.1.0 | 2023年4月29日 |
0.0.2 | 2023年4月28日 |
0.0.1 | 2023年4月28日 |
#2785 在 魔法豆
每月 38 次下载
15KB
138 行
forge-exec-ipc-client
以单独的进程执行程序并通过IPC连接到它。
由 forge-exec 使用以建立与 forge 的双向通信通道
因为Forge期望在程序退出后将ffi输出提供给stdout,所以每次收到程序回复时都会执行forge-exec-ipc-client
。
它是如何工作的?
forge-exec 被用于你的Forge项目中,并将执行以下操作
- 将执行
forge-exec-ipc-client init <program> [...<args>]
forge-exec-ipc-client
(此包) 将执行程序并附带提供的参数,并为其创建一个新的进程- 在执行此操作时,它还将附加一个随机生成的套接字/命名管道路径/名称,我们称之为
socketID
(以ipc:
前缀) - 因此,程序将通过
<program> [...<args>] ipc:<socketID>
调用 - 该程序需要尽快创建一个ipc服务器,以监听给定的
socketID
。 forge-exec-ipc-client
将尝试在 3 秒内连接到该套接字/命名管道,成功后会将socketID
作为 abi 编码的字符串打印到stdout
并退出。- forge 会捕获该信息,并执行新的 ffi 调用:
forge-exec-ipc-client exec <
> 0x forge-exec-ipc-client
会检测到第一个参数为exec
,并连接到由program
创建的 ipc 服务器。- 连接成功后,它将发送数据参数(第一次调用总是
0x
)到该服务器。 - 这意味着该
program
可以(并且需要)保持活跃状态,监听这些调用。 - 在接收到第一个调用
0x
后,程序应开始执行其用户代码。 - 当它需要向 forge 发送请求时,它只需在通过 abi 编码的数据建立的 ipc 套接字上回复即可(见下方的 格式)。
forge-exec-ipc-client
将在接收后将其写入stdin
并立即退出(尽管program
继续运行,除非它执行了最后的回复(终止))。forge-exec
会捕获数据并将其解释为请求。其中之一是终止请求,可能包含program
可能希望返回的数据。- 如果数据不是终止请求,
forge-exec
将执行请求(目前只支持 send_transaction 和 getBalance)并将数据返回。 - 它将通过以下方式返回数据:
forge-exec-ipc-client exec <
> <> - 直到程序发送终止请求,此过程会重复。
- 在某些错误情况下,
forge-exec
也可以调用terminate
请求,要求程序停止,这将导致 forge 侧发生回滚。 - 目前,在
forge-exec
侧,abi 解码可能会失败,程序将无法接收到通知。因此,程序应处理超时情况,以停止其 ipc 服务器,避免在操作系统资源上挂起。
ipc-server 实现
虽然您可以在 forge-exec-ipc-client
执行的程序中自行编写 ipc 处理,但您可能希望将其抽象化。
目前有一个用 TypeScript 实现的版本,它抽象了流程,让您可以编写以下内容:
import { execute } from "forge-exec-ipc-server";
execute(async (forge) => {
const address = await forge.create({
from: "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
data: "0x608060405234801561001057600080fd5b5060f78061001f6000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c80633fb5c1cb1460415780638381f58a146053578063d09de08a14606d575b600080fd5b6051604c3660046083565b600055565b005b605b60005481565b60405190815260200160405180910390f35b6051600080549080607c83609b565b9190505550565b600060208284031215609457600080fd5b5035919050565b60006001820160ba57634e487b7160e01b600052601160045260246000fd5b506001019056fea2646970667358221220f0cfb2159c518c3da0ad864362bad5dc0715514a9ab679237253d506773a0a1b64736f6c63430008130033",
});
return {
types: [{ type: "address" }],
values: [address],
};
});
forge-exec-ipc-server
也处理超时。
请注意,尽管 Node.js 有启动开销,但一旦程序执行,它就会保持活跃状态,因此可以执行复杂的脚本。
格式
ipc 客户端和服务器之间的通信格式如下
来自程序
作为 ipc 服务器的程序只能向 ipc 客户端发送一种类型的信息。
它们都必须以 \n
字符结束,该字符作为 ipc 信息分隔符。
这些都是表示为十六进制字符串的 abi 编码消息,并将原样(除去 \n
字符)转发到 forge-exec
的 solidity 代码。
编码的格式是一个元组 (uint32, bytes)
,其中uint32表示请求类型,bytes是特定于请求类型的abi编码数据。
请求类型 0
是终止信号,表示程序已执行完成,bytes
数据表示程序想要的内容,是 forge-exec
execute
函数调用返回的内容。
否则,目前还有2种请求,很快还会添加更多。
请参阅 请求列表
来自 forge
发送到 ipc 服务器的只有两种类型的数据:response
和 terminate
。
所有这些都必须以 \n
字符结尾
响应
响应以 response:
开头
程序实际接收到的第一条消息是一个特殊的消息: response:0x\n
,仅表示程序可以开始执行并将请求发送回 forge。
除了这个特殊请求之外,目前程序可以向 forge 发送两种类型的请求,因此目前只有两种类型的响应
请参阅 请求列表
示例
"response:\n"
终止
终止请求以 terminate:
开头
在前面是错误消息
示例
"terminate:Something Wrong Happened\n"
请求列表
终止
来自程序
示例
编码(["uint32", "bytes"],[0, "0x01"])
这将终止执行并返回 0x1 作为 bytes
forge 不会返回任何内容
发送交易
来自程序
示例
编码(["uint32", "bytes"],[1, 编码(["","","",""], [])])
来自 forge-exec-ipc-client
示例
"response:0xFFEEFFEEFFEEFFEEFFEEFFEEFFEEFFEEFFEEFFEE\n"
这返回了部署的合约地址
依赖
~2.5MB
~36K SLoC