Skip to main content

运行时(runtime)

程序功能#

运行时仅允许所有者程序借记帐户或修改其数据。 然后,程序为客户是否可以修改其拥有的帐户定义其他规则。 在系统程序的情况下,它允许用户通过识别交易签名来转移灯饰。 如果看到客户端使用密钥对的private key签署了交易,则表明客户端已授权代币传输。

换句话说,给定程序拥有的整个帐户集可以视为键值存储,其中键是帐户地址,值是特定于程序的任意二进制数据。 程序作者可以决定如何管理尽可能多的帐户的整个程序状态。

运行时执行每个事务的指令后,它将使用帐户元数据来验证是否违反了访问策略。 如果程序违反了该策略,则运行时会丢弃交易中所有指令所做的所有帐户更改,并将交易标记为失败。

政策#

程序处理完指令后,运行时将验证程序仅执行了允许的操作,并且结果符合运行时策略。

该策略如下:

  • 只有帐户所有者可以更改所有者。
    • 仅在帐户可写时。
    • 并且仅在该帐户不可执行时
    • 并且仅当数据为零初始化或为空时。
  • 未分配给该程序的帐户的余额不能减少。
  • 只读帐户和可执行帐户的余额可能不会更改。
  • 只有系统程序拥有该帐户,只有系统程序才能更改数据大小。
  • 只有所有者可以更改帐户数据。
    • 如果该帐户可写。
    • 并且该帐户不可执行。
  • 可执行文件是单向的(false->true),只有帐户所有者可以设置。
  • 没有与此帐户相关联的rent_epoch的修改。

计算预算#

为了防止程序滥用计算资源,必须为事务中的每个指令分配一个计算预算。 预算由计算单元组成,在程序执行各种操作和程序可能不会超出的范围时会消耗这些计算单元。 当程序消耗了全部预算或超出界限时,运行时将暂停程序并返回错误。

以下操作会产生计算成本:

  • 执行BPF指令
  • 呼叫系统电话
    • 记录
    • 创建程序地址
    • 跨程序调用
    • ...

对于跨程序调用,所调用的程序将继承其父级的预算。 如果被调用的程序消耗了预算或超出了限制,则整个调用链和父级都将停止。

可以在Solana SDK中找到当前的计算预算

例如,如果当前预算是:

max_units: 200,000,
log_units: 100,
log_u64_units: 100,
create_program address units: 1500,
invoke_units: 1000,
max_invoke_depth: 4,
max_call_depth: 64,
stack_frame_size: 4096,
log_pubkey_units: 100,

然后程序

  • 如果不执行其他操作,则可以执行200,000条BPF指令
  • 可以记录2,000条日志消息
  • 堆栈使用量不能超过4k
  • 不能超过BPF通话深度64
  • 不能超过4个级别的跨程序调用。

由于计算预算在程序执行时会逐渐消耗,因此总预算消耗将是其执行的各种操作成本的组合。

在运行时,程序可以记录剩余多少计算预算。 有关更多信息,请参见debugging

预算值取决于功能启用,请查看计算预算的new函数列出预算的编制方式。 需要了解功能的工作方式以及正在使用的群集上启用的功能才能确定当前预算的值。

新的功能#

随着Solana的发展,可能会引入新功能或补丁,这些新功能或补丁会更改集群的行为以及程序的运行方式。 行为的变化必须在群集的各个节点之间进行协调,如果节点不协调,则这些变化可能会导致共识破裂。 Solana支持一种称为运行时功能的机制,以方便平滑地采用更改。

运行时功能是历时协调的事件,将在集群中发生一个或多个行为更改。 对Solana的新更改(将更改行为)使用功能门进行包装,并且默认情况下处于禁用状态。 然后使用Solana工具激活功能,将其标记为未决,一旦标记为未决,该功能将在下一个时期激活。

要确定激活了哪些功能,请使用Solana命令行工具

solana功能状态

如果首先遇到问题,请确保您使用的Solana工具版本与solana cluster-version返回的版本相匹配。 如果它们不匹配,请安装正确的工具套件