发送消息
TON 区块链是基于消息的—要与其他合约通信和部署新合约,您需要发送消息。
Tact 中的消息通常使用内置Struct SendParameters
组成,它由以下部分组成:
字段 | 类型 | 说明 |
---|---|---|
bounce | Bool | 如果设置为true (默认),当接收合约不存在或无法处理消息时,消息会退回给发送者。 |
to | Address | TON 区块链中的内部接收器 Address 。 |
value | Int | 消息中要发送的nanoToncoins的金额。 此值通常用于支付转发费用,除非使用了可选标志SendPayGasSeparately 。 |
mode | Int | 一个 8 位值,用于配置发送消息的方式,默认值为 。 参见:消息模式 。 见:消息mode . |
body | Cell? | 可选消息正文作为Cell |
code | Cell? | 可选 合约的初始代码(编译后的字节码) |
data | Cell? | 可选合约的初始数据(合约的init() 函数的参数) |
字段 code
和 data
被称为初始化包,它用于新合约的部署。
发送简单回复
最简单的消息是回复收到的消息,返回消息的所有过剩值:
self.reply("Hello, World!".asComment()); // asComment converts a String to a Cell with a comment
发送消息
如果需要更高级的逻辑,可以直接使用 send()
函数和 SendParameters
Struct 。
事实上,前面使用 .reply()
的示例可以通过调用下面的 send()
函数来实现:
send(SendParameters{ // bounce is set to true by default to: sender(), // sending message back to the sender value: 0, // don't add Toncoins to the message... mode: SendRemainingValue | SendIgnoreErrors, // ...except for ones received from the sender due to SendRemainingValue body: "Hello, World".asComment(), // asComment converts a String to a Cell with a comment});
另一个示例是向指定的 Address
发送一条消息,消息的值
为 TON,body
为带有 String
"Hello, World!"
的注释:
let recipient: Address = address("...");let value: Int = ton("1");send(SendParameters{ // bounce is set to true by default to: recipient, value: value, mode: SendIgnoreErrors, // will send the message despite any errors body: "Hello, World!".asComment(),});
可选标记 SendIgnoreErrors
表示即使在发送消息过程中发生错误,也会继续发送下一条消息。 在发送阶段,没有错误会导致交易回滚。
发送输入的消息
要发送二进制类型的消息,您可以使用以下代码:
let recipient: Address = address("...");let value: Int = ton("1");send(SendParameters{ // bounce is set to true by default to: recipient, value: value, mode: SendIgnoreErrors, // don't stop in case of errors body: SomeMessage{arg1: 123, arg2: 1234}.toCell(),});
部署合约
要部署一个合约,你需要用 initOf
计算它的地址和初始状态,然后在初始化消息中发送它们:
let init: StateInit = initOf SecondContract(arg1, arg2);let address: Address = contractAddress(init);let value: Int = ton("1");send(SendParameters{ // bounce is set to true by default to: address, value: value, mode: SendIgnoreErrors, // don't stop in case of errors code: init.code, data: init.data, body: "Hello, World!".asComment(), // not necessary, can be omitted});
外发消息处理
TON 区块链上的每笔交易都由 多个阶段 组成。 发送消息是在计算阶段进行评估,但是在该阶段不是发送。 相反,它们将按照出现顺序排入操作阶段,在计算阶段中列出的所有操作,如外向消息或储备请求,都会在此阶段执行。
由于所有值都是在计算阶段中计算的,所有费用都是在计算结束前计算的,而且在操作阶段中出现异常时不会恢复交易,因此向外发送消息可能会因操作费 或转发费不足而失败,不会出现跳转。
请看下面的例子:
// This contract initially has 0 nanoToncoins on the balancecontract FailureIsNothingButAnotherStep { // And all the funds it gets are obtained from inbound internal messages receive() { // 1st outbound message evaluated and queued (but not sent yet) send(SendParameters{ to: sender(), value: ton("0.042"), // plus forward fee due to SendPayGasSeparately mode: SendIgnoreErrors | SendPayGasSeparately, });
// 2nd outbound message evaluated and queued (but not sent yet, and never will be!) send(SendParameters{ to: sender(), value: 0, mode: SendRemainingValue | SendIgnoreErrors, }); }}
在那里,第二条消息实际上不会被发送:
-
计算阶段结束后,计算合约的剩余价值 。
-
在出站消息处理过程中,假设入站消息中提供了足够的金额,第一条消息会在余额上留下 nanoToncoins 。
-
处理第二条消息时,合约会尝试发送 nano Toncoins,但发送失败,因为剩余的金额已经较少。