跳到主要内容

消息 TL-B 方案

本节详细解释消息的 TL-B 方案。

消息 TL-B

TL-B

主要消息 TL-B 方案声明为几个嵌套结构的组合

message$_ {X:Type} info:CommonMsgInfo
init:(Maybe (Either StateInit ^StateInit))
body:(Either X ^X) = Message X;

message$_ {X:Type} info:CommonMsgInfoRelaxed
init:(Maybe (Either StateInit ^StateInit))
body:(Either X ^X) = MessageRelaxed X;

_ (Message Any) = MessageAny;

这里 Message X - 是常见消息结构,MessageRelaxed X 是带有 CommonMsgInfoRelaxed 体的附加类型,而 Message Any 是两者的并集。消息结构与 X:Type 统一,换句话说就是一个 Cell。根据 TL-B,如果数据能够适应 1023 位,我们可以将所有数据组合在一个cell中,或者使用带有插入符号 ^ 的引用。

序列化的 Message X 通过 FunC 方法 send_raw_message() 放置到动作列表中,然后智能合约执行此动作并发送消息。

显式序列化的定义

根据 TL-B 结构构建有效的二进制数据,我们应该进行序列化,这对每种类型都是递归定义的。这意味着,要序列化 Message X,我们需要知道如何序列化 StateInitCommonMsgInfo 等。

我们应该根据递归链接从另一个 TL-B 方案中获取每个嵌套结构,直到顶层结构的序列化是显式的 - 每个位由布尔或类似位的类型(比特,uint,varuint)定义。

目前在常规开发中不使用的结构将在 Type 列中标记为 *,例如 *Anycast 通常在序列化中被跳过。

message$_

这是整个消息 Message X 的顶层 TL-B 方案:

message$_ {X:Type} info:CommonMsgInfo
init:(Maybe (Either StateInit ^StateInit))
body:(Either X ^X) = Message X;
结构类型必需描述
message$_构造函数按照构造函数规则定义。空标记 $_ 表示我们不会在开头添加任何位
infoCommonMsgInfo必需详细的消息属性定义目的地及其值。始终放置在消息的根cell中。
initStateInit可选通用结构,用于 TON 中初始化新合约。可以写在cell引用或根cell中。
bodyX必需消息有效载荷。可以写在cell引用或根cell中。
nothing$0 {X:Type} = Maybe X;
just$1 {X:Type} value:X = Maybe X;
left$0 {X:Type} {Y:Type} value:X = Either X Y;
right$1 {X:Type} {Y:Type} value:Y = Either X Y;

回想一下 MaybeEither 的工作方式,我们可以序列化不同的情况:

  • [CommonMsgInfo][10][StateInit][0][X] - Message X 在一个cell中


  • [CommonMsgInfo][11][^StateInit][1][^X] - Message X 带引用


CommonMsgInfo TL-B

CommonMsgInfo

CommonMsgInfo 是一系列参数的列表,定义了消息在 TON 区块链中的传递方式。

//内部消息
int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
src:MsgAddressInt dest:MsgAddressInt
value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams
created_lt:uint64 created_at:uint32 = CommonMsgInfo;

//外部传入消息
ext_in_msg_info$10 src:MsgAddressExt dest:MsgAddressInt
import_fee:Grams = CommonMsgInfo;

//外部传出消息
ext_out_msg_info$11 src:MsgAddressInt dest:MsgAddressExt
created_lt:uint64 created_at:uint32 = CommonMsgInfo;

int_msg_info$0

int_msg_info 是内部消息的一种情况。这意味着它们可以在合约之间发送,且只能在合约之间发送。 用例 - 普通的跨合约消息。

