退出代码是一个 16-bit 无符号整数,范围在 0 到 65535 之间(或 2_16 - 1$)。
0 至 127 的代码分配给 FunC (TVM), 128 至 255 的代码分配给 Tact。 从 256 到 65535 的范围内,开发人员可自由定义退出代码。
预先分配的退出代码列表:
退出代码 | 相位 | 说明 |
---|
0 | 计算阶段 | 标准成功执行退出代码 |
2 | 计算阶段 | 堆栈下溢。最后一个操作码消耗的元素多于堆栈中的元素数量 |
3 | 计算阶段 | 堆栈溢出。堆栈中存储的值超过了该版本 TVM 的允许值 |
4 | 计算阶段 | 整数溢出。整数不适合 −2256≤x<2256 或发生了零除法 |
5 | 计算阶段 | 整数超出预期范围 |
6 | 计算阶段 | 操作码无效。在当前的 TVM 版本中,指令不详 |
7 | 计算阶段 | 类型检查错误。基元参数的值类型不正确 |
8 | 计算阶段 | 电池溢出。不可能将数据写入生成器,因为操作后将有超过 1023 位或 4 个引用 |
9 | 计算阶段 | 单元下溢。从片原始码读取数据时,试图读取的比特或引用数多于现有比特或引用数 |
10 | 计算阶段 | 词典错误。处理字典(哈希图)时出错 |
13 | 计算阶段 | gas 耗尽错误。当剩余 gas 变为负值时,由 TVM 抛出 |
−14 | 计算阶段 | 这意味着 gas 耗尽错误,与 13 相同。否定,因为无法伪造 |
32 | 行动阶段 | 操作列表无效。如果执行后的 c5 寄存器包含不可解析对象,则在操作阶段设置该寄存器 |
34 | 行动阶段 | 操作无效或不支持。如果无法执行当前操作,则在操作阶段设置 |
37 | 行动阶段 | 不够吨。信息发送的吨数过多(或扣除费用后吨数不足) |
38 | 行动阶段 | 额外货币不足 |
128 | 塔克(编译) | 空引用异常—编译器预期是一个整数或单元格,但传递了一个空值 |
129 | 塔克(编译) | 无效序列化前缀—如果与之前的操作码检查有任何不一致,将抛出此退出代码 |
130 | 塔克(编译) | 收到的报文无效 - 未找到合适的操作 |
131 | 塔克(编译) | 制约因素错误 |
132 | 塔克(编译) | 拒绝访问 - 所有者以外的其他人向合同发送了信息 |
133 | 塔克(编译) | 合同已停止 - 已向停止的合同发送信息 |
134 | 塔克(编译) | 无效参数 - 无效 Base64 字符串 |
135 | 塔克(编译) | 未找到合同代码 - 字典调用的假标记 |
136 | 塔克(编译) | 无效地址 - 非 267- 位地址或无效链 id(非 0 或 -1) |
137 | 塔克(编译) | 此合约未启用主链支持 |
问:在哪里可以看到项目中所有自动生成的退出代码列表?
答:Tact 编译器会在 *.md 文件末尾收集所有退出代码,您可以在
路径”./ProjectFolder/build/ProjectName/tact_ProjectName.md “下的目录中跟踪它们。
问:** 如何观察抛出的退出代码?**
答:在 Tact 中,打印交易来查看结果是不明智的,因为它们不容易读取。 如果想查看事务的退出代码,
,在 Typescript 本地测试中使用下面的模板:
- 第一行定义发件人。
- 第二行发送交易。
- 在第三行中,您要检查结果中是否有从发送方到您的合约的交易,以及您所需的退出代码。
计算阶段
0:成功执行
该退出代码表示事务的计算阶段已成功完成。
4:整数溢出
在 TVM 中,整数的范围可以是 −2256<x<2256。
如果计算过程中的值超出了这个范围,就会抛出 4 个退出代码。
例如
5:超出预期范围的整数
如果整数值超出预期范围,则抛出 5 个退出代码。
例如,如果在 .store_uint() 函数中使用了负值。 在 Tact 中,还有其他一些新情况,例如:
1- 如你所知,你可以在 Tact 中定义更多有限的整数(小于 257 位的整数)。2- 根据 storeUint(self: Builder, value: Int, bits: Int)```函数,不能使用
storeUint(0, 257) 因为 ``0 ≤ bits ≤ 256
。
例如
8:单元格溢出
一个单元可存储 1023 位数据和 4 个指向其他单元的引用。
如果尝试写入超过 1023 位或超过 4 个引用,则会抛出 8 个退出代码。
例如
9:单元下溢
如果尝试从片段中读取的数据多于其包含的数据,则会抛出 9 个退出代码。
例如
13: 气用尽错误
如果没有足够的 TON 来处理计算阶段,则会抛出此错误。
在处理过程中,将对该值执行 NOT 操作,从而将该值更改为 -14。 这样做是为了防止使用 throw 函数伪造退出代码,因为所有此类函数都只接受正值的退出代码,这一点在前面已经讨论过。
例如
行动阶段
34行动无效或不支持
在处理操作时,该退出代码会导致大部分错误:无效信息、不正确操作等。
例如
37TON
这意味着没有足够的 TON 来发送指定的数量。
例如
塔克(编译)
128:空引用异常
如果有一个非空断言,例如 !!
操作符,而检查值是 null
,则会抛出一个退出代码为 128 的错误:“空引用异常”。
130来信无效
向合约发送信息时,信息体的前 32 位是操作码。 它决定了必须进行的操作。
在 FunC 中,如果找不到操作码,就会抛出 0xffff。 在 Tact 中,将抛出 130 个退出代码。
例如
- 首先,像下面这样定义一个空合约:
- 然后,给这份合同发送信息。 由于没有找到合适的操作,您将得到此退出代码。
132: 拒绝访问
首先,你应该导入并继承 Ownable Trait。 之后,您的合同就有了所有者。
您可以在函数中调用 self.requireOwner();
要求检查。 这将确保只有所有者才能向您的合同发送信息。
例如
133: 合同停止
stoppable 特性允许停止合约。
如果向已停止的合约发送信息,而合约通过运行 “self.requireNotStopped();```` 要求检查,则会抛出此退出代码。
在当前版本的 Tact 中,将抛出 40368 而不是 133 的退出代码。
例如
134参数无效
下面的 FunC 函数(在一堆 if 条件的最后一部分)将抛出这个问题。 该函数从 Base64 中读取内容。
如果输入字符不符合 base64 字符,就会出现此退出代码。
例如
135:未找到合同代码
它将检查字典键搜索的返回标志。
例如
136: 无效地址
在 TON 中,所有地址都是 267 位。 如果您违反了这一规则,您将面临这个退出代码。
目前,TON 只支持两个链 id。0 代表基础链,-1 代表主链。 如果地址不是来自 basechain,则会抛出 136 个退出代码。
例如
137:该合约未启用主链支持
目前,TON 只支持两个链 id。0 代表基础链,-1 代表主链。
Tact 仅支持 basechain,如果您的地址来自 masterchain,则会抛出 137 个退出代码。
例如