发送消息
消息的组成、解析和发送位于TL-B schemas、交易阶段和TVM的交汇处。
事实上,FunC有send_raw_message函数,该函数期望一个序列化消息作为参数。
由于TON是一个功能广泛的系统,支持所有这些功能的消息可能看起来相当复杂。尽管如此,大多数情况下并不使用那么多功能,消息序列化在大多数情况下可以简化为:
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();
因此,开发者不用担忧,如果这份文档中的某些内容在第一次阅读时看起来难以理解,没有关系。只需把握总体思路即可。
有时文档中可能会提到**'gram'这个词,但大多是在代码示例中,它只是toncoin**的一个过时名称。
让我们深入了解!
消息类型
有三种类型的消息:
- 外部消息 — 从区块链外部发送到区块链内部智能合约的消息。这类消息应该在所 谓的
credit_gas
阶段被智能合约明确接受。如果消息未被接受,节点不应该将其纳入进区块或转发给其他节点。 - 内部消息 — 从一个区块链实体发送到另一个区块链实体的消息。与外部消息不同,这类消息可以携带一些TON并为自己支付费用。接收此类消息的智能合约可能没有接受它,在这种情况下,消息价值中的gas将被扣除。
- 日志 — 从区块链实体发送到外部世界的消息。一般来说,没有将这类消息发送出区块链的机制。实际上,尽管网络中的所有节点对是否创建了消息达成共识,但没有关于如何处理它们的规则。日志可能被直接发送到
/dev/null
,记录到磁盘,保存到索引数据库,甚至通过非区块链手段(电子邮件/Telegram/短信)发送,所有这些都取决于给定节点的自行决定。
消息布局
我们将从内部消息布局开始。
描述智能合约可以发送的消息的TL-B方案如下:
message$_ {X:Type} info:CommonMsgInfoRelaxed
init:(Maybe (Either StateInit ^StateInit))
body:(Either X ^X) = MessageRelaxed X;
让我们用语言来描述。任何消息的序列化都包括三个字段:info(某种标题,描述来源、目的地和其他元数据)、init(仅在消息初始化时需要的字段)和body(消息有效载荷)。
Maybe
、Either
和其他类型的表达式意味着以下内容:
- 当我们有字段
info:CommonMsgInfoRelaxed
时,意味着CommonMsgInfoRelaxed
的序列化直接注入到序列化cell中。 - 当我们有字段
body:(Either X ^X)
时,意味着当我们(反)序列化某种类型X
时,我们首先放置一个either
位,如果X
被序列化到同一cell,则为0
,如果它被序列化到单独的cell,则为1
。 - 当我们有字段
init:(Maybe (Either StateInit ^StateInit))