上一期我们在 Localnet 上演示了一个最小 Counter 合约的完整流程先发布 Move package再调用 create 创建 Counter 对象接着调用 increment 修改对象最后通过 CLI 查询对象状态和版本变化。通过这个例子我们已经能看到 IOTA 的基本操作链路发布 Package → 创建 Object → 调用函数 → 修改 Object → 查询状态但是如果只把 IOTA 交易理解成“调用一次函数”或者“发起一次转账”还是不够完整。当前 IOTA 中一个非常重要的能力是 PTB也就是 Programmable Transaction Block中文可以翻译为“可编程交易块”。PTB 的核心作用是允许开发者在一笔交易中组合多个操作。它可以把对象拆分、对象合并、Move 函数调用、对象转移等多个步骤放在同一笔交易里执行。这一期就专门理解 IOTA 中的交易和 PTB。1. 先理解一笔交易到底是什么在传统理解中交易往往容易被看成“转账记录”。例如A 给 B 转 10 个代币这确实是一种交易但在智能合约平台中交易的含义要更广。交易不仅可以转账还可以调用合约函数、创建对象、修改对象、转移对象甚至把多个操作组合起来执行。在当前 IOTA 中一笔交易更准确地说是一次链上状态转换。交易执行前链上有一组对象状态Object A Object B Coin Object Package Object交易执行后这些对象可能发生变化Object A 被修改 Object B 被转移 Coin Object 被拆分或合并 New Object C 被创建 Gas Object 被扣除费用所以IOTA 交易不是简单地“写一条记录”而是让链上对象状态按照规则发生变化。可以这样理解交易 输入对象 执行逻辑 输出对象状态变化这个理解非常重要。因为后面无论是普通 Move 函数调用还是 PTB最终都围绕“对象状态如何变化”展开。2. IOTA 交易中通常包含哪些内容一笔 IOTA 交易通常会涉及几个基本要素。第一交易发送者。也就是谁发起了这笔交易。发送者需要对交易签名证明自己有权发起操作。第二Gas 对象。交易执行需要消耗资源因此需要 Gas 对象支付执行成本。第三输入对象。如果交易要修改某个 Counter 对象就需要把这个 Counter 对象作为输入。如果交易要转移某个 Coin 对象也需要把对应 Coin 对象作为输入。第四调用逻辑。交易可能调用某个 Move 函数也可能执行对象拆分、合并、转移等命令。第五输出结果。交易执行后链上对象状态会发生变化可能生成新对象也可能修改已有对象版本。可以简单表示为交易输入 - Sender - Gas Object - Object 参数 - Move 函数参数 交易执行 - 签名检查 - 权限检查 - 对象所有权检查 - MoveVM 执行 - Gas 计算 交易输出 - 新对象 - 更新后的对象 - 转移后的对象 - Gas 变化 - 交易执行状态所以看一笔交易时不要只看它“调用了哪个函数”还要看它“输入了哪些对象”和“输出了哪些对象变化”。3. 普通函数调用的局限上一期我们调用 Counter 合约时流程大致是这样的iota move call --package PACKAGE_ID --module counter --function create或者iota move call --package PACKAGE_ID --module counter --function increment --args COUNTER_OBJECT_ID这种方式很适合入门。一次命令调用一个函数逻辑非常清晰。但是在真实开发中很多操作并不是单步完成的。例如一个用户可能想做这样的事情1. 从一个 Coin 对象中拆出一部分金额 2. 用拆出的金额调用某个合约函数 3. 合约函数创建一个新对象 4. 再把这个新对象转移给另一个地址如果每一步都拆成单独交易就会带来几个问题。第一操作流程变长。用户需要连续提交多笔交易。第二中间状态暴露。第一步完成后后续步骤还没执行中间对象已经出现在链上。第三失败处理复杂。如果前两步成功、第三步失败就可能出现不完整状态。第四用户体验变差。多次签名、多次等待确认会让应用交互变得复杂。因此IOTA 需要一种方式把多个相关操作组合进一笔交易中。这就是 PTB 的作用。4. 什么是 PTBPTB 是 Programmable Transaction Block即可编程交易块。它可以理解为一笔“包含多条命令的交易”。普通交易可能只做一件事调用 counter::increment而 PTB 可以在一笔交易中做多件事拆分 Coin 调用 Move 函数 接收返回对象 转移对象 合并 Coin可以简单理解为普通交易一笔交易执行一个主要操作 PTB一笔交易中组合多个操作PTB 的关键不是“交易数量变多”而是“同一笔交易内部的操作步骤变多”。这些步骤在同一个交易上下文中执行并且共享交易输入、Gas、返回值和中间结果。5. PTB 的直观例子假设我们有一个场景用户要创建一个 Counter 对象然后把它转移给另一个地址。如果不用 PTB可能需要两笔交易交易 1调用 create 创建 Counter 交易 2把 Counter 转移给目标地址使用 PTB 后可以把它理解为一笔 PTB 1. 调用 create_for_sender 或 create 返回 Counter 2. 获取新创建的 Counter 对象 3. 把 Counter 转移给目标地址再比如一个代币支付场景一笔 PTB 1. 从 Gas Coin 或某个 Coin 中拆出 100 2. 把 100 作为参数传给支付函数 3. 支付函数创建收据对象 4. 把收据对象转移给用户这比多笔交易更加紧凑也更符合复杂应用的执行需求。6. PTB 中的命令PTB 之所以叫“可编程交易块”是因为它内部可以包含多种命令。常见操作可以理解为以下几类MoveCall调用 Move 函数 TransferObjects转移对象 SplitCoins拆分 Coin 对象 MergeCoins合并 Coin 对象 MakeMoveVec构造 Move 向量参数 Publish发布 Move package Upgrade升级 package入门阶段最常见的是前三类MoveCall调用合约函数 TransferObjects转移对象 SplitCoins拆分代币对象例如如果一个函数需要一个 Coin 对象作为付款参数但用户手里只有一个更大的 Coin 对象就可以先在 PTB 里拆分 Coin再把拆出来的小 Coin 传给函数。流程可以表示为Coin 1000 ↓ SplitCoins Coin 100 Coin 900 ↓ MoveCall 把 Coin 100 传入支付函数这就是 PTB 很实用的地方它可以把准备参数、调用函数、处理返回结果这些步骤组合在一起。7. PTB 和对象模型的关系PTB 和对象模型是紧密相关的。因为 PTB 的每一步几乎都在操作对象。例如SplitCoins 操作 Coin 对象 MergeCoins 合并 Coin 对象 MoveCall 读取或修改业务对象 TransferObjects 改变对象所有者 Publish 创建 Package 对象所以理解 PTB 时不能把它看成普通脚本。它不是在链下执行一段随意代码而是在链上交易中按照规则操作对象。可以这样理解对象模型定义“链上状态是什么” Move 函数定义“对象可以怎么变” PTB 定义“一笔交易中按什么顺序执行多个对象操作”三者关系非常清楚Object状态 Move逻辑 PTB组合操作这也是为什么前面几期先讲对象模型、Move 合约再讲 PTB。因为 PTB 是建立在对象和 Move 函数之上的交易组合能力。8. PTB 中的中间结果PTB 一个非常重要的特点是前一步操作的结果可以被后一步继续使用。例如第 1 步SplitCoins拆出一个 Coin 100 第 2 步MoveCall把 Coin 100 传给 purchase 函数 第 3 步TransferObjects把 purchase 返回的对象转移给用户这里第 1 步产生的 Coin 100不需要先单独上链再查询 ID而是可以在同一个 PTB 中作为中间结果传给后续命令。这对于复杂交易非常重要。如果没有中间结果传递开发者需要拆成多笔交易先拆 Coin → 等交易确认 → 查询新 Coin ID → 再调用函数而 PTB 可以把这个流程压缩为拆 Coin → 直接作为参数调用函数这会让开发者构造复杂交易时更加方便也能减少用户交互次数。9. PTB 的原子性理解 PTB 时还有一个关键词原子性。原子性可以简单理解为一组操作要么全部成功要么全部失败。在 PTB 中多个命令被组合到同一笔交易里执行。如果中间某个关键步骤失败整个交易通常不会产生部分成功、部分失败的混乱状态。这点非常重要。假设一个交易包含三步1. 拆分 Coin 2. 调用购买函数 3. 转移商品对象如果第 2 步购买函数失败那么系统不应该只完成第 1 步拆分 Coin却不完成后续购买逻辑。否则用户和合约状态都会变得很难处理。因此PTB 的原子性可以保证复杂操作在逻辑上保持一致。可以这样理解没有 PTB 多笔交易之间可能出现中间状态 有 PTB 多个步骤打包成一次原子执行这也是 PTB 对智能合约应用非常重要的原因。10. PTB 和 Gas 的关系PTB 虽然可以组合多个操作但它仍然是一笔交易因此需要 Gas。PTB 中的每一步操作都会消耗资源。例如拆分 Coin 消耗资源 Move 函数执行消耗资源 对象转移消耗资源 创建新对象消耗资源 存储变化也会带来成本所以PTB 越复杂可能消耗的 Gas 越多。这也提醒我们PTB 不是把无限操作免费塞进一笔交易。它只是允许把多个相关操作组合成一个原子交易但资源消耗仍然需要被计量。可以这样理解PTB 提高组合能力 Gas 约束资源使用因此在构造 PTB 时需要考虑操作数量、对象数量、Move 函数复杂度和 Gas 预算。11. PTB 和 Move 函数调用的关系PTB 中最常见的命令之一是 MoveCall也就是调用 Move 函数。Move 函数本身定义对象操作逻辑例如public entry fun increment(counter: mut Counter) { counter.value counter.value 1; }PTB 可以把这个函数调用作为其中一步MoveCall: counter::increment(counter_object)如果一个 PTB 中有多个 MoveCall就可以依次调用多个函数。例如1. 调用 registry::create_record 2. 调用 counter::increment 3. 调用 receipt::mint 4. 转移 receipt 对象这说明 PTB 不是替代 Move 合约而是调用和组合 Move 合约。Move 合约定义基础能力PTB 把这些能力拼接成一次完整操作流程。12. 一个简化的 PTB 流程示意假设我们有一个简单支付购买场景用户要支付 100 个代币购买一个 Badge 对象。PTB 可以设计为输入 - 用户地址 - Gas Coin - Payment Coin 1000 - Package ID 步骤 1. SplitCoins从 Payment Coin 中拆出 Coin 100 2. MoveCall调用 shop::buy_badge(Coin 100) 3. 接收返回的 Badge Object 4. TransferObjects把 Badge 转移给用户 输出 - 用户得到 Badge Object - 商店收到 Coin 100 - 用户剩余 Coin 900 - Gas 被扣除这个流程非常适合用 PTB 表达因为它包含多个紧密相关的操作。如果把它拆成多笔交易会比较繁琐先拆 Coin 再调用购买函数 再转移 Badge 再查询对象而 PTB 可以让整个购买过程成为一次完整交易。13. PTB 和普通交易的区别可以从几个角度总结 PTB 和普通交易的区别。第一普通交易更像单步操作PTB 更像多步操作组合。普通交易调用一个函数 PTB拆分 Coin 调用函数 转移对象第二普通交易中间结果不明显PTB 可以在同一笔交易内传递中间结果。SplitCoins 的结果可以直接传给 MoveCall MoveCall 的返回对象可以直接 TransferObjects第三普通交易适合简单交互PTB 适合复杂业务流程。简单转账普通交易即可 复杂购买、铸造、注册、组合调用PTB 更合适第四PTB 保持原子性。多个步骤要么整体成功要么整体失败第五PTB 仍然受 Gas 和交易大小限制。PTB 不是无限脚本 它仍然是一笔需要资源计量的链上交易14. PTB 常见失败原因在实际开发中PTB 构造失败很常见。常见原因包括以下几类。第一Object ID 错误。传入了不存在的对象或者对象属于另一个网络环境。第二对象所有权错误。交易发送者不是对象所有者却试图以可变方式操作对象。第三对象版本冲突。对象已经被其他交易修改当前交易引用的是旧版本。第四函数参数类型不匹配。Move 函数需要mut Counter但传入的对象类型不是 Counter。第五Coin 拆分金额不足。SplitCoins 时原 Coin 对象金额不够。第六Gas 不足。PTB 操作太多或计算复杂Gas 预算不足。第七命令顺序错误。后一步使用了前一步尚未正确产生的结果。第八共享对象处理不当。涉及共享对象时需要符合共享对象访问和共识排序规则。所以当遇到 PTB 报错时可以按照以下顺序排查网络环境是否正确 对象 ID 是否正确 对象 owner 是否正确 对象 version 是否最新 Move 函数签名是否匹配 Coin 金额是否足够 Gas 是否足够 命令顺序是否正确这比直接盯着报错信息更有效。15. 为什么 PTB 很重要PTB 对 IOTA 开发非常重要因为它提升了链上操作的组合能力。对于用户来说PTB 可以减少多次签名和多次等待确认。对于开发者来说PTB 可以把复杂业务流程组织成一次原子交易。对于应用来说PTB 可以让对象、资产和合约调用之间形成更强的组合性。可以这样理解没有 PTB 用户需要一步一步提交交易 有 PTB 开发者可以把多个步骤编排成一笔交易这对于 DeFi、NFT、游戏、身份、注册、市场、支付等应用都很有用。例如DeFi拆分代币 → 授权 → 交易 → 质押 NFT支付 → 铸造 → 转移 游戏消耗道具 → 更新状态 → 发放奖励 市场付款 → 转移商品 → 生成收据 身份创建凭证 → 写入注册表 → 转移给用户这些场景都不是单一函数调用能很好表达的而 PTB 正好提供了组合能力。16. 学习 PTB 的建议路径初学 PTB 不建议一开始就写复杂交易。可以按照下面顺序学习。第一步先理解普通 Move 函数调用。例如调用 Counter 的 create 和 increment。第二步学习 Coin 拆分。理解 Coin 对象如何被 SplitCoins 拆成多个对象。第三步学习对象转移。理解 TransferObjects 如何改变对象 owner。第四步把 SplitCoins 和 TransferObjects 放进同一个 PTB。先做最简单的组合操作。第五步再加入 MoveCall。例如拆分 Coin 后直接把 Coin 传入某个 Move 函数。第六步学习使用 MoveCall 的返回值。例如函数创建一个对象然后 PTB 后续命令继续转移这个对象。第七步最后再学习共享对象 PTB。共享对象涉及共识排序和多用户操作建议放到后面。这个顺序比较适合从简单到复杂逐步掌握。17. 小结这一期主要讲了 IOTA 中的交易与 PTB。在当前 IOTA 中交易不是简单转账而是一次链上对象状态转换。一笔交易会读取输入对象执行 Move 函数或交易命令并最终产生对象状态变化。PTB也就是可编程交易块则进一步允许开发者在一笔交易中组合多个操作。它可以包含 Coin 拆分、Coin 合并、Move 函数调用、对象转移、package 发布等命令。PTB 的重要价值在于它让多个相关步骤在同一笔交易中原子执行从而提高复杂应用的组合能力。可以用一句话总结本期内容Object 是状态Move 是逻辑PTB 是把多个对象操作和函数调用组合成一笔原子交易的执行方式。下一期我们会继续讲共享对象与多用户交互。共享对象是理解复杂 IOTA 应用的重要基础因为它涉及多个用户同时访问同一个链上状态也会进一步引出共识排序和对象版本变化。
IOTA 学习笔记(十):交易与 PTB,可编程交易块怎么理解?
发布时间:2026/6/3 15:29:33
上一期我们在 Localnet 上演示了一个最小 Counter 合约的完整流程先发布 Move package再调用 create 创建 Counter 对象接着调用 increment 修改对象最后通过 CLI 查询对象状态和版本变化。通过这个例子我们已经能看到 IOTA 的基本操作链路发布 Package → 创建 Object → 调用函数 → 修改 Object → 查询状态但是如果只把 IOTA 交易理解成“调用一次函数”或者“发起一次转账”还是不够完整。当前 IOTA 中一个非常重要的能力是 PTB也就是 Programmable Transaction Block中文可以翻译为“可编程交易块”。PTB 的核心作用是允许开发者在一笔交易中组合多个操作。它可以把对象拆分、对象合并、Move 函数调用、对象转移等多个步骤放在同一笔交易里执行。这一期就专门理解 IOTA 中的交易和 PTB。1. 先理解一笔交易到底是什么在传统理解中交易往往容易被看成“转账记录”。例如A 给 B 转 10 个代币这确实是一种交易但在智能合约平台中交易的含义要更广。交易不仅可以转账还可以调用合约函数、创建对象、修改对象、转移对象甚至把多个操作组合起来执行。在当前 IOTA 中一笔交易更准确地说是一次链上状态转换。交易执行前链上有一组对象状态Object A Object B Coin Object Package Object交易执行后这些对象可能发生变化Object A 被修改 Object B 被转移 Coin Object 被拆分或合并 New Object C 被创建 Gas Object 被扣除费用所以IOTA 交易不是简单地“写一条记录”而是让链上对象状态按照规则发生变化。可以这样理解交易 输入对象 执行逻辑 输出对象状态变化这个理解非常重要。因为后面无论是普通 Move 函数调用还是 PTB最终都围绕“对象状态如何变化”展开。2. IOTA 交易中通常包含哪些内容一笔 IOTA 交易通常会涉及几个基本要素。第一交易发送者。也就是谁发起了这笔交易。发送者需要对交易签名证明自己有权发起操作。第二Gas 对象。交易执行需要消耗资源因此需要 Gas 对象支付执行成本。第三输入对象。如果交易要修改某个 Counter 对象就需要把这个 Counter 对象作为输入。如果交易要转移某个 Coin 对象也需要把对应 Coin 对象作为输入。第四调用逻辑。交易可能调用某个 Move 函数也可能执行对象拆分、合并、转移等命令。第五输出结果。交易执行后链上对象状态会发生变化可能生成新对象也可能修改已有对象版本。可以简单表示为交易输入 - Sender - Gas Object - Object 参数 - Move 函数参数 交易执行 - 签名检查 - 权限检查 - 对象所有权检查 - MoveVM 执行 - Gas 计算 交易输出 - 新对象 - 更新后的对象 - 转移后的对象 - Gas 变化 - 交易执行状态所以看一笔交易时不要只看它“调用了哪个函数”还要看它“输入了哪些对象”和“输出了哪些对象变化”。3. 普通函数调用的局限上一期我们调用 Counter 合约时流程大致是这样的iota move call --package PACKAGE_ID --module counter --function create或者iota move call --package PACKAGE_ID --module counter --function increment --args COUNTER_OBJECT_ID这种方式很适合入门。一次命令调用一个函数逻辑非常清晰。但是在真实开发中很多操作并不是单步完成的。例如一个用户可能想做这样的事情1. 从一个 Coin 对象中拆出一部分金额 2. 用拆出的金额调用某个合约函数 3. 合约函数创建一个新对象 4. 再把这个新对象转移给另一个地址如果每一步都拆成单独交易就会带来几个问题。第一操作流程变长。用户需要连续提交多笔交易。第二中间状态暴露。第一步完成后后续步骤还没执行中间对象已经出现在链上。第三失败处理复杂。如果前两步成功、第三步失败就可能出现不完整状态。第四用户体验变差。多次签名、多次等待确认会让应用交互变得复杂。因此IOTA 需要一种方式把多个相关操作组合进一笔交易中。这就是 PTB 的作用。4. 什么是 PTBPTB 是 Programmable Transaction Block即可编程交易块。它可以理解为一笔“包含多条命令的交易”。普通交易可能只做一件事调用 counter::increment而 PTB 可以在一笔交易中做多件事拆分 Coin 调用 Move 函数 接收返回对象 转移对象 合并 Coin可以简单理解为普通交易一笔交易执行一个主要操作 PTB一笔交易中组合多个操作PTB 的关键不是“交易数量变多”而是“同一笔交易内部的操作步骤变多”。这些步骤在同一个交易上下文中执行并且共享交易输入、Gas、返回值和中间结果。5. PTB 的直观例子假设我们有一个场景用户要创建一个 Counter 对象然后把它转移给另一个地址。如果不用 PTB可能需要两笔交易交易 1调用 create 创建 Counter 交易 2把 Counter 转移给目标地址使用 PTB 后可以把它理解为一笔 PTB 1. 调用 create_for_sender 或 create 返回 Counter 2. 获取新创建的 Counter 对象 3. 把 Counter 转移给目标地址再比如一个代币支付场景一笔 PTB 1. 从 Gas Coin 或某个 Coin 中拆出 100 2. 把 100 作为参数传给支付函数 3. 支付函数创建收据对象 4. 把收据对象转移给用户这比多笔交易更加紧凑也更符合复杂应用的执行需求。6. PTB 中的命令PTB 之所以叫“可编程交易块”是因为它内部可以包含多种命令。常见操作可以理解为以下几类MoveCall调用 Move 函数 TransferObjects转移对象 SplitCoins拆分 Coin 对象 MergeCoins合并 Coin 对象 MakeMoveVec构造 Move 向量参数 Publish发布 Move package Upgrade升级 package入门阶段最常见的是前三类MoveCall调用合约函数 TransferObjects转移对象 SplitCoins拆分代币对象例如如果一个函数需要一个 Coin 对象作为付款参数但用户手里只有一个更大的 Coin 对象就可以先在 PTB 里拆分 Coin再把拆出来的小 Coin 传给函数。流程可以表示为Coin 1000 ↓ SplitCoins Coin 100 Coin 900 ↓ MoveCall 把 Coin 100 传入支付函数这就是 PTB 很实用的地方它可以把准备参数、调用函数、处理返回结果这些步骤组合在一起。7. PTB 和对象模型的关系PTB 和对象模型是紧密相关的。因为 PTB 的每一步几乎都在操作对象。例如SplitCoins 操作 Coin 对象 MergeCoins 合并 Coin 对象 MoveCall 读取或修改业务对象 TransferObjects 改变对象所有者 Publish 创建 Package 对象所以理解 PTB 时不能把它看成普通脚本。它不是在链下执行一段随意代码而是在链上交易中按照规则操作对象。可以这样理解对象模型定义“链上状态是什么” Move 函数定义“对象可以怎么变” PTB 定义“一笔交易中按什么顺序执行多个对象操作”三者关系非常清楚Object状态 Move逻辑 PTB组合操作这也是为什么前面几期先讲对象模型、Move 合约再讲 PTB。因为 PTB 是建立在对象和 Move 函数之上的交易组合能力。8. PTB 中的中间结果PTB 一个非常重要的特点是前一步操作的结果可以被后一步继续使用。例如第 1 步SplitCoins拆出一个 Coin 100 第 2 步MoveCall把 Coin 100 传给 purchase 函数 第 3 步TransferObjects把 purchase 返回的对象转移给用户这里第 1 步产生的 Coin 100不需要先单独上链再查询 ID而是可以在同一个 PTB 中作为中间结果传给后续命令。这对于复杂交易非常重要。如果没有中间结果传递开发者需要拆成多笔交易先拆 Coin → 等交易确认 → 查询新 Coin ID → 再调用函数而 PTB 可以把这个流程压缩为拆 Coin → 直接作为参数调用函数这会让开发者构造复杂交易时更加方便也能减少用户交互次数。9. PTB 的原子性理解 PTB 时还有一个关键词原子性。原子性可以简单理解为一组操作要么全部成功要么全部失败。在 PTB 中多个命令被组合到同一笔交易里执行。如果中间某个关键步骤失败整个交易通常不会产生部分成功、部分失败的混乱状态。这点非常重要。假设一个交易包含三步1. 拆分 Coin 2. 调用购买函数 3. 转移商品对象如果第 2 步购买函数失败那么系统不应该只完成第 1 步拆分 Coin却不完成后续购买逻辑。否则用户和合约状态都会变得很难处理。因此PTB 的原子性可以保证复杂操作在逻辑上保持一致。可以这样理解没有 PTB 多笔交易之间可能出现中间状态 有 PTB 多个步骤打包成一次原子执行这也是 PTB 对智能合约应用非常重要的原因。10. PTB 和 Gas 的关系PTB 虽然可以组合多个操作但它仍然是一笔交易因此需要 Gas。PTB 中的每一步操作都会消耗资源。例如拆分 Coin 消耗资源 Move 函数执行消耗资源 对象转移消耗资源 创建新对象消耗资源 存储变化也会带来成本所以PTB 越复杂可能消耗的 Gas 越多。这也提醒我们PTB 不是把无限操作免费塞进一笔交易。它只是允许把多个相关操作组合成一个原子交易但资源消耗仍然需要被计量。可以这样理解PTB 提高组合能力 Gas 约束资源使用因此在构造 PTB 时需要考虑操作数量、对象数量、Move 函数复杂度和 Gas 预算。11. PTB 和 Move 函数调用的关系PTB 中最常见的命令之一是 MoveCall也就是调用 Move 函数。Move 函数本身定义对象操作逻辑例如public entry fun increment(counter: mut Counter) { counter.value counter.value 1; }PTB 可以把这个函数调用作为其中一步MoveCall: counter::increment(counter_object)如果一个 PTB 中有多个 MoveCall就可以依次调用多个函数。例如1. 调用 registry::create_record 2. 调用 counter::increment 3. 调用 receipt::mint 4. 转移 receipt 对象这说明 PTB 不是替代 Move 合约而是调用和组合 Move 合约。Move 合约定义基础能力PTB 把这些能力拼接成一次完整操作流程。12. 一个简化的 PTB 流程示意假设我们有一个简单支付购买场景用户要支付 100 个代币购买一个 Badge 对象。PTB 可以设计为输入 - 用户地址 - Gas Coin - Payment Coin 1000 - Package ID 步骤 1. SplitCoins从 Payment Coin 中拆出 Coin 100 2. MoveCall调用 shop::buy_badge(Coin 100) 3. 接收返回的 Badge Object 4. TransferObjects把 Badge 转移给用户 输出 - 用户得到 Badge Object - 商店收到 Coin 100 - 用户剩余 Coin 900 - Gas 被扣除这个流程非常适合用 PTB 表达因为它包含多个紧密相关的操作。如果把它拆成多笔交易会比较繁琐先拆 Coin 再调用购买函数 再转移 Badge 再查询对象而 PTB 可以让整个购买过程成为一次完整交易。13. PTB 和普通交易的区别可以从几个角度总结 PTB 和普通交易的区别。第一普通交易更像单步操作PTB 更像多步操作组合。普通交易调用一个函数 PTB拆分 Coin 调用函数 转移对象第二普通交易中间结果不明显PTB 可以在同一笔交易内传递中间结果。SplitCoins 的结果可以直接传给 MoveCall MoveCall 的返回对象可以直接 TransferObjects第三普通交易适合简单交互PTB 适合复杂业务流程。简单转账普通交易即可 复杂购买、铸造、注册、组合调用PTB 更合适第四PTB 保持原子性。多个步骤要么整体成功要么整体失败第五PTB 仍然受 Gas 和交易大小限制。PTB 不是无限脚本 它仍然是一笔需要资源计量的链上交易14. PTB 常见失败原因在实际开发中PTB 构造失败很常见。常见原因包括以下几类。第一Object ID 错误。传入了不存在的对象或者对象属于另一个网络环境。第二对象所有权错误。交易发送者不是对象所有者却试图以可变方式操作对象。第三对象版本冲突。对象已经被其他交易修改当前交易引用的是旧版本。第四函数参数类型不匹配。Move 函数需要mut Counter但传入的对象类型不是 Counter。第五Coin 拆分金额不足。SplitCoins 时原 Coin 对象金额不够。第六Gas 不足。PTB 操作太多或计算复杂Gas 预算不足。第七命令顺序错误。后一步使用了前一步尚未正确产生的结果。第八共享对象处理不当。涉及共享对象时需要符合共享对象访问和共识排序规则。所以当遇到 PTB 报错时可以按照以下顺序排查网络环境是否正确 对象 ID 是否正确 对象 owner 是否正确 对象 version 是否最新 Move 函数签名是否匹配 Coin 金额是否足够 Gas 是否足够 命令顺序是否正确这比直接盯着报错信息更有效。15. 为什么 PTB 很重要PTB 对 IOTA 开发非常重要因为它提升了链上操作的组合能力。对于用户来说PTB 可以减少多次签名和多次等待确认。对于开发者来说PTB 可以把复杂业务流程组织成一次原子交易。对于应用来说PTB 可以让对象、资产和合约调用之间形成更强的组合性。可以这样理解没有 PTB 用户需要一步一步提交交易 有 PTB 开发者可以把多个步骤编排成一笔交易这对于 DeFi、NFT、游戏、身份、注册、市场、支付等应用都很有用。例如DeFi拆分代币 → 授权 → 交易 → 质押 NFT支付 → 铸造 → 转移 游戏消耗道具 → 更新状态 → 发放奖励 市场付款 → 转移商品 → 生成收据 身份创建凭证 → 写入注册表 → 转移给用户这些场景都不是单一函数调用能很好表达的而 PTB 正好提供了组合能力。16. 学习 PTB 的建议路径初学 PTB 不建议一开始就写复杂交易。可以按照下面顺序学习。第一步先理解普通 Move 函数调用。例如调用 Counter 的 create 和 increment。第二步学习 Coin 拆分。理解 Coin 对象如何被 SplitCoins 拆成多个对象。第三步学习对象转移。理解 TransferObjects 如何改变对象 owner。第四步把 SplitCoins 和 TransferObjects 放进同一个 PTB。先做最简单的组合操作。第五步再加入 MoveCall。例如拆分 Coin 后直接把 Coin 传入某个 Move 函数。第六步学习使用 MoveCall 的返回值。例如函数创建一个对象然后 PTB 后续命令继续转移这个对象。第七步最后再学习共享对象 PTB。共享对象涉及共识排序和多用户操作建议放到后面。这个顺序比较适合从简单到复杂逐步掌握。17. 小结这一期主要讲了 IOTA 中的交易与 PTB。在当前 IOTA 中交易不是简单转账而是一次链上对象状态转换。一笔交易会读取输入对象执行 Move 函数或交易命令并最终产生对象状态变化。PTB也就是可编程交易块则进一步允许开发者在一笔交易中组合多个操作。它可以包含 Coin 拆分、Coin 合并、Move 函数调用、对象转移、package 发布等命令。PTB 的重要价值在于它让多个相关步骤在同一笔交易中原子执行从而提高复杂应用的组合能力。可以用一句话总结本期内容Object 是状态Move 是逻辑PTB 是把多个对象操作和函数调用组合成一笔原子交易的执行方式。下一期我们会继续讲共享对象与多用户交互。共享对象是理解复杂 IOTA 应用的重要基础因为它涉及多个用户同时访问同一个链上状态也会进一步引出共识排序和对象版本变化。