WEEX 唯客博客, 作者:作者: Blade Research, Delphinus Lab 太长不看版: Blade Games 和 Delphinus Lab 合作打造了一个基于 WebAssembly 和 zkWASM 的去信任化zk游戏引擎(trustless game engine)。 我们的zk游戏引擎可以支持塔防、MMORTS 等实时游戏类别,以及放置游戏、卡牌/自走棋游戏和互动小说等游戏类型。简单来说,我们把游戏的逻辑放置在zkWASM内运行(一个处理计算的“zk服务器”),每局的游戏结果将会生成zkSNARK 证明而发布。这个游戏引擎还支持 C++、Go、Rust 等语言,并且即将推出 C# 和 Unity 支持。 拿塔防游戏举个例子,对于典型的 6 分钟长、100 波怪物的一局塔防游戏,总共的zkSNARK证明生成时间约为 3 分钟。 这还只是初步结果,我们正在快速优化证明生成时间。 (100万条指令的ZKP生成时间为19秒,每个怪物波是8万个指令,每局游戏800万条指令,8个zkSNARK证明在云化的计算端,生成时间是3分钟左右)。 在基于 ZKVM 的去信任游戏中,维护成本主要来自 ZK 证明生成、RPC/调用数据访问服务以及链上验证和结算费用。 随着 EIP-4844 Proto-danksharding(坎昆升级)在 L2 上生效,运行去信任游戏的成本显着降低。 此外,通过未来实施 zkSNARK 证明递归的计划以及 Nebra 的证明聚合服务,我们可以进一步降低 ZKP 的成本。 我们当前的生态系统游戏包括: 沙丘工厂:基地建设+塔防策略游戏 0xPioneer:类似《多人版饥荒》的生存游戏 Craftpunk:一款以太空为主题的开放世界大型多人在线角色扮演游戏,具有可改装的宇宙飞船和程序生成的地图 ZK游戏引擎由blade games和delphinus labs联合开发,本篇文章由双方联合撰写,旨在使更多web2游戏开发者、全链游戏开发者了解ZK游戏引擎的优势和开发路径。 这是一份关于去信任化的Web3浏览器游戏开发的指南。(另有内容在https://www.youtube.com/watch?v=dLZbfTWLGNI上展示,与注释:https://delphinuslab.com/wp-content/uploads/2023/04/zksummit-presentation-zkwasm-game-1.pdf) 随着Web3的进一步发展,全链游戏再次进入我们的视野。它们声称在去中心化、透明度、无信任和社区治理方面更加优越。然而,全链游戏也继承了区块链的去中心化、安全性、可扩展性困境——这意味着游戏开发者在全链游戏的叙事中面临着游戏内容、互动频率、去中心化、无信任和社区公平性管理的难题。 因此,很久以前,游戏开发者在架构层面达成了一些妥协,并引入了一种被广泛称为Web2.5游戏架构的实践中的最佳架构。 更确切地说,Web2.5是一个混合了Web3和传统游戏的综合术语。Web2.5强调游戏玩法的内容,因为他们相信游戏的主要受众仍然根植于Web2。同时,他们在游戏中添加了Web3的元素(NFT、经济模型、游戏赚取)以使他们的游戏脱颖而出。 标准的Web2.5游戏架构可能如下所示: 左侧图示展示了游戏引擎对游戏的状态机的控制与对玩家活动做出的反应。右侧图示展示了游戏状态的某些部分变化,并揭示了链上最有价值的那些数据。 游戏核心玩法大多在一个集中式的游戏服务器上运行,而最有价值的数据(NFT、代币奖励、记录等)则在区块链上被跟踪。 这种架构的优势在于,游戏服务器可以在处理大量用户交易的集中模式下运行,而这些交易可以在几秒钟内完成。此外,集中式服务器可以处理复杂且持续的游戏玩法,通常在原生区块链中处理这些玩法的成本太高了。 然而,在这种架构中,游戏引擎和链上协议之间的通信渠道通常由签名进行保护,因此并不是去信任的。此外,游戏内容可能会在没有与社区达成共识的情况下进行更改,这有时可能会损害现有玩家的既得利益(例如游戏经济更新、内容更新甚至奖励制度更新)。 此外,链上数据很难检查传递到区块链的数据是否是游戏玩法的有效结果。服务器可以利用职务之便对玩家行为进行区别化处理(例如有倾向性地对待游戏开发商的私人帐户)。 由于Web2游戏通常在其内容和游戏玩法上表现出色,因此将平衡和公平交给游戏提供商是可以接受的。然而,当Web2游戏决定进入Web3生态系统时,它可能需要吸引更多关心经济、所有权和在游戏过程中捕获价值的加密原生玩家。这些玩家们不仅享受通过游戏获得丰富结果的过程,而且希望他们在游戏中取得的结果能够具有一定的意义(例如“可持续性)”,甚至是增值的属性。相对的,这种对具有“可持续性”的增值效应的期待使玩家更加认真地对待他们在游戏中的选择——这意味着玩家在游戏中的思考和决策成本更高,进一步加深了他们对游戏规则公平性和可预测性的期望。 最终,玩家将要求他们能以某种方式控制游戏的“Web3特性”——公平和去信任化的特性不应该由运营商/游戏开发者而是由一套写定的代码来执行,从而达成一个更加去中心化的、完全构建于链上的游戏。 有关于此,一个简单的措施是将上面图示种左侧的所有内容都移到右侧图示(区块链)上,使架构如下所示: 显然,这个举措会导致游戏玩法的许多“退化”: 玩家的每个行动都必须通过链上签名的方式来表示他们的授权 在区块链上运行的游戏引擎的规模受到限制 需要支付大量gas费 玩家与游戏的交互频率必须减少以适应区块链的TPS(Transaction per Second,每秒交易数)限制 这是否意味着我们必须放弃复杂但丰富的内容以追求“全链哲学”呢? 在零知识虚拟机技术出现之前,答案可能是“是”。然而,基于零知识虚拟机技术现在已经被广泛研究和应用的事实,我们有了“第三种方法”,即将完全链上的游戏与去信任化计算相结合。这是如何实现的呢? ZKVM,即零知识虚拟机,是一种将零知识证明与虚拟机技术相结合的概念。要理解它,让我们拆解以下两个模块: 零知识证明(ZKP):这些是一种加密方法,允许在一方向另一方证明他们知道一个值(例如一个密钥),同时却不泄露关于该值的任何信息。零知识证明能够在交易或交互中同时保护隐私和安全,因为它们可以验证一个陈述的真实性,而不必分享实际数据。 虚拟机(VM):虚拟机是物理意义上的计算机的软件仿真。它运行操作系统和应用程序——就像现实中的计算机,只不过完全基于软件实现。虚拟机被广泛使用于云计算与在单个计算机上运行多个操作系统。 将这两点结合起来看:零知识虚拟机(ZKVM)首先是一个虚拟机,它可以执行程序或合约,并提供零知识证明的隐私和安全优势。这意味着我们可以在zkVM内运行游戏引擎(或游戏服务器),并使用zkVM生成ZK证明,向区块链证明状态不同数据的执行结果是由游戏逻辑强制执行的。因此,游戏服务器没有办法调整发送到底层区块链的数据。 有鉴于此,全链游戏的综合架构可能如下所示: 我们这样称呼此类去信任化的全链游戏:TFOC(Trustless Fully On Chain Game) 2. 研发TFOC时需要考量的因素 2.1 新手须知 游戏开发通常被认为是一件困难的事,因为它涉及到复杂的技术、珍贵的创意和项目管理等问题。当我们将ZKVM技术应用于TFOC时,可能涉及到的因素如下: 技术复杂性:在TOFC中,游戏的逻辑需要与游戏的可视化分开,并且逻辑需要是确定性的,以便ZKVM生成一个证明。此外,由于证明是在需要被执行的语言段上生成的,游戏开发者需要将游戏玩法分成执行段,并定期与链上合约同步执行。 艺术和设计:一般而言,艺术家和设计师们的工作在TFOC与其他游戏中并无不同,因为他们的工作内容不属于需要被证明的逻辑。在TFOC中,可视化开发需要基于游戏的全局状态,而UI/UX也被用作收集玩家活动的工具。 整体的游戏体验:与一般意义上的全链游戏不同,玩家不必在每次移动时签署链上行为,这增强了创建“频繁交互型游戏”的可能性——它们指那些需要或鼓励玩家频繁地进行交互的游戏。 然而,受到ZKVM证明生成时间的限制,高频率交互对于在ZKVM中运行的TFOC游戏仍然是不可行的,例如RTS(即时战略游戏)和MOBA(例如DOTA)、在这些游戏里,玩家必须持续对单位和资源进行操作并调整策略以击败对手,这种类型的游戏很难基于ZKVM被开发。 相对的,在模拟类游戏和农场类游戏中,玩家需要定期调配资源、参与市场行为或操作角色以实现在游戏中的成长——此类游戏体裁就非常适合TFOG。 此外,交互式故事游戏和视觉小说也是个不错的选择。此类游戏可能不需要持续的交互,但它们通过不断出现的决策点来吸引玩家、塑造故事并鼓励频繁交互以查看玩家们的选择所导致的结果。 下面,让我们来聊聊货币化和可持续性。 一般而言,游戏的内容会随着时间的推移而发展,以此吸引新玩家并留住老玩家。这使得游戏玩法的逻辑变得动态,从而影响了在ZKVM中运行的程序——由此带来的一个结果是验证合约可能会更改并需要更新。 有以下两种方法可以避免频繁更改需要ZK验证的合约: 游戏玩法的变更:为游戏玩法抽象出一个协议层,并将游戏的这些动态特性定义为规则。如此,开发者们就可以将这些规则集存储在链上,并将这些规则提交到一个链上哈希中。同时,当游戏引擎运行游戏逻辑时,它可以首先检查当前规则集的哈希是否与承诺匹配,然后相应地行事。 结算的变更:奖励系统可以作为游戏玩法本身的独立层。我们可以将所有的奖励算法视为游戏玩法中生成的某些事件的回调。通过这样做,我们可以将奖励回调放在链上,并根据游戏事件调用这些回调。 例如,我们有以下游戏循环: zkgame { // Game logic output(events) } 它生成的事件将成为执行的证明实例。因此,我们可以将callbacks添加到合约中: function verify( bytes calldata events_data, uint256[] calldata proof, uint256[] calldata verify_instance, uint256[] calldata aux, uint256[][] calldata instances, RidInfo calldata ridInfo ) public { … // Check the events_data pins to a has in the instances require(instances.events_hash = hash(events_data)) // Performs the zk verification verifier.verify(proof, verify_instance, aux, instances); // Call the callbacks to handle the rewarding logic for events uint256 sideEffectCalled = perform_txs(events_data, ridInfo.batch_size); … } 2.2 游戏运行逻辑应该放在哪里? 游戏逻辑主要在两个地方运行:前端或服务器端。 将游戏逻辑放在前端相对于客户端-服务器(CS)结构简化了游戏的架构。这种方法允许前端模拟游戏并在执行轨迹建立后生成零知识证明(zk-proof)。随后,它使用本地zk-prover或远程证明服务为零知识虚拟机(ZKVM)生成ZK证明。然后,将该证明上传到底层区块链以触发结算合约。 相对的,将游戏逻辑放在服务器端意味着把游戏模拟和用户之间的交互转移到一个更专用的组件(游戏服务器)中。这可以在以下方面改善整体游戏体验: 同步效果更好的游戏玩法:服务器端模拟确保所有玩家以尽可能同步的方式体验游戏。对于多人游戏来说,连接的所有客户端上的一致游戏状态对于一致和有竞争性的游戏体验至关重要。 更好的资源管理:前端可以专注于内容渲染和UI/UX,而服务器可以充当集中式的顺序控制器和默克尔树存储的提供者。 对于不需要历史数据并且具有较简单顺序逻辑的单人PVE游戏(或多人PVP游戏),将所有内容放在前端是一个不错的选择。对于像多人SLG(模拟游戏)或AW(自治世界)游戏这样复杂的游戏,服务器端游戏的表现更好。 2.3 选择游戏开发架构 由于我们将传统游戏开发与ZKVM相结合,我们需要仔细考虑工具选择。 开发语言 首先我们需要决定是使用传统编程语言如C#、Rust、C、C ++、Go来开发游戏,还是要使用特定于ZKVM的语言。 传统编程语言的后端字节码通常是MIPS、WASM、RISC-V、x86。由于没有多少ZKVM支持这些字节码,如果你的程序可以编译成RISC-V字节码,则可以选择Risc0作为底层ZKVM,如果它可以编译为WASM,则可以选择zkWASM作为底层ZKVM。 WebAssembly(WASM)是一种低级字节码格式,用作高级语言(如C、C ++、Rust等)的编译目标。它旨在使使用这些语言编写的代码在网络上以接近本机的速度运行。WebAssembly提供了一种在Web浏览器中运行性能关键代码的方式,而不会牺牲Web应用程序的安全性或速度。它是现代Web技术堆栈的关键部分,通过允许开发人员利用除JavaScript之外的其他语言进行Web开发,从而补充了JavaScript。 游戏引擎 一旦选择了编程语言,我们可以根据选择的语言选择基于该语言的游戏引擎。如果选择了特定于ZKVM的语言,则可能需要创建自己的游戏开发框架,因为可能不存在成熟的框架用于该语言。如果使用的是rust、C、typescript等语言,则有很多框架可供选择,其中我们推荐Unity和Cocos2D。 证明生成成本 通常,证明成本是以100万条指令的证明时间来衡量的。因此,它取决于游戏玩法的执行轨迹(每个游戏玩法交互的指令数量)、后端字节码的字长以及ZKVM的证明性能。对于简单的指令集,有一些ZKVM可以在几秒钟内生成100万条指令的证明(Miden:https://0xpolygonmiden.github.io/miden-base/)。对于复杂的指令集(RISCV 32位、WASM 64位),ZKVM可以在GPU中在12秒内生成100万条指令的证明(Risc0 https://www.risczero.com/)到大约30秒(zkWASM https://github.com/DelphinusLab/zkWasm)的证明。 3. 在ZKWASM中为全链游戏使用MVC(模型-视图-控制器)模式 3.1 MVC(模型-视图-控制器)模式简介 模型-视图-控制器(MVC)模式虽然一般与Web/企业应用程序开发相关联,也可以应用于游戏开发——尽管需要一些调整。以下是MVC组件在游戏开发环境中的运行方式: 模型(Model): 在游戏开发中,模型代表游戏的数据和逻辑。这包括游戏状态(如分数、级别和玩家统计)、游戏对象以及管理游戏世界的规则。模型负责管理游戏的数据和状态,通常它不知道这些数据将如何呈现或显示。 视图(View): 在游戏开发中,视图负责向玩家展示游戏状态。这涉及到渲染游戏图形、播放声音以及显示诸如分数、生命条和菜单等UI元素。视图观察模型并更新游戏世界的视觉和听觉表示以向玩家展示。在许多游戏引擎中,视图可能被封装在渲染引擎和UI系统中。 控制器(Controller): 控制器解释来自键盘、鼠标、游戏手柄或其他输入设备的用户输入,并将其转换为游戏内的动作。例如,当玩家按下按钮使角色跳跃时,控制器会处理此输入并将动作传达给模型。游戏中的控制器充当输入设备和游戏逻辑之间的中介。 在游戏开发中应用MVC具有以下的显著优点: 关注点分离:MVC可以帮助组织代码,并将游戏逻辑与用户界面分离,这可以使开发过程更易管理,代码更易维护。 灵活性:MVC允许为相同的模型创建不同的视图。这对于提供多个视角或需要支持各种显示模式的游戏非常有用。 ZK友好:通过将游戏逻辑与表示分离,模型是唯一无法去信任化地执行的部分。通过将模型放入ZKWASM中,核心游戏机制在游戏运行时自然会得到证明。 3.2 在ZKWASM中设置游戏引擎 假设控制器与模型连接,并具有一组模型处理程序。接下来,我们可以为控制器和处理程序添加一个命令编码/解码层,如下所示: struct GlobalState { … // Define your game state here } enum ControllerTag { A, B, C } /// The controller in MVC fn controller_A (c) { let handler_cmd = encode(A, c); model.handle(handler_cmd) } fn controller_B (c) { let handler_cmd = encode(B, c); model.handle(handler_cmd) } fn controller_C (c) { let handler_cmd = encode(C, c); model.handle(handler_cmd) } /// The model in MVC fn handler(command) { match command { A => {}, B => {}, C => {}, } } /// View fn render(global_state: GlobalState) { // display your game UI based on global state } 3.3 生成一份游戏玩法证明 我们可以将游戏玩法的一部分视为对处理程序的一系列控制器的调用。因此,游戏玩法的去信任化ZK证明是以下代码: fn execution(cs: Vec) { for command in cs { global_state = handler(command); } } 在游戏过程中,我们很难确定控制器发送的最后一个命令,并且很难将所有命令处理放入单个ZK证明中。因此,最佳做法是将命令拆分为多个部分并对它们进行证明,然后将它们批处理在一起生成单个证明,以便在链上进行进一步验证。 注:请注意,上述方法中存在两个缺失的部分: 如何确保每个执行段之间的状态连续 当来自不同游戏客户端的控制器相互干扰时,如何处理多玩家同时出现场景 在接下来的章节中,我们会简要介绍多玩家序列化和数据可访问性。由于每个主题都…