nanograms$_ amount:(VarUInteger 16) = Grams;
//内部消息
int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
src:MsgAddressInt dest:MsgAddressInt
value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams
created_lt:uint64 created_at:uint32 = CommonMsgInfo;
结构类型必需描述
int_msg_info$0构造函数必需$0 标记意味着序列化 CommonMsgInfo 以 0 位开始描述内部消息。
ihr_disabled布尔必需超立方体路由标志位。
bounce布尔必需如果处理过程中出现错误,消息应该被弹回。如果消息的 flat bounce = 1,它被称为可弹回。
bounced布尔必需描述消息本身是弹回结果的标志位。
srcMsgAddressInt必需消息发送者智能合约的地址。
destMsgAddressInt必需消息目的地智能合约的地址。
valueCurrencyCollection必需描述货币信息的结构,包括消息中转移的总资金。
ihr_feeVarUInteger 16必需超路由交付费用
fwd_feeVarUInteger 16必需验证者指定的转发消息费用
created_ltuint64必需验证者指定的发送消息的逻辑时间。用于对智能合约中的动作进行排序。
created_atuint32必需Unix 时间

ext_in_msg_info$10

ext_in_msg_info$10 是外部传入消息的一种情况。这意味着这种类型的消息是从合约发送到链下空间的。
用例 - 钱包应用请求钱包合约。

nanograms$_ amount:(VarUInteger 16) = Grams;
//外部传入消息
ext_in_msg_info$10 src:MsgAddressExt dest:MsgAddressInt
import_fee:Grams = CommonMsgInfo;

| 结构 | 类型 | 必需 | 描述 |

|--------------------|--------------------------------------|----------|------------------------------------------------------------------------------------------------------------------------| | ext_out_msg_info$10| 构造函数 | 必需 | $10 标记意味着序列化 CommonMsgInfo 以 10 位开始描述外部传入消息。 | | ihr_disabled | 布尔 | 必需 | 超路由标志位。(目前始终为真) | | src | MsgAddressExt | 必需 | 消息的外部发送者地址。 | | dest | MsgAddressInt | 必需 | 消息目的地智能合约的地址。 | | import_fee | VarUInteger 16 | 必需 | 执行和传递消息的费用。 |

ext_out_msg_info$11

ext_out_msg_info$11 是外部传出消息的一种情况。这意味着它们可以从合约发送到链外空间。 用例 - 日志。

//内部消息
ext_out_msg_info$11 src:MsgAddressInt dest:MsgAddressExt
created_lt:uint64 created_at:uint32 = CommonMsgInfo;
结构类型必需描述
ext_out_msg_info$11构造函数必需$11 标记意味着序列化 CommonMsgInfo 以 11 位开始描述外部传出消息。
srcMsgAddressInt必需超路由标志位。
destMsgAddressExt必需用于 TON 中初始化新合约的通用结构。可以写在cell引用或根cell中。
created_ltuint64必需验证者指定的发送消息的逻辑时间。用于对智能合约中的动作进行排序。
created_atuint32必需Unix 时间

StateInit TL-B

StateInit 用于向合约传递初始数据,并在合约部署中使用。

