想了解 AO 上应用的合约运行机制吗?那么来抓取合约代码一探究竟吧。用一个 python 小程序,轻松获取指定 Process 的合约。
作者: txohyeah
审阅:outprog
来源:内容公会 - 新闻
AO 测试网发布已经有小半年了,AO 的内容也有很多,本文的内容主要聚焦 Process 和智能合约,包括 AO 是什么,Process 是什么,Process 的生命周期。最后重点介绍下如何查看 Process 的合约代码。
AO 是 Arweave 在完善分布式存储基础上,进一步发展出的计算功能,旨在实现全面的去中心化应用支持,与以太坊先计算后存储的发展路径相对应。简单来说,AO 代表了 Arweave 平台上的智能合约或计算能力,是在其永久存储解决方案之上的逻辑层扩展。
AO 由三个单元组成,MU / SU / CU
MU:接收到用户发送的消息,以确保它们经过签名。
SU:对消息进行时间戳和排序,然后捆绑并发布到 Arweave。SU 也是我们今天会用到的主角,后面会在查看合约时,起到了重要的作用。
CU:处理消息并计算出结果。
AO 本质上是基于一个 Data Protocol 构建的超级并行计算机,其中 Data 的存在形式是 AO 中定义的基本元素 Message。那么 Process 在这其中扮演着处理 Message 的重要角色,是处理 AO 上消息的基本单元。Process 运行在 CU 上,可以看成是 CU 上的一个虚拟机。因此,Process 包含基本的能力就是在网络内接收和发送消息。然后开发者通过为 Process 添加 handler 的方式,为 Process 构建消息处理的能力。后面要讲到的合约,其实就是通过发送一条消息到 Process,再通过内置的 _eval handler 部署的。其中添加的 handler 可以理解为合约的消息处理函数。
如果要在我们现有的世界中找到一个类比,那么我认为 docker 中容器(Container)可以很好的让人对比理解 Process。下面我会借助 docker 中 Container 的生命周期类比下 Process 的生命周期。
我们都知道 docker 中 Container 的创建会依赖一个镜像(Image),比如根据 mysql 的 Image 创建一个 mysql 的 Container,而后就可以在这个容器上调用 mysql 的服务了。AO 中的 Process 也是一样,Process 的创建依赖于 Module,并且也会存在不同功能的 Module,有最简单的 Module,有支持定时任务的 Module,也有包含 sqlite 的 Module。目前已经有上百个 Module,可供开发者选择去创建自己的 Process。另外,自己也可以去制作自定义的 Module。相信在不久的将来,也会出现支持 GPU 的 Module,支持各种 AI 能力的 Module。
AO 中的 Process 也存在与 docker 中 Container 不一样的地方。Docker 中的 Container 支持启动、停止、删除等各种动作。目前在 AO 的 Process 中是没有这些操作的,毕竟在去中心化应用的世界中,这些由中心化个人控制的功能就显得很不融洽了。在 AO 中 Process 的运行完全取决于 Process 自己的价值,如果有足够的价值,那么肯定会有更多的 CU 愿意去运行它,相反,一个 Process 如果没有价值,就没有 CU 愿意去运行它,那么这个 Process 就将默默的消失。
什么是 AO 合约?对比以太坊的智能合约。AO 上运行的 Process 中的 Lua 代码可以近似的看成智能合约。
我们创建 Process 时,加载的每一个 Module 都会带有两个默认的 handler(handler 可以被理解为对其他 Process 开放的函数),其中一个函数就是 _eval handler。这个 handler 的主要功能就是运行 Lua 代码。比如你在 aos 中输入1+1,返回一个2,就是通过这个 handler 处理的。那么部署合约实际上,就是给 Process 发送消息,通过 _eval handler 给这个 Process 中添加可以处理业务逻辑的自定义 Handler。
其中需要注意一点,请看下方代码。这是官方开源 AO 项目中 process.lua 中的代码段落。只有当消息的发送者与 Process 的 Owner(Owner为创建合约时的钱包地址)一致时,才能执行 _eval handler。也就是说,如果 Owner 被设置为 nil 时(即把该 Process 设置为没有 Owner),那么这个 Process 中的合约就成为了一个没有人可以再修改的合约了。
Handlers.add("_eval",
function (msg)
return msg.Action == "Eval" and Owner == msg.From
end,
require('.eval')(ao)
)
另外,因为 AO 实际上是基于存储的共识范式(SCP,Storage-based Consensus Paradigm)构建的,所以运行的合约必定是可以在“存储共识”上找到,即在 Process 中运行的所有消息,包括通过 _eval handler 部署的合约代码,都存在了 Arweave 上。因此,任何人都可以在该“存储共识”上找到合约代码。
那么来到了今天的主题,究竟如何找到合约代码呢?下面我介绍下两种方法,并给出一份抓取合约的 Python 程序。
第一种方法当然就是直接在 Arweave 上查询(可以使用graphql https://arweave.net/graphql)。这种方法会要求在数据打包到 Arweave 后才能有用。
第二种就是今天主要介绍的办法。由于所有的数据都会经过 SU 上链,因此也可以在 SU 上查询。个人认为每个 SU 会在自己本地有一份缓存,缓存了由自己上链的数据,因此就可以根据查询 SU 找到对应的合约代码。首先,可以根据浏览器输入地址直接查询。但是该方法的缺点也很明显:1. 有些 Process 发送和接受的消息量巨大,因此上链的数据量也巨大。但是浏览器可以加载的数据有限,经常会出现浏览器崩溃。 2. 很难从海量的数据中过滤出自己想要的合约数据。
如下图,展现的是两个时间戳内,process id 为 m3PaWzK4PTG9lAaqYQPaPdOcXdO8hYqi5Fe9NWqXd0w 的进程(AO token 进程)的所有消息。
这边我写了一个小程序,借助业内大佬基于 python 写的一个 ao 的 sdk,把 Action 为 Eval 的消息过滤出来。(Action 为 Eval 的消息,即为所有由 _eval handler 处理的消息,也包括加载的合约代码。)如下图是我从SU 上面抓取的消息,其中 data 字段中的内容就是经过字符转义的一份合约代码。当然抓取的消息也会包含非部署合约代码的内容,比如执行个 1 + 1 等。但是过滤以后的消息数量已经不多了,完全可以人工选取出来合约的代码。
程序已经开源,这里是 github 的地址:https://github.com/txohyeah/ao-sc
那么让我们激动的来看看 ao token 的合约代码。(抓下来的合约代码也会一并放在开源的代码仓库中)
首先,初始化状态时,定义了 TotalSupply = "21000000000000000000" 与比特币一致的发行量。
Denomination = Denomination or 12 还定义了小数点为12位。
--[[
Initialize State
ao.id is equal to the Process.Id
]]
--
Variant = "0.0.3"
-- token should be idempotent and not change previous state updates
Denomination = Denomination or 12
Balances = Balances or {}
-- 21_000_000 AO Tokens
-- 21_000_000_000_000_000_000 Armstrongs
TotalSupply = "21000000000000000000"
Name = 'AO'
Ticker = 'AO'
Logo = Logo or 'SBCCXwwecBlDqRLUjb8dYABExTJXLieawf7m2aBJ-KY'
定义了在 100000 个区块产生之前,如果执行 transfer 函数,则直接返回 "Transfer is locked"。 由于五分钟产生一个区块,那么 100000 个区块就大约到了明年 2 月份了。
--[[
Transfer
]]
--
token.transfer = function(msg)
if MintCount < 100000 then
Send({ Target = msg.From, Data = "Transfer is locked!" })
return "Transfer is locked"
end
local status, err = pcall(function()
......
还有更多相关的信息,我就不啰嗦了。大家可以愉快的浏览这份经典的AO合约。
上面我介绍了抓取的合约代码,接下来我简单介绍下这个程序。很简单,相信不懂代码的人也可以轻松使用。
第一步,安装 python 3.12 版本。程序是 python 写的,安装 python 是必须的。
第二步,安装所需要的包。本程序依赖业内大佬的 sdk,依赖于 everpay。
pip install requests everpay setuptools
第三步,修改 fetch_sc_record.py 中的 start_time / end_time / process。并执行 fetch_sc_record.py。 start_time 和 end_time 是你需要抓取的时间段。process 是你需要抓取合约的 Process 的 id。
python fetch_sc_record.py
第四步,对应的 Eval 消息,就会出现在 msg_eval.json 的文件中了。再浏览其中的消息,就可以找到你需要的合约代码啦! PS:也需要和运行 aos 一样。设置 HTTPS_PROXY。
关于 PermaDAO:Website | Twitter | Telegram | Discord| Medium | Youtube
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!