TVM 初始化
To maximize your comprehension of this page, familiarizing yourself with the TL-B language is highly recommended.
TVM 在普通和/或其他交易的 Compute Phase 调用。
初始状态
在执行智能 合约之前,初始化 TVM 的新实例如下:
-
使用从智能合约的
code
部分创建的cell slice 初始化原始 cc(当前continuation)。如果账户处于冻结或未初始化状态,必须在传入消息的init
字段中提供代码。 -
cp(当前 TVM codepage)设置为默认值,即 0。如果智能合约想使用另一个 TVM codepage x,则必须在其代码的第一条指令中使用
SETCODEPAGE
x 切换到该codepage。 -
按照 Credit Phase 的结果初始化 gas 值(_ gas 限制_)。
-
计算 libraries(库 context)。下文描述。
-
stack 初始化过程取决于引发交易的事件,其内容在下文描述。
-
控制寄存器 c0(返回 continuation )由带有参数 0 的特殊 continuation
ec_quit
初始化。执行此 continuation 将导致 TVM 以 exit code 0 终止。 -
控制寄存器 c1(备用返回 continuation )由带有参数 1 的特殊 continuation
ec_quit
初始化。当调用时,它导致 TVM 以 exit code 1 终止。请注意, exit code 0 和 1 都被视为 TVM 的成功终止。 -
控制寄存器 c2(异常处理程序)由特殊 continuation
ec_quit_exc
初始化。调用时,它从栈顶获取整数(等于异常编号)并以等于该整数的 exit code 终止 TVM。这样, 默认情况下,所有异常都以等于异常编号的 exit code 终止智能合约执行。 -
控制寄存器 c3(代码字典)由类似于上述 cc(当前 continuation )的智能合约代码的cell初始化。
-
控制寄存器 c4(持久数据的 根)由智能合约的持久数据初始化,存储在其
data
部分中。如果账户处于冻结或未初始化状态,必须在传入消息的init
字段中提供数据。请注意,智能合约的持久数据不需要在其全部加载,而是加载根,当引用从根仅在访问时加载时,TVM 可能加载其他cell,从而提供一种虚拟内存形式。 -
控制寄存器 c5(动作的根)由空cell初始化。TVM 的“输出动作”原语,如
SENDMSG
,在此寄存器中累积 输出动作(例如,出站消息),以在智能合约成功终止后执行。其序列化的 TL-B 方案如下下文描述。 -
控制寄存器 c7(临时数据的根)初始化为元组,其结构如下下文描述。
库 context
智能合约的 库 context(库环境)是将 256 位cell(表示)哈希映射到相应cell本身的哈希映射。在执行智能合约期间访问外部cell引用时,会在库环境中查找所引用的cell,并通过找到的cell透明地替换外部cell引用。
调用智能合约的库环境计算如下:
- 取当前主链状态的当前工作链的全局库环境。
- 然后,它由智能合约的本地库环境增强,存储在智能合约状态的
library
字段中。仅考虑 256 位密钥等于相应值cell的哈希。如果密钥同时存在于全局和本地库环境中,则本地环境在合并中占优势。 - 最后,由传入消息的
init
字段(如果有)的library
字段增强。请注意,如果账户处于冻结或未初始化状态,则消息的library
字段将覆盖先前步骤中的本地库环境。消息库的优先级低于本地和全局库环境。
为 TVM 创建共享库的最常见方式是在主链中发布对库的根cell的引用。
堆栈
TVM 栈的初始化在 TVM 的初始状态形成之后进行,具体取决于引发交易的事件:
- 内部消息
- 外部消息
- tick-tock
- 拆分准备
- 合并安装
始终推送到栈的最后一个项是 函数选择器,它是一个用于标识引发交易的事件的 Integer。
内部消息
在内部消息的情况下,栈通过按以下方式推送到智能合约的 main()
函数的参数来初始化:
- 将智能合约的余额 b(将入站消息的值记入后的余额)作为 nanotons 的 Integer 金额传递。
- 将入站消息 m 的余额 bm 作为 nanotons 的 Integer 金额传递。
- 将入站消息 m 作为包含类型 Message X 的序列化值的cell传递,其中 X 是消息体的类型。
- 将入站消息的主体 mb,等于字段主体 m 的值,并作为cell片传递。
- 函数选择器 s,通常等于 0。
之后,智能合约的代码,即其初始值 c3,将被执行。根据 s,它选择正确的函数来处理函数的其余参数,然后终止。