_ split_depth:(Maybe (## 5)) special:(Maybe TickTock)
code:(Maybe ^Cell) data:(Maybe ^Cell)
library:(HashmapE 256 SimpleLib) = StateInit;
结构类型必需描述
split_depth(## 5)可选用于高负载合约的参数,定义了在不同分片中分裂为多个实例的行为。目前 StateInit 没有使用它。
specialTickTock*可选用于在区块链的每个新区块中调用智能合约。仅在主链中可用。普通用户合约没有使用它。
codeCell可选合约的序列化代码。
dataCell可选合约初始数据。
libraryHashmapE 256 SimpleLib*可选目前使用的 StateInit 没有库

哈希映射的一般详细解释

MsgAddressExt TL-B

addr_none$00 = MsgAddressExt;
addr_extern$01 len:(## 9) external_address:(bits len)
= MsgAddressExt;

MsgAddress 是地址的各种序列化方案。根据消息发送者(链下参与者或智能合约)的不同,使用不同的结构。

addr_none$00

addr_none$00 - 用于定义链下参与者的空地址。这意味着我们可以向合约发送外部消息,而不需要唯一的发件人地址。

addr_none$00 = MsgAddressExt;
结构类型必需描述
addr_none$00构造函数必需$00 标记意味着序列化 MsgAddressExt 以 00 位开始。这意味着整个外部地址是 00

addr_extern$01

addr_extern$01 len:(## 9) external_address:(bits len)
= MsgAddressExt;
结构类型必需描述
addr_extern$01

| 构造函数 | 必需 | $01 标记意味着序列化 MsgAddressExt 以 01 位开始描述外部地址。 | | len | ## 9 | 必需 | 与 uintN 相同 - 表示无符号 N 位数字 | | external_address | (bits len) | 必需 | 地址是长度等于前面的 len 的位串 |

MsgAddressInt TL-B

addr_std$10 anycast:(Maybe Anycast)
workchain_id:int8 address:bits256 = MsgAddressInt;

addr_var$11 anycast:(Maybe Anycast) addr_len:(## 9)
workchain_id:int32 address:(bits addr_len) = MsgAddressInt;

addr_std$10

addr_std$10 anycast:(Maybe Anycast)
workchain_id:int8 address:bits256 = MsgAddressInt;
结构类型必需描述
addr_std$10构造函数必需$10 标记意味着序列化 MsgAddressExt 以 10 位开始描述外部地址。
anycastAnycast*可选额外的地址数据,目前普通内部消息中未使用
workchain_idint8必需目的地地址的智能合约所在的工作链。目前始终为零。
address(bits256)必需智能合约账户 ID 号

addr_var$11

addr_var$11 anycast:(Maybe Anycast) addr_len:(## 9)
workchain_id:int32 address:(bits addr_len) = MsgAddressInt;
结构类型必需描述
addr_var$11构造函数必需$11 标记意味着序列化 MsgAddressInt 以 11 位开始描述内部合约地址。
anycastAnycast*可选额外的地址数据,目前普通内部消息中未使用
addr_len## 9必需与 uintN 相同 - 表示无符号 N 位数字
workchain_idint32必需目的地地址的智能合约所在的工作链。目前始终为零。
address(bits256)必需有效载荷地址(可以是账户 ID)

基本使用类型

CurrencyCollection

nanograms$_ amount:(VarUInteger 16) = Grams;
currencies$_ grams:Grams other:ExtraCurrencyCollection
= CurrencyCollection;
结构类型必需描述
currencies$_构造函数必需$_ 空标记意味着序列化 CurrencyCollection 时我们不会在开头添加任何位
grams(VarUInteger 16)必需以nanoTons表示的消息价值
otherExtraCurrencyCollection可选ExtraCurrencyCollection 是一个为附加货币设计的字典,通常为空
  • ExtraCurrencyCollection 是一种复杂类型,通常在消息中为空字典

VarUInteger n

var_uint$_ {n:#} len:(#< n) value:(uint (len * 8))
= VarUInteger n;
var_int$_ {n:#} len:(#< n) value:(int (len * 8))
= VarInteger n;
结构类型必需描述
var_uint$_构造函数必需var_uint$_ 空标

记意味着序列化 CurrencyCollection 时我们不会在开头添加任何位 | | len | uintN | 必需 | 下一个值的位长度参数 | | value | (uint (len * 8)) | 可选 | 以 (len * 8) 位写入的整数值 |

消息示例

常规 func 内部消息

  var msg = begin_cell()
.store_uint(0, 1) ;; 标记
.store_uint(1, 1) ;; ihr_disabled
.store_uint(1, 1) ;; 允许弹回
.store_uint(0, 1) ;; 本身不是弹回
.store_slice(source)
.store_slice(destination)
;; 序列化 CurrencyCollection(见下文)
.store_coins(amount)
.store_dict(extra_currencies)
.store_coins(0) ;; ihr_fee
.store_coins(fwd_value) ;; fwd_fee
.store_uint(cur_lt(), 64) ;; 交易的 lt
.store_uint(now(), 32) ;; 交易的 unixtime
.store_uint(0, 1) ;; 没有 init-field 标志位(Maybe)
.store_uint(0, 1) ;; 原位消息体标志位(Either)
.store_slice(msg_body)
.end_cell();

常规 func 消息简短形式

验证者总是覆盖的消息部分可以跳过(填充零位)。此处的消息发送者也被跳过,序列化为 addr_none$00

  cell msg = begin_cell()
.store_uint(0x18, 6)
.store_slice(addr)
.store_coins(amount)
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
.store_slice(message_body)
.end_cell();