---
title: The Runtime 虚拟机运行
---

## 虚拟机运行

虚拟机运行环境是并发事务处理器。 事务预先指定它们的数据依赖关系和动态内存分配。 通过将程序代码与其操作状态分离，虚拟机运行环境能够编排并发访问。 访问只读帐户的事务是并行执行的，而访问可写帐户的事务是序列化的。 运行环境通过具有良好的接口入口点与程序进行交互。 帐户中存储的数据是一种不透明类型，即字节数组。 该程序完全控制其内容。

事务结构指定公钥和这些密钥的签名的列表，在与帐户密钥相关联的状态上执行顺序指令。 提交事务，所有指令都必须成功执行；如果有任何指令中止，则整个事务失败。

#### Account Structure 账户结构

帐户保持余额和账户数据指定的内存。

## Transaction Engine 交易引擎

引擎将公钥映射到帐户，并将它们路由到程序的入口点。

### Execution 执行

事务在流水线中进行批处理。 TPU和TVU使用的是稍微不同的方法。 TPU运行时确保PoH记录已经提交到内存中。

TVU运行时确保在运行时处理任何事务之前进行PoH验证。

![运行流水线](/img/runtime.svg)

在_执行_阶段，加载的帐户没有数据依赖关系，因此所有程序都可以并行执行。

虚拟机运行强制执行以下规则：

1. 只有_所有者_程序才能修改帐户的内容。 这意味着在分配数据向量时保证为零。
2. 所有账户的余额总额在交易执行前后相等。
3. 交易执行后，只读帐户的余额必须等于交易之前的余额。
4. 交易中的所有指令都是原子性执行的。 如果一个失败，则所有帐户修改都将被丢弃。

程序的执行涉及将程序的公钥映射到一个入口点，该入口点将指针指向交易，以及一个加载的帐户数组。

### SystemProgram Interface 系统级的应用接口

接口用户编码的接口最好用`Instruction::data`来描述。

- `CreateAccount` - 允许用户使用分配的数据数组创建帐户并将其分配给程序。
- `CreateAccountWithSeed` - 和 `CreateAccount` 一样，但新帐户的地址是从
  - 账户的公开密钥派生的，
  - (助记词) 以及
  - 程序的公钥
- `Assign` -允许用户将现有帐户分配给一个程序。
- `Transfer` - 账户之间转账。

### Program State Security 程序状态安全

要使区块链正常运行，程序代码必须对用户输入具有容错性。 这就是为什么在这种设计中，特定于程序的代码是唯一可以更改分配给它的帐户中数据字节数组状态的代码。 这也是为什么`Assign`或`CreateAccount`必须将数据归零的原因。 否则，如果一些额外元数据来分配了该内存而不是本机生成的内存，程序将无法将最近分配的帐户数据与本机生成的状态转换区分开。

在程序中传递消息，接收程序必须接受消息并复制状态。 但在实践中，并不需要复制状态。 接收程序可以读取属于其他帐户的状态，而无需复制它，并且在读取过程中它可以保证发送方程序的状态。

### Notes 注意事项

- 没有动态内存分配。 客户端需要使用`CreateAccount`指令来创建内存，然后再将其传递给另一个程序。 此指令可以通过对程序本身的调用组合成单个事务。
- `CreateAccount`和`Assign`保证在将帐户分配给程序时，帐户的数据是初始化为零。
- 将帐户分配给程序或分配空间的交易必须经过帐户地址的私钥签名，除非帐户是由`CreateAccountWithSeed`创建的，在这种情况下，帐户的地址/公钥没有对应的私钥。
- 一旦分配给程序，就不能重新分配帐户。
- 虚拟机环境保证了只有这个程序代码的所有权账户才能操作程序代码数据。
- 虚拟机环境保证了只有这个账户的所有权才能发起该账户余额的交易。
- 虚拟机环境保证了各类交易后所有账户余额总和不变。
- 虚拟机环境保证了在一笔交易提交后所有指令都执行成功。

## 未来的工作

- [长时间运行交易的延续和信号](https://github.com/solana-labs/solana/issues/1485)
