跳到主要内容

消息 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 区块链中的传递方式。

//internal message
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;

//external incoming message
ext_in_msg_info$10 src:MsgAddressExt dest:MsgAddressInt
import_fee:Grams = CommonMsgInfo;

//external outgoing message
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;
//internal message
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;
//external incoming message
ext_in_msg_info$10 src:MsgAddressExt dest:MsgAddressInt
import_fee:Grams = CommonMsgInfo;
StructureTypeRequiredDescription
ext_out_msg_info$10ConstructorRequired$10 标签意味着,在序列化过程中,以 "10 "位开头的 CommonMsgInfo 描述了一条外部接收的消息。
ihr_disabledBoolRequired超级路由标志。(目前始终为真)
srcMsgAddressExtRequired外部发件人的地址。
destMsgAddressIntRequired智能合约信息目的地的地址。
import_feeVarUInteger 16Required执行和传递信息的费用。

ext_out_msg_info$11

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

//internal message
ext_out_msg_info$11 src:MsgAddressInt dest:MsgAddressExt
created_lt:uint64 created_at:uint32 = CommonMsgInfo;
StructureTypeRequiredDescription
ext_out_msg_info$11ConstructorRequired$11 标签的意思是,在序列化过程中,以 "11 "位开头的 CommonMsgInfo 描述了一条对外发送的消息。
srcMsgAddressIntRequiredHyper routing flag. v
destMsgAddressExtRequiredTON 中用于初始化新合约的一般结构。可以写入 cell 引用或根 cell 。
created_ltuint64Required验证器指定的发送信息的逻辑时间。用于智能合约中的订购操作。
created_atuint32RequiredUnix time

StateInit TL-B

StateInit 用于将初始数据交付给合约,并在合约部署时使用。

_ split_depth:(Maybe (## 5)) special:(Maybe TickTock)
code:(Maybe ^Cell) data:(Maybe ^Cell)
library:(HashmapE 256 SimpleLib) = StateInit;
StructureTypeRequiredDescription
split_depth(## 5)Optional高负载合约的参数,用于定义在不同分片中分割成多个实例的行为。目前 StateInit 不使用该参数。
specialTickTock*Optional用于在区块链的每个新区块中调用智能合约。仅在主链中可用。普通用户的合约无需使用它。
codeCellOptional合约的序列化代码。
dataCellOptional合约初始数据。
libraryHashmapE 256 SimpleLib*Optional当前使用的 StatInit 不含有任何libs

General detailed explanations for Hashmaps

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;
StructureTypeRequiredDescription
addr_none$00ConstructorRequired$00 标记表示在序列化中,MsgAddressExt 以 "00 "位开始。这意味着整个外部地址为 00

addr_extern$01

addr_extern$01 len:(## 9) external_address:(bits len)
= MsgAddressExt;
StructureTypeRequiredDescription
addr_extern$01ConstructorRequired$01 标记表示在序列化中,MsgAddressExt 以 "01 "位开始,描述一个外部地址。
len## 9Required与 uintN 相同 - 表示无符号 N 位数
external_address(bits len)Required地址是 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;
StructureTypeRequiredDescription
addr_std$10ConstructorRequired$10 标签表示,在序列化中,MsgAddressExt 以 "10 "位开始,描述一个外部地址。
anycastAnycast*Optional附加地址数据,目前不用于普通内部报文
workchain_idint8Required放置目标地址智能合约的工作链。目前总是等于零。
address(bits256)Required智能合约账户 ID 号

addr_std$10

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

addr_var$11

CurrencyCollection

nanograms$_ amount:(VarUInteger 16) = Grams;
currencies$_ grams:Grams other:ExtraCurrencyCollection
= CurrencyCollection;
StructureTypeRequiredDescription
currencies$_ConstructorRequired$_ 空标签意味着,在序列化 CurrencyCollection 时,我们不会在开头添加任何位
grams(VarUInteger 16)RequiredMessage value in nanoTons
otherExtraCurrencyCollectionOptionalExtraCurrencyCollection 是专为附加货币设计的指令,通常为空。
  • ExtraCurrencyCollection 复杂类型,通常在信息中写成空 dict

VarUInteger n

var_uint$_ {n:#} len:(#< n) value:(uint (len * 8))
= VarUInteger n;
var_int$_ {n:#} len:(#< n) value:(int (len * 8))
= VarInteger n;
StructureTypeRequiredDescription
var_uint$_ConstructorRequiredvar_uint$_ 空标签意味着,在序列化 CurrencyCollection 时,我们不会在开头添加任何位
lenuintNRequired下一数值的参数 len 位
value(uint (len * 8))Optional以 (len * 8) 位写入的整数 uint 值

VarUInteger n

常规 func 内部信息

  var msg = begin_cell()
.store_uint(0, 1) ;; tag
.store_uint(1, 1) ;; ihr_disabled
.store_uint(1, 1) ;; allow bounces
.store_uint(0, 1) ;; not bounced itself
.store_slice(source)
.store_slice(destination)
;; serialize CurrencyCollection (see below)
.store_coins(amount)
.store_dict(extra_currencies)
.store_coins(0) ;; ihr_fee
.store_coins(fwd_value) ;; fwd_fee
.store_uint(cur_lt(), 64) ;; lt of transaction
.store_uint(now(), 32) ;; unixtime of transaction
.store_uint(0, 1) ;; no init-field flag (Maybe)
.store_uint(0, 1) ;; inplace message body flag (Either)
.store_slice(msg_body)
.end_cell();

常规函数信息简表

可以跳过总是被验证器覆盖的信息部分(用零位填充)。信息的发件人也会被跳过,序列化为 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();