diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 711424e5b1..1d586894e1 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -19,6 +19,10 @@ module.exports = { crossorigin: "anonymous", }, ], + i18n: { + defaultLocale: 'en', + locales: ['en', 'zh'], + }, themeConfig: { navbar: { logo: { @@ -52,6 +56,10 @@ module.exports = { label: "Learn", position: "left", }, + { + type: 'localeDropdown', + position: 'right', + }, { href: "https://discordapp.com/invite/pquxPsq", label: "Chat", diff --git a/docs/i18n/zh/code.json b/docs/i18n/zh/code.json new file mode 100644 index 0000000000..f14456b7fc --- /dev/null +++ b/docs/i18n/zh/code.json @@ -0,0 +1,50 @@ +{ + "⛏ Start Building": { + "message": "⛏ 开始开发", + "description": "start-building" + }, + "Get started building your decentralized app or marketplace.": { + "message": "开始开发您的去中心化应用或市场。", + "description": "get-started-building" + }, + "🎛 Run a Validator Node": { + "message": "🎛 运行一个验证节点", + "description": "run-validator" + }, + "Validate transactions, secure the network, and earn rewards.": { + "message": "验证交易,保护网络并获得奖励。", + "description": "validate-transactions" + }, + "🏛 Create an SPL Token": { + "message": "🏛 创建一个 SPL 代币", + "description": "create-spl" + }, + "Launch your own SPL Token, Solana's equivalent of ERC-20.": { + "message": "启动您自己的 SPL 代币,类似于 Solana 区块链的 ERC-20。", + "description": "erc-20" + }, + "🏦 Integrate an Exchange": { + "message": "🏦 集成一个交易所。", + "description": "integrate-exchange" + }, + "Follow our extensive integration guide to ensure a seamless user experience.": { + "message": "请遵循我们通用集成指南,来确保用户体验。", + "description": "integration-guide" + }, + "📲 Manage a Wallet": { + "message": "📲 管理钱包", + "description": "manage-wallet" + }, + "Create a wallet, check your balance, and learn about wallet options.": { + "message": "创建一个钱包,检查余额,了解钱包选项。", + "description": "wallet-options" + }, + "🤯 Learn How Solana Works": { + "message": "🤯 了解 Solana 工作原理", + "description": "learn-how" + }, + "Get a high-level understanding of Solana's architecture.": { + "message": "对 Solana 架构进行深入了解。", + "description": "high-level" + } +} \ No newline at end of file diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current.json b/docs/i18n/zh/docusaurus-plugin-content-docs/current.json new file mode 100644 index 0000000000..bc13267316 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,110 @@ +{ + "version.label": { + "message": "下一步", + "description": "The label for version current" + }, + "sidebar.docs.category.About": { + "message": "关于", + "description": "The label for category About in sidebar docs" + }, + "sidebar.docs.category.Wallets": { + "message": "钱包", + "description": "The label for category Wallets in sidebar docs" + }, + "sidebar.docs.category.Web Wallets": { + "message": "网页钱包", + "description": "The label for category Web Wallets in sidebar docs" + }, + "sidebar.docs.category.Hardware Wallets": { + "message": "硬件钱包", + "description": "The label for category Hardware Wallets in sidebar docs" + }, + "sidebar.docs.category.Command-line Wallets": { + "message": "命令行钱包", + "description": "The label for category Command-line Wallets in sidebar docs" + }, + "sidebar.docs.category.Staking": { + "message": "质押", + "description": "The label for category Staking in sidebar docs" + }, + "sidebar.docs.category.Command Line": { + "message": "命令行", + "description": "The label for category Command Line in sidebar docs" + }, + "sidebar.docs.category.Developing": { + "message": "开发中", + "description": "The label for category Developing in sidebar docs" + }, + "sidebar.docs.category.Programming Model": { + "message": "编程模型", + "description": "The label for category Programming Model in sidebar docs" + }, + "sidebar.docs.category.Clients": { + "message": "客户端", + "description": "The label for category Clients in sidebar docs" + }, + "sidebar.docs.category.Builtins": { + "message": "内置模式", + "description": "The label for category Builtins in sidebar docs" + }, + "sidebar.docs.category.Deployed Programs": { + "message": "部署程序", + "description": "The label for category Deployed Programs in sidebar docs" + }, + "sidebar.docs.category.Integrating": { + "message": "集成", + "description": "The label for category Integrating in sidebar docs" + }, + "sidebar.docs.category.Validating": { + "message": "验证", + "description": "The label for category Validating in sidebar docs" + }, + "sidebar.docs.category.Incenvitized Testnet": { + "message": "激励测试网", + "description": "The label for category Incenvitized Testnet in sidebar docs" + }, + "sidebar.docs.category.Registration": { + "message": "注册", + "description": "The label for category Registration in sidebar docs" + }, + "sidebar.docs.category.Participation": { + "message": "参与", + "description": "The label for category Participation in sidebar docs" + }, + "sidebar.docs.category.Clusters": { + "message": "集群", + "description": "The label for category Clusters in sidebar docs" + }, + "sidebar.docs.category.Architecture": { + "message": "架构", + "description": "The label for category Architecture in sidebar docs" + }, + "sidebar.docs.category.Cluster": { + "message": "集群", + "description": "The label for category Cluster in sidebar docs" + }, + "sidebar.docs.category.Validator": { + "message": "验证节点", + "description": "The label for category Validator in sidebar docs" + }, + "sidebar.docs.category.Design Proposals": { + "message": "设计提案", + "description": "The label for category Design Proposals in sidebar docs" + }, + "sidebar.docs.category.Implemented": { + "message": "实现", + "description": "The label for category Implemented in sidebar docs" + }, + "sidebar.docs.category.Economic Design": { + "message": "经济设计", + "description": "The label for category Economic Design in sidebar docs" + }, + "sidebar.docs.category.Validation Client Economics": { + "message": "验证客户端经济学", + "description": "The label for category Validation Client Economics in sidebar docs" + }, + "sidebar.docs.category.Accepted": { + "message": "已接受", + "description": "The label for category Accepted in sidebar docs" + } +} \ No newline at end of file diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli.md new file mode 100644 index 0000000000..096a2e0d97 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli.md @@ -0,0 +1,16 @@ +--- +title: 命令行指南 +--- + +在本节中,我们将描述如何使用Solana命令行工具创建_钱包_,来发送和接收SOL代币以及通过委托质押来参与到集群中。 + +为了与Solana集群进行交互,我们需要使用其命令行界面,也称为CLI。 命令行是Solana核心团队首次部署新功能所用到的工具。 命令行界面不一定是最容易使用的,但它提供了对Solana帐户的最直接、灵活和安全的访问。 + +## 准备工作 + +要开始使用 Solana 命令行 (CLI) 工具: + +- [安装 Solana 工具](cli/install-solana-cli-tools.md) +- [选择一个集群](cli/choose-a-cluster.md) +- [创建一个钱包](wallet-guide/cli.md) +- [查看 CLI 协议](cli/conventions.md) diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/choose-a-cluster.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/choose-a-cluster.md new file mode 100644 index 0000000000..fb3f2d0a8c --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/choose-a-cluster.md @@ -0,0 +1,37 @@ +--- +title: 连接到一个集群 +--- + +查看 [Solana 集群](../clusters.md) 获取关于可用集群的通用信息。 + +## 配置命令行工具 + +您可以通过下述指令来检查集群正在运行的 Solana 命令行工具 (CLI): + +```bash +solana config get +``` + +通过 `solana config set` 命令来制定某个集群。 设置一个目标集群后,未来的任何子命令都会从该集群发送/接收信息。 + +例如,要指定 Devnet 集群,请运行: + +```bash +solana config set --url https://devnet.solana.com +``` + +## 确保版本相匹配 + +虽然严格来说没有必要,但是当 CLI 版本与运行在集群中的软件版本相匹配时,一般来说 CLI 版本能够发挥最大作用。 查看本地安装的 CLI 版本,请运行: + +```bash +solana --version +``` + +查看集群版本,请运行: + +```bash +solana cluster-version +``` + +确保本地的 CLI 版本比群集版本新或者至少相同。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/conventions.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/conventions.md new file mode 100644 index 0000000000..f03220d48e --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/conventions.md @@ -0,0 +1,59 @@ +--- +title: 使用 Solana CLI 命令 +--- + +在运行 Solana CLI 命令之前,让我们先来熟悉一下所有的命令。 首先,Solana CLI 实际上是你可能会用到操作的命令集合。 您可以通过运行以下操作查看所有可能命令的列表: + +```bash +solana --help +``` + +需要研究特定的命令,请运行: + +```bash +solana --help +``` + +您可以将文本 `` 替换为你想了解的命令名称。 + +命令使用信息通常包含诸如 ``、`` 或 `` 等字段。 每个字段都是 _type_ 文本的占位符,您可以使用它执行命令。 例如,您可以将 `` 替换为诸如 `42` 或 `100.42` 等数字。 您可以将 `` 替换为公钥的 base58 编码,例如 `9grmKMwTiZwUHSExjtbFzHLPTdWoXgcg1bZkhvwTrTww`。 + +## 密钥对协议 + +许多使用 CLI 工具的命令需要一个 `` 值。 密钥对应使用的值取决于您创建的 [命令行钱包的类型](../wallet-guide/cli.md)。 + +例如,显示钱包地址(也称为密钥),CLI 帮助文档显示: + +```bash +solana-keygen pubkey +``` + +下面我们来展示根据钱包类型来解决应该在 `` 中插入什么的问题。 + +#### 纸钱包 + +在纸质钱包中,密钥对源自助记词和你在钱包创建时输入的可选密码。 若要让纸钱包密钥在任意地方显示 `` 文本在示例或帮助文档中,请输入单词 `ASK`,然后程序会强制您在运行命令时输入种子单词。 + +显示纸钱包的钱包地址: + +```bash +solana-keygen pubkey +``` + +#### 文件系统钱包 + +有了一个文件系统钱包,密钥对就会存储在您的计算机上的文件中。 将 `` 替换为对密钥文件的完整文件路径。 + +例如,如果文件系统密钥对文件位置是 `/home/solana/my_wallet.json`,请输入来显示地址: + +```bash +solana-keygen pubkey /home/solana/my_wallet.json +``` + +#### 硬软件钱包 + +如果您选择了硬件钱包,请使用您的 [密钥对链接](../wallet-guide/hardware-wallets.md#specify-a-hardware-wallet-key),比如 `blap://ledger?key=0`。 + +```bash +solana-keygen pubkey usb://ledger?key=0 +``` diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/delegate-stake.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/delegate-stake.md new file mode 100644 index 0000000000..ee41c3b0ab --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/delegate-stake.md @@ -0,0 +1,149 @@ +--- +title: 委托您的质押 +--- + +通过 [ 获取 SOL ](transfer-tokens.md) 以后,您可以通过 _stake_ 将它委托给一个验证节点。 质押(Stake)就是在 _stake account_ 中的代币。 Solana 根据质押权重为验证节点分配投票权重,权重会影响它们在区块链中决定下一个有效交易区块。 然后 Solana 会按周期生成新的 SOL 来奖励质押者和验证节点。 您委托的代币越多,获得的奖励就越高。 + +## 创建一个质押账户 +要委托代币,您首先要将代币转入一个质押帐户。 而要创建一个帐户,您需要一个密钥对: 它的公钥将作为 [质押账户地址](../staking/stake-accounts.md#account-address)。 此处无需密码或加密;此密钥对将在创建密钥账户后被丢弃。 + +```bash +solana-keygen new --no-passphrase -o stake-account.json +``` + +输出结果将在文本 `pubkey:` 后面包括该地址。 + +```text +pubkey: GKvqsuNcnwWqPzzuhLmGi4rzzh55FhJtGizkhHaEJqiV +``` + +复制公钥并将它安全地存储起来。 在后续创建质押账户的操作中您将随时需要用到它。 + +创建一个质押账户: + +```bash +solana create-stake-account --from stake-account.json \ + --stake-authority --withdraw-authority \ + --fee-payer +``` + +`` 的代币从 `` 转到了 stake-account.json 公钥的一个新质押账户。 + +现在可以丢弃 stake-account.json 文件了。 要授权额外的操作,您可以通过 `--stake-authority` 或 `--rap-authority` 密钥对,而无需使用 stak-account.json。 + +使用 `solana stake-account` 命令查看新的质押账户: + +```bash +solana stake-account +``` + +结果大概呈这样: + +```text +Total Stake: 5000 SOL +Stake account is undelegated +Stake Authority: EXU95vqs93yPeCeAU7mPPu6HbRUmTFPEiGug9oCdvQ5F +Withdraw Authority: EXU95vqs93yPeCeAU7mPPu6HbRUmTFPEiGug9oCdvQ5F +``` + +### 设置质押和取款权限 +创建账号时,如果需要设置 [质押和提现权限](../staking/stake-accounts.md#understanding-account-authorities),您可以通过 `--stake-authority` and `--withdraw-authority` 选项或 `solana stake-authorize` 命令来实现。 例如,要设置一个新的质押权限,请运行: + +```bash +solana stake-authorize \ + --stake-authority --new-stake-authority \ + --fee-payer +``` + +这将针对已有的质押账号 ``,通过现有的质押权限 `` 来授权一个新的质押权限 ``。 + +### 高级功能:派生质押账户地址 + +当委托质押时,你需要将所有密钥账户中的代币委托给某一个验证节点。 而要委托给多个验证节点,您就需要多个质押账户。 为每个帐户创建一个新密钥对并管理那些地址可能比较繁琐。 好在您可以通过 `--seed` 选项来派生多个质押地址: + +```bash +solana create-stake-account --from --seed \ + --stake-authority --withdraw-authority --fee-payer +``` + +`` 是一个最多32字节的任意字符串,通常情况下是一个对应该派生账户的数字。 第一个账户是"0",第二个是 "1",以此类推。 `` 公钥发挥基本地址的作用。 该命令将从基础地址和种子字符串中派生一个新地址。 要查看派生出哪个质押地址,请使用 `solana create-address-with-seed`命令: + +```bash +solana create-address-with-seed --from STAKE +``` + +`` is the public key of the `` passed to `solana create-stake-account`. + +该命令将输出派生地址,可以用于质押操作中的 `` 参数。 + +## 委托您的质押 + +想要委托您的质押给某个验证节点,您首先需要它的投票帐号地址。 您可以通过 `solana validators` 命令来查询所有验证节点列表和他们的投票账户: + +```bash +solana 验证节点 +``` + +每行的第一列包含验证节点的身份,第二列是投票帐户地址。 选择一个验证节点,并在 `solana delegate-stake` 中使用它的投票帐户地址: + +```bash +solana delegate-stake --stake-authority \ + --fee-payer +``` + +质押权限 `` 对地址 `` 进行帐户授权操作。 该质押被委托给投票账户地址 ``。 + +委托质押后,使用 `solana stake-account` 查看质押账户的变化: + +```bash +solana stake-account +``` + +您将在输出中看到“Delegated Stake”和“Delegated Vote Account Address”两个新字段。 结果大概呈这样: + +```text +Total Stake: 5000 SOL +Credits Observed: 147462 +Delegated Stake: 4999.99771712 SOL +Delegated Vote Account Address: CcaHc2L43ZWjwCHART3oZoJvHLAe9hzT2DJNUpBzoTN1 +Stake activates starting from epoch: 42 +Stake Authority: EXU95vqs93yPeCeAU7mPPu6HbRUmTFPEiGug9oCdvQ5F +Withdraw Authority: EXU95vqs93yPeCeAU7mPPu6HbRUmTFPEiGug9oCdvQ5F +``` + +## 取消质押 + +质押委托以后,您可以使用 `solana deactivate-stake` 命令来取消委托的质押: + +```bash +solana deactivate-stake --stake-authority \ + --fee-payer +``` + +质押权限 `` 对地址 `` 进行帐户授权操作。 + +请注意,质押需要几个 epoch 才能“冷却(cool down)”。 在冷却期间进行重新质押的操作将会失败。 + +## 提现质押 + +使用 `solana withdraw-stake` 命令将代币转移出质押帐户: + +```bash +solana withdraw-stake --withdraw-authority \ + --fee-payer +``` + +其中,`` 是现有的质押帐户,质押权限 `` 是提现权限, 而 `` 是要转账给接收账户 `` 的代币数量。 + +## 拆分质押 + +在现有质押不能取款的时候,您可能想将质押分配给另外的验证节点。 无法取回的原因可能是处于质押、冷却或锁定的状态。 若要将代币从现有质押账户转移到一个新的帐户,请使用 `solana split-stake` 命令: + +```bash +solana split-stake --stake-authority \ + --fee-payer +``` + +其中,`` 是现有的质押帐户,质押权限 `` 是质押账户的权限, `` 是新账户的密钥对,`` 是要转账给新账户的代币数量。 + +若要将质押账户拆分到派生账户地址,请使用 `--seed` 选项。 详情请参阅 [衍生质押账户地址](#advanced-derive-stake-account-addresses)。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/install-solana-cli-tools.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/install-solana-cli-tools.md new file mode 100644 index 0000000000..7cf314845e --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/install-solana-cli-tools.md @@ -0,0 +1,131 @@ +--- +title: 安装 Solana 工具包 +--- + +取决于您喜欢的工作公式,在电脑上安装 Solana 工具的方法有多种: + +- [使用 Solana 的安装工具 (最简单的方法)](#use-solanas-install-tool) +- [下载预置的二进制文件](#download-prebuilt-binaries) +- [通过源代码安装](#build-from-source) + +## 通过 Solana 安装工具 + +### MacOS & Linux + +- 打开您最喜欢的终端应用 + +- 通过运行下述指令,安装 Solana 版本[LATEST_SOLANA_RELEASE_VERSION](https://github.com/solana-labs/solana/releases/tag/LATEST_SOLANA_RELEASE_VERSION) 到您的机器: + +```bash +sh -c "$(curl -sSfL https://release.solana.com/LATEST_SOLANA_RELEASE_VERSION/install)" +``` + +- 您可以用 `LATEST_SOLANA_RELEASE_VERSION` 发布标签替换想要的软件版本,或者使用以下三个通道名称之一: `stable`,`beta` 或 `edge`。 + +- 以下输出表示更新成功: + +```text +downloading LATEST_SOLANA_RELEASE_VERSION installer +Configuration: /home/solana/.config/solana/install/config.yml +Active release directory: /home/solana/.local/share/solana/install/active_release +* Release version: LATEST_SOLANA_RELEASE_VERSION +* Release URL: https://github.com/solana-labs/solana/releases/download/LATEST_SOLANA_RELEASE_VERSION/solana-release-x86_64-unknown-linux-gnu.tar.bz2 +Update successful +``` + +- 根据您的系统,安装程序消息的结束可能稍有不同 + +```bash +请更新您的 PATH 环境变量来包含 Solana 程序: +``` + +- 如果您收到上述消息,复制并粘贴下面的推荐命令来更新 `PATH` +- 通过运行以下命令来确认您已经安装了想要的 `solana` 版本: + +```bash +solana --version +``` + +- 安装成功后,就可以通过 `solana-install update` 随时更新 Solana 软件到新版本。 + +--- + +### Windows 系统 + +- 以管理员身份打开命令提示(`cmd.exe`) + + - 在 Windows 搜索栏中搜索命令提示。 当命令提示应用出现后,右键单击并选择“以管理员打开”。 如果弹出窗口请求“允许此应用进行设备更改?”,请点击是。 + +- 复制并粘贴以下命令,然后按回车下载 Solana 安装程序到临时目录: + +```bash +curl https://release.solana.com/LATEST_SOLANA_RELEASE_VERSION/solana-install-init-x86_64-pc-windows-msvc.exe --output C:\solana-install-tmp\solana-install-init.exe --create-dirs +``` + +- 复制并粘贴以下命令,然后按 Enter 安装最新版本的 Solana 软件。 如果系统弹出安全提示窗口,请选择允许程序运行。 + +```bash +C:\solana-install-tmp\solana-install-init.exe LATEST_SOLANA_RELEASE_VERSION +``` + +- 安装程序完成后,请按 Enter 键。 + +- 关闭命令提示窗口,并以普通用户身份重新打开 + - 在搜索栏中搜索“Command Prompt”,然后点击命令提示应用图标,无需以管理员身份运行) +- 通过运行以下命令来确认您已经安装了想要的 `solana` 版本: + +```bash +solana --version +``` + +- 安装成功后,就可以通过 `solana-install update` 随时更新 Solana 软件到新版本。 + +## 下载预置二进制文件 + +如果您不想通过 `solana-install` 来管理安装,您也可以手动下载并安装二进制安装包。 + +### Linux 系统 + +打开 [https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest), download **solana-release-x86_64-unknown-linux-msvc.tar.bz2** 地址,下载二进制文件,然后提取文件: + +```bash +tar jxf solana-release-x86_64-unknown-linux-gnu.tar.bz2 +cd solana-release/ +export PATH=$PWD/bin:$PATH +``` + +### MacOS 系统 + +打开 [https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest), download **solana-release-x86_64-apple-darwin.tar.bz2** 地址,下载二进制文件,然后提取文件: + +```bash +tar jxf solana-release-x86_64-apple-darwin.tar.bz2 +cd solana-release/ +export PATH=$PWD/bin:$PATH +``` + +### Windows 系统 + +- 打开 [https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest), download **solana-release-x86_64-pc-windows-msvc.tar.bz2** 地址,下载二进制文件,然后提取文件: + +- 打开命令提示并导航到提取二进制文件的目录并运行: + +```bash +cd solana-release/ +set PATH=%cd%/bin;%PATH% +``` + +## 通过源代码安装 + +如果您无法使用预构建的二进制文件或者想通过源代码安装,请打开 [https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest), download **solana-release-x86_64-unknown-linux-msvc.tar.bz2** 地址,下载二进制文件,然后提取文件: 提取代码并生成二进制文件: + +```bash +./scripts/cargo-install-all.sh . +export PATH=$PWD/bin:$PATH +``` + +然后你可以运行以下命令来获得与预置二进制文件相同的结果: + +```bash +solana-install init +``` diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/manage-stake-accounts.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/manage-stake-accounts.md new file mode 100644 index 0000000000..e4ec9c8209 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/manage-stake-accounts.md @@ -0,0 +1,71 @@ +--- +title: 管理质押账户 +--- + +如果想将质押分配到多个不同的验证节点,您需要为每个验证节点创建一个单独的质押帐户。 如果你按照约定创建了一个种子(seed)为"0"的质押帐户,那么第二个则是“1”,第三个是“2”,以此类推,然后您可以使用 `solana-stock-account` 工具对所有的账户进行单次调用。 您可以用它来汇总所有帐户的余额,将帐户移动到一个新钱包,或设置新的权限。 + +## 使用方法 + +### 创建一个质押账户 + +在质押公钥上创建一个派生的质押帐户并转账进去: + +```bash +solana-stake-accounts new \ + --stake-authority --withdraw-authority \ + --fee-payer +``` + +### 账户统计 + +统计派生账户的数量: + +```bash +solana-stake-accounts count +``` + +### 获取质押账户余额 + +汇总派生抵押账户的余额: + +```bash +solana-stake-accounts balance --num-accounts +``` + +### 获取质押账户地址 + +列出来自给定公钥的每一个质押账户地址: + +```bash +solana-stake-accounts addresses --num-accounts +``` + +### 设置新权限 + +为生成的每个抵押帐户设置新权限: + +```bash +solana-stake-accounts authorize \ + --stake-authority --withdraw-authority \ + --new-stake-authority --new-withdraw-authority \ + --num-accounts --fee-payer +``` + +### 重定向质押账户 + +重定向质押账户: + +```bash +solana-stake-accounts rebase \ + --stake-authority --num-accounts \ + --fee-payer +``` + +对每个质押账户进行原子级别重置并授权,请使用 'move' 命令: + +```bash +solana-stake-accounts move \ + --stake-authority --withdraw-authority \ + --new-stake-authority --new-withdraw-authority \ + --num-accounts --fee-payer +``` diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/transfer-tokens.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/transfer-tokens.md new file mode 100644 index 0000000000..24147b5b1f --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/transfer-tokens.md @@ -0,0 +1,125 @@ +--- +title: 发送和接收代币 +--- + +该网页展示了如何通过命令行钱包,使用命令行工具接收和发送 SOL代币,例如 [纸钱包](../wallet-guide/paper-wallet.md), [文件系统钱包](../wallet-guide/file-system-wallet.md), 或[硬件钱包](../wallet-guide/hardware-wallets.md). 在开始之前,请确认您已经创建了一个钱包,并且可以访问其地址 (pubkey) 和签名密钥对。 请查看我们的[约定来输入不同钱包类型的密钥对](../cli/conventions.md#keypair-conventions). + +## 测试您的钱包 + +在与其他人分享公钥前,您可能需要首先确认密钥的有效性,并确保真正拥有相应的私钥。 + +在这个例子中,我们将在第一个钱包的基础上再创建另一个钱包,然后转入一些代币。 这个步骤确保您可以在该钱包正常发送和接收代币。 + +该测试将通过我们的开发者测试网(称为devnet)。 测试网发行的代币**并没有**实际价值,所以无需担心资产损失。 + +#### 获取一些空投代币,开始操作 + +首先,在测试网给您的钱包_空投_ 一些虚拟代币。 + +```bash +solana airdrop 10 --url https://devnet.solana.com +``` + +其中,用您的 base58-encoded 公钥/钱包地址替换此处的 ``文本。 + +#### 检查钱包余额 + +通过检查帐户余额确认空投已经成功。 输出值应当为 `10 SOL`: + +```bash +solana balance --url https://devnet.solana.com +``` + +#### 创建第二个钱包地址 + +我们需要一个新地址来接收代币。 创建第二个密钥对并记录其公钥: + +```bash +solana-keygen new --no-passphrase --no-outfile +``` + +输出将在文本 `pubkey:` 后面包括该地址。 复制该地址。 我们在下一步中要用到它。 + +```text +pubkey: GKvqsuNcnwWqPzzuhLmGi4rzzh55FhJtGizkhHaEJqiV +``` + +您还可以通过下述方式创建任何类型的一个(或多个)钱包: [paper](../wallet-guide/paper-wallet#creating-multiple-paper-wallet-addresses), [file system](../wallet-guide/file-system-wallet.md#creating-multiple-file-system-wallet-addresses), 或者 [hardware](../wallet-guide/hardware-wallets.md#multiple-addresses-on-a-single-hardware-wallet). + +#### 将代币从您的第一个钱包转到第二个地址 + +接下来,通过发送来证明你拥有空投代币。 Solana 集群只有在您用交易发送方公钥对应的私钥签名时,才会接受交易。 + +```bash +solana transfer --from 5 --url https://devnet.solana.com --fee-payer +``` + +其中,用第一个钱包的秘钥对的路径替换 ``,用第二个钱包地址替换 ``。 + +使用 `solana balance` 确认余额已经更新: + +```bash +solana balance --url http://devnet.solana.com +``` + +其中 `` 是您密钥对的公钥或收件人的公钥。 + +#### 转账测试的完整示例 + +```bash +$ solana-keygen new --outfile my_solana_wallet.json # 创建第一个文件系统钱包 +产生新的密钥对 +为了增加安全性,输入一个密码(空白表示不设置密码): +将新密钥对写入 my_solana_wallet.json +========================================================================== +pubkey: DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK # 第一个钱包的地址 +========================================================================== +保存恢复密钥对的助记词: +width enhance concert vacant ketchup eternal spy craft spy guard tag punch # 如果这是一个真实的钱包,不要将这次单词分享到网络上! +========================================================================== + +$ solana airdrop 10 DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK --url https://devnet.solana.com # 空投 10 个 SOL 到我的钱包地址/公钥 +正在从 35.233.193.70:9900 请求 10 SOL +10 SOL + +$ solana balance DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK --url https://devnet.solana.com # 检查钱包余额 +10 SOL + +$ solana-keygen new --no-outfile # 创建第二个钱包即纸钱包 +生成新的密钥对 +为了增加安全性,输入一个密码(空白表示不设置密码): +==================================================================== +pubkey: 7S3P4HxJpyyigGzodYwHtCxZyUQe9JiBMHyRWXArAaKv # 这是第二个钱包即纸钱包的地址 +======================================================= +保存助记词(用于恢复新秘钥对): +clump panic cousin hurt coast charge engage fall eager urge win love # 如果这是一个真实的钱包,切记不要将这次单词分享到网络上! +==================================================================== + +$ solana transfer --from my_solana_wallet.json 7S3P4HxJpyyigGzodYwHtCxZyUQe9JiBMHyRWXArAaKv 5 --url https://devnet.solana.com --fee-payer my_solana_wallet.json # 发送代币到纸钱包的公钥地址 +3gmXvykAd1nCQQ7MjosaHLf69Xyaqyq1qw2eu1mgPyYXd5G4v1rihhg1CiRw35b9fHzcftGKKEu4mbUeXY2pEX2z # 该笔交易的签名 + +$ solana balance DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK --url https://devnet.solana.com +4.999995 SOL # 由于需要 0.000005 SOL 的交易费用,发送金额要稍微小于 5 SOL + +$ solana balance 7S3P4HxJpyyigGzodYwHtCxZyUQe9JiBMHyRWXArAaKv --url https://devnet.solana.com +5 SOL # 第二个钱包现在已经接收到第一个钱包发送的 5 SOL + +``` + +## 接收代币 + +首先您需要一个地址让别人来发送代币。 在 Solana 区块链,钱包地址就是密钥对的公钥。 生成密钥对的方法有好几种。 这些方法取决于您选择如何存储密钥对。 密钥对存储在钱包里。 在接收代币之前,您需要通过 [来创建一个钱包](../wallet-guide/cli.md) 完成该步骤后,您就能获得每个密钥对生成的公钥。 公钥是一个 base58 字符的长字节。 其长度从 32 到 44 个字符不等。 + +## 发送代币 + +如果您已经持有 SOL 并想要向其他人发送代币,您将需要密钥对的路径, 他们的 base58 编码公钥和准备发送的代币。 上述条件准备好了以后,您可以使用 `solana transfer` 命令来发送代币: + +```bash +solana transfer --from --fee-payer +``` + +使用 `solana balance` 确认余额已经更新: + +```bash +solana balance +``` diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/usage.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/usage.md new file mode 100644 index 0000000000..55d056121c --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cli/usage.md @@ -0,0 +1,63 @@ +--- +title: CLI 使用参考 +--- + +[solana-cli crate](https://crates.io/crates/solana-cli) 为 Solana 提供了一个命令行界面工具 + +## 示例: + +### 获取公钥 + +```bash +// 命令 +$solana-keygen pubkey + +// 返回 + +``` + +### 空投 SOL/Lamports + +```bash +// 命令 +$ solana airdrop 2 + +// 返回 +"2.0000000 SOL" +``` + +### 获取余额 + +```bash +// 命令 +$ solana balance + +// 返回 +"3.00050001 SOL" +``` + +### 确认交易 + +```bash +// 命令 +$ solana confirm + +// 返回 +"Confirmed" / "Not found" / "Transaction failed with error " +``` + +### 部署程序 + +```bash +// 命令 +$ solana deploy + +// 返回 + +``` + +## 使用方法 +### +```text + +``` diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/bench-tps.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/bench-tps.md new file mode 100644 index 0000000000..8e8d52ca5a --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/bench-tps.md @@ -0,0 +1,128 @@ +--- +title: 集群基准 +--- + +Solana git 仓库涵盖了配置本地测试网可能用到的所有脚本。 根据实现的目标,您可能想配置一个全新、增强性能的不同版本的多节点测试网,那么它可能比单纯的仅支持 Rust 的单节点测试节点要复杂得多。 如果您正在尝试开发高级功能(例如智能合约),那么利用一些已有的配置,直接使用 Rust 支持的单节点模型就好。 如果您正在对交易流程进行性能优化,请考虑增强的单节点 demo。 如果你在着手共识算法的工作,那么你将至少需要一个 Rust 的多节点 demo。 如果您想要复制 TPS 性能表,请运行强化的多节点 demo。 + +对于上述的四种变型,您可能需要最新的 Rust 工具链和 Solana 源代码: + +首先,请设置 Solana [README](https://github.com/solana-labs/solana#1-install-rustc-cargo-and-rustfmt) 中提到的 Rust、Cargo 和系统安装包。 + +请检查 github 代码: + +```bash +git clone https://github.com/solana-labs/solana.git +cd solana +``` + +演示代码有时在我们添加新的低级功能时会失败,所以如果这是您第一次运行 demo,为了提高成功的概率,请在继续操作之前先查看 [latest release](https://github.com/solana-labs/solana/releases) : + +```bash +TAG=$(git describe --tags $(git rev-list --tags --max-count=1)) +git checkout $TAG +``` + +### 设置配置 + +确保在任何节点启动之前都能建立例如投票程序之类的重要程序。 请注意,为了良好的性能,我们在这里使用版本构建的方式。 如果你想要调试构建,只需使用 `cargo build` 并省略 `NDEBUG=1` 命令的一部分。 + +```bash +cargo build --release +``` + +运行下面的脚本来初始化网络的创世账本。 + +```bash +NDEBUG=1 ./multinode-demo/setup.sh +``` + +### 水龙头 + +为了验证程序和客户端正常工作,我们需要打开一个水龙头来领取一些测试代币。 水龙头按照 Milton Friedman 的风格“空投”\(免费代币给请求客户\),然后用于测试交易。 + +打开水龙头: + +```bash +NDEBUG=1 ./multinode-demo/faucet.sh +``` + +### 单节点测试网 + +在启动验证节点之前,请确保您获取了想要启动验证节点的机器的 IP 地址,并确保 udp 端口 8000-1000 处于打开状态。 + +现在在独立的 shell 中启动验证节点: + +```bash +NDEBUG=1 ./multinode-demo/bootstrap-validator.sh +``` + +等待几秒钟进行初始化。 当准备好接收交易时,它会打印“leader ready...”。 如果领导者没有任何测试代币,它将从水龙头请求一些。 在领导者启动之前,水龙头不用一直运行。 + +### 多节点测试网 + +如果要运行一个多节点测试网,在启动一个领导者节点后,需要在独立 shell 中加入一些额外的验证节点: + +```bash +NDEBUG=1 ./multinode-demo/validator-x.sh +``` + +如果要在 Linux 上运行增强性能验证节点,必须在系统中安装 [CUDA 10.0](https://developer.nvidia.com/cuda-downloads): + +```bash +./fetch-perf-libs.sh +NDEBUG=1 SOLANA_CUDA=1 ./multinode-demo/bootstrap-validator.sh +NDEBUG=1 SOLANA_CUDA=1 ./multinode-demo/validator.sh +``` + +### 测试网客户端演示 + +现在您的单节点或多节点测试网已启动并正常运行了,接下来我们发送一些交易! + +在另一个 shell 启动客户端: + +```bash +NDEBUG=1 ./multinode-demo/bench-tps.sh # runs against localhost by default +``` + +刚刚发生了什么? 客户端演示将尽最快的速度将 500,000 笔交易发送到测试网。 然后客户端定期连接测试网,看看它当时处理了多少笔交易。 请注意,这个 demo 故意将大量 UDP 数据包发送给网络,因此网络几乎会丢失很大一部分。 这确保了试验网有机会达到 710k TPS。 客户端 demo 在确保测试网不再处理任何其他交易后就停止运行。 您应该看到一些 TPS 数值出现在屏幕上。 在多节点变体中,您也会看到每个验证节点的 TPS 测量值。 + +### 测试网调试 + +代码中有一些非常有用的调试消息,您可以在每个模块和每个级别的基础上启用它们。 在运行一个领导者或验证节点之前,请设置正常的 RUST_LOG 环境变量。 + +例如: + +- 要在任意位置启用 `info` 以及只能在 solana::banking_stage 模块中启用 `debug` : + + ```bash +export RUST_LOG=solana=info,solana::banking_stage=debug + ``` + +- 启用 BPF 程序日志记录: + + ```bash +export RUST_LOG=solana_bpf_loader=trace + ``` + +一般来说,我们正在使用 `debug` 处理不经常的调试消息, `trace` 处理可能频繁的消息, `info` 用于与性能相关的记录。 + +您也可以通过 GDB 附加到一个运行过程。 领导者进程命名为 _solana-validator_: + +```bash +sudo gdb +attach +set logging on +thread apply all bt +``` + +这将把所有线程堆栈跟踪转储到 gdb.txt + +## 开发者测试网 + +在此示例中,我们将把客户端连接到公共测试网。 在测试网上运行验证器,您需要打开 udp 端口 `8000-1000`。 + +```bash +NDEBUG=1 ./multinode-demo/bench-tps.sh --entrypoint devnet.solana.com:8001 --faucet devnet.solana.com:9900 --duration 60 --tx_count 50 +``` + +您可以在 [metrics dashboard](https://metrics.solana.com:3000/d/monitor/cluster-telemetry?var-testnet=devnet) 上观察客户端交易的影响 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/fork-generation.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/fork-generation.md new file mode 100644 index 0000000000..74713c7adb --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/fork-generation.md @@ -0,0 +1,64 @@ +--- +title: 生成分叉 +--- + +本节描述了由于 [轮换领导者](leader-rotation.md) 而自然产生分叉的情况。 + +## 概览 + +节点会变为领导者并生成编码更改的 PoH。 群集可以通过综合领导者 _**可能**_ 生成的内容,来容忍与任何领导者的连接中断,但不会进行任何的状态更改。 因此可能的分叉数量仅限于“有/无”跳过在领导者轮换时,在插槽边界可能出现的分叉列表。 在任何指定的插槽上,只接受一名领导者的交易。 + +## 消息流 + +1. 交易被当前的领导者吸纳。 +2. 领导者过滤有效的交易。 +3. 领导人执行有效交易的状态更新。 +4. 以当前 PoH 插槽为基础的领导者软件包交易记录。 +5. 领导者将条目传送到验证节点 \(嵌入签名的碎片\) + 1. PoH 流包括滴答计数;空白条目显示了领导者的主动性和集群时间的流逝。 + 2. 领导者传输首先是必要的滴答目录,以便 PoH 返回领导者最近观察到的上一个领导者插槽。 +6. 验证节点将条目重新传输给他们集合中的对等点和未来的下游节点。 +7. 验证节点验证交易并在其状态下执行它们。 +8. 验证节点计算状态的哈希值。 +9. 在特定时间, 例如特定的 PoH 滴答计数, 验证节点将投票传给领导者。 + 1. 投票是指计算状态的 PoH 滴答计数的哈希签名。 + 2. 投票也是通过 Gossip 进行传播的。 +10. 领导者进行与任何其他交易相同的选票,并将投票广播到集群。 +11. 验证节点观察他们的投票和该集群的所有选票。它 + +## 分区,分叉 + +在 PoH 滴答计数时,可能出现与投票相对应的分叉。 下一位领导者可能没有观察到最后一次投票,可能会用生成的虚拟 PoH 条目开始它们的插槽。 这些空白滴答是由集群中的所有节点按集群配置的每次滴答哈希 `Z` 生成的。 + +投票时间段中只能有两个版本的 PoH :`T` 滴答的 PoH 并且有当前领导者生成的条目或仅进行滴答的 PoH。 "只滴答"的 PoH 版本可以被视为一个虚拟账本,集群中的所有节点都可以从上一个插槽的最后一次滴答产生。 + +验证节点可以在其它方面忽略分叉\(例如从错误的领导者\),或罚没产生分叉的领导者。 + +验证节点根据贪婪算法进行投票,以最大限度提高他们在 [Tower BFT](../implemented-proposals/tower-bft.md) 中描述的奖励。 + +### 验证节点视图 + +#### 时间进度 + +下面图表代表了验证器关于 PoH 流的视图,以及一段时间内可能的分叉。 L1、L2 等是领导者插槽, `E`s 代表领导者插槽中的领导者条目。 `x`s 代表仅滴答,时间流向图表下方。 + +![生成分叉](/img/fork-generation.svg) + +注意,在同一个槽位的两个分叉上显示 `E` 是一个可罚没条件,因此一个验证节点观察 `E3` 和 `E3` 可以对 L3 进行罚没,该插槽安全地选择 `x`。 一旦验证节点承认了某个分叉,在该滴答下方的其他分叉可以被丢弃了。 对于任何插槽,验证节点只需要考虑一个单一的“有条目”链或一个由一位领导者提出的“只滴答”的链。 但由于多个虚拟条目与上一个插槽相连接,它们可能会重叠。 + +#### 时间分隔 + +将领导者轮换对 PoH 滴答计数视为集群编码状态的时间分隔非常有用。 下表列出了上述分叉树作为一个时间分隔的帐本。 + +| 领导者插槽 | L1 | L2 | L3 | L4 | L5 | +|:------- |:-- |:-- |:-- |:-- |:-- | +| 数据 | E1 | E2 | E3 | E4 | E5 | +| 自上次起的滴答 | | | | x | xx | + +请注意,领导者插槽 L3 期间只接受来自领导者 L3 的数据。 如果 L3 没有观察到 L2 的数据,L3 的数据可能包括回到 L2 以外的另一个插槽。 L4 和 L5 的传输包括“ticks to prev” PoH 条目。 + +网络数据流的这种结构允许节点将其准确保存到账本,用于重新播放、重新启动和检查点。 + +### 领导者视图 + +当新的领导者开始一个插槽时,它必须首先发送将新插槽与最近观察到并投票的插槽链接所需的任何 PoH \(ticks\)。 领导者提议的分叉将把目前的插槽连接到前一个分叉,而前一个分叉是该分叉的虚拟分叉。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/leader-rotation.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/leader-rotation.md new file mode 100644 index 0000000000..f6a662c983 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/leader-rotation.md @@ -0,0 +1,88 @@ +--- +title: 领导者轮换 +--- + +在任何时候,集群都只需要一个验证节点来生成账本条目。 由于每次只有一个领导者,所有验证节点都能够重复相同的账本副本。 然而,一次只有一名领导者的缺点是,恶意领导者可能会审查选票和交易。 由于审查无法同网络丢弃数据包区分开,因此集群不能简单地选择某一个节点来长期担任领导者角色。 相反,集群通过轮换来决定哪个节点担任领导者,从而最大限度减少恶意领导者的影响。 + +每个验证节点使用下文描述的同一种算法来选择预期的领导者。 当验证节点收到一个新的签名账本条目时,可以肯定某条目是来自预期的领导者。 分配给每位领导者的插槽顺序称为 _leader schedule(领导者安排表)_。 + +## 领导者轮换计划 + +一个验证节点会拒绝未经过 _插槽领导者_ 签名的区块。 所有插槽领导者的身份列表称为 _领导者安排表_。 领导者安排表是通过本地定期重新计算产生的。 它指派插槽领导者持续一段称为 _epoch(纪元)_ 的时间。 安排表必须早于它分配的时间段, 这样它保证了计算计划的账本状态最后能够确定。 该持续时间称为 _领导者安排表偏移时间_。 Solana 将偏移时间设置为直到下一个 epoch 的插槽持续时间。 也就是说,一个 epoch 的领导者计划通过上一个 epoch 开始时的账本状态来计算得到。 一个纪元的偏移量是比较随意的,并且假定时间足够长,使所有验证节点都将在生成下一个计划之前确定其账本状态。 集群可以选择缩短偏移时间,来缩短质押变化与领导者计划更新之间的时间。 + +在没有分区的情况下运行时间比一个 epoch 长的时候,只有在根分叉的 epoch 边界才能生成安排表。 由于安排表用于下一个纪元,因此在下一个纪元之前,任何质押给根分叉的新质押都不会被激活。 用于生成领导者计划的区块是跨过纪元边界的第一个区块。 + +如果分区比一个 epoch 时间短,集群将按以下方式运作: + +1. 验证节点在投票时不断更新自己的根分叉。 +2. 每次在纪元边缘的插槽高度的时候,验证节点将更新其领导者安排表。 + +例如: + +Epoch 持续时间为 100 个插槽。 根分叉从在插槽高度 99 处计算的分叉更新为在插槽高度 102 处计算出来的。 由于故障,跳过了插槽高度分别为 100、101 的分叉。 新的领导者计划通过分叉在高度为 102 的位置计算出来。 在插槽 200 中它处于活动状态,直到再次更新。 + +不会存在共识不一致的情况,因为当群集的根节点通过 102 时,对群集进行投票的每个验证节点都跳过了 100 和 101。 无论采用哪种投票方式,所有验证节点都将提交为 102 或 102 后代的根。 + +### 带有纪元分区的领导者轮换计划。 + +领导者安排表偏移的持续时间与群集对正确的领导者安排表不一致的可能性有直接关系。 + +考虑以下几种假设情况: + +两个分区正在生成每个区块的一半。 但它们两个都不是最终的大多数分叉。 两者都将跨过纪元 100 和 200,而实际上并没有形成一个根,因此将在整个集群范围内承诺一个新的领导者安排表。 + +在这种不稳定的情况下,存在多个有效的领导者计划。 + +- 这时候,系统将为直系父级在上一个纪元的每个分叉生成一个领导者安排表。 +- 领导者安排表在后代分叉的下一个纪元开始后才有效,直到更新为止。 + +每个分区的日程表将在一个分区持续超过一个纪元之后发生变化。 因此,纪元持续时间应当设置为远大于插槽时间和分叉提交到根的预期长度。 + +在观察集群足够长的时间后,可以根据中位数分区持续时间及其标准偏差来选择领导者安排表偏移量。 例如,偏移量长于中位数分区持续时间再加上六个标准偏差,则可以将群集中账本计划不一致的可能性降低到百万分之一。 + +## 生产创世领导者安排表 + +创世配置声明第一个纪元的第一个领导者。 该领导者计划在前两个纪元结束,因为领导者计划也在下一个时期的插槽 0 中生成。 前两个纪元的长度也可以在创世配置中指定。 前几个纪元的最小长度必须大于或等于 [Tower BFT](../implemented-proposals/tower-bft.md) 中定义的最大回滚深度。 + +## 创世领导者安排表算法 + +领导者时间表通过预定义的种子生成。 过程如下: + +1. 定期使用 PoH 滴答高度 \(单调递增的计数器\) 产生稳定的伪随机算法种子。 +2. 在该高度下,对银行中所有具有领导者身份且已在集群配置的滴答中进行投票的抵押帐户进行抽样。 该示例被称为 _活动集合(activate set)_。 +3. 按质押权重对活动集进行排序。 +4. 使用随机种子选择按质押加权的节点,来创建质押加权排序。 +5. 在群集配置的一定滴答后,该排序开始生效。 + +## 安排表攻击矢量 + +### 种子 + +所选择的种子是可预测的,但是不存在偏差。 没有任何可怕的攻击会影响其结果。 + +### 活动集 + +领导者可以通过审查验证人的投票来使活动集偏差。 领导者可能通过两种方式来审查活动集: + +- 忽略验证节点的投票 +- 拒绝使用验证节点的票对区块进行投票 + +为了减少审查的可能性,在_活动集采样期间_,网络将在领导者安排表偏移量边界上计算活动集。 有效设置的采样持续时间足够长,从而让多个领导者收集到投票。 + +### 质押 + +领导者可以审查新的质押交易,或拒绝验证有新质押的区块。 这种攻击类似于对验证节点选票的审查。 + +### 验证节点操作密钥丢失 + +领导者和验证节点应使用临时密钥进行操作,而质押所有者授权验证节点通过委托来处理其质押。 + +群集应该能够能通过领导者和验证者丢失的所有临时密钥进行恢复,这可能是所有节点共享出现的常见软件漏洞。 质押所有人应该能够通过共同签署验证节点的投票直接进行表决,即使质押已经委托给验证节点。 + +## 追加条目 + +领导者时间表的生命周期称为一个 _纪元(epoch)_。 纪元又划分为多个 _插槽_,每个插槽的持续时间 `T` 称为 PoH 滴答时间。 + +领导者在其插槽期间发送条目。 在 `T` 滴答时间后,所有验证节点都将切换到下一个预定的领导者。 验证节点必须忽略在领导者指定的插槽之外发送的条目。 + +下一位领导者必须观察所有的 `T` 滴答,以便其建立自己的条目。 如果没有观察到条目\(领导者掉线\) 或条目无效 \(领导者故障或作恶\), 则下一个领导者必须滴答来填充前一个领导者的插槽。 请注意,下一位领导者应并行执行维修请求,并推迟发送滴答,直到确信其他验证节点也没有观察到上一位领导者的条目。 如果领导者错误地产生自己的滴答,那么跟随它的领导者必须替换其所有滴答。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/managing-forks.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/managing-forks.md new file mode 100644 index 0000000000..e2201d9442 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/managing-forks.md @@ -0,0 +1,36 @@ +--- +title: 管理分叉 +--- + +在插槽边界处,账本是可能会产生分叉的。 产生的数据结构形成一个称为 _块存储(blockstore)_ 的树。 验证器解释blockstore时,它必须维护区块链中每个分叉的状态。 我们称每个实例为 _活跃分叉(active fork)_。 验证节点有责任对这些分叉进行权衡,从而最终选择一个分叉。 + +验证节点通过向该分叉的插槽负责人投票来选择一个分叉。 投票将让验证节点提交一个称为 _锁定期(lockout period)_的持续时间。 在该锁定期到期之前,验证节点无法对其他分叉进行投票。 随后,对同一分叉的每次投票都会将把锁定期延长一倍。 经过一些群集配置的投票数\(当前为32 \) 后,锁定期的持续时间达到了所谓的_最长锁定期(max lockout)_。 在达到最长锁定期之前,验证节点可以选择一直等待,直到锁定期结束然后再投票给另一个分叉。 当它在另一个分叉上投票时,所执行称为 _回滚(rollback)_ 的操作,此时状态会及时回滚到共享检查点,然后跳转到刚刚投票分叉的初始位置。 分叉能够回滚的最大限度称为 _回滚深度(rollback depth)_。 回滚深度是达到最长锁定期所需的票数。 每当验证节点投票时,超出回滚深度的所有检查点都将无法访问。 也就是说,在任何情况下,验证节点回滚的限度都不用超过回滚深度。 因此,它可以安全地 _修剪(prune)_ 无法到达的分叉,并将超出回滚深度的所有检查点 _局限(squash)_ 于根检查点中。 + +## 活跃分叉 + +活跃的分叉是一系列检查点,其长度至少比回滚深度长一倍。 最短分叉的长度刚好为回滚深度的一倍。 例如: + +![分叉](/img/forks.svg) + +以下序列是 _活跃分叉_: + +- {4, 2, 1} +- {5, 2, 1} +- {6, 3, 1} +- {7, 3, 1} + +## 修剪和挤压 + +验证节点可以对树中的任何检查点进行投票。 在上图中,就是除了树叶以外的每个节点。 投票后,验证节点修剪从比回滚深度更远的距离派生的节点,然后通过将其可以挤压到根部的任何节点,利用机会来最小化其内存使用量。 + +从上面的示例开始,回滚深度为 2,考虑对 5 投票与对 6 投票。 首先,对 5 进行投票: + +![修剪后的分叉](/img/forks-pruned.svg) + +新的根为 2,任何不为 2 后代的活跃分叉都会被修剪。 + +或者,对 6 进行投票: + +![分叉](/img/forks-pruned2.svg) + +该树的根始终为 1,因为从 6 开始的活跃分叉距它仅有 2 个检查点。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/overview.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/overview.md new file mode 100644 index 0000000000..b70a1bcb08 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/overview.md @@ -0,0 +1,42 @@ +--- +title: Solana 集群 +--- + +Solana 集群是一组验证人,共同为客户交易服务并保持账本的完整性。 可能存在着多个集群。 当两个集群都来自同一个创世区块时,它们会趋向收敛。 否则,他们就会忽略了另一个集群的存在。 发送到错误集群的交易会慢慢被拒绝。 在本章节,我们将讨论创建集群、节点加入集群、共享账本、确保账本被复制以及处理有漏洞和恶意的节点。 + +## 创建一个集群 + +在启动任何验证节点之前,首先需要创建一个_创世配置_。 该配置引用了两个公钥,一个_铸造_和一个_引导验证节点_。 拥有引导验证节点私钥的验证节点负责将第一个条目附加到账本。 它使用铸造帐户初始化其内部状态。 该帐户将保存由创世配置定义的原生代币数。 然后,第二个验证节点联系引导验证节点,来注册为一个 _验证节点_。 然后,其他验证节点将在集群的任何已注册成员中注册。 + +验证节点会收到领导者的所有条目,并提交投票以确认这些条目的有效性。 投票后,验证节点需要存储这些条目。 一旦验证节点发现存在足够多的副本,它将删除自身的副本。 + +## 加入一个集群 + +验证节点通过发送到_控制台(control plane)_的注册消息进入集群。 控制台使用 _八卦(gossip)_ 协议实现,这意味着节点可以向任何现有节点注册,并期望其注册传播到集群中的所有节点。 所有节点同步所需的时间与参与群集节点数的平方成正比。 从算法上讲,人们都认为它非常慢,但是牺牲时间所换来的,就是一个节点可以确保它最终拥有与每个其他节点相同的信息,并且任何一个节点都无法审查该信息。 + +## 将交易发送到集群 + +客户端将交易发送到任何验证节点的交易处理单元\(TPU\) 端口。 如果该节点处于验证节点角色,则它将交易转发给指定的领导者。 如果处于领导者角色,则该节点将传入的事务捆绑在一起,对其打上时间戳,来创建一个_条目(entry)_,然后将其推送到集群的 _数据中心(data plane)_。 进入数据中心后,交易将由验证节点进行验证,从而将交易有效地添加到账本中。 + +## 确认交易 + +Solana集群能够在亚秒级的时间内_确认(confirmation)_ 最多150个节点,并计划扩展到成千上万个节点。 一旦完全实施,确认时间预计只会随着验证节点数量的对数而增加,而对数的基数又很高。 例如,如果基数为一千,则意味着对于前一千个节点,确认将是三个网络跃点的持续时间加上一个最慢验证节点进行投票所花费的时间。 对于接下来的一百万个节点,确认仅增加一个网络跃点。 + +Solana将确认定义为从领导者为新条目添加时间戳到达成账本的绝大多数投票为止的持续时间。 + +八卦网络增长到一定规模后,就会变得太慢而无法实现亚秒级确认。 将消息发送到所有节点所花费的时间与节点数的平方成正比。 如果区块链想要获得低确认率并尝试使用八卦网络来做到这一点,它将被迫集中到少数几个节点上。 + +可以使用以下技术组合来实现可扩展的确认: + +1. 使用VDF样本对交易打上时间戳并签名。 +2. 将交易分为几批,将每笔交易发送到单独的节点,同时 + + 每个节点都与对等节点共享其批次。 + +3. 递归地重复上一步,直到所有节点都具有所有批次。 + +Solana以固定的时间间隔(称为_插槽_)轮换领导者。 每个领导者只能在其分配的时段内产生条目。 领导者因此对交易加上时间戳记,以便验证节点可以查找指定领导者的公钥。 然后,领导者对时间戳进行签名,以便验证节点验证签名,证明签名者是指定领导者公钥的所有者。 + +接下来,将交易分成批处理,以便节点可以将交易发送给多方,而无需进行多份复制。 例如,如果领导者需要将60笔交易发送到6个节点,则它将把60笔交易的集合分成10笔交易的批次,并向每个节点发送一个交易。 这能够让领导者将60笔交易放在网络上,而不是每个节点60笔交易。 接着,每个节点都与对等节点共享其批次。 一旦节点收集了全部6个批次,它将重建60个交易的原始集合。 + +一批交易只能进行多次拆分,直至它变得非常小,信息头成为网络带宽的主要负载。 在撰写本文时,该方法最多可扩展至约150个验证节点。 为了扩展到成千上万个验证节点,每个节点可以将与引导者节点相同的技术应用于另一组相同大小的节点。 我们称这种技术为 [_(涡轮区块传播)Turbine Block Propogation_](turbine-block-propagation.md)。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/performance-metrics.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/performance-metrics.md new file mode 100644 index 0000000000..1a0542357d --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/performance-metrics.md @@ -0,0 +1,25 @@ +--- +title: 性能指标 +--- + +Solana群集性能的衡量标准是网络可以维持的每秒平均交易数\(TPS\)。 并且,交易需要多长时间才能由群集的大多数\(确认时间\) 确认。 + +每个群集节点都维护各种计数器,它们随着某些事件增加。 这些计数器会定期上传到一个云数据库。 Solana的指标仪表板获取这些计数器,并计算性能指标,将其显示在仪表板上。 + +## TPS + +每个节点库运行时都维护一个已处理的交易计数。 仪表板首先计算集群中所有启用了指标的节点之间的交易中位数。 然后将中位数集群交易计数在2秒的时间段内取平均值,并显示在TPS时间序列图中。 仪表板还显示了TPS均值、最大TPS和总交易计数统计信息,这些统计信息都是根据交易次数的中位数计算得出的。 + +## 确认时间 + +每个验证器节点都维护一个可见的活跃账本分叉列表。 当节点已接收并处理了与该分叉相对应的所有条目时,该分叉被视为冻结。 当分叉获得了累积的绝大多数投票,并且其中一个子分叉被冻结时,该分叉将被视为已确认。 + +节点为每个新的分叉分配一个时间戳,并计算确认分叉所花费的时间。 此时间在性能指标中即为验证节点确认时间。 性能仪表板将每个验证节点的确认时间的平均值显示为时间序列图。 + +## 硬件设置 + +验证节点软件已部署到配有1TB pd-ssd磁盘和2x Nvidia V100 GPU的GCP n1-standard-16实例。 它们部署在us-west-1地区。 + +solana-bench-tps从网络在配有n1-standard-16 CPU实例的客户机的网络收敛之后开始计算,该客户机参数如下: `--tx\_count=50000 --thread-batch-sleep 1000` + +在bench-tps重新开始阶段的5分钟内,TPS和确认时间指标从仪表板编号中获取。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/rpc-endpoints.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/rpc-endpoints.md new file mode 100644 index 0000000000..c07f2f37a3 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/rpc-endpoints.md @@ -0,0 +1,18 @@ +--- +title: Solana 集群 RPC 端点 +--- + +Solana 维护专用的 API 节点来完成 [JSON RPC](developing/clients/jsonrpc-api.md) 对每个公共集群的请求,第三方同样可以提供托管 API 节点服务。 以下为目前可用的公共 RPC 端点,推荐给每个公共集群: + +## Devnet(开发者网络) + +- `https://devnet.solana.com` - 单个 Solana 托管的 api 节点;限定频率 + +## Testnet(测试网) + +- `https://testnet.solana.com` - 单个 Solana 托管的 api 节点;限定频率 + +## Mainnet Beta(主网 Beta) + +- `https://api.mainnet-beta.solana.com` - Solana 托管的 api 节点集群,由负载平衡器支持;限定频率 +- `https://solana-api.projectserum.com` - Project Serum 托管的 api 节点 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/stake-delegation-and-rewards.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/stake-delegation-and-rewards.md new file mode 100644 index 0000000000..a03ccb27ae --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/stake-delegation-and-rewards.md @@ -0,0 +1,194 @@ +--- +title: 质押委托和奖励 +--- + +质押者因帮助验证账本而获得奖励。 他们通过将其质押委托给验证节点来做到这一点。 这些验证节点会进行繁重的工作,广播账本,并将选票发送到每个节点的投票帐户(其中质押者可以委托其质押)。 当出现分叉时,集群的其余部分使用那些质押加权投票来选择一个区块。 验证节点和质押者都需要某种经济激励来发挥作用。 验证节点的硬件需要得到补偿,质押者需要获得奖励来降低其质押风险。 该部分设计详见[质押奖励](../implemented-proposals/staking-rewards.md)。 本章节将描述其实现的基本机制。 + +## 基本设计 + +通常的想法是验证节点有一个投票帐户。 投票帐户跟踪验证节点的投票,对验证节点产生的信用进行计数,并提供其他任何针对验证节点的状态。 投票帐户无法悉知委托给它的任何质押,账号本身也没有质押。 + +单独的质押帐户 \(由质押者创建\) 命名了一个将质押委托的投票帐户。 所产生的奖励与质押的lamports数量成正比。 质押帐户仅由质押人拥有。 此帐户中存储的某些部分Lamport属于质押。 + +## 被动委托 + +无需控制投票帐户或向该帐户提交投票的身份进行交互操作,任何数量的质押帐户都可以委托给一个投票帐户。 + +可以通过将投票帐户pubkey作为 `StakeState::Stake::voter_pubkey` 的所有质押帐户的总和,来计算分配给Vote帐户的总质押。 + +## 投票和质押账户 + +奖励过程分为两个链上程序。 投票程序解决了让质押处于罚没的问题状态。 质押计划是奖励池的托管人,提供被动委托。 当显示质押者的代表已参与验证账本时,Stake程序负责向质押者和投票者支付奖励。 + +### 投票状态 + +VoteState是验证节点已提交给网络的所有投票的当前状态。 VoteState包含以下状态信息: + +- `投票` - 提交的投票数据结构。 +- `积分` - 该投票程序在其整个生命期内产生的奖励总额。 +- `root_slot` - 达到奖励所需的全部锁定的最后一个插槽。 +- `佣金` - VoteState从质押者的Stake帐户获得的任何奖励中抽取的佣金。 这是奖励的百分比上限。 +- Account::lamports - 佣金累计获得的lamports。 这些并不算作质押。 +- `authorized_voter` - 只有该身份能提交投票。 此字段只能通过身份认证进行修改。 +- `node_pubkey` - 在这个帐户中投票的 Solana 节点。 +- `authorized_withdrawer` - 负责该账户lamports 实体的身份,独立于帐户地址和授权的投票签名者。 + +### VoteInstruction::Initialize\(VoteInit\) + +- `account[0]` - RW - 选票状态。 + + `VoteInit` 带有新投票帐户的 `node_pubkey`, `authorized_porer`, `authorized_withdrawer`, 和 `commission`。 + + 其他投票状态成员处于默认状态。 + +### VoteInstruction::Authorize\(Pubkey, VoteAuthorize\) + +根据VoteAuthorize参数\(`投票者`或 `提款者`\),使用新的授权投票人或提款人更新帐户。 交易必须由投票帐户当前的` 授权投票人`或`授权提款人`签名。 + +- `account[0]` - RW - VoteState。 `VoteState::authorized_voter` 或 `authorized_withdrawer` 设置为 `Pubkey`. + +### VoteInstruction::Vote\(Vote\) + +- `account[0]` - RW - The VoteState。 `VoteState::lockouts` 和 `VoteState::credit` 是根据投票锁规则更新的,参考 [Tower BFT](../implemented-proposals/tower-bft.md)。 +- `account[1]` - RO - `sysvar::slot_hash` 需要验证投票反对的一些 N 最近插槽及其哈希列表。 +- `account[2]` - RO - `sysvar::clock` 当前的网络时间,以 slot、epoch 等表示。 + +### 质押状态(StakeState) + +StakeState 通常为这个四种形式之一,StakeState::Uninitialized、StakeState::Initialized、StakeState::Stake 以及 StakeState::RewardsPool。 质押中仅使用前三种形式,但是只有 StakeState::Stake 非常有趣。 所有奖励池都是在创始时创建的。 + +### StakeState::Stake + +StakeState:: Stake 是**质押者**的当前委托首选项,并包含以下状态信息: + +- Account::lamports - 可用于质押的 lamports。 +- `stake` - 产生奖励的 \(受到预热和冷却的影响\)质押,总是小于或等于 Account::lampport。 +- `voter_pubkey` - 把 lamport 委托给 VoteState 实例的 pubkey 。 +- `credits_observed` - 在程序的整个生命周期内获得的总积分。 +- `activated` - 激活/委托质押的epoch。 所有质押将在预热后计算在内。 +- `deactivated` - 停用此质押的epoch,在完全停用帐户之前需要一些冷却epoch,才能提取质押。 +- `authorized_staker` - 必须签名委托,激活和停用交易的实体的公钥。 +- `authorized_withdrawer` - 负责该帐户实体的身份,独立于帐户的地址和授权质押者。 + +### StakeState::RewardsPool + +为避免单个网络范围内的兑换锁定或争用,在预先确定的密钥下创世的一部分包括256个奖励池,每个密钥具有std::u64::MAX信用额度,以便能够根据积分值满足赎回要求。 + +质押和奖励池是同一`质押`程序所拥有的帐户。 + +### StakeInstruction::DelegateStake + +质押账户从初始化形式转移到StakeState::Stake形式,或者从已停用(即完全冷却)的StakeState::Stake转变为激活的StakeState::Stake。 这是质押者选择其质押账户Lamport委托给的投票帐户和验证节点节点的方式。 交易必须由质押的`授权质押者`签名。 + +- `account[0]` - RW - StakeState::Stake 实例。 `StakeState::Stake::credits_observed` 已初始化到 `VoteState::credits`,`StakeState::Stake::voter_pubkey` 已初始化到 `account[1]`。 如果这是首次委托质押,`StakeState::Stake::stake` 会被初始化到账户的 lamports余额,`StakeState::Stake::activated` 被初始化到 Bank epoch,并且 `StakeState::Stake::deactivated` 被初始化到 std::u64::MAX +- `account[1]` - R - VoteState 实例。 +- `account[2]` - R - sysvar::clock 账户,包含有关当银行时间的信息。 +- `account[3]` - R - sysvar::stakehistory 帐户,包含有关质押历史的信息。 +- `account[4]` - R - stake::Config 帐户,负责预热,冷却和罚没配置。 + +### StakeInstruction::Authorize\(Pubkey, StakeAuthorize\) + +根据质押授权参数\(`质押者` 或 `提款人`\),使用新的授权质押者或提款人更新帐户。 交易必须由质押帐户当前的`授权质押人`或`授权提款者`签名。 任何质押锁定必须已到期,或者锁定托管人也必须签名交易。 + +- `account[0]` - RW - StakeState。 + + `StakeState::authorized_staker` 或 `authorized_withdrawer` 已设置为 `Pubkey`。 + +### StakeInstruction::Deactivate + +质押持有者可能希望从网络中提款。 为此,他必须首先停用自己的质押,然后等待冷却。 交易必须由质押的`授权质押者`签名。 + +- `account[0]` - RW - 读写正在停用的 StakeState::Stake 实例。 +- `account[1]` - R - 带有当前时间的 Bank 的 sysvar::clock 帐户。 + +StakeState::Stake::deactivated 停用设置为当前时间+冷却时间。 到那个epoch,帐户的质押将减少到零,并且Account::lamports将可以提款。 + +### StakeInstruction::Withdraw\(u64\) + +Lamports会随着时间在一个质押账户中累积,超过已激活质押的任何多余部分都可以提取。 交易必须由质押的`授权提款人`签名。 + +- `account[0]` - RW - 需要取款的 StakeState::Stake。 +- `account[1]` - RW - 应当计入已提取Lamport的帐户。 +- `account[2]` - R - 带有当前时间的 Bank sysvar::clock 账户,用于计算质押。 +- `account[3]` - R - 来自 Bank 的 sysvar::stake_history 帐户,具有质押预热/冷却历史记录。 + +## 这种设计的好处 + +- 所有质押者进行一次投票。 +- 清除积分变量对于索取奖励不是必需的。 +- 每个委派的质押都可以独立索取奖励。 +- 当委托质押要求奖励时,将交纳工作佣金。 + +## 示例通话流 + +![被动质押调用流](/img/passive-staking-callflow.png) + +## 质押(Staking)奖励 + +此处概述了验证者奖励制度的具体机制和规则。 通过将质押委托给正确投票的验证人来赚取奖励。 投票不正确会使验证者的质押面临[slashing(罚没)](../proposals/slashing.md)的风险。 + +### 基础知识 + +网络获得一部分网络[通胀](../terminology.md#inflation)奖励。 可用于支付时间奖励的Lamports数量是固定的,并且必须根据它们的相对权重和参与度在所有质押节点之间平均分配。 加权单位称为[积分(point)](../terminology.md#point))。 + +一个epoch结束以后,才能获得该epoch的奖励。 + +在每个epoch结束时,将在该epoch期间获得的总积分求和,并用于划分epoch通货膨胀的奖励,求出一个积分值。 该值记录在将时间映射到点值的[sysvar](../terminology.md#sysvar)中。 + +在赎回期间,质押计划会计算每个epoch的质押所赚取的点数,再乘以该epoch的点值,然后根据奖励账户的佣金设置将该金额的Lamports从奖励账户转移到质押和投票账户中。 + +### 经济学 + +一个epoch的积分取决于总的网络参与度。 如果参与epoch缩短,则那些参与epoch的分值会更提高。 + +### 赚取积分 + +验证节点对于超出最大锁定范围的每一个正确投票都会获得一票积分,即,每次验证节点的投票帐户从其锁定列表中退出某个版位时,该投票就将成为该节点的根。 + +委派给该验证程序的抵押人根据其所持质押比例获得积分。 所获得的积分是投票信用和质押的乘积。 + +### 质押预热、冷却与取回 + +质押委托以后就不会立即生效。 他们必须首先经过一个预热期。 在此期间,质押的某些部分被视为“有效”,其余部分被视为“激活”。 变化发生在epoch边界上。 + +质押程序将更改总网络质押的速率限制在质押程序的`config::warmup_rate`中\(在当前实现中设置为每个epoch 25%\)。 + +每个epoch可以预热的质押数量是前一个epoch的总有效质押,总激活质押,以及质押程序配置的预热率的函数。 + +冷却时间的工作方式相同。 取消抵押以后,某些部分将被视为“有效”,也被视为“停用”。 随着质押冷却,质押继续获得奖励并有罚没风险,但也可以取回。 + +引导质押则不需预热。 + +奖励是针对该epoch的“有效”质押部分进行支付的。 + +#### 预热示例 + +考虑在第 N 个 epoch 激活了 1,000 个单一质押的情况,网络预热率为 20%,第 N 个 epoch 的静态总网络质押为 2,000 个。 + +在第 N + 1 个阶段,可激活的网络数量为400 \(2000的20%\),在第 N 个阶段,此示例质押是唯一激活的质押,因此有权使用所有的预热质押。 + +| epoch | 有效的 | 激活中 | 总有效 | 总激活中 | +|:----- | ----:| -----:| -----:| -----:| +| N-1 | | | 2,000 | 0 | +| N | 0 | 1,000 | 2,000 | 1,000 | +| N+1 | 400 | 600 | 2,400 | 600 | +| N+2 | 880 | 120 | 2,880 | 120 | +| N+3 | 1000 | 0 | 3,000 | 0 | + +如果在epochN激活了2个质押(X和Y),他们将按其质押的比例获得20%的一部分。 在每个epoch,每个质押的有效和激活是前一个epoch的状态的函数。 + +| epoch | 有效 X | 激活 X | 有效 Y | 激活 Y | 总有效 | 总激活中 | +|:----- | ----:| -----:| ----:| ----:| -----:| -----:| +| N-1 | | | | | 2,000 | 0 | +| N | 0 | 1,000 | 0 | 200 | 2,000 | 1,200 | +| N+1 | 333 | 667 | 67 | 133 | 2,400 | 800 | +| N+2 | 733 | 267 | 146 | 54 | 2,880 | 321 | +| N+3 | 1000 | 0 | 200 | 0 | 3,200 | 0 | + +### 提现 + +任何时候都只能提取超过有效+激活质押的Lamports。 这意味着在预热期间,实际上无法取回任何抵押。 在冷却期间,超过有效质押的任何代币都可能被取回\(activating == 0\)。 由于赚取的奖励会自动添加到质押中,因此通常只有在停用后才可以提现。 + +### 锁定 + +质押账户支持锁定的概念,直到指定的时间,提款账户的余额才能提现。 锁定指定为一个epoch高度,即在可提取质押账户余额之前网络必须达到的最小epoch高度,除非交易也由指定的托管人签署。 此信息在创建质押帐户时收集,并存储在质押帐户状态的Lockup字段中。 更改授权的质押者或提款人也会受到锁定,因为这样的操作实际上就是转移代币。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/synchronization.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/synchronization.md new file mode 100644 index 0000000000..a57fac2417 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/synchronization.md @@ -0,0 +1,28 @@ +--- +title: 同步 +--- + +快速、可靠的同步是 Solana 实现超高吞吐量的最大原因。 同步到包含大量交易的传统区块链被称为区块。 通过在区块上同步,某笔交易只能在一个被称为“区块时间”的时间范围内完成。 工作量证明共识的区块时间通常非常大 \(~10分钟\) 才能最大限度地减少多个验证节点同时生成一个新有效区块的概率。 权益证明共识则不存在这样的限制,但它缺乏可靠的时间戳,验证节点无法决定进入区块的顺序。 最常见的做法是通过 [挂钟时间戳](https://en.bitcoin.it/wiki/Block_timestamp) 来标记每个区块。 由于时钟偏差和网络延迟的波动,时间戳只能保持一两小时的准确性。 要是该系统顺利运行,它们会增长区块时间,以便合理地确定每个区块上的中位时间戳总在不断增加。 + +Solana 采取了非常独特的做法,称为 _历史证明_ 或 _PoH_。 带有加密证明“时间戳”的领导节点能够证明自上次确认以来,确实已经过了一段时间。 所有哈希到证明中的数据肯定都是在证明之前发生的。 然后该节点将新区块分享给验证节点,它们能够验证这些证据。 区块可以按照任何顺序甚至延迟好几年才传到验证节点那里。 通过这种可靠的同步保证,Solana 能够将区块分解成更小的批量交易,称为 _条目(entries)_。 在达成任何共识之前,条目都会实时传输给验证节点。 + +在技术的角度,Solana 从来都没有发送 _区块_, 但是会使用这个词语来描述验证节点对条目进行投票,最终取得 _确认_。 这样,Solana 的确认时间就可以达到媲美两天苹果设备之间传输的速度。 当前的实现区块时间为 800 毫秒。 + +在这个模式下,条目很快就能传输到验证节点,因为领导节点可以将一组有效的交易归入条目。 验证节点早在投票其有效性之前就处理了这些条目。 以乐观的方式处理交易, 从收到最后一个条目到节点可以投票的期间,实际上不存在延迟。 如果对某个事件 **无法** 达成共识,节点只需要简单地回滚其状态。 这种优化处理技术早在 1981 年就发明了,被称为 [Optimistic Concurrency Control(最优同值控制)](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.65.4735)。 它也可以应用到区块链结构中,其中一个集群对代表整个账本的哈希进行投票,直到达到某个 _区块高度_。 Solana 通过使用最后一个条目的 PoH 哈希来轻松实现这一点。 + +## 与 VDF 的关系 + +Solana 在 2017 年 11 月首次介绍了历史证明技术在区块链中的使用。 次年 6 月, 斯坦福阐述了类似的技术,称为 [verifiable delay function(可验证延迟函数)](https://eprint.iacr.org/2018/601.pdf) 或简称为 _VDF_。 + +VDF 的一个优势是验证所需时间非常短。 Solana 验证其延迟函数的方法它与创建所需的时间成正比。 拆分超过 4000 个核心 GPU,它足以满足 Solana 的性能需要,但如果您请教上述论文的作者,他们可能会跟说 Solana 的方法在算法上很慢 \([因此](https://github.com/solana-labs/solana/issues/388)\),不应该叫作 VDF。 我们的观点是 VDF 一词应当指可证明的延迟方程,而不一定要满足某些性能特征。 在这个问题解决之前,Solana 很可能会继续在其特定的应用程序 VDF 使用 PoH 一词。 + +PoH 与 VDF 之间的另一个区别是,VDF 仅用于跟踪时间。 另一方面,PoH 的哈希区块链包括应用程序观察到的任何数据的哈希部分。 这些数据是一把双刃剑。 一方面,数据提供了“证明历史”――数据在哈希之后肯定是存在的。 另一方面,这意味着当数据被哈希的_时候_,应用程序可以通过更改它来操纵区块链。 因此,PoH 区块链并不是一个很好的随机数来源,但是没有这种数据的 VDF 却非常合适。 例如,Solana 的 [领导人轮换算法](synchronization.md#leader-rotation),只来源于 VDF _高度_ ,而不是该高度的哈希值。 + +## 与共识机制的关系 + +历史证明不是一个共识机制,它用于改进 Solana 权益证明共识的性能。 它还用于改进数据平面协议的性能。 + +## 关于历史证明的更多信息 + +- [水时钟类比](https://medium.com/solana-labs/proof-of-history-explained-by-a-water-clock-e682183417b8) +- [历史证明概述](https://medium.com/solana-labs/proof-of-history-a-clock-for-blockchain-cf47a61a9274) diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/turbine-block-propagation.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/turbine-block-propagation.md new file mode 100644 index 0000000000..11b1300066 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/turbine-block-propagation.md @@ -0,0 +1,88 @@ +--- +title: 涡轮(Turbine)区块传播 +--- + +Solana 集群使用一个叫做 _Turbine_ 的多层区块传播机制来广播所有节点的交易,该过程只产生少量的重复信息。 群集将自身分成小的节点集合,叫做 _neighborhoods(邻居)_。 每个节点负责与其附近的其他节点分享它收到的任何数据,同时将数据传播到其他邻居的小节点。 这样,每个节点只需要与少数节点通信。 + +在其插槽中,领导人节点会在第一个邻居的验证节点\(层 0\) 之间分配碎片。 每个验证节点在其邻居之间共享各自的数据,但也在下一层\(层 1\) 中将碎片转化为某个邻居的一个节点。 每个 1 层节点与邻居节点共享数据, 并在下一层重新传输到节点,以此类推,直到集群中的所有节点都收到了所有碎片。 + +## 邻居分配 - 权重选择 + +为了使数据扩散发挥作用,整个集群必须就如何将划分邻居达成一致。 为了实现这一点,所有公认的验证节点 \(TVU 节点\) 都按质押权重排列并存储在一个列表中。 然后以不同的方式索引这该列表,来查明邻居边界并相互重新传送。 例如,领导者只需选择第一个节点来构建层 0。 最高权重的质押持有者会让得票最多的节点优先成为领导者。 0 层和下层节点使用相同的逻辑来找到他们的邻居和下一个层节点。 + +为了减少攻击向量的可能性,每个碎片都向邻居发送一个随机树。 每个节点使用代表集群的同一批节点。 随机树是通过碎片集生成的,它使用领导者ID、插槽和碎片索引来生成种子。 + +## 层和邻居结构 + +当前领导者将其初始广播到最多 `DATA_PLANE_FANOUT` 的节点。 如果该层 0 小于集群中的节点数,则数据平面扫描机制在下面添加图层。 随后的图层遵循这些约束来决定图层容量:每个邻居包含的 `DATA_PLANE_FANOUT` 节点。 0 层从带有扩散节点的 1 个邻居开始计算。 每个附加层中的节点数量增加了一个扩散因素。 + +如上文所述, 图层中的每个节点只能向邻居广播它的碎片,并且在某些下层邻居中只能播放一个节点, 不适用于集群中的每个 TVU 节点。 有一个理解该问题的好方法:0 层从带有扩散节点的 1 个邻居开始计算,1 层增加扩散邻居, 每个带有扩散节点和 2 层的节点都会有 `扩散 * 在 1 层的节点数量`,以此类推。 + +这样,每个节点进行通信最大只能达到 `2 * DATA_PLANE_FANOUT - 1` 个节点。 + +下面的图表显示了领导人如何在 0 层向 0 令居发送两个扩散的碎片,以及 0 邻居的节点如何彼此分享他们的数据。 + +![领导者向 0 层中的 0 号邻居发送碎片](/img/data-plane-seeding.svg) + +下面的图表显示了 Neighborhood 0 如何向 Neighborhood 1和2 进行扩散。 + +![Neighborhood 0 向Neighborhood 1 和 2 号散播](/img/data-plane-fanout.svg) + +最后,下图显示两个层集群都有 2 个扩散。 + +![具有两个扩散的两层集群](/img/data-plane.svg) + +### 设置值 + +`DATA_PLANE_FANOUT` - 确定层 0 的大小。 后续的层由 `DATA_PLANE_FANOUT` 系数生成。 邻居的节点数量等于扩散值。 某个邻居要在添加新邻居之前被填满,即如果某个邻居没有满,它_必须_是最后一个。 + +目前,集群启动的时候就进行了配置。 未来这些参数可能会托管在链上,从而能够随着群组大小的变化而自行调整。 + +## 计算所需的 FEC 比率 + +Turbine 依赖于验证器之间数据包的再传输。 由于重新传输,任何网络宽包丢失都会加重, 同时每次访问的数据包未能到达目的地的概率也会增加。 FEC 比率需要考虑网络宽数据包丢失和传播深度。 + +碎片组是可以使用重建彼此的数据和编码数据集。 每个碎片组都有失败的可能性,其概率大致相当于数据包错误率超过 FEC。 如果验证节点无法重建碎片组,那就无法构建区块,它就必须先修复区块。 + +碎片组失败的概率可以通过二项分布计算。 如果 FEC 率是 `16:4`, 那么群组大小则为 20,而且至少要有 4 个碎片失败才会导致整个组失败。 这等于 20 个碎片中的四条或更多个体失败的概率之和。 + +涡轮区块成功的概率为: + +- 数据包失败的概率为: `P = 1 - (1 - network_packet_loss_rate)^2` +- FEC 率: `K:M` +- 尝试次数: `N = K + M` +- 碎片组失败率: `S = SUM of i=0 -> M for binomial(prob_failure = P, trials = N, failures = i)` +- 每个区块的碎片: `G` +- 区块成功率: `B = (1 - S) ^(G / N)` +- `i` 的精确结果的双向分布被定义为 `(N choose i) * P^i * (1 - P)^(N-i)` + +例如: + +- 网络丢包率为 15%。 +- 50k Tps 的网络每秒产生 6400个碎片。 +- FEC 率增加了每个块按 FEC 笔录的总碎片数。 + +其中 FEC 率为: `16:4` + +- `G = 8000` +- `P=1 - 0.85 * 0.85 = 1 - 0.7225 = 0.2775` +- `S = i 的总和 =0 -> 4 为二项分布(prob_fail= 0.2775, trials = 20, fails = i) = 0.689414` +- `B = (1 - 0.689) ^(8000 / 20) = 10^-203` + +其中 FEC 率为: `16:16` + +- `G = 12800` +- `S = i 的总和 =0 -> 32 为二项分布(prob_fail= 0.2775, trials = 64, fails = i) = 0.002132` +- `B = (1 - 0.002132) ^(12800 / 32) = 0.42583` + +其中 FEC 率为: `32:32` + +- `G = 12800` +- `S = i 的总和 =0 -> 32 为二项分布(prob_fail= 0.2775, trials = 64, fails = i) = 0.000048` +- `B = (1 - 0.000048) ^(12800 / 64) = 0.99045` + +## 邻居(Neighborhoods) + +以下图表显示不同层中两个邻居之间的相互作用。 若要使邻居瘫痪,就需要从上面的邻居建立足够的节点\(擦除代码+1\)。 由于每个邻居都会从上层一个邻居的多个节点收到碎片, 因此上层网络出现大规模故障,才会产生不完整的数据。 + +![邻居的内部工作](/img/data-plane-neighborhood.svg) diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/vote-signing.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/vote-signing.md new file mode 100644 index 0000000000..69772fa99f --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/cluster/vote-signing.md @@ -0,0 +1,59 @@ +--- +title: 安全投票签名 +--- + +验证节点接收当前领导者的条目并提交这些条目的确认票数。 这个投票对安全提出了一种挑战,因为违反共识规则的伪造票可以用来罚没验证节点的质押。 + +验证节点通过一个采用不对称密钥来验证签名结果的交易,来对其选定的分叉进行投票。 其他实体可以使用验证节点的公钥验证此签名。 如果验证节点密钥被用来签名不正确的数据\(例如) 对账本的多个分叉进行投票\,那么节点的质押或资源可能会受到损害。 + +解决这个风险的办法是将单独的 _投票签名者_ 服务分割出来,评估每次投票以确保它没有违反罚没条件。 + +## 验证节点,投票签名者和质押者 + +当一个验证节点收到多个区块的同一个插槽时,它会跟踪所有可能的分叉,直到确定一个“最佳”的。 验证节点通过投票选择最好的分叉,通过投票签名者尽量减少投票造成违反共识和导致质押被罚没的可能性。 + +投票签名者对验证节点提议的投票进行评估,并且只在不违反罚没条件的情况下进行投票。 一个投票签名者只需要保持它所签署的投票和其余集群成员所签署的选票处于最低状态。 它不需要处理全部的交易。 + +质押者是一个对其质押资产具有控制权的实体。 质押者可以将其质押委托给投票签署人。 一旦某个质押被委托,投票人将代表所有受委托质押行驶投票权,同时为他们带来奖励。 + +目前,验证节点和投票签名者之间是 1:1 的关系,质押人将他们的全部质押委托给某一个的签名者。 + +## 签名服务 + +投票签名服务由 JSON RPC 服务器和请求处理器组成。 启动时,服务会在配置端口启动 RPC 服务器,等待验证节点请求。 请求类型包括如下几种: + +1. 注册一个新的验证节点 + + - 请求必须包含验证节点身份\(公钥\) + - 请求必须通过验证节点的私钥签名 + - 如果无法验证请求签名,服务就会丢弃该请求 + - 服务为验证节点创建了一个新的投票权不对称密钥,并返回公钥作为响应 + - 如果验证节点试图再次注册,服务会从原有的密钥对返回公钥 + +2. 签名投票 + + - 请求必须包含投票交易和所有验证数据 + - 请求必须通过验证节点的私钥签名 + - 如果无法验证请求签名,服务就会丢弃该请求 + - 服务验证投票数据 + - 服务返回交易的签名 + +## 验证节点投票 + +某个验证节点在启动时创建一个新的投票帐户,并通过提交一个新的“投票登记表”交易,在集群中进行注册。 集群中的其他节点处理该笔交易,并在活动集合中包含新的验证节点。 随后,验证节点在每次投票事件中提交了由验证节点投票私钥签名的“新投票”交易。 + +### 配置 + +验证节点通过签名服务的网络端点\(IP/port\) 配置。 + +### 注册 + +在启动时,验证节点使用 JSON RPC 注册其签名服务。 RPC 调用返回验证节点的投票公钥。 验证节点创建一个新的“投票注册”交易并把公钥包含进去,将其提交给集群。 + +### 投票收集 + +验证节点在上次投票期间查找集群中所有节点提交的票数。 然后把该信息提交给签名服务,并附有新的投票签名请求。 + +### 新的投票签名 + +验证节点创建了一笔“新投票”交易,并通过 JSON RPC 将其发送到签名服务。 RPC 请求还包括了投票检查数据。 如果成功,RPC 调用将返回投票的签名。 如果失败,RPC 调用将返回故障编码。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/clusters.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/clusters.md new file mode 100644 index 0000000000..500164049a --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/clusters.md @@ -0,0 +1,149 @@ +--- +title: Solana 集群 +--- + +Solana维护着几个不同用途的集群。 + +在开始之前,请确保已首先安装了[Solana命令行工具](cli/install-solana-cli-tools.md) + +浏览器: + +- [http://explorer.solana.com/](https://explorer.solana.com/)。 +- [http://solanabeach.io/](http://solanabeach.io/). + +## Devnet(开发者网络) + +- Devnet可以作为希望将Solana进行测试的任何人,用户,代币持有者,应用开发者或验证者的游乐场。 +- 应用程序开发人员应针对Devnet。 +- 潜在的验证者应首先针对Devnet。 +- Devnet和Mainnet Beta之间的主要区别: + - Devnet代币是**不是真实的** + - Devnet包含用于空投的代币龙头,用于应用程序测试 + - Devnet可能会重置账本 + - Devnet通常运行比Mainnet Beta更新的软件版本 +- Devnet的八卦入口点:`entrypoint.devnet.solana.com:8001` +- Devnet的指标环境变量: +```bash +export SOLANA_METRICS_CONFIG="host=https://metrics.solana.com:8086,db=devnet,u=scratch_writer,p=topsecret" +``` +- Devnet RPC URL:`https://devnet.solana.com` + +##### 示例 `solana` 命令行配置 + +```bash +solana config set --url https://devnet.solana.com +``` + +##### 示例 `solana-validator` 命令行 + +```bash +$ solana-validator \ + --identity ~/validator-keypair.json \ + --vote-account ~/vote-account-keypair.json \ + --trusted-validator dv1LfzJvDF7S1fBKpFgKoKXK5yoSosmkAdfbxBo1GqJ \ + --no-untrusted-rpc \ + --ledger ~/validator-ledger \ + --rpc-port 8899 \ + --dynamic-port-range 8000-8010 \ + --entrypoint entrypoint.devnet.solana.com:8001 \ + --expected-genesis-hash EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG \ + --wal-recovery-mode skip_any_corrupted_record \ + --limit-ledger-size +``` + +`--trusted-validator`由 Solana 运行 + +## Testnet(测试网) + +- Testnet是我们在实时群集上重点测试最新发布功能的地方,尤其侧重于网络性能,稳定性和验证程序行为。 +- 集群[Tour de SOL](tour-de-sol.md)计划在Testnet上运行,在该计划中,我们接受恶意行为和对网络的攻击,以帮助我们发现和消除错误或网络漏洞。 +- Testnet代币**不是真实的** +- Testnet可能会重置账本。 +- Testnet包括用于空投的代币水龙头,用于应用程序测试 +- Testnet通常运行比Devnet和Mainnet Beta都更新的软件版本 +- 测试网 Gossip 入口: `entrypoint.testnet.solana.com:8001` +- Testnet的指标环境变量: +```bash +export SOLANA_METRICS_CONFIG="host=https://metrics.solana.com:8086,db=tds,u=testnet_write,p=c4fa841aa918bf8274e3e2a44d77568d9861b3ea" +``` +- Testnet 的 RPC URL: `https://testnet.solana.com` + +##### 示例 `solana` 命令行配置 + +```bash +solana config set --url https://testnet.solana.com +``` + +##### 示例 `solana-validator` 命令行 + +```bash +$ solana-validator \ + --identity ~/validator-keypair.json \ + --vote-account ~/vote-account-keypair.json \ + --trusted-validator 5D1fNXzvv5NjV1ysLjirC4WY92RNsVH18vjmcszZd8on \ + --trusted-validator ta1Uvfb7W5BRPrdGnhP9RmeCGKzBySGM1hTE4rBRy6T \ + --trusted-validator Ft5fbkqNa76vnsjYNwjDZUXoTWpP7VYm3mtsaQckQADN \ + --trusted-validator 9QxCLckBiJc783jnMvXZubK4wH86Eqqvashtrwvcsgkv \ + --no-untrusted-rpc \ + --ledger ~/validator-ledger \ + --rpc-port 8899 \ + --dynamic-port-range 8000-8010 \ + --entrypoint entrypoint.testnet.solana.com:8001 \ + --expected-genesis-hash 4uhcVJyU9pJkvQyS88uRDiswHXSCkY3zQawwpjk2NsNY \ + --wal-recovery-mode skip_any_corrupted_record \ + --limit-ledger-size +``` + +`--trusted-validator` 的身份是: + +- `5D1fNXzv5NjV1ysLjirC4WY92RNsVH18vjmcszZd8on` - testnet.solana.com (Solana) +- `ta1Uvfb7W5BRPrdGnhP9RmeCKzBySGM1hTE4rBRy6T` - Break RPC 节点 (Solana) +- `Ft5fbkqNa76vnsjYNwjDZUXoTWpP7VYm3mtsaQckQADN` - Certus One +- `9QxCLckBiJc783jnMvXZubK4wH86Eqqvashtrwvcsgkv` - Algo|Stake + +## Mainnet Beta(主网 Beta) + +适用于早期代币持有者和启动合作伙伴,未经许可的持久集群。 当前,奖励和通货膨胀被禁用。 + +- 在Mainnet Beta上发行的代币是**真实的**SOL +- 如果您通过我们的硬币清单拍卖等方式支付了购买/发行代币的费用,则这些代币将在Mainnet Beta上转移。 + - 注意:如果您使用的是非命令行钱包,例如集群[Solflare](wallet-guide/solflare.md),则该钱包将始终连接到Mainnet Beta。 +- Mainnet Beta 的 Gossip 入口: `entrypoint.mainnet-beta.solana.com:8001` +- Mainnet Beta的指标环境变量: +```bash +export SOLANA_METRICS_CONFIG="host=https://metrics.solana.com:8086,db=mainnet-beta,u=mainnet-beta_write,p=password" +``` +- Mainnet Beta 的 RPC URL: `https://api.mainnet-beta.solana.com` + +##### 示例 `solana` 命令行配置 + +```bash +solana config set --url https://api.mainnet-beta.solana.com +``` + +##### 示例 `solana-validator` 命令行 + +```bash +$ solana-validator \ + --identity ~/validator-keypair.json \ + --vote-account ~/vote-account-keypair.json \ + --trusted-validator 7Np41oeYqPefeNQEHSv1UDhYrehxin3NStELsSKCT4K2 \ + --trusted-validator GdnSyH3YtwcxFvQrVVJMm1JhTS4QVX7MFsX56uJLUfiZ \ + --trusted-validator DE1bawNcRJB9rVm3buyMVfr8mBEoyyu73NBovf2oXJsJ \ + --trusted-validator CakcnaRDHka2gXyfbEd2d3xsvkJkqsLw2akB3zsN1D2S \ + --no-untrusted-rpc \ + --ledger ~/validator-ledger \ + --rpc-port 8899 \ + --private-rpc \ + --dynamic-port-range 8000-8010 \ + --entrypoint entrypoint.mainnet-beta.solana.com:8001 \ + --entrypoint entrypoint2.mainnet-beta.solana.com:8001 \ + --entrypoint entrypoint3.mainnet-beta.solana.com:8001 \ + --entrypoint entrypoint4.mainnet-beta.solana.com:8001 \ + --entrypoint entrypoint5.mainnet-beta.solana.com:8001 \ + --expected-genesis-hash 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d \ + --wal-recovery-mode skip_any_corrupted_record \ + --limit-ledger-size +``` + +所有的四个 `--trusted-validator(可信验证节点)` 由 Solana 运行 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/backwards-compatibility.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/backwards-compatibility.md new file mode 100644 index 0000000000..803109912f --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/backwards-compatibility.md @@ -0,0 +1,115 @@ +--- +title: 后向兼容政策 +--- + +随着Solana开发人员生态系统的发展,围绕打破API和行为更改(影响为Solana构建的应用程序和工具)的明确期望也将越来越高。 在一个完美的世界中,Solana的开发可以以非常快的速度继续进行,而不会给现有开发人员造成任何问题。 但是,将需要做出一些妥协,因此,本文档尝试澄清和整理新发行版的过程。 + +### 期望值 + +- Solana软件版本包括API,SDK和CLI工具(带有一些[exceptions](#exceptions))。 +- Solana软件版本遵循语义版本控制,更多详细信息请参见下文。 +- 适用于`MINOR`版本的软件将与同一`MAJOR`版本上的所有软件兼容。 + +### 弃用过程 + +1. 在任何`PATCH`或`MINOR`版本中,功能、API、端点等都可以标记为已弃用。 +2. 根据代码升级的难度,某些功能将在几个发布周期内被弃用。 +3. 在未来的`MAJOR`版本中,不赞成使用的功能将以不兼容的方式删除。 + +### 发布时间 + +Solana RPC API、Rust SDK、CLI工具和BPF程序SDK均已更新并随每个Solana软件版本一起提供,并且应始终在特定`MINOR`版本的`PATCH`更新之间兼容。 + +#### 发布频道 + +- `edge`软件,其中包含最先进的功能,没有向后兼容策略 +- 在Solana Tour de SOL测试网集群上运行的`beta`软件 +- 在Solana Mainnet Beta和Devnet集群上运行的`stable`软件 + +#### 主要版本(x.0.0) + +`MAJOR`版本(例如2.0.0)可能包含重大更改并删除了以前不推荐使用的功能。 客户端SDK和工具将开始使用在先前`MAJOR`版本中启用的新功能和端点。 + +#### 次要版本(1.x.0) + +新功能和建议实施已添加到_new_版本的`MINOR`版本(例如1.4.0)中,并且首先在Solana的Tour de SOL测试网集群上运行。 在测试网上运行时,`MINOR`版本被认为在`beta`发布渠道中。 在对这些更改进行了修补并证明是可靠的之后,`MINOR`版本将升级到`stable`发布渠道并部署到Mainnet Beta集群。 + +#### 修补程序版本(1.0.x) + +低风险功能,不间断的更改以及安全性和错误修复作为`PATCH`版本发行版(例如1.0.11)的一部分提供。 补丁可以同时应用于`beta`和`stable`发布渠道。 + +### RPC API + +补丁发布: +- Bug修复 +- 安全修复 +- 端点/功能弃用 + +次要版本: +- 新的RPC端点和功能 + +主要版本: +- 删除过时的功能 + +### Rust Crates + +* [`solana-sdk`](https://docs.rs/solana-sdk/) - 用于创建交易和解析帐户状态的Rust SDK +* [`solana-program`](https://docs.rs/solana-program/) - 用于编写程序的Rust SDK +* [`solana-client`](https://docs.rs/solana-client/) - 用于连接RPC API的Rust客户端 +* [`solana-cli-config`](https://docs.rs/solana-cli-config/) - 用于管理Solana CLI配置文件的Rust客户端 + +补丁发布: +- Bug修复 +- 安全修复 +- 性能提升 + +次要版本: +- 新的 API + +主要版本: +- 删除过时的API +- 向后不兼容的行为更改 + +### CLI 工具 + +补丁发布: +- 错误和安全修复 +- 性能提升 +- 弃用子命令/参数 + +次要版本: +- 新的子命令 + +主要版本: +- 切换到先前主要版本中引入的新RPC API端点/配置。 +- 删除过时的功能 + +### Runtime功能 + +Solana新的runtime功能已进行功能切换并手动激活。 Runtime功能包括:引入新的本机程序,sysvars和syscalls;并改变他们的行为。 功能激活与群集无关,因此可以在Mainnet-beta上激活之前在Testnet上建立置信度。 + +发布过程如下: + +1. 新版本中包含新的runtime功能,默认情况下已禁用 +2. 一旦有足够的抵押验证程序升级到新版本,就可以通过指令手动激活runtime功能开关 +3. 该功能在下一个纪元开始时生效 + +### 基础架构变更 + +#### 公共API节点 + +Solana提供了公开可用的RPC API节点,供所有开发人员使用。 Solana团队将尽最大努力将任何更改传达给主机,端口,限速行为,可用性等。 但是,我们建议开发人员依靠自己的验证器节点来阻止对Solana操作的节点的依赖。 + +#### 本地集群脚本和Docker映像 + +重大更改将仅限于`MAJOR`版本更新。 `MINOR`和`PATCH`更新应始终向后兼容。 + +### 例外 + +#### Web3 JavaScript SDK + +Web3.JS SDK还遵循语义版本控制规范,但与Solana软件版本分开提供。 + +#### 攻击向量 + +如果在现有代码中发现了新的攻击媒介,则可以根据问题的严重性来规避上述过程,以便快速部署修复程序。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/clients/javascript-api.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/clients/javascript-api.md new file mode 100644 index 0000000000..2f5d161e83 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/clients/javascript-api.md @@ -0,0 +1,5 @@ +--- +title: Web3 JavaScript API +--- + +请查看 [solana-web3](https://solana-labs.github.io/solana-web3.js/)。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/clients/jsonrpc-api.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/clients/jsonrpc-api.md new file mode 100644 index 0000000000..12ea7f0958 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/clients/jsonrpc-api.md @@ -0,0 +1,3544 @@ +--- +title: JSON RPC API +--- + +Solana节点使用[JSON-RPC 2.0](https://www.jsonrpc.org/specification)规范接受HTTP请求。 + +要与JavaScript应用程序中的Solana节点进行交互,请使用[solana-web3.js](https://github.com/solana-labs/solana-web3.js)库,该库为RPC方法提供了方便的接口。 + +## RPC HTTP 端点 + +**Default port:** 8899 eg. [http://localhost:8899](http://localhost:8899), [http://192.168.1.88:8899](http://192.168.1.88:8899) + +## RPC PubSub WebSocket 端点 + +**Default port:** 8900 eg. ws://localhost:8900, [http://192.168.1.88:8900](http://192.168.1.88:8900) + +## 方法 + +- [getAccountInfo](jsonrpc-api.md#getaccountinfo) +- [getBalance](jsonrpc-api.md#getbalance) +- [getBlockCommitment](jsonrpc-api.md#getblockcommitment) +- [getBlockTime](jsonrpc-api.md#getblocktime) +- [getClusterNodes](jsonrpc-api.md#getclusternodes) +- [getConfirmedBlock](jsonrpc-api.md#getconfirmedblock) +- [getConfirmedBlocks](jsonrpc-api.md#getconfirmedblocks) +- [getConfirmedBlocksWithLimit](jsonrpc-api.md#getconfirmedblockswithlimit) +- [getConfirmedSignaturesForAddress](jsonrpc-api.md#getconfirmedsignaturesforaddress) +- [getConfirmedSignaturesForAddress2](jsonrpc-api.md#getconfirmedsignaturesforaddress2) +- [getConfirmedTransaction](jsonrpc-api.md#getconfirmedtransaction) +- [getEpochInfo](jsonrpc-api.md#getepochinfo) +- [getEpochSchedule](jsonrpc-api.md#getepochschedule) +- [getFeeCalculatorForBlockhash](jsonrpc-api.md#getfeecalculatorforblockhash) +- [getFeeRateGovernor](jsonrpc-api.md#getfeerategovernor) +- [getFees](jsonrpc-api.md#getfees) +- [getFirstAvailableBlock](jsonrpc-api.md#getfirstavailableblock) +- [getGenesisHash](jsonrpc-api.md#getgenesishash) +- [getHealth](jsonrpc-api.md#gethealth) +- [getIdentity](jsonrpc-api.md#getidentity) +- [getInflationGovernor](jsonrpc-api.md#getinflationgovernor) +- [getInflationRate](jsonrpc-api.md#getinflationrate) +- [getLargestAccounts](jsonrpc-api.md#getlargestaccounts) +- [getLeaderSchedule](jsonrpc-api.md#getleaderschedule) +- [getMinimumBalanceForRentExemption](jsonrpc-api.md#getminimumbalanceforrentexemption) +- [getMultipleAccounts](jsonrpc-api.md#getmultipleaccounts) +- [getProgramAccounts](jsonrpc-api.md#getprogramaccounts) +- [getRecentBlockhash](jsonrpc-api.md#getrecentblockhash) +- [getRecentPerformanceSamples](jsonrpc-api.md#getrecentperformancesamples) +- [getSignatureStatuses](jsonrpc-api.md#getsignaturestatuses) +- [getSlot](jsonrpc-api.md#getslot) +- [getSlotLeader](jsonrpc-api.md#getslotleader) +- [getStakeActivation](jsonrpc-api.md#getstakeactivation) +- [getSupply](jsonrpc-api.md#getsupply) +- [getTransactionCount](jsonrpc-api.md#gettransactioncount) +- [getVersion](jsonrpc-api.md#getversion) +- [getVoteAccounts](jsonrpc-api.md#getvoteaccounts) +- [minimumLedgerSlot](jsonrpc-api.md#minimumledgerslot) +- [requestAirdrop](jsonrpc-api.md#requestairdrop) +- [sendTransaction](jsonrpc-api.md#sendtransaction) +- [simulateTransaction](jsonrpc-api.md#simulatetransaction) +- [setLogFilter](jsonrpc-api.md#setlogfilter) +- [validatorExit](jsonrpc-api.md#validatorexit) +- [Subscription](jsonrpc-api.md#subscription-websocket) + - [accountSubscribe](jsonrpc-api.md#accountsubscribe) + - [accountUnsubscribe](jsonrpc-api.md#accountunsubscribe) + - [logsSubscribe](jsonrpc-api.md#logssubscribe) + - [logsUnsubscribe](jsonrpc-api.md#logsunsubscribe) + - [programSubscribe](jsonrpc-api.md#programsubscribe) + - [programUnsubscribe](jsonrpc-api.md#programunsubscribe) + - [signatureSubscribe](jsonrpc-api.md#signaturesubscribe) + - [signatureUnsubscribe](jsonrpc-api.md#signatureunsubscribe) + - [slotSubscribe](jsonrpc-api.md#slotsubscribe) + - [slotUnsubscribe](jsonrpc-api.md#slotunsubscribe) + +## 不稳定的方法 + +不稳定的方法可能会在补丁程序发行版中发生重大更改,并且可能永久不受支持。 + +- [getTokenAccountBalance](jsonrpc-api.md#gettokenaccountbalance) +- [getTokenAccountsByDelegate](jsonrpc-api.md#gettokenaccountsbydelegate) +- [getTokenAccountsByOwner](jsonrpc-api.md#gettokenaccountsbyowner) +- [getTokenLargestAccounts](jsonrpc-api.md#gettokenlargestaccounts) +- [getTokenSupply](jsonrpc-api.md#gettokensupply) + +## 请求格式 + +要发出 JSON-RPC 请求,请发送带有`Content-Type: +application/json`的 HTTP POST 请求。 JSON请求数据应包含4个字段: + +- `jsonrpc: `,设置为 `"2.0"` +- `id: `,一个独特的客户端生成的识别整数 +- `method: `,一个包含要调用方法的字符串 +- `params: `,一个 JSON 数组的有序参数值 + +使用curl的示例: + +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getBalance", + "params": [ + "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri" + ] + } +' +``` + +响应输出将是一个 JSON 对象,具有以下字段: + +- `jsonrpc: `, 匹配请求规范 +- `id: `, 匹配请求标识符 +- `result: `, 请求的数据或成功确认 + +通过发送JSON-RPC请求对象数组作为单个POST的数据,可以批量发送请求。 + +## 定义 + +- 哈希(Hash):一个数据块的SHA-256哈希。 +- 公钥(Pubkey):Ed25519密钥对的公钥。 +- 交易(Transaction):由客户密钥对签名以授权这些操作的Solana指令列表。 +- 签名(Signature):交易的有效载荷数据的Ed25519签名,包括指令。 它可以用来识别交易。 + +## 配置状态承诺 + +对于飞行前检查和交易处理,Solana节点根据客户端设置的承诺要求选择要查询的银行状态。 该承诺描述了该时间点块的最终确定方式。 查询账本状态时,建议使用较低级别的承诺来报告进度,而使用较高级别以确保不会回滚该状态。 + +客户可以按照承诺的降序排列(从最高确定到最低确定): + +- `"max"` - 节点将查询由集群的绝大多数确认为已达到最大锁定的最新块,这意味着集群已将该块识别为已完成 +- `"root"` - 节点将查询该节点上已达到最大锁定的最新块,这意味着该节点已将该块识别为已完成 +- `"singleGossip"` - 节点将查询由集群的多数投票的最新区块。 + - 它融合了八卦和重播的选票。 + - 它不计算该区块后代的票数,而仅对该区块的直接票数进行计数。 + - 此确认级别还支持1.3版及更高版本中的“乐观确认”保证。 +- `"recent"` - 节点将查询其最近的块。 注意,该区块可能不完整。 + +为了连续处理许多相关的事务,建议使用`"singleGossip"`承诺,以平衡速度和回滚安全性。 为了安全起见,建议使用`"max"`承诺。 + +#### 示例: + +承诺参数应作为 `params` 数组中的最后一个元素包含: + +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getBalance", + "params": [ + "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri", + { + "commitment": "max" + } + ] + } +' +``` + +#### 默认情况: + +如果未提供承诺配置,则该节点将默认为`max`承诺 + +只有查询库状态的方法才接受承诺参数。 它们在下面的API参考中指出。 + +#### RpcResponse结构 + +许多采用承诺参数的方法会返回RpcResponse JSON对象,该对象由两部分组成: + +- `context` : RpcResponseContext JSON结构,包括一个`slot`字段,在该字段上评估操作。 +- `value` :操作本身返回的值。 + +## 健康检查 + +尽管不是JSON RPC API,但RPC HTTP端点上的`GET / health`提供了一种健康检查机制,供负载平衡器或其他网络基础结构使用。 根据以下条件,此请求将始终返回带有 "ok" 或 "behind" 正文的 HTTP 200 OK 响应: + +1. 如果向`solana-validator`提供了一个或多个`--trusted-validator`参数,则当节点位于最高可信验证器的`HEALTH_CHECK_SLOT_DISTANCE`插槽内时,返回 "ok",否则返回 "behind"。 +2. 如果未提供受信任的验证器,则始终返回 "ok"。 + +## JSON RPC API 引用 + +### getAccountInfo + +返回与提供的Pubkey帐户关联的所有信息 + +#### 参数: + +- `` - 要查询的帐户的公钥,以base-58编码的字符串 +- `` -(可选)包含以下可选字段的配置对象: + - (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + - `encoding:` - 帐户数据的编码,可以是"base58"(*很慢*),"base64","base64+zstd" 或 "jsonParsed"。 "base58" 仅限于少于128个字节的帐户数据。 "base64" 将为任何大小的Account数据返回base64编码的数据。 "base64+zstd" 使用 [Zstandard](https://facebook.github.io/zstd/) 压缩帐户数据,并对结果进行base64编码。 "jsonParsed" 编码尝试使用特定于程序的状态解析器来返回更多的人类可读和显式的帐户状态数据。 如果请求了 "jsonParsed",但找不到解析器,则该字段回退为"base64"编码,当`data`字段为``类型时可以检测到。 + - (可选) `dataSlice:` - 使用提供的`offset:` 和`length:`字段限制返回的帐户数据;仅适用于 "base58","base64" 或 "base64+zstd" 编码。 + +#### 结果: + +结果是一个RpcResponse JSON对象,其`值`等于: + +- `` - 如果所请求的帐户不存在 +- `` - 否则为JSON对象,其中包含: + - `lamports: `,分配给此帐户的Lamport数量,以u64表示 + - `owner: `,此帐户已分配给该程序的base-58编码的Pubkey + - `data: <[string, encoding]|object>`,与帐户关联的数据,可以是编码的二进制数据,也可以是JSON格式的`{: }`,具体取决于编码参数 + - `executable: `,布尔值,指示帐户是否包含程序\(并且严格为只读\) + - `rentEpoch: `,此帐户下一次将要欠租金的时期,即u64 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getAccountInfo", + "params": [ + "vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg", + { + "encoding": "base58" + } + ] + } +' +``` +响应: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1 + }, + "value": { + "data": [ + "11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHRTPuR3oZ1EioKtYGiYxpxMG5vpbZLsbcBYBEmZZcMKaSoGx9JZeAuWf", + "base58" + ], + "executable": false, + "lamports": 1000000000, + "owner": "11111111111111111111111111111111", + "rentEpoch": 2 + } + }, + "id": 1 +} +``` + +#### 示例: +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getAccountInfo", + "params": [ + "4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA", + { + "encoding": "jsonParsed" + } + ] + } +' +``` +响应: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1 + }, + "value": { + "data": { + "nonce": { + "initialized": { + "authority": "Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX", + "blockhash": "3xLP3jK6dVJwpeGeTDYTwdDK3TKchUf1gYYGHa4sF3XJ", + "feeCalculator": { + "lamportsPerSignature": 5000 + } + } + } + }, + "executable": false, + "lamports": 1000000000, + "owner": "11111111111111111111111111111111", + "rentEpoch": 2 + } + }, + "id": 1 +} +``` + +### getBalance + +返回提供的 Pubkey 账户余额 + +#### 参数: + +- `` - 要查询的帐户的公钥,以base-58编码的字符串 +- `` - (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +- `RpcResponse` - RpcResponse JSON 对象有 `值` 字段设置为余额 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0", "id":1, "method":"getBalance", "params":["83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri"]} +' +``` + +结果: +```json +{"jsonrpc":"2.0","result":{"context":{"slot":1},"value":0},"id":1} +``` + +### getBlockCommitment + +返回特定区块的承诺 + +#### 参数: + +- `` - 由插槽指定的区块 + +#### 结果: + +结果字段将是一个 JSON 对象,其中包含: + +- `commitment` - 承诺,包括以下任何一项: + - `` - 未知区块 + - `` - 承诺,在每个深度从 0 到 `MAX_LOCKOUT_HISTORY` + 1 上投票的lamports中的集群质押数量 +- `totalStake` - 当前epoch的全部活跃质押(以lamports计算) + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getBlockCommitment","params":[5]} +' +``` + +结果: +```json +{ + "jsonrpc":"2.0", + "result":{ + "commitment":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,32], + "totalStake": 42 + }, + "id":1 +} +``` + +### getBlockTime + +返回已确认块的估计生产时间。 + +每个验证者通过向特定块的投票间歇性地添加时间戳,定期将其UTC时间报告给账本。 根据记录在账本上的一组最近区块中的Vote时间戳的权益加权平均值计算请求区块的时间。 + +从快照引导或限制账本大小(通过清除旧插槽) 引导的节点将返回其最低根+ `TIMESTAMP_SLOT_RANGE`以下的块的空时间戳。 对拥有此历史数据感兴趣的用户必须查询根据起源建立的节点,并保留整个账本。 + +#### 参数: + +- `` - 由插槽指定的区块 + +#### 结果: + +* `` - 估计生产时间为 Unix 时间戳 (自Unix epoch以来的秒数) +* `` - 此区块不可用的时间戳 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getBlockTime","params":[5]} +' +``` + +结果: +```json +{"jsonrpc":"2.0","result":1574721591,"id":1} +``` + +### getClusterNodes + +返回所有参与集群节点的信息 + +#### 参数: + +无 + +#### 结果: + +结果字段将是一个 JSON 对象的数组,每个子字段如下: + +- `pubkey: ` - 节点公钥作为基本58编码字符串 +- `gossip: ` - 节点的 Gossip 网络地址 +- `tpu: ` - 节点的 TPU 网络地址 +- `rpc: |null` - 节点的 JSON RPC 网络地址,或 `null` 如果未启用 JSON RPC 服务 +- `version: |null` - 节点的软件版本,或 `null` 如果版本信息不可用 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0", "id":1, "method":"getClusterNodes"} +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": [ + { + "gossip": "10.239.6.48:8001", + "pubkey": "9QzsJf7LPLj8GkXbYT3LFDKqsj2hHG7TA3xinJHu8epQ", + "rpc": "10.239.6.48:8899", + "tpu": "10.239.6.48:8856", + "version": "1.0.0 c375ce1f" + } + ], + "id": 1 +} +``` + +### getConfirmedBlock + +返回账本中已确认区块的身份和交易信息 + +#### 参数: + +- `` - 作为u64整数 +- `` - 为每个返回的交易编码,或者是"json", "jsonParsed", "base58"(*慢*), "base64"。 如果参数未提供,默认编码为“json”。 "jsonParsed"编码尝试使用针对特定程序的教学解析器返回在 `transaction.message.instruction` 列表中更易读和更明确的数据。 如果“jsonParsed”是请求的,但无法找到解析器,则该指令返回到正则JSON编码(`帐户`, `数据`和 `程序 ID 索引` 字段). + +#### 结果: + +结果字段将是具有以下字段的对象: + +- `` - 如果指定的区块未确认 +- `` - 如果区块得到确认,则具有以下字段的对象: + - `blockhash: ` - 该区块的区块哈希作为基准-58 编码字符串 + - `previousBlockhash: ` - 该区块的父级区块哈希,以base-58编码的字符串;如果由于账本清理而导致父块不可用,则此字段将返回“11111111111111111111111111111111” + - `parentSlot: ` - 该区块的父级插槽索引 + - `transactions: ` - 包含以下内容的JSON对象数组: + - `transaction: ` - [交易](#transaction-structure) 对象,采用JSON格式或已编码的二进制数据,具体取决于编码参数 + - `meta: ` - 交易状态元数据对象,包含`null`或: + - `err: ` - 如果交易失败,则返回错误;如果交易成功,则返回null。 [TransactionError定义](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L24) + - `fee: ` - 该交易收取的费用,以u64整数表示 + - `preBalances: ` - 处理交易之前的u64帐户余额数组 + - `postBalances: ` - 处理交易后的u64帐户余额数组 + - `innerInstructions: ` -[内部指令](#inner-instructions-structure)的列表,如果在此事务处理期间尚未启用内部指令记录,则将其省略 + - `logMessages: ` - 字符串日志消息的数组;如果在此事务期间尚未启用日志消息记录,则将其省略 + - DEPRECATED: `status: ` - 交易状态 + - `"Ok": ` - 交易成功 + - `"Err": ` - 事务失败,出现TransactionError + - `rewards: ` - 包含以下内容的JSON对象数组: + - `pubkey: ` - 接收奖励的帐户的公钥,以base-58编码的字符串 + - `lamports: `- 帐户贷记或借记的奖励灯饰的数量,作为i64 + - `postBalance: ` - 应用奖励后以Lamports为单位的帐户余额 + - `rewardType: ` - 奖励类型:“费用”,“租金”,“投票”,“赌注” + - `blockTime: ` - 估计的生产时间,以Unix时间戳记(自Unix时代以来的秒数)。 如果不可用,则返回null + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[430, "json"]} +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "blockTime": null, + "blockhash": "3Eq21vXNB5s86c62bVuUfTeaMif1N2kUqRPBmGRJhyTA", + "parentSlot": 429, + "previousBlockhash": "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B", + "rewards": [], + "transactions": [ + { + "meta": { + "err": null, + "fee": 5000, + "innerInstructions": [], + "logMessages": [], + "postBalances": [ + 499998932500, + 26858640, + 1, + 1, + 1 + ], + "preBalances": [ + 499998937500, + 26858640, + 1, + 1, + 1 + ], + "status": { + "Ok": null + } + }, + "transaction": { + "message": { + "accountKeys": [ + "3UVYmECPPMZSCqWKfENfuoTv51fTDTWicX9xmBD2euKe", + "AjozzgE83A3x1sHNUR64hfH7zaEBWeMaFuAN9kQgujrc", + "SysvarS1otHashes111111111111111111111111111", + "SysvarC1ock11111111111111111111111111111111", + "Vote111111111111111111111111111111111111111" + ], + "header": { + "numReadonlySignedAccounts": 0, + "numReadonlyUnsignedAccounts": 3, + "numRequiredSignatures": 1 + }, + "instructions": [ + { + "accounts": [ + 1, + 2, + 3, + 0 + ], + "data": "37u9WtQpcm6ULa3WRQHmj49EPs4if7o9f1jSRVZpm2dvihR9C8jY4NqEwXUbLwx15HBSNcP1", + "programIdIndex": 4 + } + ], + "recentBlockhash": "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B" + }, + "signatures": [ + "2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv" + ] + } + } + ] + }, + "id": 1 +} +``` + +#### 示例: +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[430, "base64"]} +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "blockTime": null, + "blockhash": "3Eq21vXNB5s86c62bVuUfTeaMif1N2kUqRPBmGRJhyTA", + "parentSlot": 429, + "previousBlockhash": "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B", + "rewards": [], + "transactions": [ + { + "meta": { + "err": null, + "fee": 5000, + "innerInstructions": [], + "logMessages": [], + "postBalances": [ + 499998932500, + 26858640, + 1, + 1, + 1 + ], + "preBalances": [ + 499998937500, + 26858640, + 1, + 1, + 1 + ], + "status": { + "Ok": null + } + }, + "transaction": [ + "AVj7dxHlQ9IrvdYVIjuiRFs1jLaDMHixgrv+qtHBwz51L4/ImLZhszwiyEJDIp7xeBSpm/TX5B7mYzxa+fPOMw0BAAMFJMJVqLw+hJYheizSoYlLm53KzgT82cDVmazarqQKG2GQsLgiqktA+a+FDR4/7xnDX7rsusMwryYVUdixfz1B1Qan1RcZLwqvxvJl4/t3zHragsUp0L47E24tAFUgAAAABqfVFxjHdMkoVmOYaR1etoteuKObS21cc1VbIQAAAAAHYUgdNXR0u3xNdiTr072z2DVec9EQQ/wNo1OAAAAAAAtxOUhPBp2WSjUNJEgfvy70BbxI00fZyEPvFHNfxrtEAQQEAQIDADUCAAAAAQAAAAAAAACtAQAAAAAAAAdUE18R96XTJCe+YfRfUp6WP+YKCy/72ucOL8AoBFSpAA==", + "base64" + ] + } + ] + }, + "id": 1 +} +``` + +#### 交易结构 + +交易与其他区块链上的交易有很大不同。 请务必阅读[交易解剖](developing/programming-model/transactions.md),以了解Solana上的交易。 + +交易的JSON结构定义如下: + +- `signatures: ` - 应用于交易的以base-58编码的签名的列表。 该列表的长度始终为`message.header.numRequiredSignatures`,并且不为空。 索引`i”`处的签名对应于`message.account_keys`中索引`i`处的公钥。 第一个用作[交易ID](../../terminology.md#transaction-id)。 +- `message: ` - 定义交易的内容。 + - `accountKeys: ` - 交易使用的base-58编码公共密钥列表,包括指令和签名。 第一个`message.header.numRequiredSignatures`公钥必须对交易进行签名。 + - `header: ` - 详细说明交易所需的帐户类型和签名。 + - `numRequiredSignatures: ` - 使交易有效所需的签名总数。 签名必须与`message.account_keys`的第一个`numRequiredSignatures`匹配。 + - `numReadonlySignedAccounts: ` - 签名密钥的最后一个`numReadonlySignedAccounts`是只读帐户。 程序可以处理多个事务,这些事务在单个PoH条目中加载只读帐户,但不允许贷记或借记Lamport或修改帐户数据。 顺序评估针对同一读写帐户的交易。 + - `numReadonlyUnsignedAccounts: ` - 未签名密钥的最后一个`numReadonlyUnsignedAccounts`是只读帐户。 + - `recentBlockhash: ` - 账本中最近区块的基数为58的编码哈希,用于防止交易重复并延长交易寿命。 + - `instructions: ` - 程序指令的列表,如果全部成功,这些指令将依次执行并在一次原子事务中提交。 + - `programIdIndex: ` - 在`message.accountKeys`数组中的索引,指示执行该指令的程序帐户。 + - `accounts: ` - `message.accountKeys`数组中的有序索引列表,指示要传递给程序的帐号。 + - `data: ` - 程序输入的数据以base-58字符串编码。 + +#### 内部指令结构 + +Solana运行时记录在事务处理期间调用的跨程序指令,并使这些程序可用,以提高每个事务指令在链上执行的内容的透明度。 调用的指令按原始事务处理指令分组,并按处理顺序列出。 + +内部指令的JSON结构定义为以下结构中的对象列表: + +- `index: number` - 内部指令源自的(一个或多个) 交易指令的索引 +- `instructions: ` - 内部程序指令的有序列表,在单个事务指令期间被调用。 + - `programIdIndex: ` - 在`message.accountKeys`数组中的索引,指示执行该指令的程序帐户。 + - `accounts: ` - `message.accountKeys`数组中的有序索引列表,指示要传递给程序的帐号。 + - `data: ` - 程序输入的数据以base-58字符串编码。 + +### getConfirmedBlocks + +返回两个插槽之间已确认区块的列表 + +#### 参数: + +- `` - start_slot,作为u64整数 +- `` - (可选) end_slot,作为u64整数 + +#### 结果: + +结果字段将是一个u64整数数组,其中列出了在`start_slot`和`end_slot`之间(如果提供)或最近确认的块(包括首尾)之间的已确认块。 允许的最大范围是500,000个插槽。 + + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc": "2.0","id":1,"method":"getConfirmedBlocks","params":[5, 10]} +' +``` + +结果: +```json +{"jsonrpc":"2.0","result":[5,6,7,8,9,10],"id":1} +``` + +### getConfirmedBlocksWithLimit + +返回从给定插槽开始的已确认块的列表 + +#### 参数: + +- `` -start_slot,作为u64整数 +- `` - 限制,如u64整数 + +#### 结果: + +结果字段将是一个u64整数数组,其中列出了已确认的块(从`start_slot`开始),最多到`limit`个块(包括上限)。 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc": "2.0","id":1,"method":"getConfirmedBlocksWithLimit","params":[5, 3]} +' +``` + +结果: +```json +{"jsonrpc":"2.0","result":[5,6,7],"id":1} +``` + +### getConfirmedSignaturesForAddress + +**不推荐使用:请改用getConfirmedSignaturesForAddress2** + +返回指定槽位范围内涉及地址的事务的所有已确认签名的列表。 允许的最大范围是10,000个插槽 + +#### 参数: + +- `` - 帐户地址为base-58编码的字符串 +- `` - 起始插槽(包含在内) +- `` -末端插槽(包含在内) + +#### 结果: + +结果字段将是以下内容的数组: + +- `` - 交易签名为以base-58编码的字符串 + +签名将根据其在其中确认的插槽进行排序,从最低到最高 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getConfirmedSignaturesForAddress", + "params": [ + "6H94zdiaYfRfPfKjYLjyr2VFBg6JHXygy84r3qhc3NsC", + 0, + 100 + ] + } +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": [ + "35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby", + "4bJdGN8Tt2kLWZ3Fa1dpwPSEkXWWTSszPSf1rRVsCwNjxbbUdwTeiWtmi8soA26YmwnKD4aAxNp8ci1Gjpdv4gsr", + "4LQ14a7BYY27578Uj8LPCaVhSdJGLn9DJqnUJHpy95FMqdKf9acAhUhecPQNjNUy6VoNFUbvwYkPociFSf87cWbG" + ], + "id": 1 +} +``` + +### getConfirmedSignaturesForAddress2 + +从提供的签名或最近确认的块中返回涉及时间在后的地址的交易的确认签名 + +#### 参数: +* `` - 帐户地址为base-58编码的字符串 +* `` - (可选) 包含以下字段的配置对象: + * `limit: ` - (可选) 要返回的最大交易签名 (1到1,000之间,默认值:1,000)。 + * `before: ` -(可选) 从此事务签名开始向后搜索。 如果未提供,则从最大已确认最大块的顶部开始搜索。 + * `until: ` - (可选) 搜索直到此交易签名,如果在达到限制之前被发现。 + +#### 结果: +结果字段将是交易签名信息的数组,按从新到旧的顺序排列: +* `` + * `signature: ` - 交易签名为以base-58编码的字符串 + * `slot: ` - 包含交易区块的插槽 + * `err: ` - 如果事务失败,则返回错误;如果事务成功,则返回null。 [TransactionError定义](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L24) + * `memo: ` - 与交易关联的备忘录,如果没有备忘录,则为null + +#### 示例: +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getConfirmedSignaturesForAddress2", + "params": [ + "Vote111111111111111111111111111111111111111", + { + "limit": 1 + } + ] + } +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": [ + { + "err": null, + "memo": null, + "signature": "5h6xBEauJ3PK6SWCZ1PGjBvj8vDdWG3KpwATGy1ARAXFSDwt8GFXM7W5Ncn16wmqokgpiKRLuS83KUxyZyv2sUYv", + "slot": 114 + } + ], + "id": 1 +} +``` + +### getConfirmedTransaction + +返回已确认交易的交易详细信息 + +#### 参数: + +- `` - 交易签名,以base-58编码的字符串,N编码尝试使用特定于程序的指令解析器来返回`transaction.message.instructions`列表中更多的人性化和显式的数据。 如果请求“jsonParsed”但找不到解析器,则该指令将退回到常规JSON编码(`帐户`,`数据`和`programIdIndex`字段)。 +- `` -(可选) 用于返回的事务的编码,可以是“ json”,“ jsonParsed”,“ base58”(* slow *)或“ base64”。 如果未提供参数,则默认编码为JSON。 + +#### 结果: + +- `` - 如果未找到交易或未确认 +- `` - 如果区块得到确认,则具有以下字段的对象: + - `slot: ` - 处理该交易记录的插槽 + - `transaction: ` - [Transaction](#transaction-structure) 对象,采用JSON格式或已编码的二进制数据,具体取决于编码参数 + - `meta: ` - 交易状态元数据对象: + - `err: ` - 如果交易失败,则返回错误;如果交易成功,则返回null。 [TransactionError定义](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L24) + - `fee: ` - 此交易收取的费用,以u64整数表示 + - `preBalances: ` - 处理交易之前的u64帐户余额数组 + - `postBalances: ` - 处理交易后的u64帐户余额数组 + - `innerInstructions: ` -[内部指令](#inner-instructions-structure)列表,如果在此交易处理期间尚未启用内部指令记录,则将其省略 + - `logMessages: ` - 字符串日志消息的数组;如果在此交易期间尚未启用日志消息记录,则将其省略 + - DEPRECATED: `status: ` - 交易状态 + - `"Ok": ` - 交易成功 + - `"Err": ` - 交易失败,出现TransactionError + +#### 示例: +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getConfirmedTransaction", + "params": [ + "2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv", + "json" + ] + } +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "meta": { + "err": null, + "fee": 5000, + "innerInstructions": [], + "postBalances": [ + 499998932500, + 26858640, + 1, + 1, + 1 + ], + "preBalances": [ + 499998937500, + 26858640, + 1, + 1, + 1 + ], + "status": { + "Ok": null + } + }, + "slot": 430, + "transaction": { + "message": { + "accountKeys": [ + "3UVYmECPPMZSCqWKfENfuoTv51fTDTWicX9xmBD2euKe", + "AjozzgE83A3x1sHNUR64hfH7zaEBWeMaFuAN9kQgujrc", + "SysvarS1otHashes111111111111111111111111111", + "SysvarC1ock11111111111111111111111111111111", + "Vote111111111111111111111111111111111111111" + ], + "header": { + "numReadonlySignedAccounts": 0, + "numReadonlyUnsignedAccounts": 3, + "numRequiredSignatures": 1 + }, + "instructions": [ + { + "accounts": [ + 1, + 2, + 3, + 0 + ], + "data": "37u9WtQpcm6ULa3WRQHmj49EPs4if7o9f1jSRVZpm2dvihR9C8jY4NqEwXUbLwx15HBSNcP1", + "programIdIndex": 4 + } + ], + "recentBlockhash": "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B" + }, + "signatures": [ + "2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv" + ] + } + }, + "id": 1 +} +``` + +#### 示例: +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getConfirmedTransaction", + "params": [ + "2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv", + "base64" + ] + } +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "meta": { + "err": null, + "fee": 5000, + "innerInstructions": [], + "postBalances": [ + 499998932500, + 26858640, + 1, + 1, + 1 + ], + "preBalances": [ + 499998937500, + 26858640, + 1, + 1, + 1 + ], + "status": { + "Ok": null + } + }, + "slot": 430, + "transaction": [ + "AVj7dxHlQ9IrvdYVIjuiRFs1jLaDMHixgrv+qtHBwz51L4/ImLZhszwiyEJDIp7xeBSpm/TX5B7mYzxa+fPOMw0BAAMFJMJVqLw+hJYheizSoYlLm53KzgT82cDVmazarqQKG2GQsLgiqktA+a+FDR4/7xnDX7rsusMwryYVUdixfz1B1Qan1RcZLwqvxvJl4/t3zHragsUp0L47E24tAFUgAAAABqfVFxjHdMkoVmOYaR1etoteuKObS21cc1VbIQAAAAAHYUgdNXR0u3xNdiTr072z2DVec9EQQ/wNo1OAAAAAAAtxOUhPBp2WSjUNJEgfvy70BbxI00fZyEPvFHNfxrtEAQQEAQIDADUCAAAAAQAAAAAAAACtAQAAAAAAAAdUE18R96XTJCe+YfRfUp6WP+YKCy/72ucOL8AoBFSpAA==", + "base64" + ] + }, + "id": 1 +} +``` + +### getEpochInfo + +返回当前epoch的信息 + +#### 参数: + +- `` -(可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +结果字段具有以下字段的对象: + +- `absoluteSlot: `,当前插槽 +- `块高度: `,当前区块高度 +- `epoch: `,目前的epoch +- `slotIndex: `,相对于当前epoch开始的插槽 +- `slotsInEpoch: `,此epoch的插槽数 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getEpochInfo"} +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "absoluteSlot": 166598, + "blockHeight": 166500, + "epoch": 27, + "slotIndex": 2790, + "slotsInEpoch": 8192 + }, + "id": 1 +} +``` + +### getEpochSchedule + +从该集群的创世配置返回epoch时间表信息 + +#### 参数: + +无 + +#### 结果: + +结果字段具有以下字段的对象: + +- `slotsPerEpoch: `,每个时期的最大插槽数 +- `leaderScheduleSlotOffset:`,在某个时期开始之前的槽数,以计算该时期的领导者时间表 +- `warmup:`,epoch是否开始短而长 +- `firstNormalEpoch:`,第一个正常长度的时期,log2(slotsPerEpoch) - log2(MINIMUM_SLOTS_PER_EPOCH) +- `firstNormalSlot:`,MINIMUM_SLOTS_PER_EPOCH \ *(2.pow(firstNormalEpoch)-1) + +#### 例子: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getEpochSchedule"} +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "firstNormalEpoch": 8, + "firstNormalSlot": 8160, + "leaderScheduleSlotOffset": 8192, + "slotsPerEpoch": 8192, + "warmup": true + }, + "id": 1 +} +``` + +### 获取费用计算器对于Blockhash + +返回与查询区块哈希关联的费用计算器,如果区块哈希已过期,则返回`null` + +#### 参数: + +- `` - 查询 blockhash 作为 Base58 编码的字符串 +- `` - (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +结果将是一个 RpcResponse JSON 对象,其 `value` 等于: + +- `` - 如果查询 blockhash 已过期 +- `` - 否则为 JSON 对象,其中包含: + - `feeCalculator:`,`FeeCalculator`对象描述了在查询的区块哈希中的集群费率 + +#### 例子: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getFeeCalculatorForBlockhash", + "params": [ + "GJxqhuxcgfn5Tcj6y3f8X4FeCDd2RQ6SnEMo1AAxrPRZ" + ] + } +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 221 + }, + "value": { + "feeCalculator": { + "lamportsPerSignature": 5000 + } + } + }, + "id": 1 +} +``` + +### getFeeRateGovernor + +从根银行返回费率调控者信息 + +#### 参数: + +没有 + +#### 结果: + +` 结果`字段将是具有以下字段的`对象`: + +- `burnPercent:`,收取的销毁费用百分比 +- `maxLamportsPerSignature:`,` lamportsPerSignature` 可以获取最大值 +- `minLamportsPerSignature: `,`lamportsPerSignature` 可以达到最小值 +- `targetLamportsPerSignature:`,集群所需的费率 +- `targetSignaturesPerSlot:`,集群所需的签名率 + +#### 例子: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getFeeRateGovernor"} +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 54 + }, + "value": { + "feeRateGovernor": { + "burnPercent": 50, + "maxLamportsPerSignature": 100000, + "minLamportsPerSignature": 5000, + "targetLamportsPerSignature": 10000, + "targetSignaturesPerSlot": 20000 + } + } + }, + "id": 1 +} +``` + +### getFees + +从账本中返回最近的区块哈希值,可以用来计算使用该账目提交交易成本的费用明细表,以及该区块哈希值将在其中有效的最后一个时隙。 + +#### 参数: + +- `` - (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +结果将是RpcResponse JSON对象,其中`value`设置为具有以下字段的JSON对象: + +- `blockhash:` - 以 base-58 编码的 Hash 字符串 +- `feeCalculator:` - FeeCalculator 对象,此区块哈希的费用明细表 +- `lastValidSlot:` - 区块哈希有效的最后一个插槽 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getFees"} +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1 + }, + "value": { + "blockhash": "CSymwgTNX1j3E4qhKfJAUE41nBWEwXufoYryPbkde5RR", + "feeCalculator": { + "lamportsPerSignature": 5000 + }, + "lastValidSlot": 297 + } + }, + "id": 1 +} +``` + +### getFirstAvailableBlock + +返回尚未从账本清除的最低确认区块的插槽 + +#### 参数: + +无 + +#### 结果: + +- `` - 插槽 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getFirstAvailableBlock"} +' +``` + +结果: +```json +{"jsonrpc":"2.0","result":250000,"id":1} +``` + +### getGenesisHash + +返回起源哈希值 + +#### 参数: + +无 + +#### 结果: + +- `` - 哈希值以 base-58 编码的字符串 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getGenesisHash"} +' +``` + +结果: +```json +{"jsonrpc":"2.0","result":"GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC","id":1} +``` + +### getHealth + +返回节点的当前运行状况。 + +如果将一个或多个 `--trusted-validator` 参数提供给 `solana-validator`,则当节点位于最高可信验证器的 `HEALTH_CHECK_SLOT_DISTANCE` 插槽内时,将返回 "ok",否则将返回错误。 如果未提供受信任的验证器,则始终返回“ ok”。 + +#### 参数: + +无 + +#### 结果: + +如果该节点运行状况良好,则为 "ok";如果该节点运行状况不良,则将返回 JSON RPC 错误响应。 错误响应的详细信息是 **不稳定**,将来可能会更改 + + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getHealth"} +' +``` + +健康结果: +```json +{"jsonrpc":"2.0","result": "ok","id":1} +``` + +不健康的结果(通用): +```json +{ + "jsonrpc": "2.0", + "error": { + "code": -32005, + "message": "Node is unhealthy", + "data": {} + }, + "id": 1 +} +``` + +不健康的结果(如果有其他信息可用) +```json +{ + "jsonrpc": "2.0", + "error": { + "code": -32005, + "message": "Node is behind by 42 slots", + "data": { + "numSlotsBehind": 42 + } + }, + "id": 1 +} +``` + +### getIdentity + +返回当前节点的身份发布密钥 + +#### 参数: + +无 + +#### 结果: + +结果字段将是具有以下字段的 JSON 对象: + +- `identity`,当前节点的身份发布密钥(以 base-58 编码的字符串) + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getIdentity"} +' +``` + +结果: +```json +{"jsonrpc":"2.0","result":{"identity": "2r1F4iWqVcb8M1DbAjQuFpebkQHY9hcVU4WuW2DJBppN"},"id":1} +``` + +### getInflationGovernor + +返回当前的通胀调控器 + +#### 参数: + +- `` -(可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +结果字段将是具有以下字段的JSON对象: + +- `initial:`,从时间 0 开始的初始通胀百分比 +- `terminal:`,终端通胀百分比 +- `taper:`,每年降低通货膨胀率 +- `foundation:`,分配给基金会的总通货膨胀百分比 +- `foundationTerm:`,基础池通货膨胀的持续时间,以年为单位 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getInflationGovernor"} +' +``` + +结果: +```json +No translations matched your search +{ + "jsonrpc": "2.0", + "result": { + "foundation": 0.05, + "foundationTerm": 7, + "initial": 0.15, + "taper": 0.15, + "terminal": 0.015 + }, + "id": 1 +} +``` + +### getInflationRate + +返回当前epoch的特定通货膨胀值 + +#### 参数: + +无 + +#### 结果: + +结果字段将是具有以下字段的JSON对象: + +- `total:`,总通货膨胀 +- `validator:`,分配给验证节点的通货膨胀 +- `foundation:`,将通货膨胀分配给基金会 +- `epoch:`,这些值对其有效的时代 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getInflationRate"} +' +``` + +结果: +```json +{"jsonrpc":"2.0","result":{"epoch":100,"foundation":0.001,"total":0.149,"validator":0.148},"id":1} +``` + +### getLargestAccounts + +按Lamport余额返回20个最大帐户 + +#### 参数: + +- `` -(可选) 包含以下可选字段的配置对象: + - (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + - (可选)`filter:` - 按帐户类型过滤结果;当前支持:`circulating | nonCirculating` + +#### 结果: + +结果将是一个RpcResponse JSON对象,其`值`等于一个数组: + +- `` - 否则为JSON对象,其中包含: + - `address:`,以 Base-58 为底的帐户编码地址 + - `lamports:`,帐户中 lamport 的数量,以 u64 表示 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getLargestAccounts"} +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 54 + }, + "value": [ + { + "lamports": 999974, + "address": "99P8ZgtJYe1buSK8JXkvpLh8xPsCFuLYhz9hQFNw93WJ" + }, + { + "lamports": 42, + "address": "uPwWLo16MVehpyWqsLkK3Ka8nLowWvAHbBChqv2FZeL" + }, + { + "lamports": 42, + "address": "aYJCgU7REfu3XF8b3QhkqgqQvLizx8zxuLBHA25PzDS" + }, + { + "lamports": 42, + "address": "CTvHVtQ4gd4gUcw3bdVgZJJqApXE9nCbbbP4VTS5wE1D" + }, + { + "lamports": 20, + "address": "4fq3xJ6kfrh9RkJQsmVd5gNMvJbuSHfErywvEjNQDPxu" + }, + { + "lamports": 4, + "address": "AXJADheGVp9cruP8WYu46oNkRbeASngN5fPCMVGQqNHa" + }, + { + "lamports": 2, + "address": "8NT8yS6LiwNprgW4yM1jPPow7CwRUotddBVkrkWgYp24" + }, + { + "lamports": 1, + "address": "SysvarEpochSchedu1e111111111111111111111111" + }, + { + "lamports": 1, + "address": "11111111111111111111111111111111" + }, + { + "lamports": 1, + "address": "Stake11111111111111111111111111111111111111" + }, + { + "lamports": 1, + "address": "SysvarC1ock11111111111111111111111111111111" + }, + { + "lamports": 1, + "address": "StakeConfig11111111111111111111111111111111" + }, + { + "lamports": 1, + "address": "SysvarRent111111111111111111111111111111111" + }, + { + "lamports": 1, + "address": "Config1111111111111111111111111111111111111" + }, + { + "lamports": 1, + "address": "SysvarStakeHistory1111111111111111111111111" + }, + { + "lamports": 1, + "address": "SysvarRecentB1ockHashes11111111111111111111" + }, + { + "lamports": 1, + "address": "SysvarFees111111111111111111111111111111111" + }, + { + "lamports": 1, + "address": "Vote111111111111111111111111111111111111111" + } + ] + }, + "id": 1 +} +``` + +### getLeaderSchedule + +获取领导者时间表 + +#### 参数: + +- `` -(可选) 获取与提供的插槽相对应的时代的领导者时间表。 如果未指定,则获取当前时期的领导者时间表 +- `` -(可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +- `` - 如果未找到请求的 epoch +- `` - 否则,结果字段将是领导者公钥(以 Base-58 编码的字符串) 及其对应的领导者插槽索引作为值的字典(索引相对于所请求 epoch 中的第一个插槽) + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getLeaderSchedule"} +' +``` + +结果: +```json +{ + "jsonrpc":"2.0", + "result":{ + "4Qkev8aNZcqFNSRhQzwyLMFSsi94jHqE8WNVTJzTP99F":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63] + }, + "id":1 +} +``` + +### getMinimumBalanceForRentExemption + +返回免除帐户租金所需的最低余额。 + +#### 参数: + +- `` - 帐户数据长度 +- `` - (可选的) [承诺](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +- `` - 帐户中所需的最低 lamport + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0", "id":1, "method":"getMinimumBalanceForRentExemption", "params":[50]} +' +``` + +结果: +```json +{"jsonrpc":"2.0","result":500,"id":1} +``` + +### getMultipleAccounts + +返回帐户信息以获取公钥列表 + +#### 参数: + +- `` - 要查询的公钥数组,以 base-58 编码的字符串 +- `` -(可选) 包含以下可选字段的配置对象: + - (可选)[承诺](jsonrpc-api.md#configuring-state-commitment) + - `encoding:` - 帐户数据的编码,可以是 "base58"(*慢一点*),"base64","base64+zstd" 或 "jsonParsed"。 "base58" 仅限于少于 128 个字节的帐户数据。 "base64" 将为任何大小的帐户数据返回 base64 编码的数据。 "base64+zstd" 使用 [Zstandard](https://facebook.github.io/zstd/) 压缩帐户数据,并对结果进行 base64 编码。 "jsonParsed" 编码尝试使用特定于程序的状态解析器来返回更多的人类可读和显式的帐户状态数据。 如果请求了"jsonParsed",但找不到解析器,则该字段回退为 "base64" 编码,当 `data` 字段为 `` 类型时可以检测到。 + - (可选) `dataSlice:` - 使用提供的 `offset:` 和 `length:`字段限制返回的帐户数据;仅适用于 "base58","base64" 或 "base64+zstd" 编码。 + + +#### 结果: + +结果将是一个RpcResponse JSON对象,其`值`等于: + +数组: + +- `` - 如果该 Pubkey 上的帐户不存在 +- `` - 否则为 JSON 对象,其中包含: + - `lamports:`,分配给此帐户的 lamport 数量,以 u64 表示 + - `owner:`,此帐户已分配给该程序的 base-58 编码的 Pubkey + - `data:<[string,encoding] | object>`,与帐户关联的数据,可以是编码的二进制数据,也可以是 JSON 格式的 `{: }`,具体取决于编码参数 + - `executable:`,布尔值,指示帐户是否包含程序(并且严格为只读) + - `rentEpoch:`,此帐户下一次将要欠租金的时期,即 u64 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getMultipleAccounts", + "params": [ + [ + "vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg", + "4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA" + ], + { + "dataSlice": { + "offset": 0, + "length": 0 + } + } + ] + } +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1 + }, + "value": [ + { + "data": [ + "AAAAAAEAAAACtzNsyJrW0g==", + "base64" + ], + "executable": false, + "lamports": 1000000000, + "owner": "11111111111111111111111111111111", + "rentEpoch": 2 + }, + { + "data": [ + "", + "base64" + ], + "executable": false, + "lamports": 5000000000, + "owner": "11111111111111111111111111111111", + "rentEpoch": 2 + } + ] + }, + "id": 1 +} +``` + +#### 示例: +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getMultipleAccounts", + "params": [ + [ + "vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg", + "4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA" + ], + { + "encoding": "base58" + } + ] + } +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1 + }, + "value": [ + { + "data": [ + "11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHRTPuR3oZ1EioKtYGiYxpxMG5vpbZLsbcBYBEmZZcMKaSoGx9JZeAuWf", + "base58" + ], + "executable": false, + "lamports": 1000000000, + "owner": "11111111111111111111111111111111", + "rentEpoch": 2 + }, + { + "data": [ + "", + "base58" + ], + "executable": false, + "lamports": 5000000000, + "owner": "11111111111111111111111111111111", + "rentEpoch": 2 + } + ] + }, + "id": 1 +} +``` + +### getProgramAccounts + +返回提供的程序公钥拥有的所有帐户 + +#### 参数: + +- `` - 程序的发布密钥,以 base-58 编码的字符串 +- `` -(可选) 包含以下可选字段的配置对象: + - (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + - `encoding` - 帐户数据的编码,可以是 "base58"(*slow*),"base64","base64+zstd" 或 "jsonParsed"。 "base58" 仅限于少于 128 个字节的帐户数据。 "base64" 将为任何大小的帐户数据返回 base64 编码的数据。 "base64+zstd" 使用 [Zstandard](https://facebook.github.io/zstd/) 压缩帐户数据,并对结果进行 base64 编码。 "jsonParsed" 编码尝试使用特定于程序的状态解析器来返回更多的人类可读和显式的帐户状态数据。 如果请求了"jsonParsed",但找不到解析器,则该字段回退为 "base64" 编码,当 `data` 字段为 `` 类型时可以检测到。 + - (可选)`dataSlice:` - 使用提供的 `offset: ` 和 `length: ` 字段限制返回的帐户数据;仅适用于 "base58","base64" 或 "base64+zstd" 编码。 + - (可选)`filters:` - 使用各种 [filter objects](jsonrpc-api.md#filters) 过滤结果;帐户必须满足所有过滤条件,才能包含在结果中 + +##### 过滤器: +- `memcmp:` - 比较提供的一系列字节和程序帐户数据的特定偏移量。 栏位: + - `offset:` - 进入计划帐户数据的偏移量以开始比较 + - `bytes:` - 要匹配的数据,以 base-58 编码的字符串 + +- `dataSize:` - 比较程序帐户数据长度与提供的数据大小 + +#### 结果: + +结果字段将是一个JSON对象数组,其中包含: + +- `pubkey:` - 帐户 Pubkey 作为以 Base-58 为底的编码字符串 +- `account:` - 一个 JSON 对象,具有以下子字段: + - `lamports:`,分配给此帐户的 lamport 数量,以 u64 表示 + - `owner:`,此帐户已分配给程序的 base-58 编码程序的 Pubkey `data:<[string,encoding] | object>`,与帐户相关联的数据,可以是编码的二进制数据或 JSON 格式为 `{: }`,具体取决于编码参数 + - `executable:`,布尔值,指示帐户是否包含程序(并且严格为只读) + - `rentEpoch:`,此帐户下一次将要欠租金的时期,即 u64 + +#### 示例: +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0", "id":1, "method":"getProgramAccounts", "params":["4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T"]} +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": [ + { + "account": { + "data": "2R9jLfiAQ9bgdcw6h8s44439", + "executable": false, + "lamports": 15298080, + "owner": "4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T", + "rentEpoch": 28 + }, + "pubkey": "CxELquR1gPP8wHe33gZ4QxqGB3sZ9RSwsJ2KshVewkFY" + } + ], + "id": 1 +} +``` + +#### 示例: +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getProgramAccounts", + "params": [ + "4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T", + { + "filters": [ + { + "dataSize": 17 + }, + { + "memcmp": { + "offset": 4, + "bytes": "3Mc6vR" + } + } + ] + } + ] + } +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": [ + { + "account": { + "data": "2R9jLfiAQ9bgdcw6h8s44439", + "executable": false, + "lamports": 15298080, + "owner": "4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T", + "rentEpoch": 28 + }, + "pubkey": "CxELquR1gPP8wHe33gZ4QxqGB3sZ9RSwsJ2KshVewkFY" + } + ], + "id": 1 +} +``` + +### getRecentBlockhash + +从账本返回最近的区块哈希值,以及可用于计算使用该账目提交交易的费用的费用表。 + +#### 参数: + +- `` -(可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +一个 RPC 响应,其中包含一个由字符串 blockhash 和 FeeCalculator JSON 对象组成的JSON 对象。 + +- `RpcResponse ` - RpcResponse JSON 对象,其中 `value` 字段设置为 JSON 对象,包括: +- `blockhash:` - 以 base-58 编码的 Hash 字符串 +- `feeCalculator:` - FeeCalculator 对象,此区块哈希的费用明细表 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d 'i + {"jsonrpc":"2.0","id":1, "method":"getRecentBlockhash"} +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1 + }, + "value": { + "blockhash": "CSymwgTNX1j3E4qhKfJAUE41nBWEwXufoYryPbkde5RR", + "feeCalculator": { + "lamportsPerSignature": 5000 + } + } + }, + "id": 1 +} +``` + +### getRecentPerformanceSamples + +以相反的插槽顺序返回最近的性能样本列表。 每60秒进行一次性能采样,其中包括在给定时间窗口内发生的交易和插槽的数量。 + +#### 参数: +- `limit:` -(可选) 要返回的样本数(最大为 720) + +#### 结果: + +数组: + +- `RpcPerfSample` + - `slot:` - 在以下位置采样的插槽 + - `numTransactions:` - 样本中的交易数量 + - `numSlots:` - 样本中的插槽数 + - `samplePeriodSecs:` - 示例窗口中的秒数 + +#### 示例: + +请求: +```bash +// Request +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0", "id":1, "method":"getRecentPerformanceSamples", "params": [4]} +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": [ + { + "numSlots": 126, + "numTransactions": 126, + "samplePeriodSecs": 60, + "slot": 348125 + }, + { + "numSlots": 126, + "numTransactions": 126, + "samplePeriodSecs": 60, + "slot": 347999 + }, + { + "numSlots": 125, + "numTransactions": 125, + "samplePeriodSecs": 60, + "slot": 347873 + }, + { + "numSlots": 125, + "numTransactions": 125, + "samplePeriodSecs": 60, + "slot": 347748 + } + ], + "id": 1 +} +``` + + +### getSnapshotSlot + +返回节点具有快照的最高插槽 + +#### 参数: + +无 + +#### 结果: + +- `` - Snapshot slot + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getSnapshotSlot"} +' +``` + +结果: +```json +{"jsonrpc":"2.0","result":100,"id":1} +``` + +节点没有快照时的结果: +```json +{"jsonrpc":"2.0","error":{"code":-32008,"message":"No snapshot"},"id":1} +``` + +### getSignatureStatuses + +返回签名列表的状态。 除非包括`searchTransactionHistory`配置参数,否则此方法仅搜索签名的最新状态缓存,该缓存会保留所有活动插槽以及` MAX_RECENT_BLOCKHASHES`根目录插槽的状态。 + +#### 参数: + +- `` - 确认交易签名的数组,以 base-58 编码的字符串 +- `` -(可选) 包含以下字段的配置对象: + - `searchTransactionHistory:` - 如果为 true,Solana 节点将在其账本缓存中搜索在最近状态缓存中未找到的任何签名 + +#### 结果: + +一个 RpcResponse,其中包含一个由 TransactionStatus 对象数组组成的 JSON 对象。 + +- `RpcResponse ` - 具有 `value` 字段的 RpcResponse JSON 对象: + +数组: + +- `` - 未知交易 +- `` + - `slot:` - 交易处理的插槽 + - ` confirmations:` - 自签名确认以来的块数,如果已植根则为 null,并由集群的绝大多数决定 + - `err:` - 如果交易失败,则返回错误;如果交易成功,则返回 null。 [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L24) + - `confirmationStatus:` - 交易的集群确认状态; `processed`,` confirmed` 或 `finalized`。 有关乐观确认的更多信息,请参见 [承诺](jsonrpc-api.md#configuring-state-commitment)。 + - 弃用:` status:` - 交易状态 + - `"Ok":` - 交易成功 + - `"Err":` - 交易失败,出现 TransactionError + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getSignatureStatuses", + "params": [ + [ + "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW", + "5j7s6NiJS3JAkvgkoc18WVAsiSaci2pxB2A6ueCJP4tprA2TFg9wSyTLeYouxPBJEMzJinENTkpA52YStRW5Dia7" + ] + ] + } +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 82 + }, + "value": [ + { + "slot": 72, + "confirmations": 10, + "err": null, + "status": { + "Ok": null + }, + "confirmationStatus": "confirmed", + }, + null + ] + }, + "id": 1 +} +``` + +#### 示例: +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getSignatureStatuses", + "params": [ + [ + "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW", + "5j7s6NiJS3JAkvgkoc18WVAsiSaci2pxB2A6ueCJP4tprA2TFg9wSyTLeYouxPBJEMzJinENTkpA52YStRW5Dia7" + ] + ] + } +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 82 + }, + "value": [ + { + "slot": 48, + "confirmations": null, + "err": null, + "status": { + "Ok": null + }, + "confirmationStatus": "finalized", + }, + null + ] + }, + "id": 1 +} +``` + +### getSlot + +返回节点正在处理的当前插槽 + +#### 参数: + +- `` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +- `` - 当前插槽 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getSlot"} +' +``` + +结果: +```json +{"jsonrpc":"2.0","result":1234,"id":1} +``` + +### getSlotLeader + +返回当前的插槽领导 + +#### 参数: + +- `` -(可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +- `` - 节点身份 Pubkey 作为 base-58 编码的字符串 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getSlotLeader"} +' +``` + +结果: +```json +{"jsonrpc":"2.0","result":"ENvAW7JScgYq6o4zKZwewtkzzJgDzuJAFxYasvmEQdpS","id":1} +``` + +### getStakeActivation + +返回权益账户的epoch激活信息 + +#### 参数: + +* `` - 要查询的股份账户的公钥,以 base-58 编码的字符串 +* `` - (可选) 包含以下可选字段的配置对象: + * (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + * (可选)`epoch:` - 用于计算激活详细信息的时期。 如果未提供参数,则默认为当前 epoch。 + +#### 结果: + +结果将是具有以下字段的JSON对象: + +* `state:` - 时期有效的股份 +* `inactive:` - 在新时期无效的股份 + +#### 示例: +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getStakeActivation", "params": ["CYRJWqiSjLitBAcRxPvWpgX3s5TvmN2SuRY3eEYypFvT"]} +' +``` + +结果: +```json +{"jsonrpc":"2.0","result":{"active":197717120,"inactive":0,"state":"active"},"id":1} +``` + +#### 示例: +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getStakeActivation", + "params": [ + "CYRJWqiSjLitBAcRxPvWpgX3s5TvmN2SuRY3eEYypFvT", + { + "epoch": 4 + } + ] + } +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "active": 124429280, + "inactive": 73287840, + "state": "activating" + }, + "id": 1 +} +``` + +### getSupply + +返回有关当前电源的信息。 + +#### 参数: + +- `` - (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +结果将是RpcResponse JSON对象,其`值`等于包含以下内容的JSON对象: + +- `total:` - Lamports 的总供应量 +- ` circulating:` - 以 lamports 的循环供应 +- ` nonCirculating:` - 以 lamports 的的非循环供应 +- `nonCirculatingAccounts:` - 非流通账户的账户地址数组,作为字符串 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0", "id":1, "method":"getSupply"} +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1114 + }, + "value": { + "circulating": 16000, + "nonCirculating": 1000000, + "nonCirculatingAccounts": [ + "FEy8pTbP5fEoqMV1GdTz83byuA8EKByqYat1PKDgVAq5", + "9huDUZfxoJ7wGMTffUE7vh1xePqef7gyrLJu9NApncqA", + "3mi1GmwEE3zo2jmfDuzvjSX9ovRXsDUKHvsntpkhuLJ9", + "BYxEJTDerkaRWBem3XgnVcdhppktBXa2HbkHPKj2Ui4Z" + ], + "total": 1016000 + } + }, + "id": 1 +} +``` + +### getTokenAccountBalance + +返回SPL令牌帐户的代币余额。 **UNSTABLE** + +#### 参数: + +- `` - 要查询的代币帐户的公钥,以 base-58 编码的字符串 +- `` - (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +结果将是RpcResponse JSON对象,其`值`等于包含以下内容的JSON对象: + +- `uiAmount:` - 余额,使用薄荷规定的小数 +- `amount:` - 不带小数的原始余额,u64 的字符串表示形式 +- `decimals:` - 小数点右边的以 10 为基数的数字 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0", "id":1, "method":"getTokenAccountBalance", "params": ["7fUAJdStEuGbc3sM84cKRL6yYaaSstyLSU4ve5oovLS7"]} +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1114 + }, + "value": { + "uiAmount": 98.64, + "amount": "9864", + "decimals": 2 + }, + "id": 1 + } +} +``` + +### getTokenAccountsByDelegate + +通过批准的代表返回所有SPL令牌帐户。 **UNSTABLE** + +#### 参数: + +- `` - 要查询的帐户委托人的公钥,以 base-58 编码的字符串 +- `` - 可以: + * `mint:` - 特定令牌Mint的发布密钥,用于将帐户限制为以 base-58 编码的字符串;或者 + * `programId:` - 拥有帐户的Token程序 ID 的 Pubkey,以 base-58 编码的字符串 +- `` - (可选) 包含以下可选字段的配置对象: + - (可选)[承诺](jsonrpc-api.md#configuring-state-commitment) + - `encoding:` - 帐户数据的编码,可以是 "base58"(*慢一点*),"base64","base64+zstd" 或 "jsonParsed"。 "jsonParsed" 编码尝试使用特定于程序的状态解析器来返回更多的人类可读和显式的帐户状态数据。 如果请求 "jsonParsed",但找不到特定帐户的有效铸造,则该帐户将从结果中滤除。 + - (可选) `dataSlice:` - 使用提供的 `offset: ` 和 `length: `字段限制返回的帐户数据;仅适用于 "base58","base64" 或 "base64+zstd" 编码。 + +#### 结果: + +结果将是RpcResponse JSON对象,其`值`等于JSON对象的数组,其中将包含: + +- `pubkey:` - 帐户 Pubkey 作为以 Base-58 为底的编码字符串 +- `account:` - 一个JSON对象,具有以下子字段: + - `lamports:`,分配给此帐户的 lamport 数量,以 u64 表示 + - `owner:`,此帐户已分配给该程序的 base-58 编码的 Pubkey + - `data:`,与帐户关联的令牌状态数据,可以是编码的二进制数据,也可以是JSON 格式的 `{: }` + - `executable: `,布尔值,指示帐户是否包含程序 \(并且严格为只读\) + - ` rentEpoch:`,此帐户下一次将要欠租金的时期,即 u64 + +#### 示例: + +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getTokenAccountsByDelegate", + "params": [ + "4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T", + { + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "encoding": "jsonParsed" + } + ] + } +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1114 + }, + "value": [ + { + "data": { + "program": "spl-token", + "parsed": { + "accountType": "account", + "info": { + "tokenAmount": { + "amount": "1", + "uiAmount": 0.1, + "decimals": 1 + }, + "delegate": "4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T", + "delegatedAmount": 1, + "isInitialized": true, + "isNative": false, + "mint": "3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E", + "owner": "CnPoSPKXu7wJqxe59Fs72tkBeALovhsCxYeFwPCQH9TD" + } + } + }, + "executable": false, + "lamports": 1726080, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "rentEpoch": 4 + } + ] + }, + "id": 1 +} +``` + +### getTokenAccountsByOwner + +按代币所有者返回所有SPL代币帐户。 **UNSTABLE** + +#### 参数: + +- `` - 要查询的帐户所有者的公钥,以 base-58 编码的字符串 +- `` - 可以: + * `mint:` - 特定代币 Mint 的发布密钥,用于将帐户限制为以 base-58 编码的字符串;或者 + * `programId:` - 拥有帐户的 Token 程序ID的 Pubkey,以base-58编码的字符串 +- `` - (可选) 包含以下可选字段的配置对象: + - (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + - `encoding: ` - 帐户数据的编码,可以是 "base58"(*slow*),"base64","base64+zstd" 或 "jsonParsed"。 "jsonParsed" 编码尝试使用特定于程序的状态解析器来返回更多的人类可读和显式的帐户状态数据。 如果请求 "jsonParsed",但找不到特定帐户的有效铸造,则该帐户将从结果中滤除。 + - (可选) `dataSlice:` - 使用提供的 `offset:` 和 `length:`字段限制返回的帐户数据;仅适用于 "base58","base64" 或 "base64+zstd" 编码。 + +#### 结果: + +结果将是RpcResponse JSON对象,其`值`等于JSON对象的数组,其中将包含: + +- `pubkey:` - 帐户 Pubkey 作为以 Base-58 为底的编码字符串 +- `account:` - 一个JSON 对象,具有以下子字段: + - `lamports:`,分配给此帐户的 lamport 数量,以 u64 表示 + - `owner:`,此帐户已分配给该程序的 base-58 编码的 Pubkey + - `data:`,与帐户关联的令牌状态数据,可以是编码的二进制数据,也可以是JSON 格式的 `{: }` + - `executable: `,布尔值,指示帐户是否包含程序\(并且严格为只读\) + - `rentEpoch:`,此帐户下一次将要欠租金的时期,即 u64 + +#### 示例: + +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getTokenAccountsByOwner", + "params": [ + "4Qkev8aNZcqFNSRhQzwyLMFSsi94jHqE8WNVTJzTP99F", + { + "mint": "3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E" + }, + { + "encoding": "jsonParsed" + } + ] + } +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1114 + }, + "value": [ + { + "data": { + "program": "spl-token", + "parsed": { + "accountType": "account", + "info": { + "tokenAmount": { + "amount": "1", + "uiAmount": 0.1, + "decimals": 1 + }, + "delegate": null, + "delegatedAmount": 1, + "isInitialized": true, + "isNative": false, + "mint": "3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E", + "owner": "4Qkev8aNZcqFNSRhQzwyLMFSsi94jHqE8WNVTJzTP99F" + } + } + }, + "executable": false, + "lamports": 1726080, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "rentEpoch": 4 + } + ] + }, + "id": 1 +} +``` + +### getTokenLargestAccounts + +返回特殊的 SPL Token 类型的 20 个最大账户。 **UNSTABLE** + +#### 参数: + +- `` - 要查询的代币 Mint 的公钥,以 base-58 编码的字符串 +- `` - (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +结果将是RpcResponse JSON对象,其`值`等于包含以下内容的JSON对象数组: + +- `address:` - 代币帐户的地址 +- `uiAmount:` - 代币账户余额,使用薄荷规定的小数 +- `amount:` - 不带小数的原始令牌帐户余额,是 u64 的字符串表示形式 +- `decimals:` - 小数点右边的以 10 为基数的数字 + +#### 示例: + +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0", "id":1, "method":"getTokenLargestAccounts", "params": ["3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E"]} +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1114 + }, + "value": [ + { + "address": "FYjHNoFtSQ5uijKrZFyYAxvEr87hsKXkXcxkcmkBAf4r", + "amount": "771", + "decimals": 2, + "uiAmount": 7.71 + }, + { + "address": "BnsywxTcaYeNUtzrPxQUvzAWxfzZe3ZLUJ4wMMuLESnu", + "amount": "229", + "decimals": 2, + "uiAmount": 2.29 + } + ] + }, + "id": 1 +} +``` + +### getTokenSupply + +返回SPL代币类型的总供给。 **UNSTABLE** + +#### 参数: + +- `` - 要查询的代币 Mint 的公钥,以 base-58 编码的字符串 +- `` - (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +结果将是RpcResponse JSON对象,其`值`等于包含以下内容的JSON对象: + +- `uiAmount:` - 代币总供给,使用薄荷规定的小数 +- `amount:` - 不带小数的原始令牌总数,u64 的字符串表示形式 +- `decimals:` - 小数点右边的以 10 为基数的数字 + +#### 示例: + +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0", "id":1, "method":"getTokenSupply", "params": ["3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E"]} +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1114 + }, + "value": { + "uiAmount": 1000, + "amount": "100000", + "decimals": 2 + } + }, + "id": 1 +} +``` + +### getTransactionCount + +从账本中返回当前交易计数 + +#### 参数: + +- `` - (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +- `` - 计数 + +#### 示例: + +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getTransactionCount"} +' + +``` + +结果: +```json +{"jsonrpc":"2.0","result":268,"id":1} +``` + +### getVersion + +返回在节点上运行的当前solana版本 + +#### 参数: + +无 + +#### 结果: + +结果字段将是具有以下字段的JSON对象: + +- `solana-core`,solana-core 的软件版本 +- `feature-set`,当前软件功能集的唯一标识符 + +#### 示例: + +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getVersion"} +' +``` + +结果: +```json +{"jsonrpc":"2.0","result":{"solana-core": "1.6.0"},"id":1} +``` + +### getVoteAccounts + +返回当前银行中所有有投票权的帐户的帐户信息和相关权益。 + +#### 参数: + +- `` - (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +结果字段将是 `current` 帐户和 `delinquent` 帐户的JSON对象,每个帐户都包含带有以下子字段的JSON对象数组: + +- `votePubkey:` - 投票帐户公钥,以base-58编码的字符串 +- `nodePubkey:` - 节点公钥,以base-58编码的字符串 +- `activatedStake:` - 抽奖活动中的股份,委托给该投票帐户,并在该时期处于活动状态 +- `epochVoteAccount:` - 布尔,是否为此时代投注了投票帐户 +- `commission: `,应支付给投票帐户的奖励支出的百分比(0-100) +- `lastVote:` - 此投票帐户最近投票过的广告位 +- `epochCredits:` - 每个时期结束时获得多少学分的历史,以包含 `[epoch,credits,previousCredits]` 的阵列数组的形式出现 + +#### 示例: +请求: +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getVoteAccounts"} +' +``` + +结果: +```json +{ + "jsonrpc": "2.0", + "result": { + "current": [ + { + "commission": 0, + "epochVoteAccount": true, + "epochCredits": [ + [ 1, 64, 0 ], + [ 2, 192, 64 ] + ], + "nodePubkey": "B97CCUW3AEZFGy6uUg6zUdnNYvnVq5VG8PUtb2HayTDD", + "lastVote": 147, + "activatedStake": 42, + "votePubkey": "3ZT31jkAGhUaw8jsy4bTknwBMP8i4Eueh52By4zXcsVw" + } + ], + "delinquent": [ + { + "commission": 127, + "epochVoteAccount": false, + "epochCredits": [], + "nodePubkey": "6ZPxeQaDo4bkZLRsdNrCzchNQr5LN9QMc9sipXv9Kw8f", + "lastVote": 0, + "activatedStake": 0, + "votePubkey": "CmgCk4aMS7KW1SHX3s9K5tBJ6Yng2LBaC8MFov4wx9sm" + } + ] + }, + "id": 1 +} +``` + +### minimumLedgerSlot + +返回节点在其账本中具有有关信息的最低插槽。 如果将节点配置为清除较早的账本数据,则此值可能会随着时间增加 + +#### 参数: + +无 + +#### 结果: + +- `u64` - 最小账本插槽 + +#### 示例: + +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"minimumLedgerSlot"} +' + +``` + +结果: +```json +{"jsonrpc":"2.0","result":1234,"id":1} +``` + +### requestAirdrop + +向空头请求空投空投 + +#### 参数: + +- `` - 帐户的公钥,用于接收 lamport,以 base-58 编码的字符串 +- `` - lamports,如 u64 +- `` - (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) (用于检索区块哈希和验证空投成功) + +#### 结果: + +- `` - 空投的交易签名,以base-58编码的字符串 + +#### 示例: + +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"requestAirdrop", "params":["83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri", 50]} +' + +``` + +结果: +```json +{"jsonrpc":"2.0","result":"5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW","id":1} +``` + +### sendTransaction + +将已签名的交易提交到集群以进行处理。 + +此方法不会以任何方式更改交易;它将客户端创建的交易按原样中继到节点。 + +如果节点的rpc服务接收到该交易,则此方法将立即成功,而无需等待任何确认。 此方法的成功响应不能保证集群能够处理或确认交易。 + +尽管rpc服务将合理地重试提交,但是如果交易的 `recent_blockhash` 在到达之前到期,则该交易可能会被拒绝。 + +使用 [`getSignatureStatuses`](jsonrpc-api.md#getsignaturestatuses) 确保交易得到处理和确认。 + +提交之前,请执行以下飞行前检查: + +1. 交易签名已验证 +2. 根据预检承诺指定的银行插槽模拟交易。 失败时将返回错误。 如果需要,可以禁用预检检查。 建议指定相同的承诺和飞行前承诺,以避免混淆行为。 + +返回的签名是交易中的第一个签名,用于标识交易([交易ID](../../terminology.md#transanction-id))。 在提交之前,可以很容易地从交易数据中提取该标识符。 + +#### 参数: + +- `` - 完全签名的交易,作为编码的字符串 +- `` -(可选) 包含以下字段的配置对象: + - `skipPreflight:` - 如果为 true,则跳过预检交易检查(默认值:false) + - `preflightCommitment:` -(可选) [承诺](jsonrpc-api.md#configuring-state-commitment) 用于预检的级别(默认值:`"max"`)。 + - `encoding:` -(可选)用于交易数据的编码。 `"base58"`(*slow*,**DEPRECATED**) 或 `"base64"`。 (默认值:`"base58"`)。 + +#### 结果: + +- `` - 嵌入在交易中的第一个交易签名,以 base-58 编码的字符串([transaction id](../../terminology.md#transanction-id)) + +#### 示例: + +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "sendTransaction", + "params": [ + "4hXTCkRzt9WyecNzV1XPgCDfGAZzQKNxLXgynz5QDuWWPSAZBZSHptvWRL3BjCvzUXRdKvHL2b7yGrRQcWyaqsaBCncVG7BFggS8w9snUts67BSh3EqKpXLUm5UMHfD7ZBe9GhARjbNQMLJ1QD3Spr6oMTBU6EhdB4RD8CP2xUxr2u3d6fos36PD98XS6oX8TQjLpsMwncs5DAMiD4nNnR8NBfyghGCWvCVifVwvA8B8TJxE1aiyiv2L429BCWfyzAme5sZW8rDb14NeCQHhZbtNqfXhcp2tAnaAT" + ] + } +' + +``` + +结果: +```json +{"jsonrpc":"2.0","result":"2id3YC2jK9G5Wo2phDx4gJVAew8DcY5NAojnVuao8rkxwPYPe8cSwE5GzhEgJA2y8fVjDEo6iR6ykBvDxrTQrtpb","id":1} +``` + +### simulateTransaction + +模拟发送交易 + +#### 参数: + +- `` - 交易,作为编码的字符串。 该交易必须具有有效的散列,但不要求对其进行签名。 +- `` -(可选) 包含以下字段的配置对象: + - `sigVerify:` - 如果为 true,则将验证交易签名(默认值:false) + - `commitment:` - (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) 级别以(默认值:`"max"`) 模拟交易。 + - `encoding:` - (可选) 用于交易数据的编码。 `"base58"` (*slow*,**DEPRECATED**) 或 `"base64"`。 (默认值:`"base58"`)。 + +#### 结果: + +包含TransactionStatus对象的RpcResponse结果将是RpcResponse JSON对象,其中`value`设置为具有以下字段的JSON对象: + +- `err:` - 如果交易失败,则返回错误;如果交易成功,则返回null。 [TransactionError定义](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L24) +- `logs:` - 交易指令在执行期间输出的日志消息数组,如果在交易能够执行之前模拟失败(例如,由于无效的哈希或签名验证失败),则返回 null + +#### 示例: + +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "simulateTransaction", + "params": [ + "4hXTCkRzt9WyecNzV1XPgCDfGAZzQKNxLXgynz5QDuWWPSAZBZSHptvWRL3BjCvzUXRdKvHL2b7yGrRQcWyaqsaBCncVG7BFggS8w9snUts67BSh3EqKpXLUm5UMHfD7ZBe9GhARjbNQMLJ1QD3Spr6oMTBU6EhdB4RD8CP2xUxr2u3d6fos36PD98XS6oX8TQjLpsMwncs5DAMiD4nNnR8NBfyghGCWvCVifVwvA8B8TJxE1aiyiv2L429BCWfyzAme5sZW8rDb14NeCQHhZbtNqfXhcp2tAnaAT" + ] + } +' +``` + +Result: +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 218 + }, + "value": { + "err": null, + "logs": [ + "BPF program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri success" + ] + } + }, + "id": 1 +} +``` + +### setLogFilter + +在验证器上设置日志过滤器 + +#### 参数: + +- `` - 要使用的新日志过滤器 + +#### 结果: + +- `` + +#### 示例: + +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"setLogFilter", "params":["solana_core=debug"]} +' +``` + +结果: +```json +{"jsonrpc":"2.0","result":null,"id":1} +``` + +### validatorExit + +如果验证器在启用RPC退出的情况下启动(`--enable-rpc-exit`参数),则此请求将导致验证器退出。 + +#### 参数: + +无 + +#### 结果: + +- `` - 验证程序退出操作是否成功 + +#### 示例:: + +```bash +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"validatorExit"} +' + +``` + +结果: +```json +{"jsonrpc":"2.0","result":true,"id":1} +``` + +## 订阅Websocket + +在 `ws://
/` 连接到RPC PubSub Websocket之后: + +- 使用以下方法向Websocket提交订阅请求 +- 多个订阅可能一次处于活动状态 +- 许多订阅都采用可选的[`commitment` 参数](jsonrpc-api.md#configuring-state-commitment),定义了如何最终完成更改以触发通知。 对于订阅,如果未指定承诺,则默认值为 `"singleGossip"`。 + +### accountSubscribe + +订阅一个帐户以在给定帐户公钥的灯饰或数据发生更改时接收通知 + +#### 参数: + +- `` - 帐户 Pubkey,以 base-58 编码的字符串 +- `` - (可选) 包含以下可选字段的配置对象: + - `` -(可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + - `encoding:` - 帐户数据的编码,可以是 "base58"(*slow*),"base64","base64+zstd" 或 "jsonParsed"。 "jsonParsed" 编码尝试使用特定于程序的状态解析器来返回更多的人类可读和显式的帐户状态数据。 如果请求 "jsonParsed" 但找不到解析器,则该字段将退回到二进制编码,当 `data` 字段为 `` 类型时可检测到。 + +#### 结果: + +- `` - Subscription id \(needed to unsubscribe\) + +#### 示例: + +请求: +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "accountSubscribe", + "params": [ + "CM78CPUeXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNH12", + { + "encoding": "base64", + "commitment": "root" + } + ] +} +{ + "jsonrpc": "2.0", + "id": 1, + "method": "accountSubscribe", + "params": [ + "CM78CPUeXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNH12", + { + "encoding": "jsonParsed" + } + ] +} +``` + +Result: +```json +{"jsonrpc": "2.0","result": 23784,"id": 1} +``` + +#### 通知形式 + +Base58 编码: +```json +{ + "jsonrpc": "2.0", + "method": "accountNotification", + "params": { + "result": { + "context": { + "slot": 5199307 + }, + "value": { + "data": ["11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHPXHRDEHrBesJhZyqnnq9qJeUuF7WHxiuLuL5twc38w2TXNLxnDbjmuR", "base58"], + "executable": false, + "lamports": 33594, + "owner": "11111111111111111111111111111111", + "rentEpoch": 635 + } + }, + "subscription": 23784 + } +} +``` + +Parsed-JSON编码: +```json +{ + "jsonrpc": "2.0", + "method": "accountNotification", + "params": { + "result": { + "context": { + "slot": 5199307 + }, + "value": { + "data": ["11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHPXHRDEHrBesJhZyqnnq9qJeUuF7WHxiuLuL5twc38w2TXNLxnDbjmuR", "base58"], + "executable": false, + "lamports": 33594, + "owner": "11111111111111111111111111111111", + "rentEpoch": 635 + } + }, + "subscription": 23784 + } +} +``` + +### accountUnsubscribe + +取消订阅帐户更改通知 + +#### 参数: + +- `` - 要取消的帐户订阅ID + +#### 结果: + +- `` - 取消订阅成功消息 + +#### 示例: + +请求: +```json +{"jsonrpc":"2.0", "id":1, "method":"accountUnsubscribe", "params":[0]} + +``` + +结果: +```json +{"jsonrpc": "2.0","result": true,"id": 1} +``` + +### logsSubscribe + +订阅交易日志记录。 **UNSTABLE** + +#### 参数: + +- `filter:` - 过滤条件,日志按帐户类型接收结果;目前支持: + - "all" - 订阅除简单投票交易以外的所有交易 + - "allWithVotes" - 订阅所有交易,包括简单的投票交易 + - `{ "mentions": [ ] }` - 订阅所有提及提供的Pubkey的交易(以 base-58 编码的字符串) +- `` -(可选) 包含以下可选字段的配置对象: + - (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +- `` - Subscription id \(needed to unsubscribe\) + +#### 示例: + +请求: +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "logsSubscribe", + "params": [ + { + "mentions": [ "11111111111111111111111111111111" ] + }, + { + "commitment": "max" + } + ] +} +{ + "jsonrpc": "2.0", + "id": 1, + "method": "logsSubscribe", + "params": [ "all" ] +} +``` + +结果: +```json +{"jsonrpc": "2.0","result": 24040,"id": 1} +``` + +#### 通知形式 + +Base58 编码: +```json +{ + "jsonrpc": "2.0", + "method": "logsNotification", + "params": { + "result": { + "context": { + "slot": 5208469 + }, + "value": { + "signature": "5h6xBEauJ3PK6SWCZ1PGjBvj8vDdWG3KpwATGy1ARAXFSDwt8GFXM7W5Ncn16wmqokgpiKRLuS83KUxyZyv2sUYv", + "err": null, + "logs": [ + "BPF program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri success" + ] + } + }, + "subscription": 24040 + } +} +``` + +### logsUnsubscribe + +退订交易日志 + +#### 参数: + +- `` - 要取消的订阅 id + +#### 结果: + +- `` - 取消订阅成功消息 + +#### 示例: + +请求: +```json +{"jsonrpc":"2.0", "id":1, "method":"logsUnsubscribe", "params":[0]} + +``` + +结果: +```json +{"jsonrpc": "2.0","result": true,"id": 1} +``` + +### programSubscribe + +订阅程序以在程序拥有的给定帐户的灯饰或数据发生更改时接收通知 + +#### 参数: + +- `` - program_id Pubkey,以 base-58 编码的字符串 +- `` -(可选) 包含以下可选字段的配置对象: + - (可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + - `encoding:` - 帐户数据的编码,可以是“ base58”(*slow*),“ base64”,“ base64 + zstd”或“ jsonParsed”。 “jsonParsed”编码尝试使用特定于程序的状态解析器来返回更多的人类可读和显式的帐户状态数据。 如果请求“ jsonParsed”但找不到解析器,则该字段将回退为base64编码,当 `data` 字段为 `` 类型时可检测到。 + - (可选) `filters:` - 使用各种 [filter objects](jsonrpc-api.md#filters) 过滤结果;帐户必须满足所有过滤条件,才能包含在结果中 + +#### 结果: + +- `` - Subscription id \(needed to unsubscribe\) + +#### 示例: + +请求: +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "programSubscribe", + "params": [ + "11111111111111111111111111111111", + { + "encoding": "base64", + "commitment": "max" + } + ] +} +{ + "jsonrpc": "2.0", + "id": 1, + "method": "programSubscribe", + "params": [ + "11111111111111111111111111111111", + { + "encoding": "jsonParsed" + } + ] +} +{ + "jsonrpc": "2.0", + "id": 1, + "method": "programSubscribe", + "params": [ + "11111111111111111111111111111111", + { + "encoding": "base64", + "filters": [ + { + "dataSize": 80 + } + ] + } + ] +} +``` + +结果: +```json +{"jsonrpc": "2.0","result": 24040,"id": 1} +``` + +#### 通知形式 + +Base58 编码: +```json +{ + "jsonrpc": "2.0", + "method": "programNotification", + "params": { + "result": { + "context": { + "slot": 5208469 + }, + "value": { + "pubkey": "H4vnBqifaSACnKa7acsxstsY1iV1bvJNxsCY7enrd1hq", + "account": { + "data": ["11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHPXHRDEHrBesJhZyqnnq9qJeUuF7WHxiuLuL5twc38w2TXNLxnDbjmuR", "base58"], + "executable": false, + "lamports": 33594, + "owner": "11111111111111111111111111111111", + "rentEpoch": 636 + }, + } + }, + "subscription": 24040 + } +} +``` + +Parsed-JSON 编码: +```json +{ + "jsonrpc": "2.0", + "method": "programNotification", + "params": { + "result": { + "context": { + "slot": 5208469 + }, + "value": { + "pubkey": "H4vnBqifaSACnKa7acsxstsY1iV1bvJNxsCY7enrd1hq", + "account": { + "data": ["11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHPXHRDEHrBesJhZyqnnq9qJeUuF7WHxiuLuL5twc38w2TXNLxnDbjmuR", "base58"], + "executable": false, + "lamports": 33594, + "owner": "11111111111111111111111111111111", + "rentEpoch": 636 + }, + } + }, + "subscription": 24040 + } +} +``` + +### programUnsubscribe + +退订计划拥有的帐户更改通知 + +#### 参数: + +- `` - 要取消的帐户订阅 Id + +#### 结果: + +- `` - 取消订阅成功消息 + +#### 示例: + +请求: +```json +{"jsonrpc":"2.0", "id":1, "method":"programUnsubscribe", "params":[0]} + +``` + +Result: +```json +{"jsonrpc": "2.0","result": true,"id": 1} +``` + +### signatureSubscribe + +订阅交易签名以在交易确认后接收通知。在 `signatureNotification` 上,订阅将自动取消。 + +#### 参数: + +- `` - 交易签名,以 base-58 编码的字符串 +- `` -(可选) [承诺](jsonrpc-api.md#configuring-state-commitment) + +#### 结果: + +- `integer` - 订阅 id(需要取消订阅) + +#### 示例: + +请求: +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "signatureSubscribe", + "params": [ + "2EBVM6cB8vAAD93Ktr6Vd8p67XPbQzCJX47MpReuiCXJAtcjaxpvWpcg9Ege1Nr5Tk3a2GFrByT7WPBjdsTycY9b" + ] +} + +{ + "jsonrpc": "2.0", + "id": 1, + "method": "signatureSubscribe", + "params": [ + "2EBVM6cB8vAAD93Ktr6Vd8p67XPbQzCJX47MpReuiCXJAtcjaxpvWpcg9Ege1Nr5Tk3a2GFrByT7WPBjdsTycY9b", + { + "commitment": "max" + } + ] +} +``` + +Result: +```json +{"jsonrpc": "2.0","result": 0,"id": 1} +``` + +#### 通知形式 +```bash +{ + "jsonrpc": "2.0", + "method": "signatureNotification", + "params": { + "result": { + "context": { + "slot": 5207624 + }, + "value": { + "err": null + } + }, + "subscription": 24006 + } +} +``` + +### signatureUnsubscribe + +退订签名确认通知 + +#### 参数: + +- `` - 要取消的订阅 Id + +#### 结果: + +- `` - 取消订阅成功消息 + +#### 示例: + +请求: +```json +{"jsonrpc":"2.0", "id":1, "method":"signatureUnsubscribe", "params":[0]} + +``` + +Result: +```json +{"jsonrpc": "2.0","result": true,"id": 1} +``` + +### slotSubscribe + +订阅者可在验证节点处理插槽后随时接收通知 + +#### 参数: + +无 + +#### 结果: + +- `integer` - 订阅id(需要取消订阅) + +#### 示例: + +请求: +```json +{"jsonrpc":"2.0", "id":1, "method":"slotSubscribe"} + +``` + +Result: +```json +{"jsonrpc": "2.0","result": 0,"id": 1} +``` + +#### 通知形式 + +```bash +{ + "jsonrpc": "2.0", + "method": "slotNotification", + "params": { + "result": { + "parent": 75, + "root": 44, + "slot": 76 + }, + "subscription": 0 + } +} +``` + +### slotUnsubscribe + +取消订阅槽通知 + +#### 参数: + +- `` - 需要取消的订阅 id + +#### 结果: + +- `` - 取消订阅成功消息 + +#### 示例: + +请求: +```json +{"jsonrpc":"2.0", "id":1, "method":"slotUnsubscribe", "params":[0]} + +``` + +结果: +```json +{"jsonrpc": "2.0","result": true,"id": 1} +``` + +### rootSubscribe + +只要验证节点设置了新的根目录,即可订阅以接收通知。 + +#### 参数: + +无 + +#### 结果: + +- `integer` - 订阅 id (需要取消订阅) + +#### 示例: + +请求: +```json +{"jsonrpc":"2.0", "id":1, "method":"rootSubscribe"} + +``` + +结果: +```json +{"jsonrpc": "2.0","result": 0,"id": 1} +``` + +#### 通知形式 + +结果是最新的根插槽号 + +```bash +{ + "jsonrpc": "2.0", + "method": "rootNotification", + "params": { + "result": 42, + "subscription": 0 + } +} +``` + +### 取消订阅 + +退订根通知 + +#### 参数: + +- `` - 要取消的订阅ID + +#### 结果: + +- `` - 取消订阅成功消息 + +#### 示例:: + +请求: +```json +{"jsonrpc":"2.0", "id":1, "method":"rootUnsubscribe", "params":[0]} + +``` + +结果: +```json +{"jsonrpc": "2.0","result": true,"id": 1} +``` + +### 投票订阅-不稳定,默认情况下处于禁用状态 + +**此订阅是不稳定的,并且仅在验证器以`--rpc-pubsub-enable-vote-subscription`标志启动时可用。 此订阅的格式将来可能会更改** + +订阅以在八卦中观察到新的投票时接收通知。 这些票是事先同意的,因此不能保证这些票会进入账本。 + +#### 参数: + +无 + +#### 结果: + +- `integer` - 订阅 id (需要取消订阅) + +#### 示例: + +请求: +```json +{"jsonrpc":"2.0", "id":1, "method":"voteSubscribe"} + +``` + +Result: +```json +{"jsonrpc": "2.0","result": 0,"id": 1} +``` + +#### 通知形式 + +结果是最新的投票,其中包含其哈希值,已投票的时隙列表以及可选的时间戳。 + +```json +{ + "jsonrpc": "2.0", + "method": "voteNotification", + "params": { + "result": { + "hash": "8Rshv2oMkPu5E4opXTRyuyBeZBqQ4S477VG26wUTFxUM", + "slots": [1, 2], + "timestamp": null + }, + "subscription": 0 + } +} +``` + +### 投票退订 + +退订投票通知 + +#### 参数: + +- `` - 要取消的订阅ID + +#### 结果: + +- `` - 取消订阅成功消息 + +#### 示例: + +请求: +```json +{"jsonrpc":"2.0", "id":1, "method":"voteUnsubscribe", "params":[0]} +``` + +响应: +```json +{"jsonrpc": "2.0","result": true,"id": 1} +``` diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/debugging.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/debugging.md new file mode 100644 index 0000000000..c657877297 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/debugging.md @@ -0,0 +1,72 @@ +--- +title: "调试" +--- + +Solana程序在链上运行,因此在链外调试可能会很困难。 为了使调试程序更容易,开发人员可以编写单元测试以通过Solana运行时直接测试其程序的执行情况,或者运行允许RPC客户端与其程序进行交互的本地集群。 + +## 运行单元测试 {#running-unit-tests} + +- [用Rust进行测试](developing-rust.md#how-to-test) +- [用C进行测试](developing-c.md#how-to-test) + +## 记录 {#logging} + +在程序执行期间,运行时,程序日志状态和错误消息均会出现。 + +有关如何从程序登录的信息,请参阅特定语言的文档: +- [从Rust程序记录日志](developing-rust.md#logging) +- [从C程序记录日志](developing-c.md#logging) + +运行本地集群时,只要通过`RUST_LOG`日志掩码启用了日志,日志就会写入stdout。 从程序开发的角度来看,仅关注运行时和程序日志,而不关注其余的集群日志会有所帮助。 为了专注于程序特定的信息,建议使用以下日志掩码: + +`export +RUST_LOG=solana_runtime::system_instruction_processor=trace,solana_runtime::message_processor=info,solana_bpf_loader=debug,solana_rbpf=debug` + +直接来自程序(而不是runtime) 的日志消息将以以下形式显示: + +`Program log: ` + +## 错误处理 {#error-handling} + +可以通过事务错误传达的信息量是有限的,但是有很多可能的失败点。 以下是可能的故障点,有关预期发生哪些错误以及在何处获取更多信息的信息: +- BPF加载程序可能无法解析程序,这应该不会发生,因为加载程序已经对程序的帐户数据进行了_最终处理_。 + - `InstructionError::InvalidAccountData`将作为交易错误的一部分返回。 +- BPF加载程序可能无法设置程序的执行环境 + - `InstructionError::Custom(0x0b9f_0001)`将作为交易错误的一部分返回。 "0x0b9f_0001"是[`VirtualMachineCreationFailed`](https://github.com/solana-labs/solana/blob/bc7133d7526a041d1aaee807b80922baa89b6f90/programs/bpf_loader/src/lib.rs#L44)的十六进制表示形式。 +- BPF加载程序可能在程序执行过程中检测到致命错误(紧急情况,内存冲突,系统调用错误等)。 + - `InstructionError::Custom(0x0b9f_0002)`将作为交易错误的一部分返回。 "0x0b9f_0002"是[`VirtualMachineFailedToRunProgram`](https://github.com/solana-labs/solana/blob/bc7133d7526a041d1aaee807b80922baa89b6f90/programs/bpf_loader/src/lib.rs#L46)的十六进制表示。 +- 程序本身可能返回错误 + - `InstructionError::Custom()`将被返回。 “用户定义的值”不得与任何[内置运行时程序错误](https://github.com/solana-labs/solana/blob/bc7133d7526a041d1aaee807b80922baa89b6f90/sdk/program/src/program_error.rs#L87)相冲突 。 程序通常使用枚举类型来定义从零开始的错误代码,因此它们不会冲突。 + +如果出现`VirtualMachineFailedToRunProgram`错误,则将有关失败原因的详细信息写入[程序的执行日志](debugging.md#logging)。 + +例如,涉及堆栈的访问冲突将如下所示: + +`BPF程序4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM失败:out of bounds +memory store (insn #615), addr 0x200001e38/8` + +## 监控计算预算消耗 {#monitoring-compute-budget-consumption} + +程序可以记录停止程序执行之前将允许的剩余计算单元数。 程序可以使用这些日志来包装希望分析的操作。 + +- [从Rust程序记录剩余的计算单元](developing-rust.md#compute-budget) +- [从C程序记录剩余的计算单元](developing-c.md#compute-budget) + +有关更多信息,请参见[计算预算](developing/programming-model/runtime.md#compute-budget)。 + +## ELF转储 {#elf-dump} + +可以将BPF共享对象的内部信息转储到文本文件中,以更深入地了解程序的组成及其在运行时的工作方式。 + +- [创建Rust程序的转储文件](developing-rust.md#elf-dump) +- [创建C程序的转储文件](developing-c.md#elf-dump) + +## 指令追踪 {#instruction-tracing} + +在执行期间,可以将运行时BPF解释器配置为记录每个执行的BPF指令的跟踪消息。 对于诸如精确指出导致内存访问冲突的运行时上下文之类的事情,这可能非常有用。 + +跟踪日志与[ELF转储](#elf-dump)一起可以提供更多参考(尽管跟踪会产生很多信息)。 + +要在本地集群中打开BPF解释器跟踪消息,请将`RUST_LOG`中的`solana_rbpf`级别配置为`trace`。 例如: + +`export RUST_LOG=solana_rbpf=trace` diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/deploying.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/deploying.md new file mode 100644 index 0000000000..55598abfbb --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/deploying.md @@ -0,0 +1,11 @@ +--- +title: "部署" +--- + +![SDK 工具](/img/sdk-tools.svg) + +如上图所示,程序作者创建了一个程序,将它编译成包含 BFF 字节代码的 ELF 共享对象,然后包含一笔特殊的 _deploy_ 交易,将其上传到 Solana 集群。 群集通过一个 _program ID_ 将其提供给客户端。 程序 ID 是部署时指定的 _地址_,用于在后续交易中引用程序。 + +一旦部署成功,持有程序的账户将被标记为可执行,并且其账户数据变得永久不可篡改。 如果程序需要更改(功能、补丁等...),新程序必须部署到一个新程序 ID。 + +Solana 命令行接口支持部署程序,更多信息请见 [`deploy`](cli/usage.md#deploy-program) 命令行使用 文档。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/developing-c.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/developing-c.md new file mode 100644 index 0000000000..dfac55f02e --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/developing-c.md @@ -0,0 +1,131 @@ +--- +title: "用 C 语言开发" +--- + +Solana 支持使用 C 和 C++ 语言编写链上的程序。 + +## 项目布局 {#project-layout} + +C 项目规定如下: + +``` +/src/ +/makefile +``` + +`makefile` 应该包含以下内容: + +```bash +OUT_DIR := +include ~/.local/share/solana/install/active_release/bin/sdk/bpf/c/bpf.mk +``` + +Bpf-sdk可能不在上面指定的确切位置,但是如果您根据[如何开发](#how-to-build)来设置环境,那么就是这样。 + +来看一下的 C 程序的[helloworld](https://github.com/solana-labs/example-helloworld/tree/master/src/program-c)示例。 + +## 如何开发 {#how-to-build} + +首先设置环境: +- 从https://rustup.rs安装最新的Rust稳定版本 +- 从https://docs.solana.com/cli/install-solana-cli-tools安装最新的Solana命令行工具 + +然后使用make构建: +```bash +make -C +``` + +## 如何测试 {#how-to-test} + +Solana 使用 [Criterion](https://github.com/Snaipe/Criterion) 测试框架,并且在每次构建程序时都会执行测试,[如何开发](#how-to-build)。 + +要添加测试,请在源文件`test_.c`旁边创建一个新文件,并使用标准测试用例填充它。 有关示例,请参见[helloworld C测试](https://github.com/solana-labs/example-helloworld/blob/master/src/program-c/src/helloworld/test_helloworld.c)或[Criterion文档](https://criterion.readthedocs.io/en/master),获取编写测试用例的信息。 + +## 程序入口点 {#program-entrypoint} + +程序导出一个已知的入口点符号,在调用程序时,Solana运行时将查找并调用该入口点符号。 Solana支持多个[BPF加载程序版本](overview.md#versions),它们之间的入口点可能会有所不同。 程序必须为相同的加载器编写并部署。 有关更多详细信息,请参见[概览](overview#loaders)。 + +当前有两个受支持的加载器:[BPF加载器](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/bpf_loader.rs#L17)和[已弃用BFT加载器](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/bpf_loader_deprecated.rs#L14)。 + +它们都有相同的原始入口点定义,以下是运行时查找和调用的原始符号: + +```c +extern uint64_t entrypoint(const uint8_t *input) +``` + +该入口点采用通用字节数组,其中包含序列化的程序参数(程序ID,帐户,指令数据等)。 为了反序列化参数,每个加载器都包含其自己的[帮助器函数](#Serialization)。 + +请参阅 [使用入口点的简单实例](https://github.com/solana-labs/example-helloworld/blob/bc0b25c0ccebeff44df9760ddb97011558b7d234/src/program-c/src/helloworld/helloworld.c#L37),来看看它们是如何配合使用的。 + +### 序列化 {#serialization} + +请参阅[helloworld对反序列化功能的使用](https://github.com/solana-labs/example-helloworld/blob/bc0b25c0ccebeff44df9760ddb97011558b7d234/src/program-c/src/helloworld/helloworld.c#L43)。 + +每个加载程序都提供一个帮助程序功能,该功能将程序的输入参数反序列化为 C 类型: +- [BPF加载器反序列化](https://github.com/solana-labs/solana/blob/d2ee9db2143859fa5dc26b15ee6da9c25cc0429c/sdk/bpf/c/inc/solana_sdk.h#L304) +- [BPF 加载器已弃用的反序列化](https://github.com/solana-labs/solana/blob/8415c22b593f164020adc7afe782e8041d756ddf/sdk/bpf/c/inc/deserialize_deprecated.h#L25) + +某些程序可能希望自己执行序列化,并且可以通过提供其自己的[原始入口点](#program-entrypoint)实现来实现。 请注意,提供的反序列化功能会将引用保留回序列化字节数组,以引用允许程序修改的变量(lamport,帐户数据)。 这样做的原因是,在返回时,加载程序将读取这些修改,以便可以将其提交。 如果程序实现其自己的反序列化功能,则需要确保将程序希望进行的所有修改都写回到输入字节数组中。 + +有关加载程序如何序列化程序输入的详细信息,请参见[Input Parameter Serialization](overview.md#input-parameter-serialization)文档。 + +## 数据类型 {#data-types} + +加载程序的反序列化助手函数将填充[SolParameters](https://github.com/solana-labs/solana/blob/8415c22b593f164020adc7afe782e8041d756ddf/sdk/bpf/c/inc/solana_sdk.h#L276)结构: + +```c +/** + * 程序进入点输入数据被反序列化的结构。 + */ +typef structt volt_ + SolAccountInfo* ka; /** 指向SolAccountInfo阵列的指针, 必须已经 + 指向一个 SolAccountInfos */ + uint64_t ka_num; /** `ka`中的 SolAccountInfo 条目数 */ + const uint8_t *数据; /** 指示数据指针*/ + uint64_t data_len; /** 指令数据字节长度 */ + const SolPubkey *program_id; /** 当前正在执行的程序 */ +} Solameters; +``` + +“ ka”是指令引用帐户的有序数组,并表示为[SolAccountInfo](https://github.com/solana-labs/solana/blob/8415c22b593f164020adc7afe782e8041d756ddf/sdk/bpf/c/inc/solana_sdk.h#L173)结构。 帐户在数组中的位置表示其含义,例如,在转移lamports时,一条指令可以将第一个帐户定义为源,将第二个帐户定义为目的地。 + +`AccountInfo`结构的成员是只读的,但`lamports`和`data`除外。 程序都可以根据[runtime执行策略](developing/programming-model/accounts.md#policy)对两者进行修改。 当一条指令多次引用相同的帐户时,数组中可能有重复的`SolAccountInfo`条目,但它们都指向原来的输入字节数组。 程序应谨慎处理这些情况,以避免对同一缓冲区的读/写重叠。 如果程序实现其自己的反序列化功能,则应注意适当地处理重复帐户。 + +`数据`是正在处理的[指令的指令数据](developing/programming-model/transactions.md#instruction-data)中的通用字节数组。 + +`program_id`是当前正在执行的程序的公钥。 + +## 堆(Heap){#heap} + +C 程序可以通过系统调用[`calloc`](https://github.com/solana-labs/solana/blob/c3d2d2134c93001566e1e56f691582f379b5ae55/sdk/bpf/c/inc/solana_sdk.h#L245)或者通过虚拟的 32 Kb heap 区域顶部实现它们自己的堆地址 x300000000。 堆区域也被 `calloc` 使用,因此如果一个程序实现了自己的堆,它不应该同时调用 `calloc`。 + +## 日志 {#logging} + +运行时提供了两个系统调用,这些系统调用将获取数据并将其记录到程序日志中。 + +- [`sol_log(const char*)`](https://github.com/solana-labs/solana/blob/d2ee9db2143859fa5dc26b15ee6da9c25cc0429c/sdk/bpf/c/inc/solana_sdk.h#L128) +- [`sol_log_64(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t)`](https://github.com/solana-labs/solana/blob/d2ee9db2143859fa5dc26b15ee6da9c25cc0429c/sdk/bpf/c/inc/solana_sdk.h#L134) + +[调试](debugging.md#logging) 章节有更多关于程序日志工作的信息。 + +## 计算预算 {#compute-budget} + +使用系统调用[`sol_log_compute_units()`](https://github.com/solana-labs/solana/blob/d3a3a7548c857f26ec2cb10e270da72d373020ec/sdk/bpf/c/inc/solana_sdk.h#L140)记录包含剩余编号的消息暂停执行之前程序可能消耗的计算单元数。 + +相关的更多信息,请参见[计算预算](developing/programming-model/runtime.md#compute-budget)。 + +## ELF转储 {#elf-dump} + +可以将BPF共享对象的内部信息转储到文本文件中,以更深入地了解程序的组成及其在运行时的工作方式。 转储将包含ELF信息以及所有符号和实现它们的指令的列表。 一些BPF加载程序的错误日志消息将引用发生错误的特定指令号。 可以在ELF转储中查找这些引用,以标识有问题的指令及其上下文。 + +创建一个转储文件: + +```bash +$ cd +$ make dump_ +``` + +## 示例 {#examples} + +[Solana 程序库github](https://github.com/solana-labs/solana-program-library/tree/master/examples/c)代码库包含了 C 语言的例子集合。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/developing-rust.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/developing-rust.md new file mode 100644 index 0000000000..84d690ef31 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/developing-rust.md @@ -0,0 +1,272 @@ +--- +title: "用Rust开发" +--- + +Solana 支持使用[Rust](https://www.rust-lang.org/) 编程语言编写链上的程序。 + +## 项目布局 {#project-layout} + +Solana Rust程序遵循典型的[Rust项目布局](https://doc.rust-lang.org/cargo/guide/project-layout.html): + +``` +/inc/ +/src/ +/Cargo.toml +``` + +但也必须包括: +``` +/Xargo.toml +``` +必须包含: +``` +[target.bpfel-unknown-unknown.dependencies.std] +features = [] +``` + +Solana Rust 程序可能会直接依赖于对方,以便在进行 [交叉程序调用](developing/programming-model/calling-between-programs.md#cross-program-invocations)时获得指令协助。 这样做时,重要的是不要拉入依赖程序的入口点符号,因为它们可能与程序本身的符号冲突。 为避免这种情况,程序应在 `Cargo.toml` 中定义一个 ` exclude_entrypoint `功能,并使用它来排除入口点。 + +- [定义特性](https://github.com/solana-labs/solana-program-library/blob/a5babd6cbea0d3f29d8c57d2ecbbd2a2bd59c8a9/token/program/Cargo.toml#L12) +- [排除入口点](https://github.com/solana-labs/solana-program-library/blob/a5babd6cbea0d3f29d8c57d2ecbbd2a2bd59c8a9/token/program/src/lib.rs#L12) + +然后,当其他程序将此程序作为依赖项包括在内时,它们应该使用`exclude_entrypoint`功能来实现这一点。 +- [不将入口点包含在内](https://github.com/solana-labs/solana-program-library/blob/a5babd6cbea0d3f29d8c57d2ecbbd2a2bd59c8a9/token-swap/program/Cargo.toml#L19) + +## 项目依赖关系 {#project-dependencies} + +至少,Solana Rust程序必须引入[solana-program](https://crates.io/crates/solana-program)。 + +Solana BPF程序具有某些[限制](#Restrictions),可能会阻止将某些箱体作为依赖项包含进来或需要特殊处理。 + +例如: +- 要求架构的箱体(Crates)是官方工具链支持箱体的子集。 除非解决了这个问题,并且没有将BPF添加到那些体系结构检查中,否则没有解决方法。 +- 箱体可能取决于Solana确定性程序环境中不支持的`rand`。 要包含`rand`相关的箱体,请参考[在 Rand 开发](#depending-on-rand)。 +- 即使程序本身未包含堆栈溢出代码,箱体也可能会使堆栈溢出。 有关的更多信息,请参见[Stack](overview.md#stack)。 + +## 如何开发 {#how-to-build} + +首先设置环境: +- 从https://rustup.rs/安装最新的Rust稳定版本 +- 从https://docs.solana.com/cli/install-solana-cli-tools安装最新的Solana命令行工具 + +正常的cargo构建可用于针对您的主机构建程序,该程序可用于单元测试: + +```bash +$ cargo build +``` + +要为可部署到集群的Solana BPF目标构建一个特定的程序,例如SPL代币,请执行以下操作: + +```bash +$ cd +$ cargo build-bpf +``` + +## 如何测试 {#how-to-test} + +通过直接行使程序功能,可以通过传统的`cargo test`机制对Solana程序进行单元测试。 + +为了帮助在更接近实时集群的环境中进行测试,开发人员可以使用[`program-test`](https://crates.io/crates/solana-program-test)箱体。 `程序测试`箱体将启动运行时的本地实例,并允许测试发送多个事务,同时在测试期间保持状态。 + +有关更多信息,请参见[在sysvar示例中测试](https://github.com/solana-labs/solana-program-library/blob/master/examples/rust/sysvar/tests/functional.rs),来学习如何包含一条指令syavar帐户由程序发送和处理。 + +## 程序入口点 {#project-entrypoint} + +程序导出一个已知的入口点符号,在调用程序时,Solana运行时将查找并调用该入口点符号。 Solana支持多个[BPF加载程序版本](overview.md#versions),它们之间的入口点可能会有所不同。 程序必须为相同的加载器编写并部署。 有关更多详细信息,请参见[概览](overview#loaders)。 + +当前有两个受支持的加载器:[BPF加载器](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/bpf_loader.rs#L17)和[已弃用BFT加载器](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/bpf_loader_deprecated.rs#L14)。 + +它们都有相同的原始入口点定义,以下是运行时查找和调用的原始符号: + +```rust +#[no_mangle] +pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64; +``` + +该入口点采用通用字节数组,其中包含序列化的程序参数(程序ID,帐户,指令数据等)。 为了反序列化参数,每个加载程序都包含其自己的包装宏,该宏导出原始入口点,反序列化参数,调用用户定义的指令处理函数并返回结果。 + +您可以在此处找到入口点宏: +- [BPF加载程序的入口点宏](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/entrypoint.rs#L46) +- [BPF 加载器不推荐使用的入口点宏](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/entrypoint_deprecated.rs#L37) + +入口点宏调用的程序定义的指令处理功能必须具有以下形式: + +```rust +pub type ProcessInstruction = + fn(program_id: &Pubkey, accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult; +``` + +请参阅 [使用入口点的简单实例](https://github.com/solana-labs/example-helloworld/blob/c1a7247d87cd045f574ed49aec5d160aefc45cf2/src/program-rust/src/lib.rs#L15),来看看它们是如何配合使用的。 + +### 参数反序列化 {#parameter-deserialization} + +每个加载程序都提供一个帮助程序功能,该功能将程序的输入参数反序列化为Rust类型。 入口点宏会自动调用反序列化帮助器: +- [BPF加载器反序列化](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/entrypoint.rs#L104) +- [BPF 加载器已弃用的反序列化](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/entrypoint_deprecated.rs#L56) + +某些程序可能希望自己执行反序列化,并且可以通过提供其自己的[原始入口点](#program-entrypoint)实现来实现。 请注意,提供的反序列化功能会将引用保留回序列化字节数组,以引用允许程序修改的变量(lamport,帐户数据)。 这样做的原因是,在返回时,加载程序将读取这些修改,以便可以将其提交。 如果程序实现其自己的反序列化功能,则需要确保将程序希望进行的所有修改都写回到输入字节数组中。 + +有关加载程序如何序列化程序输入的详细信息,请参见[Input Parameter Serialization](overview.md#input-parameter-serialization)文档。 + +### 数据类型 {#data-types} + +加载程序的入口点宏使用以下参数调用程序定义的指令处理器功能: + +```rust +program_id: &Pubkey, +accounts: &[AccountInfo], +instruction_data: &[u8] +``` + +程序ID是当前正在执行的程序的公钥。 + +帐户是指令引用的帐户的有序切片,并表示为[AccountInfo](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/account_info.rs#L10)结构。 帐户在数组中的位置表示其含义,例如,在转移lamports时,一条指令可以将第一个帐户定义为源,将第二个帐户定义为目的地。 + +`AccountInfo`结构的成员是只读的,但`lamports`和`data`除外。 程序都可以根据[runtime执行策略](developing/programming-model/accounts.md#policy)对两者进行修改。 这两个成员都受`RustRefCell`构造的保护,因此必须借用它们以对其进行读写。 这样做的原因是它们都指向原始输入字节数组,但是帐户片中可能有多个条目指向同一帐户。 使用`RefCell`确保程序不会通过多个`AccountInfo`结构意外地对相同的基础数据执行重叠的读/写操作。 如果程序实现其自己的反序列化功能,则应注意适当地处理重复帐户。 + +指令数据是正在处理的[指令的指令数据](developing/programming-model/transactions.md#instruction-data)中的通用字节数组。 + +## 堆(Heap){#heap} + +Rust程序通过定义自定义[`global_allocator`](https://github.com/solana-labs/solana/blob/8330123861a719cd7a79af0544617896e7f00ce3/sdk/program/src/entrypoint.rs#L50)直接实现堆。 + +程序可以根据其特定需求实现自己的`global_allocator`。 相关的更多信息,请参考[自定义heap示例](#examples)。 + +## 限制 {#restrictions} + +链上Rust程序支持Rust的大多数libstd,libcore和liballoc,以及许多第三方包装箱。 + +由于这些程序在资源受限的单线程环境中运行,因此存在一定的局限性,并且必须是确定性的: + +- 无法访问 + - `rand` + - `std::fs` + - `std::net` + - `std::os` + - `std::future` + - `std::net` + - `std::process` + - `std::sync` + - `std::task` + - `std::thread` + - `std::time` +- 有限的访问权: + - `std::hash` + - `std::os` +- 二进制代码在周期和调用深度上在计算上都非常昂贵,应该尽量避免。 +- 应该避免字符串格式化,因为它在计算上也很昂贵。 +- 不支持 `println!`,`print!`,应该使用Solana [logging helpers](#logging)。 +- 运行时对程序在一条指令的处理过程中可以执行的指令数施加了限制。 相关的更多信息,请参见[计算预算](developing/programming-model/runtime.md#compute-budget)。 + +## 在Rand开发 {#depending-on-rand} + +程序必须确定性地运行,因此不能使用随机数。 有时,即使程序不使用任何随机数功能,程序也可能依赖于自己的`rand`。 如果程序依赖于`rand`,则编译将失败,因为对Solana没有对`get-random`进行支持。 报错通常如下所示: + +``` +error: target is not supported, for more information see: https://docs.rs/getrandom/#unsupported-targets + --> /Users/jack/.cargo/registry/src/github.com-1ecc6299db9ec823/getrandom-0.1.14/src/lib.rs:257:9 + | +257 | / compile_error!("\ +258 | | target is not supported, for more information see: \ +259 | | https://docs.rs/getrandom/#unsupported-targets\ +260 | | "); + | |___________^ +``` + +要解决此依赖性问题,请将以下依赖性添加到程序的`Cargo.toml`中: + +``` +getrandom = { version = "0.1.14", features = ["dummy"] } +``` + +## 日志 {#logging} + +Rust的`println`宏在计算上很昂贵,不被支持。 而是提供了辅助宏[`msg!`](https://github.com/solana-labs/solana/blob/6705b5a98c076ac08f3991bb8a6f9fcb280bf51e/sdk/program/src/log.rs#L33)。 + +`msg!` 有两种形式: + +```rust +msg!("A string"); +``` +或者 +```rust +msg!(0_64, 1_64, 2_64, 3_64, 4_64); +``` + +两者都将输出结果到程序日志。 如果程序愿意,他们可以使用`format!`来模拟`println!`: + +```rust +msg!("Some variable: {:?}", variable); +``` + +[debugging](debugging.md#logging)章节提供了有关使用程序日志的更多信息,[Rust示例](#examples)包含一个日志记录示例。 + +## 恐慌(Panicking){#panicking} + +默认情况下,Rust 的`panic!`、`assert!`和内部恐慌结果被打印到[程序日志](debugging.md#logging)。 + +``` +INFO solana_runtime::message_processor] Finalized account CGLhHSuWsp1gT4B7MY2KACqp9RUwQRhcUFfVSuxpSajZ +INFO solana_runtime::message_processor] Call BPF program CGLhHSuWsp1gT4B7MY2KACqp9RUwQRhcUFfVSuxpSajZ +INFO solana_runtime::message_processor] Program log: Panicked at: 'assertion failed: `(left == right)` + left: `1`, + right: `2`', rust/panic/src/lib.rs:22:5 +INFO solana_runtime::message_processor] BPF program consumed 5453 of 200000 units +INFO solana_runtime::message_processor] BPF program CGLhHSuWsp1gT4B7MY2KACqp9RUwQRhcUFfVSuxpSajZ failed: BPF program panicked +``` + +### 自定义恐慌处理器 {#custom-panic-handler} + +程序可以通过提供自己的实现来覆盖默认的紧急处理程序。 + +首先在程序的`Cargo.toml`中定义`custom-panic`功能。 + +```toml +[features] +default = ["custom-panic"] +custom-panic = [] +``` + +然后提供应急处理程序的自定义实现: + +```rust +#[cfg(all(feature = "custom-panic", target_arch = "bpf"))] +#[no_mangle] +fn custom_panic(info: &core::panic::PanicInfo<'_>) { + solana_program::msg!("program custom panic enabled"); + solana_program::msg!("{}", info); +} +``` + +在上面的代码段中,显示了默认的实现,但是开发人员可以用更适合他们需求的东西代替它。 + +默认情况下,支持完整的紧急消息的副作用之一是程序会产生将Rust的更多`libstd`实现引入程序共享对象的代价。 典型的程序将已经引入了相当数量的`libstd`,并且可能不会注意到共享对象大小的增加。 但是那些通过避免使用`libstd`显式地试图变得很小的程序可能会产生很大的影响(~25kb)。 为了消除这种影响,程序可以为自己的自定义应急处理程序提供空的实现。 + +```rust +#[cfg(all(feature = "custom-panic", target_arch = "bpf"))] +#[no_mangle] +fn custom_panic(info: &core::panic::PanicInfo<'_>) { + // Do nothing to save space +} +``` + +## 计算预算 {#compute-budget} + +使用系统调用[`sol_log_compute_units()`](https://github.com/solana-labs/solana/blob/d3a3a7548c857f26ec2cb10e270da72d373020ec/sdk/program/src/log.rs#L102)]记录包含剩余编号的消息暂停执行之前程序可能消耗的计算单元数。 + +相关的更多信息,请参见[计算预算](developing/programming-model/runtime.md#compute-budget)。 + +## ELF转储 {#elf-dump} + +可以将BPF共享对象的内部信息转储到文本文件中,以更深入地了解程序的组成及其在运行时的工作方式。 转储将包含ELF信息以及所有符号和实现它们的指令的列表。 一些BPF加载程序的错误日志消息将引用发生错误的特定指令号。 可以在ELF转储中查找这些引用,以标识有问题的指令及其上下文。 + +创建一个转储文件: + +```bash +$ cd +$ cargo build-bpf --dump +``` + +## 示例 {#examples} + +[Solana 程序库github](https://github.com/solana-labs/solana-program-library/tree/master/examples/rust)代码库包含了Rust例子集合。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/examples.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/examples.md new file mode 100644 index 0000000000..8bbf530460 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/examples.md @@ -0,0 +1,48 @@ +--- +title: "示例" +--- + + +## Hello World + +Hello World是一个演示项目,展示了如何使用Solana Javascript API以及Rust和C程序来构建、部署、与Solana区块链程序进行交互。 + +该项目包括: + - 链上的Hello World程序 + - 向某个帐户发送 hello 并获取发送次数。 + +### 构建并运行 + +首先获取示例代码的最新版本: + +```bash +$ git clone https://github.com/solana-labs/example-helloworld.git +$ cd example-helloworld +``` + +接下来,按照git仓库[README](https://github.com/solana-labs/example-helloworld/blob/master/README.md)中的步骤进行操作。 + + +## 中断 + +[Break](https://break.solana.com/)是一个React应用程序,它使用户对Solana网络的速度和高性能有熟悉的感觉。 你能_干倒_Solana区块链吗? 在15秒的游戏过程中,每次单击按钮或击键都会向集群发送新的事务。 尽可能快地敲击键盘,并观看交易实时实时完成,而网络正在正常运行! + +可以在我们的Devnet、Testnet和Mainnet Beta网络上来玩这个游戏。 在Devnet和Testnet可以免费测试,用户可从网络水龙头获得空投测试代币。 在Mainnet Beta上,用户每次玩耍需要支付0.08 SOL的费用。 可以通过本地密钥库钱包或通过扫描Trust Wallet的QR码以传输代币,为测试帐户转入代币。 + +[点击这里玩这个游戏](https://break.solana.com/) + +### 构建并运行 + +首先获取示例代码的最新版本: + +```bash +$ git clone https://github.com/solana-labs/break.git +$ cd break +``` + +接下来,按照git仓库的[README](https://github.com/solana-labs/break/blob/master/README.md)中的步骤进行操作。 + +## 特定语言 + +- [Rust](developing-rust.md#examples) +- [C](developing-c.md#examples) diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/faq.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/faq.md new file mode 100644 index 0000000000..47fe1edc4d --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/faq.md @@ -0,0 +1,61 @@ +--- +title: "常见问题解答" +--- + +在编写或与Solana程序进行交互时,经常会遇到一些常见的问题或困难。 以下是有助于回答这些问题的资源。 + +如果还没有解决您的问题,那么Solana[#developers](https://discord.gg/RxeGBH)Discord频道是一个不错的资源。 + +## `CallDepth`错误 + +此错误意味着跨程序调用超出了允许的调用深度。 + +请参见[跨程序调用调用深度](developing/programming-model/calling-between-programs.md#call-depth) + +## `CallDepthExceeded`错误 + +此错误表示已超出BPF堆栈深度。 + +请参阅[通话深度](overview.md#call-depth) + +## 计算约束 + +请参见[计算约束](developing/programming-model/runtime.md#compute-budget) + +## 浮动Rust类型 + +请参见[浮动支持](overview.md#float-support) + +## Heap大小 + +请参见[heap](overview.md#heap) + +## 无效账户数据 + +该程序错误的发生可能有很多原因。 通常,这是由于在指令中的错误位置或与正在执行的指令不兼容的帐户向程序传递了程序不期望的帐户所致。 + +当执行跨程序指令而忘记提供您正在调用的程序的帐户时,程序的实现也可能导致此错误。 + +## 无效指示数据 + +尝试反序列化指令时,可能会发生此程序错误,请检查传入的结构是否与指令完全匹配。 字段之间可能会有一些填充。 如果程序实现了Rust的`Pack`特性,则尝试打包和解压缩指令类型`T`以确定程序期望的确切编码: + +https://github.com/solana-labs/solana/blob/v1.4/sdk/program/src/program_pack.rs + +## MissingRequiredSignature + +有些说明要求帐户必须是签名者;如果预计将对帐户进行签名但未签名,则返回此错误。 + +当执行需要签名程序地址的跨程序调用时,程序的实现也可能会导致此错误,但是传递的签名者种子将传递给[`invoke_signed`](developing/programming-model/calling-between-programs.md)与用于创建程序地址[`create_program_address`](developing/programming-model/calling-between-programs.md#program-derived-addresses)的签名者种子不匹配。 + +## `rand` Rust依赖导致编译失败 + +请参见[Rust项目依赖项](developing-rust.md#project-dependencies) + +## Rust限制 + +请参见[Rust限制](developing-rust.md#restrictions) + +## 堆栈大小 + +请参见[stack](overview.md#stack) \ No newline at end of file diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/overview.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/overview.md new file mode 100644 index 0000000000..df20e7aab8 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/on-chain-programs/overview.md @@ -0,0 +1,127 @@ +--- +title: "概述" +--- + +开发人员可以编写自己的程序并将其部署到Solana区块链。 + +[Helloworld示例](examples.md#helloworld)是了解如何编写、构建、部署、与链上程序交互的入门材料。 + +## Berkley数据包过滤器(BPF) + +Solana链上程序通过[LLVM编译器基础结构](https://llvm.org/)编译为[可执行和可链接格式(ELF)](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format),其中包含了[Berkley数据包过滤器(BPF)](https://en.wikipedia.org/wiki/Berkeley_Packet_Filter)字节码的变体。 + +由于Solana使用LLVM编译器基础结构,因此可以使用可以针对LLVM的BPF后端的任何编程语言编写程序。 Solana当前支持用Rust和C / C ++编写程序。 + +BPF提供了有效的[指令集](https://github.com/iovisor/bpf-docs/blob/master/eBPF.md),可以在解释的虚拟机中执行,也可以作为高效的即时编译原生执行指令。 + +## 内存映射 + +Solana BPF程序使用的虚拟地址内存映射是固定的,其布局如下 + +- 程序代码从0x100000000开始 +- 堆栈数据从0x200000000开始 +- 堆数据从0x300000000开始 +- 程序输入参数从0x400000000开始 + +上面的虚拟地址是起始地址,但是程序可以访问存储器映射的子集。 如果程序尝试读取或写入未授予其访问权限的虚拟地址,则会panic,并且将返回`AccessViolation`错误,其中包含尝试违反的地址和大小。 + +## 堆栈 {#stack} + +BPF使用堆栈帧而不是可变堆栈指针。 每个堆栈帧的大小为4KB。 + +如果程序违反了该堆栈帧大小,则编译器将报告溢出情况,作为警告。 + +例如:`Error: Function +_ZN16curve25519_dalek7edwards21EdwardsBasepointTable6create17h178b3d2411f7f082E +Stack offset of -30728 exceeded max offset of -4096 by 26632 bytes, please +minimize large stack variables` + +该消息标识哪个符号超出了其堆栈框架,但是如果它是Rust或C ++符号,则名称可能会被修饰。 要对Rust符号进行解码,请使用[rustfilt](https://github.com/luser/rustfilt)。 上面的警告来自Rust程序,因此,已取消组合的符号名称为: + +```bash +$ rustfilt _ZN16curve25519_dalek7edwards21EdwardsBasepointTable6create17h178b3d2411f7f082E +curve25519_dalek::edwards::EdwardsBasepointTable::create +``` + +要对C ++符号进行解码,请使用binutils中的`c++filt`。 + +报告警告而不提示错误的原因是,即使程序不使用该功能,某些从属工具也可能包含违反堆栈框架限制的功能。 如果程序在运行时违反了堆栈大小,则会报告`AccessViolation`错误。 + +BPF堆栈帧占用一个从0x200000000开始的虚拟地址范围。 + +## 调用深度 + +程序被限制为必须快速运行,并且为了方便起见,程序的调用堆栈被限制为最大深度为64帧。 + +## 堆(Heap) + +程序可以直接在C中或通过Rust `alloc` API来访问运行时堆。 为了促进快速分配,使用了一个简单的32KB凹凸堆。 堆不支持`free`或`realloc`,因此请慎重使用它。 + +在内部,程序可以访问从虚拟地址0x300000000开始的32KB内存区域,并且可以根据程序的特定需求实现自定义堆。 + +- [Rust程序堆使用情况](developing-rust.md#heap) +- [C程序堆使用情况](developing-c.md#heap) + +## 浮点数支持 + +程序支持Rust的float操作的有限子集,尽管由于涉及的开销而强烈不建议使用。 如果程序尝试使用不受支持的浮点运算,则运行时将报告未解决的符号错误。 + +## 静态可写入数据 + +程序共享对象不支持可写共享数据。 使用相同的共享只读代码和数据在多个并行执行之间共享程序。 这意味着开发人员不应在程序中包含任何静态可写变量或全局变量。 将来,可以添加写时复制机制以支持可写数据。 + +## 签名分配 + +BPF 指令集不支持 [签名分配](https://www.kernel.org/doc/html/latest/bpf/bpf_design_QA.html#q-why-there-is-no-bpf-sdiv-for-signed-divide-operation)。 添加签名分配的指令是一个考虑因素。 + +## 加载程序(loader) + +程序由运行时加载程序部署并执行,目前有两个受支持的加载程序[BPF加载程序](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/bpf_loader.rs#L17)]和[不建议使用BPF加载程序](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/bpf_loader_deprecated.rs#L14) + +加载程序可能支持不同的应用程序二进制接口,因此开发人员必须为其编写程序并将其部署到同一加载程序中。 如果为一个装载程序编写的程序被部署到另一个装载程序,则由于程序输入参数的反序列化不匹配,结果通常是`AccessViolation`错误。 + +出于所有实际目的,应始终将程序编写为以最新的BPF加载程序为目标,并且最新的加载程序是命令行界面和javascript API的默认设置。 + +有关为特定加载程序实现程序的语言特定信息,请参见: +- [Rust程序入口点](developing-rust.md#program-entrypoint) +- [C程序入口点](developing-c.md#program-entrypoint) + +### 部署 + +BPF程序部署是将BPF共享对象上载到程序帐户的数据中并标记该帐户可执行文件的过程。 客户端将BPF共享对象分成较小的部分,并将其作为[`Write`](https://github.com/solana-labs/solana/blob/bc7133d7526a041d1aaee807b80922baa89b6f90/sdk/program/src/loader_instruction.rs#L13)的指令数据发送向加载程序的指令,加载程序在此将数据写入程序的帐户数据。 一旦收到所有片段,客户端就会向加载程序发送[`Finalize`](https://github.com/solana-labs/solana/blob/bc7133d7526a041d1aaee807b80922baa89b6f90/sdk/program/src/loader_instruction.rs#L30)指令,然后加载程序将验证BPF数据是否有效,并将程序帐户标记为_executable_。 一旦程序帐户被标记为可执行,随后的交易就可以发出该程序要处理的指令。 + +当指令针对可执行的BPF程序时,加载程序将配置程序的执行环境,序列化程序的输入参数,调用程序的入口点,并报告遇到的任何错误。 + +有关更多信息,请参见[deploying](deploying.md) + +### 输入参数序列化 + +BPF加载程序将程序输入参数序列化为字节数组,然后将其传递到程序的入口点,由程序负责在链上反序列化它。 不赞成使用的加载器和当前加载器之间的变化之一是,输入参数以某种方式序列化,导致各种参数落在对齐字节数组内的对齐偏移量上。 这允许反序列化实现直接引用字节数组并提供指向程序的对齐指针。 + +有关序列化的特定于语言的信息,请参见: +- [Rust程序参数反序列化](developing-rust.md#parameter-deserialization) +- [C程序参数反序列化](developing-c.md#parameter-deserialization) + +最新的加载器按如下方式序列化程序输入参数(所有编码均为小尾数法): + +- 8字节无符号帐户数 +- 对于每个帐户 + - 1个字节,指示这是否是重复帐户,如果不是重复帐户,则值为0xff,否则值为与其重复的帐户的索引。 + - 填充7个字节 + - 如果不重复 + - 1个字节的填充 + - 1个字节的布尔值,如果account是签名者,则为true + - 1字节布尔值,如果帐户可写,则为true + - 1字节布尔值,如果帐户可执行,则为true + - 4个字节的填充 + - 32个字节的帐户公钥 + - 该帐户的所有者公共密钥的32个字节 + - 该帐户拥有的Lamport的8字节无符号数 + - -8个字节的无符号帐户数据字节数 + - x字节的帐户数据 + - 10k字节的填充,用于重新分配 + - 足够的填充以将偏移量对齐到8个字节。 + - 8个字节的租用纪元 +- 8个字节的无符号指令数据 +- -x字节的指令数据 +- -程序ID的32个字节 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/programming-model/accounts.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/programming-model/accounts.md new file mode 100644 index 0000000000..f866250ef5 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/programming-model/accounts.md @@ -0,0 +1,91 @@ +--- +title: "账户" +--- + +## 在交易之间存储状态 + +如果程序需要在交易之间存储状态,则可以使用_accounts_进行存储。 帐户类似于Linux等操作系统中的文件。 就像文件一样,帐户可以保存任意数据,并且该数据会在程序的生存期内持续存在。 帐户也像文件一样,包含元数据,该元数据告诉运行时允许谁访问数据以及如何访问数据。 + +与文件不同,该帐户包含文件生存期内的元数据。 该存在时间用“代币”表示,即称为_lamports_的许多局部原生代币。 帐户保存在验证节点的内存中,并支付[“rent”](#rent)留在那里。 每个验证节点都会定期扫描所有帐户并收取租金。 任何掉落到零零花的账户都将被清除。 如果帐户包含足够数量的Lamport,也可以标记为[rent-exempt](#rent-exemption)。 + +与Linux用户使用路径查找文件的方式相同,Solana客户端使用_address_查找帐户。 该地址是一个256位公共密钥。 + +## 签名者 + +交易可以包括与交易所引用的账户的公共密钥相对应的数字[签名](terminology.md#signature)。 当存在相应的数字签名时,它表示该帐户的私钥持有人已签名并因此“授权”了该交易,因此该帐户称为_signer_。 帐户是否为签名者将作为帐户元数据的一部分传达给程序。 然后,程序可以使用该信息来制定权限决策。 + +## 只读 + +事务可以[指示](transactions.md#message-header-format)它引用的某些帐户被视为_只读帐户_,以便能够在事务之间进行并行帐户处理。 运行时允许多个程序同时读取只读帐户。 如果程序尝试修改只读帐户,则运行时将拒绝该事务。 + +## 可执行 + +如果某个帐户在其元数据中被标记为“可执行”,则将其视为可以通过将帐户的公钥包含在指令的[程序ID](transactions.md#program-id)中来执行的程序。 在成功的程序部署过程中,拥有该帐户的加载程序将帐户标记为可执行文件。 例如,在BPF程序部署期间,一旦加载程序确定帐户数据中的BPF字节码有效,则加载程序会将程序帐户永久标记为可执行文件。 一旦可执行,运行时将强制该帐户的数据(程序) 是不可变的。 + +## 创建 + +为了创建一个帐户,客户端生成一个_keypair_并使用`SystemProgram::CreateAccount`指令注册其公共密钥,并预先分配了固定的存储大小(以字节为单位)。 当前帐户数据的最大大小为10MB。 + +帐户地址可以是任意的256位值,并且高级用户可以使用一些机制来创建派生地址(`SystemProgram::CreateAccountWithSeed`,[`Pubkey::CreateProgramAddress`](calling-between-programs.md#program-derived-addresses))。 + +从未通过系统程序创建的帐户也可以传递到程序。 当指令引用以前尚未创建的帐户时,程序将通过系统程序拥有的帐户,该帐户具有0个Lamport和0个数据。 但是,该帐户将反映它是否是该交易的签名者,因此可以用作授权。 在这种情况下,授权机构向程序传达与帐户的公共密钥相关联的私有密钥的持有者对交易进行了签名。 该程序可能知道该帐户的公钥,也可能将其记录在另一个帐户中,并表示对该程序控制或执行的资产或操作具有某种所有权或授权。 + +## 程序的所有权和分配 + +创建的帐户由称为System程序的内置程序初始化为_owned_,并适当地称为_system account_。 帐户包含“所有者”元数据。 所有者是一个程序ID。 如果运行时的ID与所有者匹配,则运行时将授予该程序对该帐户的写访问权限。 对于System程序,运行时允许客户端转移Lamport,并且重要的是_转移_帐户所有权,这意味着将所有者更改为其他程序ID。 如果某个帐户不属于某个程序,则仅允许该程序读取其数据并将该帐户记入贷方。 + +## 承租 + +使帐户在Solana上保持活动状态会产生称为_rent_的存储成本,因为集群必须积极维护数据以处理其上的任何将来的事务。 这与比特币和以太坊不同,在比特币和以太坊中,存储帐户不会产生任何费用。 + +租金是在当前时期通过事务在第一次访问(包括初始帐户创建) 时通过运行时从帐户余额中扣除的,如果没有交易,则在每个时期一次。 该费用目前是固定费率,以字节乘以时期为单位。 该费用将来可能会更改。 + +为了简化租金计算,租金始终是在一个完整的时期内收取的。 租金不是按比例分配的,这意味着部分时期既不收费也不退款。 这意味着,在创建帐户时,收取的首笔租金不是针对当前的部分时期,而是针对下一个完整的时期而预先收取的租金。 随后的租金收取是未来的进一步时期。 另一方面,如果一个已出租的帐户的余额降到另一个租金费用的中间时期以下,则该帐户将在当前时期继续存在,并在即将到来的时期开始时立即被清除。 + +如果帐户保持最低余额,则可以免交租金。 此免租金描述如下。 + +### 租金计算 + +注意:租金率将来可能会改变。 + +在撰写本文时,在testnet和mainnet-beta群集上,固定租金为每字节纪元19.055441478439427兰特。 一个[epoch](terminology.md#epoch)的目标是2天(对于devnet,租金为每字节纪元 0.3608183131797095 lamports,长度为54m36s长)。 + +计算得出该值的目标是每兆字节天0.01 SOL(与每兆字节年3.56SOL完全匹配): + +```text +租金:19.055441478439427=10_000_000(0.01SOL)*365(一年中大约一天)/(1024*1024)(1MiB)/(365.25/2)(一年中的纪元) +``` + +租金计算以`f64`精度完成,最终结果在Lamports中被截断为`u64`。 + +租金计算包括帐户大小的帐户元数据(地址、所有者、lamports等)。 因此,用于租金计算的最小帐户为128字节。 + +例如,创建的帐户初始转移了10,000 lamports,并且没有其他数据。 租金会在创建时立即从中扣除,从而产生7,561 lamports的余款: + + +```text +租金:2,439=19.055441478439427(租金)*128字节(最小帐户大小)*1(纪元) +帐户余额:7,561=10,000(转让的兰特)-2,439(此帐户的时期租金) +``` + +即使没有活动,帐户余额也将在下一个时期减少到5,122 lamports: + +```text +帐户余额:5,122=7,561(当前余额) -2,439(该帐户的租金,用于某个时期) +``` + +因此,如果转移的兰特小于或等于2439,则最小尺寸帐户将在创建后立即删除。 + +### 免租金 + +另外,通过存入至少2年的租金,可以使一个帐户完全免收租金。 每次帐户余额减少时都会进行检查,一旦余额低于最低金额,便会立即从租金中扣除。 + +运行时要求程序可执行帐户免租金,以免被清除。 + +注意:请使用[`getMinimumBalanceForRentExemption`RPC端点](developing/clients/jsonrpc-api.md#getminimumbalanceforrentexemption)计算特定帐户大小的最小余额。 以下计算仅是说明性的。 + +例如,一个程序可执行文件的大小为15,000字节,则需要105,290,880 lamports(=〜0.105SOL) 的余额才能免租: + +```text +105,290,880=19.055441478439427(手续费率)*(128+15_000)(包括元数据的帐户大小)*((365.25/2)*2)(以2年为周期) +``` diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/programming-model/calling-between-programs.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/programming-model/calling-between-programs.md new file mode 100644 index 0000000000..91d5d1f11c --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/programming-model/calling-between-programs.md @@ -0,0 +1,198 @@ +--- +title: 程序之间的调用 +--- + +## 跨程序调用 {#cross-program-invocations} + +Solana运行时允许程序通过称为跨程序调用的机制相互调用。 程序之间的调用是通过一个程序调用另一个程序的指令来实现的。 调用程序将暂停,直到被调用的程序完成对指令的处理为止。 + +例如,客户可以创建一个交易来修改两个帐户,每个帐户都由单独的链上程序拥有: + +```rust,ignore +let message = Message::new(vec![ + token_instruction::pay(&alice_pubkey), + acme_instruction::launch_missiles(&bob_pubkey), +]); +client.send_and_confirm_message(&[&alice_keypair, &bob_keypair], &message); +``` + +客户可以代之以允许`acme`程序代表客户方便地调用`token`指令: + +```rust,ignore +let message = Message::new(vec![ + acme_instruction::pay_and_launch_missiles(&alice_pubkey, &bob_pubkey), +]); +client.send_and_confirm_message(&[&alice_keypair, &bob_keypair], &message); +``` + +给定两个链上程序`token`和`acme`,每个程序分别执行指令`pay()`和`launch_missiles()`,可以通过调用`token`模块中定义的函数来实现acme跨程序调用: + +```rust,ignore +mod acme { + use token_instruction; + + fn launch_missiles(accounts: &[AccountInfo]) -> Result<()> { + ... + } + + fn pay_and_launch_missiles(accounts: &[AccountInfo]) -> Result<()> { + let alice_pubkey = accounts[1].key; + let instruction = token_instruction::pay(&alice_pubkey); + invoke(&instruction, accounts)?; + + launch_missiles(accounts)?; + } +``` + +Solana的运行时内置了`invoke()`,它负责通过指令的`program_id`字段将给定指令路由到`token`程序。 + +请注意,`invoke` 要求调用者传递被调用指令所需的所有帐户。 这意味着可执行帐户(与指令的程序ID匹配的帐户) 和传递给指令处理器的帐户都可以。 + +在调用`pay()`之前,运行时必须确保`acme`没有修改`token`拥有的任何帐户。 它通过在`acme`调用`invoke`时将运行时策略应用于帐户的当前状态,而不是在`acme`指令开始时将帐户的初始状态应用到帐户的当前状态。 在`pay()`完成之后,运行时必须再次通过应用运行时的策略来确保`token`不会修改`acme`拥有的任何帐户,但是这次使用`token`程序ID。 最后,在`pay_and_launch_missiles()`完成之后,运行时必须再次使用runtime 策略,这通常是正常的时间,但要使用所有更新的`pre_ *`变量。 如果执行直到`pay()`为止的`pay_and_launch_missiles()`没有任何无效的帐户更改,`pay()`没有任何无效的更改,并且从`pay()`一直执行到`pay_and_launch_missiles()`返回,则没有无效的更改,然后,runtime可以过渡性地假设`pay_and_launch_missiles()`总体上没有进行无效的帐户更改,因此可以提交所有这些帐户修改。 + +### 需要特权的指令 + +运行时使用授予调用者程序的特权来确定可以扩展给被调用者的特权。 在这种情况下,特权是指签名者和可写帐户。 例如,如果调用者正在处理的指令包含签名者或可写帐户,则调用者可以调用也包含该签名者和/或可写帐户的指令。 + +此特权扩展依赖于程序是不可变的这一事实。 对于`acme`程序,运行时可以安全地将事务签名视为`token`指令签名。 当运行时看到`token`指令引用`alice_pubkey`时,它将在`acme`指令中查找密钥,以查看该密钥是否与已签名的帐户相对应。 在这种情况下,它会这样做并因此授权`token`程序修改Alice的帐户。 + +### 程序签名帐户 + +程序可以使用[程序派生地址](#program-derived-addresses)发出包含未在原始交易中签名的已签名帐户的指令。 + +为了用程序派生的地址签署一个帐户,程序可以`invoke_signed()`。 + +```rust,ignore + invoke_signed( + &instruction, + accounts, + &[&["First addresses seed"], + &["Second addresses first seed", "Second addresses second seed"]], + )?; +``` + +### 调用深度 + +跨程序调用允许程序直接调用其他程序,但当前深度限制为4。 + +### 可重入 + +目前,可重入仅限于以固定深度为上限的直接自递归。 此限制可防止程序可能在不知道稍后会被调用回状态的情况下从中间状态调用另一个程序的情况。 直接递归可以使程序在被调用时完全控制其状态。 + +## 程序派生地址 + +程序派生的地址允许在[程序之间调用](#cross-program-invocations)时使用以编程方式生成的签名。 + +使用程序派生的地址,可以向某个程序授予某个帐户的权限,然后再将该权限转移给另一个帐户。 这是可能的,因为该程序可以在授予权限的事务中充当签名者。 + +例如,如果两个用户想要对Solana中的游戏结果押注,则他们每个人都必须将其下注的资产转移到将遵守协议的某些中介机构上。 当前,在Solana中尚无办法将此中介程序作为程序来实现,因为该中介程序无法将资产转让给获胜者。 + +对于许多DeFi应用程序来说,此功能是必需的,因为它们要求将资产转移到托管代理,直到发生确定新所有者的事件为止。 + +- 去中心化交易所,可在匹配的买价和卖价之间转移资产。 + +- 将资产转移给获胜者的拍卖。 + +- 收集奖品并将其重新分配给获奖者的游戏或预测市场。 + +程序派生地址: + +1. 允许程序控制特定的地址(称为程序地址),以使任何外部用户都无法生成带有这些地址签名的有效交易。 + +2. 允许程序以编程方式签名通过[跨程序调用](#cross-program-invocations)调用的指令中存在的程序地址。 + +在这两个条件下,用户可以安全地将链上资产的权限转移或分配给程序地址,然后程序可以自行决定在其他地方分配该权限。 + +### 程序地址的私钥 + +程序地址不在ed25519曲线上,因此没有与之关联的有效私钥,因此无法生成签名。 虽然它没有自己的私钥,但是程序可以使用它来发布包含程序地址作为签名者的指令。 + +### 基于哈希的生成程序地址 + +程序地址是使用256位抗映像前哈希函数从种子和程序ID的集合中确定性地得出的。 程序地址一定不能位于ed25519曲线上,以确保没有关联的私钥。 如果发现地址位于曲线上,则在生成过程中将返回错误。 对于给定的种子和程序ID集合,这种情况大约发生50/50的变化。 如果发生这种情况,可以使用另一组种子或种子凹凸(附加的8位种子) 来查找曲线外的有效程序地址。 + +程序的确定性程序地址遵循与使用`system_instruction::create_address_with_seed`实现的用`SystemInstruction::CreateAccountWithSeed`创建的帐户类似的派生路径。 + +作为参考,该实现如下: + +```rust,ignore +pub fn create_address_with_seed( + base: &Pubkey, + seed: &str, + program_id: &Pubkey, +) -> Result { + if seed.len() > MAX_ADDRESS_SEED_LEN { + return Err(SystemError::MaxSeedLengthExceeded); + } + + Ok(Pubkey::new( + hashv(&[base.as_ref(), seed.as_ref(), program_id.as_ref()]).as_ref(), + )) +} +``` + +程序可以使用种子确定性地派生任意数量的地址。 这些种子可以象征性地标识地址的使用方式。 + +来自`Pubkey`:: + +```rust,ignore +///生成派生程序地址 +/// *种子,用于派生密钥的符号关键字 +/// * program_id,为该地址派生的程序 +pub fn create_program_address( + seeds: &[&[u8]], + program_id: &Pubkey, +) -> Result +``` + +### 使用程序地址 + +客户可以使用`create_program_address`函数生成目标地址。 + +```rust,ignore +//确定性地导出托管密钥 +let escrow_pubkey = create_program_address(&[&["escrow"]], &escrow_program_id); + +//使用该密钥构造传输消息 +let message = Message::new(vec![ + token_instruction::transfer(&alice_pubkey, &escrow_pubkey, 1), +]); + +//处理将一个1令牌传输到托管的消息 +client.send_and_confirm_message(&[&alice_keypair], &message); +``` + +程序可以使用相同的函数来生成相同的地址。 程序在下面的功能中从程序地址发出`token_instruction::transfer`,就好像它具有用于签署交易的私钥一样。 + +```rust,ignore +fn transfer_one_token_from_escrow( + program_id: &Pubkey, + keyed_accounts: &[KeyedAccount] +) -> Result<()> { + + //用户提供目的地 + let alice_pubkey = keyed_accounts[1].unsigned_key(); + + //确定性派生托管公钥。 + let escrow_pubkey = create_program_address(&[&["escrow"]], program_id); + + //创建转移指令 +let instruction = token_instruction::transfer(&escrow_pubkey, &alice_pubkey, 1); + + //运行时确定性地从当前 + //执行程序ID和提供的关键字。 + //如果派生地址与指令中标记为已签名的键匹配 + //然后该密钥被接受为已签名。 + invoke_signed(&instruction, &[&["escrow"]])? +} +``` + +### 需要签名者的说明 + +用`create_program_address`生成的地址与任何其他公钥都没有区别。 运行时验证地址是否属于程序的唯一方法是使程序提供用于生成地址的种子。 + +运行时将在内部调用`create_program_address`,并将结果与指令中提供的地址进行比较。 + +## 示例 + +请参阅 [使用Rust开发](developing/on-chain-programs/developing-rust.md#examples) 和 [使用C开发](developing/on-chain-programs/developing-c.md#examples)以获取有关如何使用跨程序调用的示例。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/programming-model/overview.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/programming-model/overview.md new file mode 100644 index 0000000000..d6c9d37ac4 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/programming-model/overview.md @@ -0,0 +1,7 @@ +--- +title: "概述" +--- + +一个[app](terminology.md#app)通过向Solana集群发送带有一个或多个[指令](transactions.md#instructions)的[事务](transactions.md)来与之交互。 Solana [runtime](runtime.md) 会将这些指令传递给应用程序开发人员事先部署的[程序](terminology.md#program)。 例如,一条指令可能告诉程序将[lamports](terminology.md#lamports)从一个[账户](accounts.md)转移到另一个,或创建一个交互协议来管理Lamport的转移方式。 指令针对每个交易顺序地和原子级地执行。 如果任何指令无效,则交易中的所有帐户更改都将被丢弃。 + +要立即开始开发,您可以构建,部署和运行[示例](developing/on-chain-programs/examples.md)之一。 \ No newline at end of file diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/programming-model/runtime.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/programming-model/runtime.md new file mode 100644 index 0000000000..595d0edc46 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/programming-model/runtime.md @@ -0,0 +1,86 @@ +--- +title: "运行时(runtime)" +--- + +## 程序功能 + +运行时仅允许所有者程序借记帐户或修改其数据。 然后,程序为客户是否可以修改其拥有的帐户定义其他规则。 在系统程序的情况下,它允许用户通过识别交易签名来转移灯饰。 如果看到客户端使用密钥对的_private key_签署了交易,则表明客户端已授权代币传输。 + +换句话说,给定程序拥有的整个帐户集可以视为键值存储,其中键是帐户地址,值是特定于程序的任意二进制数据。 程序作者可以决定如何管理尽可能多的帐户的整个程序状态。 + +运行时执行每个事务的指令后,它将使用帐户元数据来验证是否违反了访问策略。 如果程序违反了该策略,则运行时会丢弃交易中所有指令所做的所有帐户更改,并将交易标记为失败。 + +### 政策 + +程序处理完指令后,运行时将验证程序仅执行了允许的操作,并且结果符合运行时策略。 + +该策略如下: +- 只有帐户所有者可以更改所有者。 + - 仅在帐户可写时。 + - 并且仅在该帐户不可执行时 + - 并且仅当数据为零初始化或为空时。 +- 未分配给该程序的帐户的余额不能减少。 +- 只读帐户和可执行帐户的余额可能不会更改。 +- 只有系统程序拥有该帐户,只有系统程序才能更改数据大小。 +- 只有所有者可以更改帐户数据。 + - 如果该帐户可写。 + - 并且该帐户不可执行。 +- 可执行文件是单向的(false->true),只有帐户所有者可以设置。 +- 没有与此帐户相关联的rent_epoch的修改。 + +## 计算预算 {#compute-budget} + +为了防止程序滥用计算资源,必须为事务中的每个指令分配一个计算预算。 预算由计算单元组成,在程序执行各种操作和程序可能不会超出的范围时会消耗这些计算单元。 当程序消耗了全部预算或超出界限时,运行时将暂停程序并返回错误。 + +以下操作会产生计算成本: +- 执行BPF指令 +- 呼叫系统电话 + - 记录 + - 创建程序地址 + - 跨程序调用 + - ... + +对于跨程序调用,所调用的程序将继承其父级的预算。 如果被调用的程序消耗了预算或超出了限制,则整个调用链和父级都将停止。 + +可以在Solana SDK中找到当前的[计算预算](https://github.com/solana-labs/solana/blob/d3a3a7548c857f26ec2cb10e270da72d373020ec/sdk/src/process_instruction.rs#L65)。 + +例如,如果当前预算是: + +```rust +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](developing/on-chain-programs/debugging.md#monitoring-compute-budget-consumption)。 + +预算值取决于功能启用,请查看计算预算的[new](https://github.com/solana-labs/solana/blob/d3a3a7548c857f26ec2cb10e270da72d373020ec/sdk/src/process_instruction.rs#L97)函数列出预算的编制方式。 需要了解[功能](runtime.md#features)的工作方式以及正在使用的群集上启用的功能才能确定当前预算的值。 + +## 新的功能 + +随着Solana的发展,可能会引入新功能或补丁,这些新功能或补丁会更改集群的行为以及程序的运行方式。 行为的变化必须在群集的各个节点之间进行协调,如果节点不协调,则这些变化可能会导致共识破裂。 Solana支持一种称为运行时功能的机制,以方便平滑地采用更改。 + +运行时功能是历时协调的事件,将在集群中发生一个或多个行为更改。 对Solana的新更改(将更改行为)使用功能门进行包装,并且默认情况下处于禁用状态。 然后使用Solana工具激活功能,将其标记为未决,一旦标记为未决,该功能将在下一个时期激活。 + +要确定激活了哪些功能,请使用[Solana命令行工具](cli/install-solana-cli-tools.md): + +```bash +solana功能状态 +``` + +如果首先遇到问题,请确保您使用的Solana工具版本与`solana cluster-version`返回的版本相匹配。 如果它们不匹配,请[安装正确的工具套件](cli/install-solana-cli-tools.md)。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/programming-model/transactions.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/programming-model/transactions.md new file mode 100644 index 0000000000..c887c49264 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/programming-model/transactions.md @@ -0,0 +1,113 @@ +--- +title: "交易" +--- + +程序执行从将[transaction](terminology.md#transaction)提交到集群开始。 Solana运行时将执行一个程序,以按顺序和原子方式处理事务中包含的每个[指令](terminology.md#instruction)。 + +## 交易剖析 + +本节介绍事务的二进制格式 + +### 交易格式 + +事务包含签名的[compact-array](#compact-array-format),然后是[message](#message-format)。 签名数组中的每个项目都是给定消息的[数字签名](#signature-format)。 Solana运行时验证签名数是否与[message heade](#message-header-format)的前8位中的数字匹配。 它还验证每个签名是否由与邮件帐户地址数组中相同索引处的公钥相对应的私钥签名。 + +#### 签名格式 + +每个数字签名均为ed25519二进制格式,占用64个字节。 + +### 邮件格式 + +一条消息包含[header](#message-header-format),然后是[account address](#account-addresses-format)的紧凑数组,然后是最近的[blockhash](#blockhash-format),紧接着是[指令](#instruction-format)的紧凑数组。 + +#### 邮件标题格式 + +消息头包含三个无符号的8位值。 第一个值是包含交易中所需签名的数量。 第二个值是那些对应的只读帐户地址的数量。 邮件标题中的第三个值是不需要签名的只读帐户地址的数量。 + +#### 帐户地址格式 + +要求签名的地址出现在帐户地址数组的开头,其地址首先请求写访问权限,然后请求只读帐户。 不需要签名的地址跟在需要签名的地址之后,再次是先读写帐户,然后是只读帐户。 + +#### Blockhash区块链哈希值格式 + +区块哈希包含一个32字节的SHA-256哈希。 它用于指示客户最后一次观察分类帐的时间。 当区块哈希值太旧时,验证程序将拒绝交易。 + +### 指令格式 + +一条指令包含一个程序ID索引,后跟一个帐户地址索引的紧凑数组,然后是一个不透明的8位数据的紧凑数组。 程序ID索引用于标识可以解释不透明数据的链上程序。 程序ID索引是消息的帐户地址数组中帐户地址的无符号8位索引。 帐户地址索引是同一数组中的无符号8位索引。 + +### 紧凑数组格式 + +紧凑数组被序列化为数组长度,随后是每个数组项。 数组长度是一种特殊的多字节编码,称为compact-u16。 + +#### Compact-u16格式 + +一个compact-u16是16位的多字节编码。 第一个字节在其低7位中包含该值的低7位。 如果该值大于0x7f,则设置高位,并将该值的后7位放入第二个字节的低7位。 如果该值大于0x3fff,则设置高位,并将该值的其余2位放入第三个字节的低2位。 + +### 帐户地址格式 + +帐户地址是32字节的任意数据。 当地址需要数字签名时,运行时会将其解释为ed25519密钥对的公钥。 + +## 指示 + +每个[instruction](terminology.md#instruction)都指定一个程序,应传递给该程序的交易帐户的子集以及一个传递给该程序的数据字节数组。 该程序解释数据数组并在指令指定的帐户上运行。 该程序可以成功返回,或者带有错误代码。 错误返回会导致整个事务立即失败。 + +程序通常提供帮助程序功能来构造它们支持的指令。 例如,系统程序提供了以下Rust助手来构建[`SystemInstruction::CreateAccount`](https://github.com/solana-labs/solana/blob/6606590b8132e56dab9e60b3f7d20ba7412a736c/sdk/program/src/system_instruction.rs#L63)指令: + +```rust +pub fn create_account( + from_pubkey: &Pubkey, + to_pubkey: &Pubkey, + lamports: u64, + space: u64, + owner: &Pubkey, +) -> Instruction { + let account_metas = vec![ + AccountMeta::new(*from_pubkey, true), + AccountMeta::new(*to_pubkey, true), + ]; + Instruction::new( + system_program::id(), + &SystemInstruction::CreateAccount { + lamports, + space, + owner: *owner, + }, + account_metas, + ) +} +``` + +可以在这里找到: + +https://github.com/solana-labs/solana/blob/6606590b8132e56dab9e60b3f7d20ba7412a736c/sdk/program/src/system_instruction.rs#L220 + +### 程序ID + +指令的[程序ID](terminology.md#program-id)指定将处理该指令的程序。 程序帐户的所有者指定应使用哪个加载程序来加载和执行程序,并且数据包含有关运行时应如何执行程序的信息。 + +对于[已部署的BPF程序](developing/on-chain-programs/overview.md),所有者是BPF加载程序,帐户数据包含BPF字节码。 一旦成功部署,程序帐户便会被加载程序永久标记为可执行文件。 运行时将拒绝指定不可执行程序的事务。 + + +与已部署的程序不同,[runtime facilities](developing/runtime-facilities/programs.md)的处理方式有所不同,因为它们直接内置在Solana运行时中。 + +### 帐户 + +指令引用的帐户代表链上状态,并且既作为程序的输入又作为输出。 有关帐户的更多信息,请参见[帐户](accounts.md)章节。 + +### 指令数据 + +每个指令都带有一个通用字节数组,该字节数组与帐户一起传递给程序。 指令数据的内容是特定于程序的,通常用于传达程序应执行的操作以及这些操作在帐户所包含的内容之外可能需要的任何其他信息。 + +程序可以自由指定如何将信息编码到指令数据字节数组中。 数据编码方式的选择应考虑到解码的开销,因为该步骤是由链上程序执行的。 据观察,一些常见的编码(例如Rust的bincode) 效率很低。 + +[Solana程序库的代币程序](https://github.com/solana-labs/solana-program-library/tree/master/token)提供了一个示例,说明如何有效地对指令数据进行编码,但是请注意,这种方法仅支持固定大小的类型。 代币利用[Pack](https://github.com/solana-labs/solana/blob/master/sdk/program/src/program_pack.rs)特征来对代币指令和代币的指令数据进行编码/解码帐户状态。 + +## 签名 + +每笔交易都明确列出了交易指令所引用的所有帐户公钥。 这些公钥的子集每个都带有交易签名。 这些签名向链上程序发出信号,表明帐户持有人已授权交易。 通常,程序使用授权来允许借记帐户或修改其数据。 有关如何将授权传达给程序的更多信息,请参见[帐户](accounts.md#signers)。 + + +## 最近的区块链哈希值 + +事务包括最近的[blockhash](terminology.md#blockhash),以防止重复并赋予事务生命周期。 任何与上一个交易完全相同的交易都会被拒绝,因此添加一个更新的区块哈希可以使多个交易重复完全相同的操作。 事务还具有由Blockhash定义的生存期,因为Blockhash太旧的任何事务都将被拒绝。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/runtime-facilities/programs.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/runtime-facilities/programs.md new file mode 100644 index 0000000000..2b77ccff06 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/runtime-facilities/programs.md @@ -0,0 +1,95 @@ +--- +title: "构建程序" +--- + +Solana包含少量内置程序,这些程序是运行验证程序节点所必需的。 与第三方程序不同,内置程序是验证程序实现的一部分,可以作为群集升级的一部分进行升级。 可能会进行升级以添加功能,修复错误或提高性能。 个别指令的界面更改很少(如果有的话)发生。 相反,当需要更改时,将添加新指令,并且将先前的指令标记为已弃用。 应用程序可以在自己的时间表上进行升级,而无需担心升级过程中的中断。 + +对于每个内置程序,将提供每个支持的指令的程序ID和说明。 事务可以混合和匹配来自不同程序的指令,也可以包括来自已部署程序的指令。 + +## 系统程序 + +创建帐户并在它们之间转移Lamport + +- 程序ID:`11111111111111111111111111111111` +- 说明:[SystemInstruction](https://docs.rs/solana-sdk/VERSION_FOR_DOCS_RS/solana_sdk/system_instruction/enum.SystemInstruction.html) + +## 配置程序 + +将配置数据添加到链和允许对其进行修改的公钥列表中 + +- 程序ID:`Config1111111111111111111111111111111111111111` +- 说明:[config_instruction](https://docs.rs/solana-config-program/VERSION_FOR_DOCS_RS/solana_config_program/config_instruction/index.html) + +与其他程序不同,Config程序未定义任何单独的指令。 它只有一条隐式指令,即“存储”指令。 它的指令数据是一组密钥,用于控制对帐户的访问以及存储在其中的数据。 + +## 权益计划 + +创建权益账户并将其委托给验证者 + +- 程序ID:`Stake11111111111111111111111111111111111111` +- 说明: [StakeInstruction](https://docs.rs/solana-stake-program/VERSION_FOR_DOCS_RS/solana_stake_program/stake_instruction/enum.StakeInstruction.html) + +## 投票程序 + +创建投票账户并对区块进行投票 + +- 程序ID:`Vote111111111111111111111111111111111111111` +- 说明:[VoteInstruction](https://docs.rs/solana-vote-program/VERSION_FOR_DOCS_RS/solana_vote_program/vote_instruction/enum.VoteInstruction.html) + +## BPF加载程序 + +将程序添加到链中并执行它们。 + +- 程序ID:`BPFLoader11111111111111111111111111111111111` +- 说明:[LoaderInstruction](https://docs.rs/solana-sdk/VERSION_FOR_DOCS_RS/solana_sdk/loader_instruction/enum.LoaderInstruction.html) + +BPF加载程序将其自身标记为它创建的用于存储程序的可执行帐户的“所有者”。 当用户通过程序ID调用指令时,Solana运行时将同时加载您的可执行帐户及其所有者BPF Loader。 然后,运行时将您的程序传递给BPF加载程序以处理指令。 + +## Secp256k1程序 + +验证secp256k1公钥恢复操作(ecrecover)。 + +- 程序ID:`KeccakSecp256k11111111111111111111111111111111` +- 说明:[new_secp256k1_instruction](https://github.com/solana-labs/solana/blob/c1f3f9d27b5f9534f9a37704bae1d690d4335b6b/programs/secp256k1/src/lib.rs#L18) + +Secp256k1程序处理一条指令,该指令将在指令数据中序列化的以下结构的计数作为第一个字节: + +``` +struct Secp256k1SignatureOffsets { + secp_signature_key_offset: u16, // offset to [signature,recovery_id,etherum_address] of 64+1+20 bytes + secp_signature_instruction_index: u8, // instruction index to find data + secp_pubkey_offset: u16, // offset to [signature,recovery_id] of 64+1 bytes + secp_signature_instruction_index: u8, // instruction index to find data + secp_message_data_offset: u16, // offset to start of message data + secp_message_data_size: u16, // size of message data + secp_message_instruction_index: u8, // index of instruction data to get message data +} +``` + +伪代码的操作: +``` +process_instruction() { + for i in 0..count { + // i'th index values referenced: + instructions = &transaction.message().instructions + signature = instructions[secp_signature_instruction_index].data[secp_signature_offset..secp_signature_offset + 64] + recovery_id = instructions[secp_signature_instruction_index].data[secp_signature_offset + 64] + ref_eth_pubkey = instructions[secp_pubkey_instruction_index].data[secp_pubkey_offset..secp_pubkey_offset + 32] + message_hash = keccak256(instructions[secp_message_instruction_index].data[secp_message_data_offset..secp_message_data_offset + secp_message_data_size]) + pubkey = ecrecover(signature, recovery_id, message_hash) + eth_pubkey = keccak256(pubkey[1..])[12..] + if eth_pubkey != ref_eth_pubkey { + return Error + } + } + return Success +} +``` + +这允许用户在事务中指定用于签名和消息数据的任何指令数据。 通过指定一种特殊的指令sysvar,也可以从事务本身接收数据。 + +交易成本将计算要验证的签名数乘以签名成本验证乘数。 + +### 优化注意事项 + +该操作将必须在(至少部分) 反序列化之后进行,但是所有输入都来自交易数据本身,这使得它相对于交易处理和PoH验证并行执行相对容易。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/runtime-facilities/sysvars.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/runtime-facilities/sysvars.md new file mode 100644 index 0000000000..928733c291 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/developing/runtime-facilities/sysvars.md @@ -0,0 +1,80 @@ +--- +title: Sysvar群集数据 +--- + +Solana通过[`sysvar`](terminology.md#sysvar)帐户向程序公开了各种群集状态数据。 这些帐户填充在[`solana-program`开发工具](https://docs.rs/solana-program/VERSION_FOR_DOCS_RS/solana_program/sysvar/index.html)中发布的已知地址以及帐户布局中,并在下面概述。 + +要将sysvar数据包括在程序操作中,请在事务处理的帐户列表中传递sysvar帐户地址。 可以像其他任何帐户一样在您的指令处理器中读取该帐户。 始终以*只读方式*访问sysvars帐户。 + +## 时钟 + +Clock sysvar包含有关群集时间的数据,包括当前时间段,时期和估计的Wall-clock Unix时间戳。 它在每个插槽中更新。 + +- 地址:`SysvarC1ock11111111111111111111111111111111` +- 布局:[时钟](https://docs.rs/solana-program/VERSION_FOR_DOCS_RS/solana_program/clock/struct.Clock.html) +- 栏位: + - `slot`:当前的插槽 + - `epoch_start_timestamp`:此epoch中第一个插槽的Unix时间戳。 在纪元的第一个时隙中,此时间戳与`unix_timestamp`(如下所示) 相同。 + - `epoch`:当前纪元 + - `leader_schedule_epoch`:已经为其生成了领导者时间表的最新纪元 + - `unix_timestamp`:此插槽的Unix时间戳。 + + 每个插槽都有一个基于历史证明的估计持续时间。 但实际上,时隙的流逝可能比此估计更快或更慢。 结果,将基于投票验证程序的oracle输入生成插槽的Unix时间戳。 此时间戳的计算方式为投票提供的时间戳估计的赌注加权中位数,以自纪元开始以来经过的预期时间为界。 + + 更明确地说:对于每个插槽,每个验证节点提供的最新投票时间戳用于生成当前时隙的时间戳估计(自投票时间戳以来经过的插槽假定为Bank:: ns_per_slot)。 每个时间戳估计都与委派给该投票帐户的股份相关联,以按股份创建时间戳分布。 除非将自`epoch_start_timestamp`以来的经过时间与预期经过时间相差超过25%,否则将中值时间戳记用作`unix_timestamp`。 + +## Epoch时间表 + +这时间段表sysvar包含在创世中设置的时间段常量,并允许计算给定时间段中的时隙数,给定时隙的时间段等。(注意:时间段时间表与[`leader时间表不同`](terminology.md#leader-schedule)) + +- 地址:`SysvarEpochSchedu1e111111111111111111111111` +- 布局:[EpochSchedule](https://docs.rs/solana-program/VERSION_FOR_DOCS_RS/solana_program/epoch_schedule/struct.EpochSchedule.html) + +## 费用 + +Fees sysvar包含当前广告位的费用计算器。 它会根据费用调节器在每个时段进行更新。 + +- 地址:`SysvarFees111111111111111111111111111111111` +- 布局:[费用](https://docs.rs/solana-program/VERSION_FOR_DOCS_RS/solana_program/sysvar/fees/struct.Fees.html) + +## 指示 + +指令sysvar在处理消息时在消息中包含序列化的指令。 这允许程序指令引用同一事务中的其他指令。 阅读有关[指令自省](implemented-proposals/instruction_introspection.md)的更多信息。 + +- 地址:`` Sysvar1nstructions1111111111111111111111111` `` +- 布局:[指令](https://docs.rs/solana-program/VERSION_FOR_DOCS_RS/solana_program/sysvar/instructions/type.Instructions.html) + +## 最近的区块散列值 + +最近的区块哈希系统变量包含活动的最近区块哈希及其关联的费用计算器。 它在每个插槽中更新。 + +- 地址:`SysvarRecentB1ockHashes11111111111111111111` +- 布局:[RecentBlockhashes](https://docs.rs/solana-program/VERSION_FOR_DOCS_RS/solana_program/sysvar/recent_blockhashes/struct.RecentBlockhashes.html) + +## 承租 + +Rent sysvar包含租金。 目前,该比率是静态的,并且是根据发生率设定的。 通过手动激活功能可以修改租金燃烧百分比。 + +- 地址:`SysvarRent111111111111111111111111111111111` +- 赞成:[出租](https://docs.rs/solana-program/VERSION_FOR_DOCS_RS/solana_program/rent/struct.Rent.html) + +## 插槽哈希 + +SlotHashes sysvar包含插槽父库的最新哈希。 它在每个插槽中更新。 + +- 地址:`SysvarS1otHashes111111111111111111111111111111` +- 布局:[SlotHashes](https://docs.rs/solana-program/VERSION_FOR_DOCS_RS/solana_program/slot_hashes/struct.SlotHashes.html) + +## 插槽历史 + +SlotHistory sysvar包含在最后一个时期出现的插槽的位向量。 它在每个插槽中更新。 + +- 地址:`SysvarS1otHistory11111111111111111111111111111` +- 布局:[SlotHistory](https://docs.rs/solana-program/VERSION_FOR_DOCS_RS/solana_program/slot_history/struct.SlotHistory.html) + +## 权益历史 + +StakeHistory sysvar包含每个时期群集范围内的权益激活和停用的历史记录。 在每个时间段开始时都会对其进行更新。 + +- 地址:`` SysvarStakeHistory11111111111111111111111111` `` +- 布局:[StakeHistory](https://docs.rs/solana-program/VERSION_FOR_DOCS_RS/solana_program/stake_history/struct.StakeHistory.html) diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/history.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/history.md new file mode 100644 index 0000000000..a99b58fe82 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/history.md @@ -0,0 +1,15 @@ +--- +title: 发展历史 +--- + +2017年11月,Anatoly Yakovenko发布了一份白皮书,描述了历史证明,一种在彼此不信任的计算机之间保持时间同步的技术。 根据Anatoly在Qualcomm、Mesosphere和Dropbox上设计分布式系统的先前经验,他知道可靠的时钟可使网络同步变得非常简单。 如果同步很简单,那么生成的网络将很快受到限制,仅受网络带宽限制。 + +Anatoly深刻地见识了没有时钟的区块链系统,例如比特币和以太坊。账本在全球范围内难以扩展到每秒15笔交易以上,而Visa等中心化支付系统需要达到65,000账本tps的峰值。 很明显,如果没有一个时钟,永远都不会成就他们梦寐以求的全球支付系统或全球超级计算机。 当Anatoly解决了让彼此不信任的计算机按时达成协议的问题时,他拥有的将40年分布式系统研究,是带入区块链世界的关键武器。 账本最终的集群将提高速度到10倍,100倍或1000倍,甚至10,000倍! + +Anatoly的操作开始于私有代码库,并以C编程语言实现。 Greg Fitzgerald以前曾在半导体巨头高通公司(Qualcomm Incorporated)与Anatoly合作,他鼓励他用Rust编程语言重新实现该项目。 Greg致力于LLVM编译器基础结构,该基础结构是Clang C/C++编译器和Rust编译器的基础。 Greg声称该语言的安全保证将提高软件生产效率,并且缺少垃圾收集器将使该程序能够像用C编写的程序一样完美执行。Anatoly试了一下,仅两周后,他就将整个代码库迁移到了Rust。 成功了! 这个计划将全球所有交易整合到一个可扩展的单个区块链中,Anatoly称其为Loom项目。 + +在2018年2月13日,Greg开始对Anatoly的白皮书的第一个开源执行进行原型设计。 该项目已在织机组织中以Silk的名称发布到GitHub。 2月28日,Greg发布了他的第一个版本,演示了将在短短半秒钟内完成1万笔已签名交易的验证和处理。 不久之后,另一位前高通的研究人员Stephen Akridge展示了通过将签名验证卸载到图形处理器上可以大大提高吞吐量。 Anatoly招募了Greg、Stephen和其他三个人,共同创立了一家公司,当时名为Loom。 + +大约在同一时间,基于以太坊的项目织机网络,如雨后春笋般涌现,许多人对于他们是否属于同一项目感到困惑。 织机团队决定将其品牌重塑。 他们选择了Solana这个名字来表示对圣地亚哥北部一个名为Solana Beach的海滩小镇的怀念。Anatoly,Greg和Stephen在高通公司工作的时候在那里生活和冲浪了三年。 3月28日,该团队创建了Solana Labs GitHub组织,并将Greg的原型Silk重命名为Solana。 + +在2018年6月,该团队扩大了该技术的运行范围,使其可以基于云网络运行,并于7月19日发布了一个50节点,经过许可的公共测试网,该网络始终支持每秒250,000次交易。 在12月发布的名为v0.10 Pillbox的更高版本中,该团队发布了一个许可的测试网,该测试网在千兆位网络上运行150个节点,并演示了浸泡测试,该测试每秒处理_平均_20万笔事务,突发次数超过50万笔。 该项目还得到扩展,以支持用C编程语言编写的链上程序,并在称为BPF的安全执行环境中并行运行。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Communication/Adress-book#1.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Communication/Adress-book#1.svg new file mode 100644 index 0000000000..fc68582c09 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Communication/Adress-book#1.svg @@ -0,0 +1,11 @@ + + + + Stockholm图标 / 沟通 / 地址簿#1 + 用 Sketch 创建。 + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Communication/Delete-user.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Communication/Delete-user.svg new file mode 100644 index 0000000000..4af48479e0 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Communication/Delete-user.svg @@ -0,0 +1,11 @@ + + + + Stockholm图标 / 沟通 / 删除用户 + 通过 Sketch 创建。 + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Communication/Snoozed-mail.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Communication/Snoozed-mail.svg new file mode 100644 index 0000000000..4c765423f6 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Communication/Snoozed-mail.svg @@ -0,0 +1,11 @@ + + + + Stockholm图标 / 沟通 / 延迟邮件 + 用 Sketch 创建。 + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Cooking/Baking-glove.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Cooking/Baking-glove.svg new file mode 100644 index 0000000000..9a97298ee2 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Cooking/Baking-glove.svg @@ -0,0 +1,11 @@ + + + + Stockholm-图标 / 烹饪 / 面包工具 + 用 Sketch 创建。 + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Cooking/Saucepan.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Cooking/Saucepan.svg new file mode 100644 index 0000000000..6f541720b9 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Cooking/Saucepan.svg @@ -0,0 +1,11 @@ + + + + Stockholm-图标 / 烹饪 / 平底锅 + 用 Sketch 创建。 + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Design/Polygon.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Design/Polygon.svg new file mode 100644 index 0000000000..129216fb4d --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Design/Polygon.svg @@ -0,0 +1,10 @@ + + + + Stockholm-图标 / 设计 / 多边形 + 用 Sketch 创建。 + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Devices/Android.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Devices/Android.svg new file mode 100644 index 0000000000..b2fc5d76a1 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Devices/Android.svg @@ -0,0 +1,11 @@ + + + + Stockholm-图标 / 设备 / 安卓 + 用 Sketch 创建。 + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Files/Cloud-upload.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Files/Cloud-upload.svg new file mode 100644 index 0000000000..cc74886fc0 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Files/Cloud-upload.svg @@ -0,0 +1,11 @@ + + + + Stockholm-图标 / 文件 / 云上传 + 用 Sketch 创建。 + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Files/Compilation.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Files/Compilation.svg new file mode 100644 index 0000000000..b7415b163e --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Files/Compilation.svg @@ -0,0 +1,14 @@ + + + + Stockholm-图标 / 文件 / 编辑 + 用 Sketch 创建。 + + + + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Files/Folder.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Files/Folder.svg new file mode 100644 index 0000000000..712fad4310 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Files/Folder.svg @@ -0,0 +1,10 @@ + + + + Stockholm-图标 / 文件 / 文件夹 + 用 Sketch 创建。 + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Food/Cheese.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Food/Cheese.svg new file mode 100644 index 0000000000..a704d1c742 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Food/Cheese.svg @@ -0,0 +1,11 @@ + + + + Stockholm-图标 / 食物 / 芝士 + 通过 Sketch 创建。 + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/General/Clip.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/General/Clip.svg new file mode 100644 index 0000000000..a2f6b44193 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/General/Clip.svg @@ -0,0 +1,10 @@ + + + + Stockholm-图标 / 通用 / 素材 + 用 Sketch 创建。 + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/General/Half-heart.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/General/Half-heart.svg new file mode 100644 index 0000000000..ef6435832b --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/General/Half-heart.svg @@ -0,0 +1,11 @@ + + + + Stockholm-图标 / 通用 / 半心 + 用 Sketch 创建。 + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/General/Hidden.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/General/Hidden.svg new file mode 100644 index 0000000000..4683407834 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/General/Hidden.svg @@ -0,0 +1,12 @@ + + + + Stockholm-图标 / 通用 / 隐藏 + 用 Sketch 创建。 + + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Home/Commode#2.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Home/Commode#2.svg new file mode 100644 index 0000000000..c32791b25b --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Home/Commode#2.svg @@ -0,0 +1,11 @@ + + + + Stockholm-图标 / 主页 / 洗脸台#2 + 用 Sketch 创建。 + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Home/Flower#2.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Home/Flower#2.svg new file mode 100644 index 0000000000..106373e48f --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Home/Flower#2.svg @@ -0,0 +1,14 @@ + + + + Stockholm-图标 / 主页 / 鲜花#2 + 通过 Sketch 创建。 + + + + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Media/Airplay-video.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Media/Airplay-video.svg new file mode 100644 index 0000000000..9574c78102 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Media/Airplay-video.svg @@ -0,0 +1,11 @@ + + + + Stockholm-图标 / 媒体 / 播放视频 + 用 Sketch 创建。 + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Navigation/Angle-double-up.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Navigation/Angle-double-up.svg new file mode 100644 index 0000000000..0c57e3a2f2 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Navigation/Angle-double-up.svg @@ -0,0 +1,11 @@ + + + + Stockholm-图标 / 导航 / 双箭头 + 用 Sketch 创建。 + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Navigation/Arrows-v.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Navigation/Arrows-v.svg new file mode 100644 index 0000000000..5fb6ee286a --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Navigation/Arrows-v.svg @@ -0,0 +1,12 @@ + + + + Stockholm-图标 / 导航/箭头-v + 用 Sketch 创建。 + + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Navigation/Waiting.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Navigation/Waiting.svg new file mode 100644 index 0000000000..d88f2737f7 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Navigation/Waiting.svg @@ -0,0 +1,10 @@ + + + + Stockholm-图标 / 导航 / 等待中 + 用 Sketch 创建。 + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Text/Edit-text.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Text/Edit-text.svg new file mode 100644 index 0000000000..33aadf7190 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Text/Edit-text.svg @@ -0,0 +1,11 @@ + + + + Stockholm-图标 / 文本 / 编辑文本 + 用 Sketch 创建。 + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Weather/Snow#1.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Weather/Snow#1.svg new file mode 100644 index 0000000000..dbef6130cf --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Weather/Snow#1.svg @@ -0,0 +1,11 @@ + + + + Stockholm-图标 / 天气 / 雪#1 + 用 Sketch 创建。 + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Weather/Sun.svg b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Weather/Sun.svg new file mode 100644 index 0000000000..1629203db9 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/icons/duotone-icons/Weather/Sun.svg @@ -0,0 +1,11 @@ + + + + Stockholm-图标 / 天气 / 太阳 + 用 Sketch 创建。 + + + + + + diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/abi-management.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/abi-management.md new file mode 100644 index 0000000000..b0043e9b4f --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/abi-management.md @@ -0,0 +1,96 @@ +--- +title: Solana ABI管理流程 +--- + +本文件提出了Solana ABI管理流程。 ABI管理流程是一种工程实践和一个支持性的技术框架,以避免引入意外的不兼容的ABI变化。 + +# 面临的问题 + +Solana ABI(集群的二进制接口) 目前仅由实现隐式定义,需要非常仔细的观察才能注意到破坏性的变化。 这使得在不重启账本的情况下,在现有集群上升级软件非常困难。 + +# 需求和目标 + +- 意外的ABI变化可以被机械地检测为CI故障 +- 新的实现必须能够处理最老的数据(世纪以来),一旦我们进入主网。 +- 这个建议的目的是保护ABI,同时通过选择机械过程而不是非常长的人为驱动的审计过程来维持相当快速的发展。 +- 一旦经过加密签名,数据blob必须是相同的,所以无论在线系统的入站和出站,都不可能进行原地数据格式更新。 另外,考虑到我们要处理的交易量,最好不要进行追溯性的就地更新。 + +# 解决方案 + +我们需要一个系统性的保证,在修改源码时不破坏集群,而不是自然的人为尽职,因为人为尽职被假定为经常发生故障。 + +为此,我们引入了一种机制,在源代码中对每一个与ABI相关的事物(`struct`s, `enum`s) 用新的`#[frozen_abi]`属性进行标记。 它通过`ser::Serialize`从其字段的类型中提取硬编码的摘要值。 而且该属性会自动生成一个单元测试,试图检测任何未经批准的对标记的ABI相关事物的更改。 + +但是,检测不可能是完全的,无论我们如何努力静态分析源代码,仍然有可能破坏ABI。 例如,这包括非`派生`的手写`ser::Serialize`、底层库的实现变化(例如`bincode`)、CPU架构差异。 对这些可能的ABI不兼容的检测不在这个ABI管理的范围之内。 + +# 定义 + +ABI项目/类型:用于序列化的各种类型,共同构成任何系统组件的整个ABI。 例如,这些类型包括`struct`s和`enum`s。 + +ABI项目摘要。从ABI项的字段的类型信息导出的一些固定的哈希值。 + +# 示例 + +```patch ++#[frozen_abi(digest="eXSMM7b89VY72V...")] + #[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone)] + pub struct Vote { + /// A stack of votes starting with the oldest vote + pub slots: Vec, + /// signature of the bank's state at the last slot + pub hash: Hash, + } +``` + +# 开发者的工作流程 + +为了知道新的ABI项目的摘要,开发人员可以用一个随机的摘要值添加`frozen_abi`,然后运行单元测试,并从断言测试错误信息中用正确的摘要来替换它。 + +一般来说,一旦我们添加了`frozen_abi`,并且它的变化被发布在稳定版本频道中,它的摘要应该永远不会改变。 如果需要这样的改变,我们应该选择定义一个新的`struct`,比如`FooV1`。 而特殊的发布流程,比如硬分叉,则应该类似。 + +# 实施说明 + +我们使用某种程度的宏机制来自动生成单元测试,并从ABI项目中计算出一个摘要。 通过巧妙地使用`serde::Serialize`(`[1]`)和`any::type_name`(`[2]`)可以实现这一点。 对于类似的实现先例,Parity Technologies`[3]`中的`ink`可以作为参考。 + +# 实现细节 + +本实施方案的目标是尽可能自动检测ABI的意外变化。 为此,结构性ABI信息的摘要是以最大努力的准确性和稳定性计算的。 + +当ABI摘要检查运行时,通过重复使用`serde`的序列化功能、过程宏和通用特殊化功能,对ABI项的字段的ABI进行递归摘要,动态计算出ABI摘要。 然后,检查`assert!`其最终的摘要值与`frozen_abi`属性中指定的相同。 + +为了实现这一点,它创建了一个该类型的实例和一个自定义的`Serializer`实例,为`serde`递归遍历它的字段,就像真正的序列化实例一样。 这种遍历必须通过`serde`来完成,才能真正捕捉到什么样的数据实际上会被`serde`序列化,即使考虑到定制的非`派生`的`Serialize`接口实现。 + +# ABI摘要过程 + +这一部分有点复杂。 有三个相互依赖的部分:`AbiExample`、`AbiDigester`和`AbiEnumVisitor`。 + +首先,生成的测试会创建一个摘要类型的实例,这个实例有一个叫做`AbiExample`的接口,它应该像`Serialize`一样为所有的摘要类型实现,并像`Default`接口一样返回`Self`。 通常情况下,它是通过通用的接口特殊化来提供给大多数常见类型的。 也可以为`struct`和`enum`进行`派生`,如果需要,也可以手工编写。 + +自定义的`serializer`被称为`AbiDigester`。 而当它被`serde`调用来序列化一些数据时,它会尽可能地递归收集ABI信息。 `AbiDigester`根据数据类型的不同,对ABI摘要的内部状态进行不同的更新。 这个逻辑是通过一个名为`AbiEnumVisitor`的接口为每个`enum`类型专门重定向的。 顾名思义,没有必要为其他类型实现`AbiEnumVisitor`。 + +总结一下这种相互作用,`serde`与`AbiDigester`串联处理递归序列化控制流。 测试中的初始入口点和子`AbiDigester`使用`AbiExample`递归地创建一个示例对象层次图。 而`AbiDigester`使用`AbiEnumVisitor`使用构建的样本查询实际的ABI信息。 + +`Default`对于`AbiExample`来说是不够的。 多种集合的`::default()`是空的,但我们想用实际的项目来摘要它们。 而且,ABI摘要不能只用`AbiEnumVisitor`来实现。 需要`AbiExample`是因为需要一个实际的类型实例来通过`serde`实际遍历数据。 + +另一方面,ABI摘要也不能只用`AbiExample`来完成。 需要`AbiEnumVisitor`,因为一个`enum`的所有变体不能只用它的一个变体作为ABI实例来遍历。 + +可摘要的信息: + +- rust的类型名称 +- `serde`的数据类型名称。 +- `struct`中的所有字段 +- `enum`中的所有变体。 +- `struct`:正常(`struct {...}`) 和元组式(`struct(...)`) +- `enum`:正常变体和`struct`-和`tuple`-风格。 +- 属性:`serde(serialize_with=...)`和`serde(skip)` + +不可摘要的信息: + +- `AbiExample`提供的样本未触及的任何自定义序列化代码路径。 (技术上不可能) +- 属(必须是具体类型;对具体类型别名使用`frozen_abi`) + +# 参考文献 + +1. [(De)Serialization with type info · Issue #1095 · serde-rs/serde](https://github.com/serde-rs/serde/issues/1095#issuecomment-345483479) +2. [`std::any::type_name` - Rust](https://doc.rust-lang.org/std/any/fn.type_name.html) +3. [Parity's ink to write smart contracts](https://github.com/paritytech/ink) diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/bank-timestamp-correction.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/bank-timestamp-correction.md new file mode 100644 index 0000000000..c99a6741dc --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/bank-timestamp-correction.md @@ -0,0 +1,37 @@ +--- +title: 银行时间戳更正 +--- + +每家银行都有一个时间戳,存放在时钟sysvar中,用来评估基于时间的质押账户锁定情况。 然而,自创世纪以来,这个值一直是基于理论上的每秒插槽数而不是现实,所以它是相当不准确的。 这给锁仓带来了问题,因为在锁仓设定到期的日期(或临近的任何时候),账户都不会登记为无锁仓。 + +块时间已经被估计缓存在Blockstore和长期存储中,使用[验证者时间戳预言机](validator-timestamp-oracle.md);这个数据提供了一个机会,使银行时间戳与现实世界的时间更接近。 + +所提出的实施方案的总体轮廓如下。 + +- 插槽使用验证者提供的时间戳来修正每个银行时间戳。 +- 插槽更新验证者提供的时间戳计算,使用质押加权中值,而不是质押加权平均值。 +- 插槽对时间戳校正进行约束,使其不能偏离预期的理论估计值太远。 + +## 时间戳更正 + +在每一个新的银行上,使用验证者时间戳预言机数据实时计算一个现实的时间戳估计值。 如果银行的时间戳大于或等于前一个银行的时间戳,那么银行的时间戳就会被修正到这个值。 也就是说,时间不应该倒退,所以被锁住的账户可能会因为修正而被释放,但一旦被释放,账户永远不能因为时间修正而被重新锁住。 + +### 计算质押加权中值时间戳。 + +为了计算特定银行的估计时间戳,运行时首先需要从活动验证者集中获取最近的投票时间戳。 `Bank::vote_accounts()`方法提供了投票账户的状态,这些账户可以被过滤到所有账户,其最近的时间戳是在上一个epoch内提供的。 + +从每个投票时间戳中,使用epoch的目标ns_per_slot计算出当前银行的估计值,用于银行插槽和时间戳插槽之间的任何差 。每个时间戳估计值都与委托给该投票账户的质押相关联,所有时间戳都被收集起来,以创建一个质押加权的时间戳分布。 + +从这组时间戳中,选择质押加权中值时间戳--即50%的质押人估计时间戳较大或相等,50%的质押人估计时间戳较小或相等的时间戳--作为潜在的更正时间戳。 + +这种质押加权的中值时间戳比质押加权的平均值更可取,因为在平均值计算中,质押乘以提议的时间戳,使得质押很小的节点仍然可以通过提议一个很大或很小的时间戳对结果的时间戳有很大的影响。 例如,使用之前的`calculate_stake_weighted_timestamp()`方法,一个拥有0.00003%质押的节点提出一个`i64::MAX`的时间戳,就可以将时间戳前移97000年! + +### 边界时间戳 + +除了防止时间倒退,我们还可以通过将修正后的时间戳与理论上的预期时间的偏差限制在一个可接受的水平上来防止恶意活动。 + +这个提议建议,允许每个时间戳从纪元开始后与预期时间的偏差最多为25%。 + +为了计算时间戳的偏差,每个银行需要在时钟sysvar中记录`epoch_start_timestamp`。 这个值被设置为每个epoch的第一个插槽的`Clock::unix_timestamp`。 + +然后,运行时根据修正后的时间戳,比较自纪元开始以来的预期经过时间和建议的经过时间。 如果修正后的经过时间在预期的+/插槽25%以内,则接受修正后的时间戳。 否则,它将被限制在可接受的偏差范围内。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/commitment.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/commitment.md new file mode 100644 index 0000000000..d6b9973d04 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/commitment.md @@ -0,0 +1,68 @@ +--- +title: 承诺 +--- + +承诺度量旨在为客户提供一个衡量特定区块上的网络确认和利益水平的标准。 然后,客户可以使用这些信息来推导出自己的承诺度量。 + +# 计算远程调用 + +客户端可以通过`get_block_commitment(s: Signature) -> BlockCommitment`,使用远程调用向验证节点请求签名`s`的承诺指标。 `BlockCommitment`结构包含一个u64`[u64,MAX_CONFIRMATIONS]`的数组。 这个数组表示验证节点投票的最后一个区块`M`时,包含签名`s`的特定区块`N`的承诺度量。 + +`BlockCommitment`数组中索引`i`处的条目`s`意味着验证节点观察到`s`在某一区块`M`中观察到的集群中的总质押达到`i`个确认的区块`N`。 这个数组中会有`MAX_CONFIRMATIONS`元素,代表从1到`MAX_CONFIRMATIONS`的所有可能的确认数。 + +# 承诺度量的计算 + +建立这个`BlockCommitment`结构利用了为建立共识而进行的计算。 `consensus.rs`中的`collect_vote_lockouts`函数建立了一个HashMap,其中每个条目的形式是`(b, s)`,其中`s`是银行`b`的质押数量。 + +对可投票候选银行`b`的计算如下。 + +```text + let output: HashMap = HashMap::new(); + for vote_account in b.vote_accounts { + for v in vote_account.vote_stack { + for a in ancestors(v) { + f(*output.get_mut(a), vote_account, v); + } + } + } +``` + +其中`f`是一些累积函数,它用一些可从投票`v`和`vote_account`派生的数据(stake、lockout等) 来修改插槽`a`的`stake`条目。 这里注意,这里的`ancestors`只包括当前状态缓存中存在的插槽。 比状态缓存中存在的更早的银行的签名无论如何也查询不到,所以这里的承诺计算中不包括这些银行。 + +现在,我们自然可以通过以下方法来增强上述计算,为每一个银行`b`也建立一个`BlockCommitment`数组。 + +1. 增加一个`ForkCommitmentCache`来收集`BlockCommitment`结构 +2. 用`f`代替`f'`,使上述计算也为每一个银行`b`建立这个`BlockCommitment`。 + +由于1) 是不是很重要,所以我们将继续讨论2) 的细节。 + +在继续之前,值得注意的是,对于某个验证节点的投票账户`a`,该验证节点在插槽`s`上的本地确认数为`v.num_confirmations`,其中`v`是投票堆栈`a.vails`中最小的一票,这样`v.slot >= s`(即不需要查看任何大于v的投票>,因为确认数会更低)。 + +现在更具体的说,我们把上面的计算增强为。 + +```text + let output: HashMap = HashMap::new(); + let fork_commitment_cache = ForkCommitmentCache::default(); + for vote_account in b.vote_accounts { + // vote stack is sorted from oldest vote to newest vote + for (v1, v2) in vote_account.vote_stack.windows(2) { + for a in ancestors(v1).difference(ancestors(v2)) { + f'(*output.get_mut(a), *fork_commitment_cache.get_mut(a), vote_account, v); + } + } + } +``` + +其中`f'`被定义为: + +```text + fn f`( + stake: &mut Stake, + some_ancestor: &mut BlockCommitment, + vote_account: VoteAccount, + v: Vote, total_stake: u64 + ){ + f(stake, vote_account, v); + *some_ancestor.commitment[v.num_confirmations] += vote_account.stake; + } +``` diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/durable-tx-nonces.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/durable-tx-nonces.md new file mode 100644 index 0000000000..89f56813b8 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/durable-tx-nonces.md @@ -0,0 +1,84 @@ +--- +title: 持久交易编号(Nonces) +--- + +## 问题 + +为了防止重花,Solana 交易包含一个有“最近”块哈希值的非空值。 包含太久的(撰文时为 ~2分钟) 区块哈希交易被网络拒绝为无效。 很不幸,某些情况下(例如托管服务),需要更多时间来生成交易的签名。 需要一种机制来支持这些潜在的线下网络参与者。 + +## 需求 + +1. 交易签名必须包括编号值 +2. 即使是在签名密钥披露的情况下,nonce 也不可以重复使用。 + +## 基于合约的解决办法 + +这里我们描述了一种基于合约的解决方法,其中客户端可以在最近一次交易的 `recent_blockhash` 字段中“存放”一个未来可以使用的 nonce 值。 这个方法类似于通过一些 CPU ISA 实现的比较和交换原子指令。 + +当使用后续的 nonce 时,客户端必须首先从账户数据查询它的值。 现在的交易是正常的,但需要满足以下附加要求: + +1. 后续的 nonce 值用于 `recent_blockhash` 字段 +2. `AdvanceNonceAccount` 指令是交易中第一次发出的 + +### 合约机制 + +未完成工作:svgbob 将其变成一个流程图 + +```text +Start +Create Account + state = Uninitialized +NonceInstruction + if state == Uninitialized + if account.balance < rent_exempt + error InsufficientFunds + state = Initialized + elif state != Initialized + error BadState + if sysvar.recent_blockhashes.is_empty() + error EmptyRecentBlockhashes + if !sysvar.recent_blockhashes.contains(stored_nonce) + error NotReady + stored_hash = sysvar.recent_blockhashes[0] + success +WithdrawInstruction(to, lamports) + if state == Uninitialized + if !signers.contains(owner) + error MissingRequiredSignatures + elif state == Initialized + if !sysvar.recent_blockhashes.contains(stored_nonce) + error NotReady + if lamports != account.balance && lamports + rent_exempt > account.balance + error InsufficientFunds + account.balance -= lamports + to.balance += lamports + success +``` + +客户端想要使用该功能,首先需要在系统程序下创建一个 nonce 帐户。 此帐户将处于 `Uninitialized` 状态,且没有存储哈希,因此无法使用。 + +要初始化该新创建的帐户,必须发出 `InitializeNonceAccount` 指令。 该指令需要一个 `Pubkey`参数,它位于账户 [授权](../offline-signing/durable-nonce.md#nonce-authority) 中。 Nonce 帐户必须是 [rent-exempt](rent.md#two-tiered-rent-regime) 状态,才能满足数据持续性功能的要求, 因此它要求初始化之前先存入足够的 lamports。 初始化成功后,集群最近的区块哈希与指定 nonce 授权的 `Pubkey` 将一同存储。 + +`AdvanceNonceAccount` 指令用于管理帐户存储的 nonce 值。 它在账户的状态数据中存储集群最新的区块哈希,如果与已存储的值相匹配,那么会提示失败。 这个检查可以防止在同一个区块内重新广播交易。 + +由于 nonce 帐户的 [免租](rent.md#two-tiered-rent-regime) 要求,一个自定义提现指令用于将资产从帐户中移出。 `WithdrawNonceAccount` 指令需要一个单一参数,提示取款信号,强制免除租金,防止账户余额下降至低于免租金的最低值。 该检查的一个例外情况是,最终余额是零,从而让账户能够删除。 这个账户关闭详细信息还有一个额外要求,即存储的 nonce 值必须与集群最近的区块不匹配, 正如 `AdvanceNonceAccount`。 + +账户的 [nonce authority](../offline-signing/durable-nonce.md#nonce-authority) 可以通过 `AuthorizeNonceAccount` 说明进行更改。 它需要传入一个参数,新授权的 `Pubkey`。 执行该指令将把完全的帐户及其余额控制权转移给新的授权。 + +> `AdvanceNonceAccount`,`WithdrawNonceAccount` 和 `AuthorizeNonceAccount` 都需要当前 [nonce authority](../offline-signing/durable-nonce.md#nonce-authority) 才能签署交易。 + +### 运行时(Runtime)支持 + +合约本身并不足以实现这个功能。 为了在交易上强制执行一个现有的`recent_blockhash`,并防止通过失败的交易重放来窃取费用,runtime的修改是必要的。 + +任何未能通过通常的`check_hash_age`验证的交易将被测试为持久交易Nonce。 这是由包括一个`AdvanceNonceAccount`指令作为交易中的第一条指令发出的信号。 + +如果runtime确定使用了一个持久事务Nonce,它将采取以下额外的操作来验证事务: + +1. 加载`Nonce`指令中指定的`NonceAccount`。 +2. `NonceAccount` 的数据字段反序列化`NonceState`,并确认其处于`Initialized`状态。 +3. 存储在`NonceAccount`中的nonce值与交易的`recent_blockhash`字段中指定的nonce值进行匹配测试。 + +如果上述三项检查都成功,则允许交易继续验证。 + +由于以`InstructionError`失败的交易会被收取费用,并且其状态的改变会被回滚,所以如果`AdvanceNonceAccount`指令被回滚,则费用可能会被盗。 恶意验证者可以重放失败的交易,直到存储的nonce被成功推进。 Runtime的更改可以防止这种行为。 当一个持久的nonce事务失败时,除了`AdvanceNonceAccount`指令外,还有一个`InstructionError`,nonce账户会像往常一样被回滚到执行前的状态。 然后,runtime将其nonce值和高级nonce账户存储起来,就像已经成功了。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_economic_sustainability.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_economic_sustainability.md new file mode 100644 index 0000000000..a53905e500 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_economic_sustainability.md @@ -0,0 +1,9 @@ +--- +title: 经济可持续性 +--- + +**规则有可能发生变化。** + +长期经济可持续性是Solana经济设计的指导原则之一。 虽然不可能预测去中心化经济将如何随着时间的推移而发展,特别是具有灵活的去中心化治理的经济体,但我们可以安排经济组成部分,以便在某些条件下,一个可持续的经济可能在长期内形成。 在Solana网络的情况下,这些组成部分采取代币发行(通过通货膨胀) 和代币销毁的形式。 + +Solana 矿池的主要汇兑是验证节点奖励。 反通货膨胀是一个统一的、协议规定的、经过调整的、每笔交易费用的百分比。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_mvp.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_mvp.md new file mode 100644 index 0000000000..4d9b52a807 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_mvp.md @@ -0,0 +1,14 @@ +--- +title: 经济设计MVP +--- + +**规则有可能发生变化。** + +前面几节在[经济设计概述](ed_overview.md)中概述了一个可持续发展的Solana经济的长期愿景。 当然,我们并不期望最终的实施能与上面描述的内容完全一致。 我们打算在整个实施阶段(即预试网、试网、主网)与网络利益相关者充分接触,以确保该系统支持并代表各网络参与者的利益。 然而,实现这一目标的第一步是概述一些期望的MVP经济功能,以便为早期的预试验网和试验网参与者提供。 下面是一个粗略的草图,概述了基本的经济功能,从中可以开发出一个更完整的功能系统。 + +## MVP 经济功能 + +- 水龙头向验证节点提供测试网SOL,以便进行挖矿和应用开发。 +- 通过网络膨胀来奖励验证节点的机制。 +- 能够将代币委托给验证节点节点。 +- 验证节点设置委托代币利息的佣金费用。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_overview.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_overview.md new file mode 100644 index 0000000000..e67dda5a9e --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_overview.md @@ -0,0 +1,19 @@ +--- +title: 集群经济学 +--- + +**根据实际情况,规则可能发生变化。 请在Solana论坛上关注最近的经济讨论:https://forums.Solana.com。** + +Solana的加密经济系统旨在促进健康、长期的自给经济,参与者的激励机制与网络的安全性和去中心化保持一致。 这个经济的主要参与者是验证客户端。 下面讨论他们对网络、状态验证的贡献及其必要的激励机制。 + +参与者汇兑的主要渠道被称为基于协议(通货膨胀) 的奖励和交易费用。 基于协议的奖励是由一个全球的、协议定义的、通货膨胀率发行的。 这些奖励将构成交付给验证客户的总奖励,剩余的来源于交易费用。 在网络的早期,基于协议的奖励很可能会根据预定义的发行时间表进行部署,将推动大多数参与者参与网络的动机。 + +这些基于协议的奖励,将在网络上的主动质押代币中分配,将是全球供应膨胀率的结果,按Solana纪元计算,并在活跃的验证者集中分配。 如下文所讨论的那样,每年的通货膨胀率是基于一个预先确定的去通货膨胀时间表。 这为网络提供了货币供应的可预测性,支持长期的经济稳定和安全。 + +交易费用是以市场为基础的参与者之间的转移,附加在网络互动中,作为纳入和执行一项拟议交易的必要动机和补偿。 下文还将讨论通过对每笔交易费进行部分销毁来实现长期经济稳定和分叉保护的机制。 + +下文**图1**为Solana加密经济设计的高层示意图。 验证客户端经济的具体细节在以下章节中作了介绍: [验证客户端经济学](ed_validation_client_economics/ed_vce_overview.md),[通货膨胀计划](ed_validation_client_economics/ed_vce_state_validation_protocol_based_rewards.md) 以及 [交易费](ed_validation_client_economics/ed_vce_state_validation_transaction_fees.md)。 另外,在标题为[验证质押委托](ed_validation_client_economics/ed_vce_validation_stake_delegation.md)的章节,最后还讨论了验证节点委托的机会和市场。 此外,在[存储租金经济学](ed_storage_rent_economics.md)中,我们描述了存储租金的实现,以说明维持账本活跃状态的外部性成本。 [经济设计MVP](ed_mvp.md)章节讨论了MVP经济设计的特征概要。 + +![](/img/economic_design_infl_230719.png) + +**图1**: Solana 经济奖励设计的简明概述。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_references.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_references.md new file mode 100644 index 0000000000..36f4efddec --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_references.md @@ -0,0 +1,7 @@ +--- +title: 参考文献 +--- + +1. [https://blog.eferum.org/2016/07/27/inflation-transaction-fees-cryptocurrency-monetary-policy/](https://blog.ethereum.org/2016/07/27/inflation-transaction-fees-cryptocurrency-monetary-policy/) +2. [https://med.com/solana-labs/how to create-decentralized-storage-for-a-multi-petabyte-digital-ledger-2499a3a8c281](https://medium.com/solana-labs/how-to-create-decentralized-storage-for-a-multi-petabyte-digital-ledger-2499a3a8c281) +3. [https://med.com/solana-labs/how to create-decentralized-storage-for-a-multi-petabyte-digital-ledger-2499a3a8c281](https://medium.com/solana-labs/how-to-create-decentralized-storage-for-a-multi-petabyte-digital-ledger-2499a3a8c281) diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_storage_rent_economics.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_storage_rent_economics.md new file mode 100644 index 0000000000..dfcf6ba880 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_storage_rent_economics.md @@ -0,0 +1,17 @@ +--- +title: 存储租赁经济 +--- + +提交 Solana 账本的每笔交易都要支付费用。 理论上,验证和添加数据到账本的交易费应当由提交人支付,验证节点进行收费。 在此过程中未计入的活跃账本状态的中期存储,则需要由轮换的验证节点所维护。 这种类型的储存不仅给验证节点带来费用,而且也给更广泛的网络带来费用,因为活跃状态的增加会导致数据传输和验证间接费用的增加。 为了计算这些费用,此处介绍储存租金的初步设计和实施。 + +存储租金可以通过下述两种方法支付: + +方法1:设置然后忽略它 + +采用这种办法,有两年租金保证金的账户将免收网络租金费用。 保持这个最低平衡以后,网络整体上将受益于流动性降低,账户持有人可以相信他们的 `Account::data` 将被保留以便获得持续的存取/使用。 + +方法2:按字节支付 + +如果一个帐户存入的租金不到两年,网络在每个 epoch 收取租金,并在下一个 epoch 继续计算租金。 这笔租金按初始规定的费率扣除,每千字节以 lamports 扣除。 + +关于此设计的技术实现详细信息,请参阅 [Rent](../rent.md) 章节。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_validation_client_economics/ed_vce_overview.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_validation_client_economics/ed_vce_overview.md new file mode 100644 index 0000000000..5460e2028a --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_validation_client_economics/ed_vce_overview.md @@ -0,0 +1,9 @@ +--- +title: 验证节点经济模型 +--- + +**规则一直在改变 关注Solana论坛最近的经济模型讨论:https://forums.solana.com** + +验证节点质押代币以获取大量的的佣金收入 这是对验证节点的补偿,验证节点提供 (CPU+GPU) 计算资源来验证并投票给定的 PoH 状态。 这些基于协议的奖励是通过算法实现通货紧缩计划来决定的,作为代币总量的一部分用途。 预计网络将启动初期,年通货膨胀率约为8%,每年减少15%,直到长期稳定在1.5%, 然而,这些参数尚待社区最后确定。 这些发行将被分割并分发给参与验证者。 发放令牌中约有95%分配给验证者作为初始奖励(其余5%保留给基金会作为业务费用)。 因为该网络将在定量的通货膨胀奖励中分配给质押代币的验证节点, 质押的收益和质押的总量成一个比例函数。 + +此外,验证节点可以通过状态验证交易赚取费用收入。 为了明确起见,我们分别描述了这些收入分配的设计和动机:基于状态-验证协议的奖励以及状态-验证交易费用和租金。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_validation_client_economics/ed_vce_state_validation_protocol_based_rewards.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_validation_client_economics/ed_vce_state_validation_protocol_based_rewards.md new file mode 100644 index 0000000000..c9a250569c --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_validation_client_economics/ed_vce_state_validation_protocol_based_rewards.md @@ -0,0 +1,63 @@ +--- +title: 通货膨胀规划 +--- + +**规则有可能发生变化。 请在Solana论坛上关注最近的经济讨论:https://forums.Solana.com。** + +验证节点客户端在Solana网络中具有两种功能作用。 + +- 验证节点对他们观察到的PoH的当前全球状态进行\(投票\)。 +- 验证节点在利益加权的循环计划中被选为 "领导者",在此期间,他们负责收集未完成的交易,并将其纳入其观察到的PoH中,从而更新网络的全球状态,并提供区块链的连续性。 + +验证节点客户端对这些服务的奖励将在每个Solana纪元结束时分配。 如前所述,验证节点-客户的报酬是通过基于协议的年度通货膨胀率收取的佣金来提供的,该佣金按照每个验证节点节点的质押权重比例分配(见下文),同时还包括每次领导者轮换期间可用的领导者主张的交易费用。 举例说明 即在给定的验证节点-客户端被选为领导者期间,它有机会保留每笔交易费的一部分,减去协议规定的被销毁的金额 (见[验证节点-客户端状态交易费](ed_vce_state_validation_transaction_fees.md))。 + +验证节点客户端收到的协议级别有效质押收益率/(%/),每一个纪元将是以下因素的函数: + +- 验证节点当前的全局通货膨胀率,由预先确定的去通货膨胀发行计划表推导出来的(见[验证客户端经济学](ed_vce_overview.md))。 +- 验证节点当前总循环供应量中,质押的SOL占比。 +- 验证节点服务收取的佣金。 +- 验证节点在上一个纪元中,给定验证节点的在线/参与\[的投票 %\]。 + +第一个因素仅是协议参数的函数\(即独立于验证节点在给定纪元中的行为\),其结果是设计了一个膨胀时间表,以激励早期参与,提供明确的货币稳定性,并在网络中提供最佳的安全性。 + +作为理解*通胀计划*对Solana经济的第一个影响,我们模拟了在当前研究的通胀时间表参数范围内,代币发行随时间推移可能出现的上下限范围。 + +具体而言: + +- *初始通货膨胀率*: 7-9% +- *通货膨胀率降低比例*: -14-16% +- *长期通货膨胀率*: 1-2% + +使用这些范围来模拟一些可能的通货膨胀表,我们可以探索一段时间内的通货膨胀: + +![](/img/p_inflation_schedule_ranges_w_comments.png) + +在上图中,确定了范围的平均值,以说明每个参数的贡献。 从这些模拟的*通货膨胀表*中,我们还可以推算出一段时间内代币发行的范围。 + +![](/img/p_total_supply_ranges.png) + +最后,如果我们引入一个额外的参数,也就是之前讨论过的*质押SOL百分比*,我们就可以估算出质押SOL的*质押收益*。 + + +%~\text{SOL Staked} = \frac{\text{Total SOL Staked}}{\text{Total Current Supply}} CONTEXT + + +在这种情况下,由于*质押SOL百分比*是一个必须估计的参数(不同于*通胀表*参数),所以使用具体的*通胀表*参数,探索*质押SOL百分比*的范围比较容易。 在下面的例子,我们选择了上面探讨的参数范围的中间值: + +- *初始通货膨胀率*: 8% +- *通货膨胀率降低比例*: -15% +- *长期通货膨胀率*: 1.5% + +根据投资者和验证节点社区的反馈,以及在类似权益证明协议中观察到的情况,*质押SOL百分比*的范围在60%-90%之间,我们认为这涵盖了我们预期观察到的可能范围。 + +![](/img/p_ex_staked_yields.png) + +同样,上面显示的是Solana网络的一个例子,在指定的*通货膨胀时间表*下,一个质押者可能会期望随着时间的推移而获得的*质押收益*。 这是一个理想化的*质押收益*,因为它忽略了验证节点正常运行时间对奖励的影响,验证节点佣金,潜在的收益率节流和潜在的罚没事件。 此外,它还忽略了*质押SOL百分比*是动态设计的——它的经济激励由*通货膨胀表*设置。 + +### 调整后的质押收益 + +质押代币潜力盈利的完整评估应考虑到质押*代币稀释*及其对质押收益率的影响。 为此,我们将*调整后的质押收益*定义为:由于通货膨胀发行量的分布而导致的质押代币在流通量占比的变化。 即 通货膨胀的正向稀释效应。 + +我们可以将*调整后的质押收益*作为通货膨胀率和网络上的质押代币百分比的函数来考察。 我们可以在这里看到各种质押占比的情况。 + +![](/img/p_ex_staked_dilution.png) diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_validation_client_economics/ed_vce_state_validation_transaction_fees.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_validation_client_economics/ed_vce_state_validation_transaction_fees.md new file mode 100644 index 0000000000..06feba1f82 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_validation_client_economics/ed_vce_state_validation_transaction_fees.md @@ -0,0 +1,20 @@ +--- +title: 状态验证交易费 +--- + +**规则有可能发生变化。** + +网络发送的每一笔交易,如果要由当前的领导者验证客户端处理并确认为全球状态交易,必须包含一笔交易费。 交易费在Solana经济设计中提供了许多好处,例如: + +- 为验证者网络提供处理状态交易所需的CPU/GPU资源的单位补偿。 +- 通过引入真实的交易成本来减少网络垃圾信息。 +- 为交易市场开辟渠道,以激励验证客户端在其作为领导者的职能中收集和处理提交的交易。 +- 并通过协议捕获的每笔交易的最低费用金额为网络提供潜在的长期经济稳定性,如下所述。 + +当前许多区块链经济体(如比特币、以太坊),在短期内依靠基于协议的奖励来支持经济,并假设通过交易费产生的收入将在长期内支持经济,当协议衍生的奖励到期时。 为了通过基于协议的奖励和交易费创造一个可持续发展的经济,每笔交易费中固定的部分被销毁,剩余的费用将归当前处理交易的领导者所有。 一个预定的全球通货膨胀率为通过上述过程分配给验证客户端的奖励提供了来源。 + +交易费由网络集群根据最近的历史吞吐量来设置,参见[拥堵驱动费用](../../transaction-fees.md#congestion-driven-fees)。 每个交易费的最低价格可以根据历史gas费动态调整。 通过这种方式,协议可以使用最低费用来锁定所需的硬件利用率。 通过监控协议指定的gas使用量与期望的、目标使用量之间的关系,可以提高/降低最低费用,这反过来应该降低/提高每个区块的实际gas使用量,直到它达到目标量。 这个调整过程可以被认为是类似于比特币协议中的难度调整算法,不过在这种情况下,它是在调整最低交易费用,以引导交易处理硬件使用量达到预期水平。 + +如前所述,每笔交易费中都有固定比例要被销毁。 这种设计的意图是保留领导激励,在领导槽时间内包含尽可能多的交易,同时提供一个限制通货膨胀的机制,以防止 "逃税 "攻击\(即侧通道费用支付)[1](../ed_references.md)。 + +此外,费用销毁也可以作为分叉选择的一个考虑因素。 在 PoH 分叉有一个恶意的、审查的领导者的情况下,由于审查所损失的费用,我们希望被破坏的总费用比可比的诚实分叉要少。 如果审查领导者要补偿这些损失的协议费,他们就必须自己替换掉自己分叉的费用销毁,从而有可能降低首先进行审查的动机。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_validation_client_economics/ed_vce_validation_stake_delegation.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_validation_client_economics/ed_vce_validation_stake_delegation.md new file mode 100644 index 0000000000..10c7d87d7e --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/ed_overview/ed_validation_client_economics/ed_vce_validation_stake_delegation.md @@ -0,0 +1,28 @@ +--- +title: 验证节点质押委托 +--- + +**可作出修改。** + +运行一个 Solana 验证客户端需要的预先硬件投入成本相对较小。 **表 2** 提供了一个支持 ~1M tx/s 的示例硬件配置,预计其“现货”费用为: + +| 组件: | 示例: | 费用估计 | +|:---------- |:------------------------------------------------ |:--------- | +| GPU | 2x 2080 Ti | \$2500 | +| 或者 | 4x 1080 Ti | \$2800 | +| 操作系统/账本存储 | Samsung 860 Evo 2TB | \$370 | +| 账户存储 | 2x Samsung 970 Pro M.2 512GB | \$340 | +| RAM | 32 Gb | \$300 | +| 主板 | AMD x399 | \$400 | +| CPU | AMD Threadriper 2920x | \$650 | +| 案例: | | \$100 | +| 电量 | EVGA 1600W | \$300 | +| 网络 | > 500 mbps | | +| 网络 \(1\) | Google webpass business bay area 1gbps unlimited | \$5500/月 | +| 网络 \(2\) | Hurricane Electric bay area colo 1gbps | \$500/月 | + +**表 2** 示例了用于运行 Solana 客户端的高端硬件安装程序。 + +尽管从资本投资的角度来看,搭建一个验证节点的门槛很低,在任何发展中国家经济中都是如此,节点可靠性、UX/UI、API和其他软件可访问工具证明的可信验证服务存在着许多机会和需要。 此外,虽然与类似的网络相比,Solana 的验证节点启动成本是名义上的,但对某些潜在的参与者来说仍然可能有些限制。 本着发展真正去中心化、无需许可网络的精神, 这些感兴趣的参与者可以通过授权使用可靠的验证节点获取部分利息,从而参与到 Solana 网络/经济活动中。 + +将代币委托给验证节点是其中一种方法,让被动的 Solana 代币持有者成为活跃 Solana 经济的一部分,并获得与委托验证节点一样的收益。 此外,该功能旨在创建一个健康的验证节点市场,潜在的验证服务节点相互竞争,从而打造可靠、透明和可持续发展的委托服务。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/implemented-proposals.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/implemented-proposals.md new file mode 100644 index 0000000000..6816256ab6 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/implemented-proposals.md @@ -0,0 +1,5 @@ +--- +title: 已实现的设计提议 +--- + +Solana团队已经接受并实施了以下架构方案。 任何可能在未来发生变化的设计都将在具体的提案页中注明。 已被接受但尚未实施的设计方案可在 [ 已接受的方案](../proposals/accepted-design-proposals.md) 中找到。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/installer.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/installer.md new file mode 100644 index 0000000000..e82f01f7e7 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/installer.md @@ -0,0 +1,216 @@ +--- +title: 集群软件安装和更新 +--- + +目前用户需要自己从git仓库中构建Solana集群软件,并手动更新,容易出错且不方便。 + +本文档提出了一个简单易用的软件安装和更新程序,可以用来为支持的平台部署预建的二进制文件。 用户可以选择使用由Solana或任何其他他们信任的方提供的二进制文件。 更新的部署是通过链上更新清单程序来管理的。 + +## 激励的例子 + +### 使用bootstrap curl/shell脚本获取并运行一个预构建的安装程序。 + +支持的平台上最简单的安装方法。 + +```bash +$ curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v1.0.0/install/solana-install-init.sh | sh +``` + +这个脚本将检查github以获取最新的标签版本,并从那里下载并运行`Solana-install-init`二进制文件。 + +如果在安装过程中需要指定额外的参数,可以使用下面的shell语法。 + +```bash +$ init_args=.... # arguments for `solana-install-init ...` +$ curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v1.0.0/install/solana-install-init.sh | sh -s - ${init_args} +``` + +### 从Github发布的版本中获取并运行一个预构建的安装程序。 + +通过知名的发布URL,可以获得支持平台的预构建二进制文件。 + +```bash +$ curl -o solana-install-init https://github.com/solana-labs/solana/releases/download/v1.0.0/solana-install-init-x86_64-apple-darwin +$ chmod +x ./solana-install-init +$ ./solana-install-init --help +``` + +### 从源代码构建并运行安装程序。 + +如果预制的二进制文件不能用于特定的平台,那么从源码中构建安装程序始终是一种选择。 + +```bash +$ git clone https://github.com/solana-labs/solana.git +$ cd solana/install +$ cargo run -- --help +``` + +### 向集群部署新的更新。 + +如果Solana发布的tarball\(由`ci/publish-tarball.sh`创建\) 已经上传到一个可公开访问的URL中,以下命令将部署更新。 + +```bash +$ solana-keygen new -o update-manifest.json # <-- only generated once, the public key is shared with users +$ solana-install deploy http://example.com/path/to/solana-release.tar.bz2 update-manifest.json +``` + +### 运行一个自动更新的验证器节点。 + +```bash +$ solana-install init --pubkey 92DMonmBYXwEMHJ99c9ceRSpAmk9v6i3RdvDdXaVcrfj # <-- pubkey is obtained from whoever is deploying the updates +$ export PATH=~/.local/share/solana-install/bin:$PATH +$ solana-keygen ... # <-- runs the latest solana-keygen +$ solana-install run solana-validator ... # <-- runs a validator, restarting it as necesary when an update is applied +``` + +## 链上更新清单 + +更新清单用于在 Solana 集群上宣传部署新版本的 tarballs。 更新清单使用 `config` 程序存储,每个更新清单账户描述了一个给定目标三倍的逻辑更新通道(例如,`x86_64-apple-darwin`)。 账户公钥在部署新更新的实体和消费这些更新的用户之间是众所周知的。 + +更新的压缩包本身在其他地方托管,不在链上,可以从指定的 `download_url` 获取。 + +```text +use solana_sdk::signature::Signature; + +/// Information required to download and apply a given update +pub struct UpdateManifest { + pub timestamp_secs: u64, // When the release was deployed in seconds since UNIX EPOCH + pub download_url: String, // Download URL to the release tar.bz2 + pub download_sha256: String, // SHA256 digest of the release tar.bz2 file +} + +/// Data of an Update Manifest program Account. +#[derive(Serialize, Deserialize, Default, Debug, PartialEq)] +pub struct SignedUpdateManifest { + pub manifest: UpdateManifest, + pub manifest_signature: Signature, +} +``` + +请注意,`manifest` 字段本身包含一个相应的签名\(`manifest_signature`\),以防止 `solana-install` 工具和 Solana 集群 RPC API 之间的中间人攻击。 + +为了防止回滚攻击,`solana-install` 将拒绝安装比当前安装的 `timestamp_secs` 更早的更新。 + +## 版本存档内容 + +一个发行版的归档文件应该是一个用bzip2压缩的tar文件,其内部结构如下: /version. yml - 一个简单的YAML文件,包含"target"字段。 + +- `/version.yml` - 一个简单的YAML文件,包含 `"target"` - + + 目标元组。 任何额外的字段将被忽略。 + +- `/bin/` -- 发行版中包含可用程序的目录。 + + `solana-install` 会将这个目录以符号链接的方式连接到 + + `~/.local/share/Solana-install/bin` 供 `PATH` 环境变量使用。 + + 变量。 + +- `...` -- 允许有任何其他文件和目录。 + +## solana-install 工具 + +用户使用 `solana-install` 工具来安装和更新他们的集群软件。 + +它在用户的主目录中管理以下文件和目录: ~/. config/Solana/install/config. yml -- 用户配置和当前集群软件的信息。 + +- `~/.config/Solana/install/config.yml` - 用户配置和当前安装的软件版本信息。 +- `~/.local/share/solana/install/bin` - 当前版本的符号链接, 例如,`~/.local/share/Solana-update/-/bin`。 +- `~/.local/share/Solana/install/releases//` - 版本内容。 + +### 命令行界面 + +```text +solana-install 0.16.0 +The solana cluster software installer + +USAGE: + solana-install [OPTIONS] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -c, --config Configuration file to use [default: .../Library/Preferences/solana/install.yml] + +SUBCOMMANDS: + deploy deploys a new update + help Prints this message or the help of the given subcommand(s) + info displays information about the current installation + init initializes a new installation + run Runs a program while periodically checking and applying software updates + update checks for an update, and if available downloads and applies it +``` + +```text +solana-install-init +initializes a new installation + +USAGE: + solana-install init [OPTIONS] + +FLAGS: + -h, --help Prints help information + +OPTIONS: + -d, --data_dir Directory to store install data [default: .../Library/Application Support/solana] + -u, --url JSON RPC URL for the solana cluster [default: http://devnet.solana.com] + -p, --pubkey Public key of the update manifest [default: 9XX329sPuskWhH4DQh6k16c87dHKhXLBZTL3Gxmve8Gp] +``` + +```text +solana-install info +displays information about the current installation + +USAGE: + solana-install info [FLAGS] + +FLAGS: + -h, --help Prints help information + -l, --local only display local information, don't check the cluster for new updates +``` + +```text +solana-install deploy +deploys a new update + +USAGE: + solana-install deploy + +FLAGS: + -h, --help Prints help information + +ARGS: + URL to the solana release archive + Keypair file for the update manifest (/path/to/keypair.json) +``` + +```text +solana-install update +checks for an update, and if available downloads and applies it + +USAGE: + solana-install update + +FLAGS: + -h, --help Prints help information +``` + +```text +solana-install run +Runs a program while periodically checking and applying software updates + +USAGE: + solana-install run [program_arguments]... + +FLAGS: + -h, --help Prints help information + +ARGS: + program to run + ... arguments to supply to the program + +The program will be restarted upon a successful software update +``` diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/instruction_introspection.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/instruction_introspection.md new file mode 100644 index 0000000000..5e3518afd5 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/instruction_introspection.md @@ -0,0 +1,22 @@ +--- +title: 指令反省 +--- + +## 面临的问题 + +一些智能合约程序可能想要验证另一个指令是否存在于给定的消息中,因为该指令可能是在预编译函数中执行某些数据的验证。 (参见secp256k1/_instruction的例子)。 + +## 解决方案 + +增加一个新的sysvar Sysvar1nstructions1111111111111111111111111,程序可以在里面引用和接收消息的指令数据,也可以引用当前指令的索引。 + +可以使用两个辅助函数来提取这些数据: + +``` +fn load_current_index(instruction_data: &[u8]) -> u16; +fn load_instruction_at(instruction_index: usize, instruction_data: &[u8]) -> Result; +``` + +运行时将识别这条特殊的指令,为其序列化消息指令数据,同时写入当前的指令索引,然后bpf程序就可以从中提取必要的信息。 + +注意:使用自定义序列化指令是因为二进制码在原生代码中的速度要慢10倍左右,而且超过了当前bpf指令的限制。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/leader-leader-transition.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/leader-leader-transition.md new file mode 100644 index 0000000000..2544feab01 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/leader-leader-transition.md @@ -0,0 +1,55 @@ +--- +title: 领导者之间的过渡 +--- + +这个设计描述了领导者如何在每个领导者产生自己的插槽时,相互之间过渡PoH账本的生产。 + +## 挑战 + +当前领先者和下一个领先者都在竞相产生当前插槽的最后一个刻度。 下一个领导者可能会在处理当前领导者的条目时到达该插槽。 + +理想的情况是,下一个领导者在能够为当前领导者投票之后,马上生成自己的插槽。 很有可能在当前领导者完成整个区块的广播之前,下一个领导者就会到达自己的PoH插槽高度。 + +下一任领导者必须做出决定,是将自己的区块附加到最后完成的区块上,还是等待最后确定待播区块。 下一个领导者有可能会产生一个提出当前领导者失败的区块,即使网络的其他部分观察到该区块成功。 + +当前领导者有激励机制来尽早启动其区块以获取经济奖励。 这些激励因素需要与领导者需要将其区块附加到一个网络其余部分承诺最多的区块上进行平衡。 + +## 领导者超时 + +当一个领导者正在积极地接收前一个插槽的条目时,领导者可以实时延迟广播其块的开始。 延时时间由每个领队在本地配置,可以根据前一个领队的行为进行动态配置。 如果在超时之前,前一个领队的区块被领队的TVU确认,则PoH被重置为该插槽的开始,这个领队立即产生其区块。 + +缺点是 + +-  领导者延迟了自己的时间,可能让下一个领导者有更多的时间追赶。 + + . + +优点是: + +- 一个区块中所有的空间都被用于输入。 +- 超时不固定。 +- 超时是领导者的局部,因此可以很聪明。 领导者的启发式可以考虑涡轮性能。 +- 这种设计不需要账本硬分叉更新。 +- 上一个领导者可以将区块中的最后一个条目冗余地传送给下一个领导者,下一个领导者可以推测性地决定信任它来生成它的区块,而不需要验证上一个区块。 +-  领导者可以推测性地从最后一个接收到的条目中生成最后一个行情。 +-  领导者可以投机地处理交易,猜测哪些交易不会被上一个领导者编码。 这也是一种审查攻击向量。 当前的领导者可能会扣留从客户端收到的交易,这样它就可以将它们编码到自己的插槽中。 一旦处理完毕,条目就可以快速重放到PoH中。 + +## 其他设计方案 + +### 警卫在插槽的末端打勾 + +一个领导者在_倒数第二个tick_之后不会在其区块中产生条目,这是下一个插槽的第一个tick之前的最后一个tick。 网络会对_最后一个tick_进行投票,所以_倒数第二个tick_和_最后一个tick_之间的时间差是整个网络的强制延迟,也是下一个领导者在产生新的插槽之前的延迟。 网络可以从_倒数第二个tick_产生_最后一个 tick_。 + +如果下一个领导者在它产生自己的_第一个tick_之前收到了_倒数第二的tick_,它将重置它的PoH,并从上一个领导者的_倒数第二个tick_产生_第一个tick_。 其余的网络也会重置自己的PoH,产生_最后一个tick_作为投票的id。 + +弊端: + +- 每次投票和确认都会有固定的超时时间。 1 tick,也就是100ms左右。 +- 平均一个交易的案例确认时间至少会差50ms。 +- 这是账本定义的一部分,所以要改变这种行为需要硬分叉。 +- 并非所有可用空间都用于条目。 + +与领导者超时相比,其优点是: + +- 下一个领导者已经收到了之前所有的条目,所以它可以开始处理交易,而不需要将它们记录到PoH中。 +- 上一个领导者可以将包含_倒数第二个tick_的最后一个条目冗余地传输给下一个领导者。 下一个领导可以在收到_倒数第二个tick_后立即推测生成_最后一个tick_,甚至在验证它之前。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/leader-validator-transition.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/leader-validator-transition.md new file mode 100644 index 0000000000..99195e0a3d --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/leader-validator-transition.md @@ -0,0 +1,52 @@ +--- +title: 领导者到验证节点的过渡 +--- + +验证节点通常把时间花在验证区块上。 但是,如果一个质押者将自己的质押委托给一个验证节点,那么它偶尔会被选为_插槽领导者_。 作为一个插槽领导者,验证节点负责在指定的_插槽_内产生区块。 一个插槽有一定数量的预先配置的_出块_持续时间。 这些ticks的持续时间是通过本文后面描述的_PoH记录器_来估计的。 + +## BankFork + +BankFork跟踪银行状态在特定插槽上的变化。 一旦最后一次勾选被登记,状态就会被冻结。 任何写入的尝试都会被拒绝。 + +## 验证节点 + +验证节点对银行状态的许多不同的并发分叉进行操作,直到生成一个高度在其领导插槽内的PoH哈希。 + +## 插槽领导者 + +一个插槽领导者只在一个分叉上搭积木,也就是它最后投票的那个分叉。 + +## PoH记录器 + +插槽领导者和验证员使用PoH记录仪来估计插槽高和记录交易。 + +### 验证时的PoH记录器 + +PoH记录器在验证时充当一个简单的VDF。 它告诉验证节点何时需要切换到插槽领导者角色。 每次验证节点对一个分叉进行投票时,它应该使用分叉最新的[blockhash](../terminology.md#blockhash)来重新播种VDF。 重新播种解决了两个问题。 首先,它将自己的VDF与leader的VDF同步,让它更准确地确定自己的leader插槽开始的时间。 第二,如果上一个领导者倒下了,所有的挂钟时间都会被计入下一个领导者的PoH流中。 例如,如果领导者开始时少了一个区块,那么它产生的区块应该有两个区块的PoH持续时间。 较领导者的持续时间可以确保下一个领导不会试图从上一个领导的插槽中抢走所有的事务。 + +### 领导时的PoH记录器 + +插槽领导者使用PoH记录器记录交易,及时锁定其位置。 PoH散列必须来自于前一个领导者的最后一个区块。 如果不是,其区块将无法通过PoH验证并被集群拒绝。 + +PoH记录器的作用还在于当其插槽结束时,通知插槽领导者。 如果记录交易会在其指定的插槽之外产生PoH高度,领导者需要注意不要修改其库。 因此,领导者在生成条目的PoH哈希值之前,不应承诺修改账户。 当PoH高度落在其插槽之外时,其管道中的任何交易可能会被放弃或转发到下一个领导者。 转发是优选的,因为它将最大限度地减少网络拥堵,允许集群宣传更高的TPS容量。 + +## 验证节点循环 + +PoH记录器管理模式之间的过渡。 一旦账本被重放,验证节点可以运行,直到记录器指示它应该成为插槽领导者。 作为插槽领导者,该节点就可以执行和记录交易。 + +循环与PoH同步,并做插槽领导者功能的同步启动和停止。 停止后,验证节点的TVU应该发现自己的状态和不同的领导者给它发送相同的块一样。 以下是该循环的伪代码。 + +1. 查询LeaderScheduler的下一个分配的插槽。 +2. 在所有的分叉上运行TVU。 1. TVU将把投票发给它认为是 "最好的 "分叉。 2. 每次投票后,重启PoH记录器,直到下一个指定的分叉。 + + 插槽。 + +3. 做插槽领导者的时候,启动TPU。 将其指向最后一个分叉的 + + TVU投了赞成票。 + +4. 制作作品,直至档期结束。 1. 在档期内,TVU不得对其他分叉进行投票。 2. 插槽期结束后,TPU冻结其BankFork。 冻结后, + + 该TVU可以恢复投票。 + +5. 回到第一点。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/persistent-account-storage.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/persistent-account-storage.md new file mode 100644 index 0000000000..167b1ea51c --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/persistent-account-storage.md @@ -0,0 +1,95 @@ +--- +title: 持久账户存储 +--- + +## 持久账户存储 + +账户集代表了验证节点处理过的所有交易的当前计算状态。 每个验证节点都需要维护这整个集合。 网络提出的每一个区块都代表着对这个集合的改变,由于每个区块都是一个潜在的回滚点,所以改变需要是可逆的。 + +NVME等持久性存储比DDR便宜20到40倍。 持久性存储的问题是,写和读的性能比DDR慢很多,必须注意数据的读写方式。 读取和写入都可以在多个存储驱动器之间分割,并行访问。 本设计提出了一种数据结构,允许存储的并发读取和并发写入。 写入通过使用AppendVec数据结构进行优化,允许单个写入者进行追加,同时允许多个并发读取者访问。 账户索引维护一个指针,指向每次分叉追加账户的位置,从而消除了对状态的显式检查点的需求。 + +## AppendVec + +AppendVec是一个数据结构,它允许随机读取与单一的纯追加写入同时进行。 增长或调整AppendVec的容量需要独占访问。 这是用一个原子`offset`来实现的,它在一个完成的追加结束时更新。 + +AppendVec的底层内存是一个内存映射的文件。 内存映射文件允许快速的随机访问,分页由操作系统处理。 + +## 账户索引 + +账户索引的设计是为了支持所有当前分叉账户的单一索引。 + +```text +type AppendVecId = usize; + +type Fork = u64; + +struct AccountMap(Hashmap); + +type AccountIndex = HashMap; +``` + +该索引是账户公钥的映射到分叉的映射,以及AppendVec中账户数据的位置。 要想获得一个特定分叉的账户版本。 + +```text +/// Load the account for the pubkey. +/// This function will load the account from the specified fork, falling back to the fork's parents +/// * fork - a virtual Accounts instance, keyed by Fork. Accounts keep track of their parents with Forks, +/// the persistent store +/// * pubkey - The Account's public key. +pub fn load_slow(&self, id: Fork, pubkey: &Pubkey) -> Option<&Account> +``` + +通过指向存储偏移量的`AppendVecId`中的内存映射位置来满足读取。 可以返回一个没有拷贝的引用。 + +### 验证节点根分叉 + +[塔式BFT](tower-bft.md)最终选择一个分叉作为根分叉,分叉被压扁。 被压扁的/根分叉不能回滚。 + +当一个分叉被压扁时,它的父账户中所有还没有出现在分叉中的账户都会通过更新索引被拉升到分叉中。 被压扁的分叉中余额为零的账户会通过更新索引从分叉中移除。 + +当一个账户被_压扁_导致无法访问时,可以将其垃圾回收。 + +有三种可能的选择。 + +- 维护一个HashSet的根分叉。 预计每秒钟创建一个。 整个树可以在以后被垃圾回收。 另外,如果每个分叉都保持一个账户的引用计数,那么在更新索引位置时,垃圾收集可能会发生。 +- 从索引中删除任何修剪过的分叉。 任何剩余的比根号低的分叉都可以被认为是根号。 +- 扫描索引,将任何旧的根迁移到新的索引中。 任何比新根数低的剩余分叉都可以在以后删除。 + +## 只写附录 + +所有对账户的更新都是以纯追加更新的方式进行的。 每一次账户更新,AppendVec中都会存储一个新版本。 + +可以通过在一个分叉中返回一个已经存储的账户的可变引用来优化单个分叉内的更新。 银行已经跟踪账户的并发访问,并保证对特定账户分叉的写与对该分叉中的账户的读不会同时发生。 为了支持这个操作,AppendVec应该实现这个函数。 + +```text +fn get_mut(&self, index: u64) -> &mut T; +``` + +该API允许对`index`的内存区域进行并发的可变更访问。 它依靠银行保证对该索引的独家访问。 + +## 垃圾收集 + +随着账户的更新,它们会移动到AppendVec的末尾。 一旦容量用完,可以创建一个新的AppendVec,并将更新的内容存储在那里。 最终,对旧的AppendVec的引用将消失,因为所有的账户都已更新,旧的AppendVec可以被删除。 + +为了加快这个过程,可以将最近没有更新的账户移到新的 AppendVec 的前面。 这种形式的垃圾收集可以在不需要对任何数据结构进行独占锁的情况下完成,除了索引更新。 + +垃圾收集的初始实现是,一旦AppendVec中的所有账户成为陈旧版本,它就会被重用。 账户一旦被追加,就不会被更新或移动。 + +## 索引回收 + +在追加过程中,每个银行线程都有对账户的独占访问权,因为在数据提交之前,账户锁不能被释放。 但是在独立的AppendVec文件之间没有明确的写入顺序。 为了创建一个顺序,索引维护了一个原子写版本计数器。 每一次对AppendVec的追加都会在AppendVec中账户的条目中记录该追加的索引写版本号。 + +为了恢复索引,所有的AppendVec文件可以以任何顺序读取,并且每次分叉的最新写版本应该存储在索引中。 + +## 快照 + +要进行快照,需要将AppendVec中的底层内存映射文件刷新到磁盘。 索引也可以写到磁盘上。 + +## 性能 + +- 只进行追加写入的速度很快。 SSD和NVME,以及所有操作系统级别的内核数据结构,都允许在PCI或NVMe带宽允许的情况下以最快的速度运行追加(2,700 MB/s)。 +- 每个重放和银行线程都会同时写入自己的AppendVec。 +- 每个AppendVec可能会被托管在一个单独的NVMe上。 +- 每个重放和银行线程都可以并发读取所有AppendVec,而不会阻止写入。 +- 索引需要一个专属的写锁进行写入。 HashMap更新的单线程性能在每秒10m左右。 +- Banking和Replay阶段应该使用每个NVMe的32个线程。 NVMe使用32个并发读取器或写入器具有最佳性能。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/readonly-accounts.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/readonly-accounts.md new file mode 100644 index 0000000000..66d1c3d6e7 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/readonly-accounts.md @@ -0,0 +1,25 @@ +--- +title: 只读账户 +--- + +这个设计涵盖了[runtime](../validator/runtime.md)对只读和可写账户的处理。 修改同一账户的多个事务必须串行处理,以便它们总是以相同的顺序重放。 否则,这可能会给账本引入非确定性。 然而,有些事务只需要读取,而不需要修改特定账户的数据。 由于重放顺序并不重要,因此可以并行处理多个只读取同一账户的事务,从而提供性能优势。 + +为了识别只读账户,事务MessageHeader结构包含`num_readonly_signed_accounts`和`num_readonly_unsigned_accounts`。 指令`program_ids`作为只读、无符号账户包含在账户向量中,因为可执行账户同样不能在指令处理过程中被修改。 + +## Runtime处理 + +Runtime的交易处理规则需要稍微更新。 程序仍然不能写入或花费不属于自己的账户。 但新的runtime规则保证了只读账户不能被修改,即使是拥有这些账户的程序也不能修改。 + +只读账户具有以下属性。 + +- 只读访问所有账户字段,包括lamports(不能贷记或借记) 和账户数据。 + +贷记、借记或修改只读账户的指令将失败。 + +## 账户锁定优化 + +账户模块在runtime跟踪当前锁定的账户,从而将只读账户和可写账户分开。 默认的账户锁给一个账户赋予了 "可写 "的称号,并且一次只能由一个处理线程访问。 只读账户由一个单独的机制锁定,允许并行读取。 + +虽然还没有实现,但只读账户可以缓存在内存中,并由所有执行事务的线程共享。 一个理想的设计是,当一个只读账户被任何在runtime移动的事务引用时,保持这个缓存,并在最后一个事务退出runtime释放缓存。 + +只读账户也可以作为引用传入处理器,保存一个额外的副本。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/reliable-vote-transmission.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/reliable-vote-transmission.md new file mode 100644 index 0000000000..c94052b2da --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/reliable-vote-transmission.md @@ -0,0 +1,60 @@ +--- +title: 可靠的投票传输 +--- + +验证节点投票是对网络的共识和持续运行具有关键功能的信息。 因此,可靠地传递这些信息并将其编码到账本中是至关重要的。 + +## 挑战 + +1. 领导者轮换是由PoH触发的,PoH是具有高漂移的时钟。 所以很多节点很可能对下一个领导者是否实时活跃有一个错误的看法。 +2. 下一个领导者可能很容易被淹没。 因此DDOS不仅会阻碍常规事务的传递,也会阻碍共识消息的传递。 +3. UDP是不可靠的,我们的异步协议要求任何传输的消息都要重传,直到在账本中观察到它。 重传有可能会对有大量验证节点的领导者造成无意的_过大流量冲击_。 最坏的情况下,冲击量会达到`(num_nodes * num_retransmits)`。 +4. 通过账本跟踪投票是否已经传送,并不能保证它将出现在确认块中。 当前观察到的区块可能会被解卷。 验证节点需要为每一次投票和分叉保持状态。 + +## 设计 + +1. 通过gossip以推送信息的方式送票。 这样可以保证将票数传递给所有下一届领导,而不仅仅是下一届未来的领导。 +2. 领导者将读取Crds表以获取新的投票,并将任何新收到的投票编码到他们提出的区块中。 这样就可以让验证节点的投票被所有未来的领导者纳入回滚分叉中。 +3. 在账本中收到投票的验证节点将把它们添加到他们的本地crds表中,而不是作为推送请求,而是简单地将它们添加到表中。 这样就缩短了推送消息协议,所以验证消息不需要在网络上重传两次。 +4. 投票的CrdsValue应该是这样的`Votes()` + +每个投票事务都应该在其数据中保持一个`wallclock`。 投票的合并策略将保留本地客户端配置的最后N组投票。 对于push/pull,向量是递归遍历的,每个Transaction被视为一个单独的CrdsValue,有自己的本地wallclock和签名。 + +Gossip被设计为高效的状态传播。 通过gossip-push发送的消息被分批发送,并以最小的生成树传播到网络的其他部分。 树上的任何部分故障都会通过gossip-pull协议主动修复,同时将任何节点之间的数据传输量降到最低。 + +## 这种设计如何解决挑战。 + +1. 因为在领导的 "活跃 "状态,验证节点没有简单的方法与领导同步,所以无论在什么状态下,gossip都可以最终交付。 +2. Gossip会将消息传递给所有后续的领导者,所以如果当前领导者被淹没,下一个领导者就会已经收到这些票数,并且能够对其进行编码。 +3. Gossip通过维护一个高效的生成树,并使用bloom过滤器来修复状态,从而最大限度地减少通过网络的请求次数。 所以重传回退是没有必要的,消息是分批的。 +4. 读取crds表进行投票的领导会对表中出现的所有新的有效投票进行编码。 即使这个领导的区块被取消,下一个领导也会尝试添加同样的票数,而不需要验证节点做任何额外的工作。 因此,不仅保证了最终的交付,也保证了最终编码到账本中。 + +## 性能 + +1. 最坏情况下传播到下一个领导者的时间是Log/(N/) 跳,基数取决于fanout。 以我们目前默认的fanout为6,到20k节点约为6跳。 +2. 领导者应该收到20k张验证票,通过gossip-push汇总成MTU大小的碎片。 这样可以将20k网络的数据包数量减少到80个碎片。 +3. 每个验证节点的票数都会在全网复制。 为了维持5个以前投票的队列,Crds表将增长25兆字节。 `(20000节点*256字节*5)`。 + +## 两步实施推出 + +初期网络只需通过网络传输和维护1个投票,就可以可靠地执行当前的投票实施。 对于小型网络,6个fanout就足够了。 对于小型网络,内存和推送开销很小。 + +### 1k验证节点子网络 + +1. Crds只是维护验证节点最新的投票。 +2. 无论票数是否出现在分类账中,都会被推送和重传。 +3. 6的fanout。 +4. 最坏情况下每个节点256kb的内存开销。 +5. 最坏情况下4跳传播到每个节点。 +6. 领导者应该在4个推送消息碎片中收到整个验证节点投票集。 + +### 20k子网络 + +在上述子网加上以下几点。 + +1. CRDS表维护着5个最新验证节点投票的向量。 +2. 投票编码一个挂钟。 CrdsValue::Votes是一个类型,它递归到所有Gossip协议的事务向量中。 +3. 将fanout增加到20。 +4. 最坏情况下每个节点的内存开销为25mb。 +5. 在最坏的情况下,用4个跳来传送到整个网络。 +6. 领队收到的所有验证机信息80个碎片。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/rent.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/rent.md new file mode 100644 index 0000000000..aa11b75c98 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/rent.md @@ -0,0 +1,69 @@ +--- +title: 出租 +--- + +Solana 上的帐户可能处于所有者控制的状态 \(`Account::data`\) 该帐户独立于帐户的余额 \(`Account::lamports`\)。 因为网络上的验证节点需要在内存中保留此状态的工作副本,因此网络需要收取基于时间空间的一部分费用,也称为租金。 + +## 二级租金制度 + +那些账户最低余额相当于2年租金的账户可以免税。 _2 年_ 是因为硬件成本每2年会下降一半的事实,以及由于几何序列引起的收敛。 余额低于此阈值的账户按起始规定的费率收取租金,按每个年份的灯塔收取。 网络基于每个轮次收取租金,同时计入下一个轮次的租金,`Account:::rent_epoch` 也会保存下次应该从帐户中收集的租金。 + +目前,租金费用从一开始就已经固定了。 然而,我们预计它是动态的,反映了当下的硬件储存成本。 因此,随着技术进步以及硬件成本的下降,价格一般都会逐渐降低。 + +## 收取租金的时间 + +从帐户收取租金的时间有 2 次:\(1\) 进行交易,\(2\) 每个轮次定期收一次。 \(1\) 包括创建新账户本身的交易,而且它作为银行加载阶段,进行正常交易期间的一个步骤,。 \(2\) 该步骤是为了确保从旧账户中收取租金,这些账户在最新的轮次中基本都没有被引用。 \(2\) 需要扫描整个帐户,并以帐户地址前缀为基础将其分布到一个轮次,以避免由于收取租金而导致的加载波动。 + +相反,收取租金不适用于任何协议级账簿程序直接操纵的账户,其中包括: + +- 收租本身的分配(以往,这可能导致重复收租的问题) +- 在每个新轮次开始的时候,质押奖励的分配 (尽量减少在新轮次开始时的波动幅度) +- 每个slot结束时的交易费分配 + +即使这些过程超出了收取租金的范围,所有被操纵的账户最终都将由 \(2\) 机制处理。 + +## 收集租金的实际过程 + +租金到期的期限为一个 epoch,取决于租金制度,帐户有 `current_epoch` 或 `current_epoch + 1` 的 `Account::rent_epoch` 。 + +如果帐户处于免责状态, `Account::rent_epoch` 就只更新到 `current_epoch`。 + +如果帐户不处于免责状态,下一个 epoch 和 `Account::rent_epoch` 之间的差额用于计算此账户所欠的租金金额\(通过 `Rent::due()`\)。 计算中的任何分数端口灯都是被截断的。 已从 `Account::lamport` 和 `Account::rent_epoch` 更新到 `current_epoch + 1` (= 下一个 epoch)。 如果到期租金少于一个 lamport,则不对该账户作任何更改。 + +余额不足以支付租金的账户仅仅会无法加载。 + +一定比例的租金被销毁。 其余部分(即交易费)按质押权重,在每个 slot 结束的时候分配给验证节点账号。 + +最后,根据协议级别的帐户更新进行租金收取(就像向验证节点分发租金),这意味着没有相应的租金扣减交易。 因此,租金收取的过程其实非常隐秘,只能通过最近的交易或其账户地址前缀预先确定的时间来观察到。 + +## 设计考虑因素 + +### 当前设计依据 + +根据前面的设计,不可能有帐户处于遗漏、不会交互或者不支付租金的状态。 除了免租金、系统服务和可执行账户,其他账户在每个epoch都需要支付一次租金。 + +这就是设计上的考虑。 否则, 如果任何人可能不公平地获得租金(当前的领导者) 或因预期的浮动租金费用去节省费用,就有可能通过 `Noop` 指令启动未经授权的租金收取。 + +这个设计还有另一个副作用:我们注意到这种定期收取租金的做法有效地迫使验证节点不将陈旧帐户变成冷存储,从而节省储存费用,这一点不利于账户所有者,可能导致他们的交易停顿时间比其他人更长。 但是在另一方面,它防止了恶意用户累积大量垃圾帐户,加重验证节点的负担。 + +该设计的总体思路为:所有账户具有相同的性能特征,作为验证节点的工作集存储起来,直观地反映出统一的租金定价结构。 + +### 特别收藏 + +考虑按需要收取租金\(即当帐户被加载/访问的时候\)。 采取这种办法的问题是: + +- 某笔交易加载为“信用额度”的帐户可能会很合理地指望存在一个租金期限, + + 但是任何这类交易都无法写入 + +- "打败忙碌”的机制\(即寻找需要支付租金的帐户\) 是可取的, + + 不经常加载的帐户可以获得一些免费的机会 + +### 收取租金的系统说明 + +通过系统指示收取租金时需要注意,它会自然把租金分配给活跃和质押权重的节点,并且可以逐步进行。 然而: + +- 它会对网络流量产生不利影响 +- 该过程需要在运行时间之前进行特殊的套件处理,因为非系统程序所有者的帐户可能会被此指示扣除。 +- 必须有人发布一笔交易 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/repair-service.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/repair-service.md new file mode 100644 index 0000000000..ccb36100ce --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/repair-service.md @@ -0,0 +1,58 @@ +--- +title: 维修服务 +--- + +## 维修服务 + +修复服务负责检索未能通过Turbine等主要通信协议传送的遗失碎片。 它负责管理下面`维修协议`部分中描述的协议。 + +## 挑战。 + +1\) 验证节点可能会因为网络故障而无法接收特定的碎片。 + +2\) 考虑一个场景,blockstore包含一组插槽{1, 3, 5}。 那么Blockstore接收到一些插槽7的碎片,其中对于每一个碎片b,b.parent == 6,那么父子关系6 -> 7就存储在blockstore中。 但是,没有办法将这些插槽链到Blockstore中任何一个现有的库中,因此,`碎片修复`协议不会修复这些插槽。 如果这些插槽恰好是主链的一部分,这将停止该节点上的重放进度。 + +## 修复相关基元 + +纪元插槽: 每个验证节点都在Gossip上分别广播`纪元插槽`的各个部分。 + +- `储藏`:一个以纪元为单位的所有已完成插槽的压缩集。 +- `缓存`:最新的`N`个已完成的插槽的运行长度编码(RLE),从某个插槽`M`开始,其中`N`是一个MTU大小的数据包所能容纳的插槽数。 + +gossip中的`Epoch Slots`每当验证节点收到一个在epoch内的完整插槽时,就会更新。 已完成的插槽由blockstore检测,并通过通道发送到维修服务。 需要注意的是,我们知道当一个插槽`X`完成的时候,包含插槽`X`的纪元必须存在纪元时间表,因为WindowService会拒绝未确认的纪元的碎片。 + +每完成一个`N/2`插槽,最老的`N/2`插槽就会从`缓存`移到`stash`中。 RLE的基值`M`也要更新。 + +## 修复请求协议 + +修复协议为进步Blockstore的分叉结构做了最好的尝试。 + +不同的协议策略来解决上述难题。 + +1. Shred Repair\(解决挑战\#1\):这是最基本的修复协议,目的是检测和填补账本中的 "漏洞"。 Blockstore会跟踪最新的根插槽。 然后,RepairService会从根插槽开始定期迭代blockstore中的每一个分叉,向验证节点发送修复请求,以获取任何缺失的碎片。 它每次迭代最多会发送一些`N`修复请求。 碎片修复应该根据领导者的分叉重量来优先修复分叉。 验证节点应该只向在其EpochSlots中标记该插槽已完成的验证节点发送修复请求。 验证节点应该优先修复他们负责通过涡轮重传的每个插槽中的碎片。 验证节点可以计算出他们负责重传的碎片,因为turbine的种子是基于leader id、slot和碎片 index的。 + + 注意:验证节点只接受当前可验证的epoch (验证节点有领袖时间表的epoch) 内的碎纸片。 + +2. Preemptive Slot Repair\(解决挑战 \#2\):这个协议的目标是发现 "孤儿 "插槽的链路关系,这些插槽目前没有链到任何已知的分叉。 碎片修复应该根据领导者的分叉权重来优先修复孤儿插槽。 + + - Blockstore将在一个单独的列族中跟踪 "孤儿 "插槽的集合。 + - 修复服务将定期为blockstore中的每个孤儿提出`Orphan`请求。 + + `Orphan(orphan)`请求--`orphan`是请求者想知道的孤儿插槽的父母`Orphan(orphan)`响应--请求的`orphan`的前`N`个父母的最高分叉量。 + + 在收到响应`p`时,其中`p`是父插槽中的一些碎片,验证节点将: + + - 如果它还不存在,那么就在区块存储中为`p.slot`插入一个空的`SlotMeta`。 + - 如果`p.slot`确实存在,根据`父辈`更新`p`的父插槽。 + + 注意:一旦这些空插槽被添加到区块存储中,`Shred Repair`协议应该尝试填补这些插槽。 + + 注意:验证节点只会接受包含当前可验证的epoch (验证节点有领导时间表的epoch) 内的碎片的响应。 + +验证节点应该尝试将孤儿请求发送给在其EpochSlots中已将该孤儿标记为已完成的验证节点。 如果不存在这样的验证节点,那么就以利害关系加权的方式随机选择一个验证节点。 + +## 修复响应协议 + +当验证节点收到一个碎片`S`的请求时,如果他们有碎片,他们就会响应。 + +当验证节点通过修复响应收到碎纸片时,他们会检查`EpochSlots`,看看是否有 <= `1/3` 的网络已经将这个插槽标记为完成。 如果是这样,他们就会通过其相关的涡轮路径重新提交这个碎片,但前提是这个验证节点之前没有重传过这个碎片。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/rpc-transaction-history.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/rpc-transaction-history.md new file mode 100644 index 0000000000..8faab25ce9 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/rpc-transaction-history.md @@ -0,0 +1,66 @@ +# 长期RPC事务历史 +RPC需要提供至少6个月的交易历史。 当前的历史记录,以天为单位,对于下游用户来说是不够的。 + +6个月的交易数据实际上无法存储在验证节点的rocksdb账本中,所以需要一个外部数据存储。 验证节点的rocksdb账本将继续作为主要数据源,然后将回落到外部数据存储中。 + +受影响的RPC端点是: * [getFirstAvailableBlog]。 +* [getFirstAvailableBlock](developing/clients/jsonrpc-api.md#getfirstavailableblock) +* [getConfirmedBlock](developing/clients/jsonrpc-api.md#getconfirmedblock) +* [getConfirmedBlocks](developing/clients/jsonrpc-api.md#getconfirmedblocks) +* [getConfirmedSignaturesForAddress](developing/clients/jsonrpc-api.md#getconfirmedsignaturesforaddress) +* [getConfirmedTransaction](developing/clients/jsonrpc-api.md#getconfirmedtransaction) +* [getSignatureStatuses](developing/clients/jsonrpc-api.md#getsignaturestatuses) + +需要注意的是,不支持[getBlockTime](developing/clients/jsonrpc-api.md#getblocktime),因为一旦https://github.com/Solana-labs/Solana/issues/10089 被修复,那么`getBlockTime`就可以被删除。 + +一些系统设计限制。 +* 需要存储和搜索的数据量可以快速的跳到TB级,并且是不可改变的。 +* 系统应该尽可能的轻量化,以满足SRE的要求。 例如一个SQL数据库集群,需要SRE不断地监控和重新平衡节点是不可取的。 +* 数据必须可以实时搜索--花几分钟或几小时运行的批量查询是不可接受的。 +* 易于在全球范围内复制数据,以便与将利用数据的RPC端点共同定位。 +* 与外部数据存储的接口应该是容易的,不需要依赖风险较小的社区支持的代码库。 + +基于这些约束条件,选择Google的BigTable产品作为数据存储。 + +## 表模式 +一个BigTable实例用来保存所有的交易数据,分成不同的表,以便快速搜索。 + +新数据可以随时复制到实例中,而不影响现有数据,所有数据都是不可改变的。 一般情况下,人们期望当前一个纪元完成后就会上传新数据,但对数据转储的频率没有限制。 + +通过适当配置实例表的数据保留策略,旧数据的清理是自动的,只是消失了。 因此数据添加的时间顺序就变得很重要。 例如如果在N-1纪元的数据之后添加了N纪元的数据,那么旧纪元的数据就会比新数据的寿命更长。 然而除了在查询结果中产生_holes_之外,这种无序删除不会有任何不良影响。 请注意,这种清理方法有效地允许存储无限量的事务数据,只是受限于这样做的货币成本。 + +表布局s只支持现有的RPC端点。 未来新的RPC端点可能需要对模式进行添加,并有可能对所有事务进行迭代以建立必要的元数据。 + +## 访问BigTable +BigTable有一个gRPC端点,可以使用[tonic](https://crates.io/crates/crate)] 和原始protobuf API进行访问,因为目前还没有针对BigTable的更高级别的Rust crate存在。 实际上,这使得BigTable查询结果的解析变得更加复杂,但并不是一个重要的问题。 + +## 数据群 +通过使用新的`solana-ledger-tool`命令,将给定插槽范围的rocksdb数据转换为实例模式,实例数据的持续填充将以一个纪元的节奏进行。 + +同样的过程将被手动运行一次,以回填现有的账本数据。 + +### 区块表格:`block` + +此表包含了给定插槽的压缩块数据。 + +行键是通过取插槽的16位小写十六进制表示来生成的,以确保当行被列出时,具有已确认块的最老的插槽总是排在第一位。 例如,插槽42的行键是00000000000000002a。 + +行数据是一个压缩的`StoredConfirmedBlock`结构。 + + +### 账户地址交易签名查询表: `tx-by-addr` + +该表包含了影响给定地址的事务。 + +行的键是`/`。 行数据是一个压缩的`TransactionByAddrInfo`结构。 + +取插槽的一的补码允许列出插槽,确保最新的插槽与影响地址的事务总是会先列出。 + +Sysvar地址是没有索引的。 然而,经常使用的程序,如 Vote 或 System 是有索引的,并且很可能为每个确认的插槽有一行。 + +### 事务签名查询表: `tx` + +该表将交易签名映射到其确认的区块,以及该区块中的索引。 + +行键是base58编码的交易签名。 行数据是一个压缩的`TransactionInfo`结构。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/snapshot-verification.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/snapshot-verification.md new file mode 100644 index 0000000000..5f401290f1 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/snapshot-verification.md @@ -0,0 +1,48 @@ +--- +title: 快照核查 +--- + +## 面临的问题 + +当验证节点从快照启动时,它需要一种方法来验证账户集与网络其他部分所看到的快速匹配。 潜在的攻击者可以给验证节点一个不正确的状态,然后试图说服它接受一个本来会被拒绝的交易。 + +## 解决方案 + +目前,银行哈希值是通过对一个插槽中账户的差异状态进行哈希,然后与之前的银行哈希值相结合而得出的。 这样做的问题是,哈希值列表将按链处理的插槽数顺序增长,成为传输和验证成功的负担。 + +另一种原始的方法可以是创建一个账户状态的哈希树。 这样做的缺点是,每次账户更新,都要从系统中所有活账户的整个账户状态中重新计算出哈希树。 + +为了验证快照,我们进行以下工作: + +在非零lamport账户的账户存储中,我们对以下数据进行哈希处理: + +- 帐户所有者 +- 账户数据 +- 帐户公钥 +- 账户余额 +- 帐户存储分叉 + +使用这个产生的哈希值作为一个扩展函数的输入,该函数将哈希值扩展为一个图像值。 该函数将创建一个440字节的数据块,其中前32个字节是哈希值,接下来的440-32个字节由Chacha RNG以哈希值为种子生成。 + +然后用xor结合账户图像。 前一个账户值将被xored到状态,新的账户值也被xored到状态。 + +投票和sysvar哈希值与产生的完整映像值的哈希值一起发生。 + +在验证节点启动时,当它从快照加载时,它会用设置的账户验证哈希值。 然后,它将使用SPV来显示投票支持所给哈希值的网络百分比。 + +由此产生的值可以被验证节点验证为所有当前账户状态一起xoring的结果。 + +在创建之前和验证过程中,必须清除零lamport账户的快照,因为零lamport账户不会影响哈希值,但可能会导致验证节点银行读到一个账户不存在,而它确实应该存在。 + +可以对xor状态进行攻击来影响它的值: + +因此,440字节的图像大小来自于这篇论文,避免xor与0的碰撞(或因此任何其他给定的比特模式):\[[https://link.springer.com/content/pdf/10.1007%2F3-540-45708-9_19.pdf](https://link.springer.com/content/pdf/10.1007%2F3-540-45708-9_19.pdf)\] + +在这种情况下,数学提供了128位的安全性。 + +```text +O(k * 2^(n/(1+lg(k))) +k=2^40 accounts +n=440 +2^(40) * 2^(448 * 8 / 41) ~= O(2^(128)) +``` diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/staking-rewards.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/staking-rewards.md new file mode 100644 index 0000000000..cd0beebad3 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/staking-rewards.md @@ -0,0 +1,57 @@ +--- +title: 质押奖励 +--- + +这里概述了一个权益证明/(PoS),/(即使用协议内资产SOL,提供安全共识/)设计。 Solana实现了集群中验证节点节点的权益证明奖励/安全方案。 其目的有三点。 + +- 通过风险的游戏中的皮肤存款,使验证节点的激励措施与大群的激励措施相一致。 + + . + +- 通过实施旨在促进分叉收敛的削减规则,避免 "事不关己 "的分叉投票问题。 + + . + +- 为验证节点提供一个作为验证节点参与集群的功能而提供的验证节点奖励渠道。 + + . + +虽然目前很多具体实施的细节还在考虑中,预计会通过Solana测试网的具体建模研究和参数探索成为焦点,但我们在这里概述一下我们目前对PoS系统主要组成部分的思考。 这个思路大部分是基于Casper FFG的现状,在Solana的历史证明 (PoH) 区块链数据结构允许的情况下进行优化和具体属性修改。 + +## 总体概述 + +Solana的账本验证设计是基于一个轮流的、经过质押加权的选定的领导者在PoH数据结构中向验证节点广播交易。 这些节点在收到领导者的广播后,有机会通过签署交易到PoH流中对当前状态和PoH高度进行投票。 + +要成为Solana验证节点,必须在合约中存入/锁定一定数量的SOL。 这个SOL在特定的时间段内是无法使用的。 押金锁定期的确切时间还没有确定。 但是我们可以考虑这段时间的三个阶段,这三个阶段将需要特定的参数。 + +- _预热期_:SOL质押在哪个节点,哪个节点便无法进入, + + 然而,PoH交易验证还没有开始。 最有可能的顺序是 + + 天到周 + +- _验证期_:交存的SOL的最短期限。 + + 无法进入,有可能被罚没(见下文罚没规则),并赚取。 + + 对审定者的参与给予奖励。 可能持续的时间为数月至一年。 + + . + +- _冷却期_:提交“取款“业务后的一段时间。 + + . 在此期间,验证责任已被删除, + + 资金仍无法进入。 累积奖励 + + 应在这一时期结束时交付,同时归还首期存款; + + . + +Solana的PoH数据结构所提供的无信任的时间感和秩序感,以及其[turbine](https://www.youtube.com/watch?v=qt_gDRXHrHQ&t=1s)数据广播和传输设计,应该提供亚秒级的交易确认时间,其规模与集群中节点数量的对数相一致。 这意味着我们不应该用一个令人望而却步的 "最低存款 "来限制验证节点的数量,并期望节点能够以名义上的SOL质押量成为验证节点。 同时,Solana对高吞吐量的关注应该为验证客户端提供高性能和可靠的硬件创造动力。 再加上潜在的最低网络速度门槛,作为验证客户加入,我们预计一个健康的验证委托市场将会出现。 为此,Solana的testnet将导致 "Tour de SOL "验证客户竞争,重点是吞吐量和正常运行时间,对testnet验证节点进行排名和奖励。 + +## 处罚 + +如[经济设计](ed_overview/ed_overview.md)一节所述,验证节点的年利率将被规定为已质押的流通供应总量百分比的函数。 集群对在整个_验证期_内在线并积极参与验证过程的验证节点进行奖励。 对于在此期间离线/未能验证交易的验证节点,他们的年度奖励会有效减少。 + +同样,我们可以考虑在验证节点离线的情况下,通过算法降低其活跃金额质押金额。 例如, 如果一个验证节点在一段时间内不活跃,无论是由于分区还是其他原因,他们被认为是 "活跃 "的质押金额(有资格获得奖励) 可能会减少。 这种设计的结构将有助于长期存在的分区最终达到各自链的最终性,因为随着时间的推移,无投票权的总股权比例会减少,直到每个分区的活跃验证节点可以达到超级多数。 同样,在重新参与时,"活跃 "的股权数量将以某种确定的速度重新上线。 根据分区/活跃集的大小,可以考虑不同的质押减少率。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/testing-programs.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/testing-programs.md new file mode 100644 index 0000000000..5436613ee9 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/testing-programs.md @@ -0,0 +1,53 @@ +--- +title: 测试程序 +--- + +应用程序将交易发送到Solana集群和查询验证者,以确认交易被处理,并检查每个交易的结果。 当集群的行为与预期不符时,可能有多种原因。 + +- 程序有问题 +- BPF加载器拒绝了一条不安全的程序指令。 +- 这笔交易太大 +- 交易无效 +- 运行时试图执行交易时,另一个人正在访问 + + 同一个账户 + +- 网络放弃了交易 +- 集群回滚账目 +- 一个验证者恶意回应查询 + +## AsyncClient和SyncClient特征 + +为了排除故障,应用程序应该重新瞄准一个较低级的组件,因为在那里可能出现的错误较少。 重定向可以通过AsyncClient和SyncClient特性的不同实现来完成。 + +组件实现了以下主要方法。 + +```text +trait AsyncClient { + fn async_send_transaction(&self, transaction: Transaction) -> io::Result; +} + +trait SyncClient { + fn get_signature_status(&self, signature: &Signature) -> Result>>; +} +``` + +用户发送交易并异步和同步等待结果。 + +### 集群的轻量级客户端 + +最高级别的实现,ThinClient,以Solana集群为目标,它可能是一个已部署的测试网,也可能是一个在开发机器上运行的本地集群。 + +### 针对 TPU 的 TpuClient + +下一个层次是TPU的实现,目前还没有实现。 在TPU层面,应用程序通过Rust通道发送交易,在这个通道中,不会出现来自网络队列或丢包的意外。 TPU实现了所有 "正常 "的交易错误。 它进行签名验证,可能会报告账户使用中的错误,否则就会在分类账中产生结果,并完成历史哈希证明。 + +## 低级测试 + +### 银行的银行客户端 + +TPU下面是银行。 银行不进行签名验证,也不生成账本。 银行是一个方便的层,可以测试新的链上程序。 它允许开发者在本地程序实现和 BPF 编译的变体之间切换。 这里不需要Transact特性。 银行的API是同步的。 + +## 使用runtime进行单元测试 + +Bank下面是Runtime。 Runtime是单元测试的理想测试环境。 通过将Runtime静态地链接到本地程序实现中,开发者可以获得尽可能短的编辑-编译-运行循环。 在没有任何动态链接的情况下,堆栈痕迹包括调试符号,程序错误也很容易排除。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/tower-bft.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/tower-bft.md new file mode 100644 index 0000000000..4eb498126b --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/tower-bft.md @@ -0,0 +1,138 @@ +--- +title: Tower BFT +--- + +本设计介绍了Solana的_塔式BFT_算法。 它解决了以下问题。 + +- 一些分叉可能最终不会被集群的超级多数接受,投票者需要从对这些分叉的投票中恢复过来。 +- 许多分叉可能会被不同的投票者投票,而每个投票者可能会看到一组不同的可投票分叉。 被选中的分叉最终应该为集群收敛。 +- 基于奖励的投票有相关的风险。 投票者应该有能力配置他们承担多少风险。 +- [回滚成本](tower-bft.md#cost-of-rollback)需要是可计算的。 这对于依赖某种可衡量形式的一致性的客户来说很重要。 破坏一致性的成本需要是可计算的,对于老票来说,成本会超线性增加。 +- 节点之间的ASIC速度是不同的,攻击者可以采用比集群其他部分快很多的历史证明ASIC。 共识需要抵御利用历史证明ASIC速度差异性的攻击。 + +为了简明扼要,本设计假设一个有质押的投票者被部署为集群中的单个验证节点。 + +## 时间 + +Solana集群通过可验证的延迟函数生成时间源,我们调用[历史证明](../cluster/synchronization.md)。 + +历史证明用于为所有活跃的领导者创建一个确定性的循环赛时间表。 在任何给定的时间,只有1个领导者可以提出分叉,这可以从账本本身计算出来。 更多细节,请参见[分叉生成](../cluster/fork-generation.md)和[领袖轮换](../cluster/leader-rotation.md)。 + +## 锁定 + +锁定的目的是迫使验证节点对特定的分叉承诺机会成本。 锁定是以时隙来衡量的,因此代表了验证节点在打破对一个分叉的承诺之前需要等待的实时强制延迟。 + +违反锁定时间并在锁定时间内投票给分歧的分叉的验证节点应该受到惩罚。 建议的惩罚措施是,如果能向集群证明在锁定期内同时投票给非下级分叉,则罚没验证节点的股权。 + +## 算法 + +这种方法的基本思路是堆叠共识投票和双重锁定。 栈中的每一票都是对一个分叉的确认。 每一个确认的分叉都是它上面的分叉的祖先。 每一票都有一个以时隙为单位的`锁定`,然后验证节点才能提交一个不包含确认的分叉作为祖先的投票。 + +当一个投票被添加到堆栈中时,堆栈中所有前一个投票的锁定会翻倍(更多内容请参见[Rollback](tower-bft.md#Rollback))。 每一次新的投票,验证节点都会将之前的投票投入到一个不断增加的锁定中。 在32票时,我们可以认为投票处于`最大锁定`的任何锁定等于或高于`1<<32`的投票都会被dequeued\(FIFO\)。 去排队投票是奖励的触发器。 如果一个投票在去排队之前就过期了,那么它和它上面的所有投票都会从投票堆栈中被弹出\(LIFO\)。 验证节点需要从这一点开始重建栈。 + +### 回滚 + +在投票被推送到堆栈之前,投票前所有锁定时间低于新投票的票数都会被弹出。 回滚后锁定时间不会翻倍,直到验证节点追上票数的回滚高度。 + +例如,一个投票栈的状态如下。 + +| 票数 | 票数时间 | 锁定时间 | 锁定到期时间 | +| --:| ----:| ----:| ------:| +| 4 | 4 | 2 | 6 | +| 3 | 3 | 4 | 7 | +| 2 | 2 | 8 | 10 | +| 1 | 1 | 16 | 17 | + +_第5票_是在时间9,结果状态是 + +| 票数 | 票数时间 | 锁定时间 | 锁定到期时间 | +| --:| ----:| ----:| ------:| +| 5 | 9 | 2 | 11 | +| 2 | 2 | 8 | 10 | +| 1 | 1 | 16 | 17 | + +_第6票_在第10时 + +| 票数 | 票数时间 | 锁定时间 | 锁定到期时间 | +| --:| ----:| ----:| ------:| +| 6 | 10 | 2 | 12 | +| 5 | 9 | 4 | 13 | +| 2 | 2 | 8 | 10 | +| 1 | 1 | 16 | 17 | + +在10时,新的票数赶上了之前的票数。 但是_投票2_在10时到期,所以在11时应用_投票7_时,包括_投票2_以上的投票将被弹出。 + +| 票数 | 票数时间 | 锁定时间 | 锁定到期时间 | +| --:| ----:| ----:| ------:| +| 7 | 11 | 2 | 13 | +| 1 | 1 | 16 | 17 | + +第1票的锁定将不会从16票增加,直到堆栈包含5票。 + +### 罚没和奖励 + +验证节点如果尽可能频繁地选择群组其他成员选择的分叉,就应该得到奖励。 这与当投票堆栈满了,需要对最老的投票进行排队时产生奖励是一致的。 因此,每一个成功的dequeue都应该产生一个奖励。 + +### 回滚的成本 + +回滚_分叉A_的成本被定义为验证节点确认任何不包括_分叉A_为祖先的其他分叉的锁定时间成本。 + +在**经济终局性**方面,_分叉A_可以计算为_分叉A_及其后裔回滚所带来的所有奖励损失,再加上由于确认_分叉A_的投票被锁定而带来的机会成本。 + +### 门槛 + +每个验证节点可以在该验证节点提交分叉之前,独立设置一个集群承诺的阈值。 例如,在票堆索引7处,锁定时间单位为256个。 除非指数7的投票在集群中的承诺度大于50%,否则验证节点可以扣留投票,让0-7的投票失效。 这使得每个验证节点可以独立控制承诺分叉的风险有多大。 以更高的频率承诺分叉,可以让验证节点获得更多的奖励。 + +### 算法参数 + +以下参数需要调整: + +- 在dequeue发生之前堆栈中的投票数\(32\)。 +- 栈中锁定的增长率 (2x/)。 +- 开始的默认锁定\(2\)。 +- 最小集群承诺的阈值深度,在承诺分叉之前 (8)。 +- 最小集群承诺大小在阈值深度 (50%+)。 + +### 自由选择 + +"自由选择 "是一种不可强制执行的验证节点动作。 协议没有办法对这些动作进行编码和强制执行,因为每个验证节点都可以修改代码和调整算法。 一个在所有可能的期货上最大化自我回报的验证节点,其行为应该是系统稳定的,局部贪婪选择的结果应该是在所有可能的期货上贪婪选择。 一组从事破坏协议的选择的验证节点应该受到其利益权重的约束而拒绝服务。 验证节点有两种选择出口。 + +- 一个验证节点可以在虚拟生成中超越之前的验证节点,并提交一个并发的分叉。 +- 验证节点可以不投票,观察多个分叉后再投票 + +在这两种情况下,集群中的验证节点都有几个分叉可以同时选择,即使每个分叉代表不同的高度。 在这两种情况下,协议不可能检测到验证节点的行为是否是故意的。 + +### 贪婪地选择并发分叉 + +当评估多个分叉时,每个验证节点应使用以下规则。 + +1. Forks必须满足_Threshold_规则。 +2. 选取能使所有祖先分叉的总集群锁定时间最大化的分叉。 +3. 选取集群交易费用最大的分叉。 +4. 选取PoH最晚的分叉。 + +群集交易费是指存入矿池的费用,详见[质押奖励](staking-rewards.md)章节。 + +## PoH ASIC抗性 + +投票数和锁定数呈指数级增长,而ASIC的速度是线性增长。 有两种可能的攻击向量涉及更快的ASIC。 + +### ASIC审查 + +攻击者产生一个并发的分叉,它的速度超过了之前的领导者,以达到审查的目的。 这个攻击者提出的分叉将与下一个可用的领导者同时出现。 节点要选择这个分叉,必须满足_Greedy Choice_规则。 + +1. Fork必须对祖先分叉有同等数量的投票。 +2. 分叉不能是一个头,以至于导致票数过期。 +3. Fork必须有更多的群交易费。 + +这种攻击就仅限于删掉前面的领导费,和个人交易费。 但它不能停止集群,也不能减少验证节点集,相比并发的分叉。 费用审查仅限于访问费用去领导,而不是验证节点。 + +### ASIC回滚 + +攻击者从一个旧区块中生成一个并发分叉,试图回滚集群。 在这种攻击中,并发分叉与已经被投票的分叉竞争。 这种攻击受到锁定的指数增长的限制。 + +- 1票有2个时隙的锁定。 并发分叉必须至少领先2个时隙,并在1个时隙内产生。 因此需要快2倍的ASIC。 +- 2票有4个时隙的锁存。 并发分叉必须至少领先4个时隙,并在2个时隙中产生。 因此需要快2倍的ASIC。 +- 3票有8个时隙的锁定。 并发分叉必须至少领先8个时隙,并在3个时隙中生产。 因此需要一个ASIC快2.6倍。 +- 10票有1024个时隙的锁定。 1024/10,即快102.4倍的ASIC。 +- 20票有2^20个时隙的锁定。 2^20/20,或快52428.8倍的ASIC。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/transaction-fees.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/transaction-fees.md new file mode 100644 index 0000000000..ed0cd9a42c --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/transaction-fees.md @@ -0,0 +1,32 @@ +--- +title: 确定性交易费用 +--- + +目前,交易包括一个费用字段,表示插槽领导者处理交易时允许收取的最大费用字段。 而集群则商定一个最低费用。 如果网络拥挤,插槽领导者可能会优先处理提供较高费用的交易。 这意味着在交易被集群确认并检查剩余余额之前,客户端不会知道获得了多少费用。 这闻起来正是我们不喜欢的以太坊"Gas",非确定性的味道。 + +## 拥堵引起的费用 + +验证节点使用_signatures per slot_\(SPS\) 来估计网络拥堵,然后通过_SPS target_来估计集群的期望处理能力。 验证节点从genesis config中获得SPS target信息,而它从最近处理的事务中计算SPS。 Genesis config还定义了一个目标`lamports_per_signature`,这是集群在_SPS target_运行时对每个签名收取的费用。 + +## 费用计算 + +客户端使用 JSON RPC API 来查询集群的当前收费参数。 这些参数被标记了一个区块哈希,并保持有效,直到该区块哈希足够老,被插槽领导者拒绝。 + +在向集群发送交易之前,客户端可以将交易和收费账户数据提交给一个名为_收费计算器_的SDK模块。 只要客户端的SDK版本与插槽领导者的版本相匹配,客户端就可以保证其账户被更改的lamports数量与费用计算器返回的数量完全相同。 + +## 费用参数 + +在该设计的第一个实现中,唯一的收费参数是`lamports_per_signature`。 集群需要验证的签名越多,费用越高。 具体的lamports数量由SPS与SPS目标的比例决定。 在每个时段结束时,当SPS低于目标值时,集群会降低`lamports_per_signature`,当高于目标值时,集群则会相应提高它的值。 `lamports_per_signature`的最小值是目标`lamports_per_signature`的50%,最大值是目标lamports_per_signature的10倍。 + +未来的参数可能包括: + +- `lamports_per_pubkey` - 加载一个账户的费用 +- `lamports_per_slot_dimit` - 加载非常老的账户费用较高 +- `lamports_per_byte` - 按账户大小加载的费用 +- `lamports_per_bpf_instruction` - 运行一个程序的成本 + +## 攻击 + +### 劫持SPS目标 + +一群验证节点如果能说服群组将SPS目标提高到其他验证者能跟上的程度,就可以将群组集中起来。 提高目标会导致费用下降,大概创造更多的需求,从而提高TPS。 如果验证者没有硬件可以那么快地处理那么多交易,它的确认票最终会变得很长,以至于集群将被迫启动它。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/validator-timestamp-oracle.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/validator-timestamp-oracle.md new file mode 100644 index 0000000000..f89c4e32d6 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/implemented-proposals/validator-timestamp-oracle.md @@ -0,0 +1,61 @@ +--- +title: 验证节点时间戳预言机 +--- + +Solana的第三方用户有时需要知道一个区块产生的真实时间,一般是为了满足外部审计人员或执法部门的合规性要求。 本提案描述了一个验证节点时间戳预言机,它将允许Solana集群满足这一需求。 + +提议的实现的总体轮廓如下: + +- 每隔一段时间,每个验证节点记录其在链上已知插槽的观察时间(通过添加到插槽投票中的时间戳)。 +- 客户端可以使用`getBlockTimeRPC`方法请求一个根块的块时间。 当客户端请求块N的时间戳时: + + 1. 验证节点通过观察记录在账本上的所有引用该插槽的时间戳投票指令,确定块N之前的最近时间戳插槽的 "集群 "时间戳,并确定质押加权平均时间戳。 + + 2. 然后,使用该集群建立的插槽持续时间来计算块N的时间戳,使用这个最近的平均时间戳来计算块N的时间表 + +要求: + +- 任何验证节点在未来重放账本时,都必须在创世以来的每一个区块中找到相同的时间。 +- 在解析到真实世界(预言机) 数据之前,估计的区块时间不应偏移超过一个小时左右。 +- 块时间不是由单一的集中式预言机控制的,但理想的情况是基于一个使用所有验证节点输入的函数 +- 每个验证节点必须维护一个时间戳预言机 + +同样的实现可以为尚未生根的区块提供一个时间戳估计。 然而,由于最近的时间戳插槽可能生根,也可能还没有生根,所以这个时间戳将是不稳定的(可能不符合要求1)。 最初的实现将以生根的块为目标,但如果有最近的块时间戳的用例,在未来添加远程调用API将是小事一桩。 + +## 记录时间 + +在对某一插槽位进行投票时,每一个验证节点每隔一段时间就会在其提交的投票指令中加入一个时间戳来记录其观察到的时间。 时间戳对应的插槽位是投票向量中最新的插槽位(`Vote::slots.iter().max()`)。 它和一般的投票一样,由验证节点的身份密钥对签名。 为了实现这个报告,需要扩展Vote结构以包含一个时间戳字段,`timestamp: Option`,在大多数投票中,它将被设置为`None`。 + +从https://github.com/Solana-labs/Solana/pull/10630,验证节点每次投票都会提交一个时间戳。 这样就可以实现一个区块时间缓存服务,允许节点在区块生根后立即计算出估计的时间戳,并将该值缓存在Blockstore中。 这提供了持久的数据和快速查询,同时还能满足上面的需求1)。 + +### 投票账户 + +验证节点的投票账户将在VoteState中保留其最新的插槽期时间戳。 + +### 投票程序 + +链上投票程序需要扩展,以处理验证节点发送的带有投票指令的时间戳。 除了其当前的process_vote功能(包括加载正确的投票账户和验证交易签名者是预期的验证节点),这个过程需要将时间戳和对应的插槽位与当前存储的值进行比较,以验证它们都是单调增加的,并将新的插槽位和时间戳存储在账户中。 + +## 计算质押加权平均时间戳。 + +为了计算某一特定区块的估计时间戳,验证节点首先需要确定最近的时间戳插槽。 + +```text +let timestamp_slot = floor(current_slot / timestamp_interval); +``` + +然后验证节点需要使用`Blockstore::get_slot_entries()`从账本中收集所有引用该插槽的时间戳投票交易。 由于这些交易可能需要一定的时间才能到达并被领导者处理,因此验证节点需要扫描时间戳插槽之后的几个已完成的区块,以获得一组合理的时间戳。 具体的插槽数量需要调整。更多的插槽位将使更多的集群参与和更多的时间戳数据点;更少的插槽位将加快时间戳过滤所需的时间。 + +从这个交易集合中,验证节点计算出质押加权的平均时间戳,交叉引用`staking_utils::staked_nodes_at_epoch()`中的纪元质押。 + +任何验证节点重放账本时,都应该通过处理相同数量的时段的时间戳交易,得出相同的桩号加权平均时间戳。 + +## 计算特定区块的估计时间 + +一旦计算出一个已知插槽的平均时间戳,计算后续块N的估计时间戳就很简单了。 + +```text +let block_n_timestamp = mean_timestamp + (block_n_slot_offset * slot_duration); +``` + +其中`block_n_slot_offset`是区块N的插槽与时间戳插槽之间的差值,`slot_duration`是根据集群的`slots_per_year`得出的。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/integrations/exchange.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/integrations/exchange.md new file mode 100644 index 0000000000..372555c426 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/integrations/exchange.md @@ -0,0 +1,552 @@ +--- +title: 添加 Solana 到您的交易所 +--- + +本指南描述了如何将 Solana 的原生代币 SOL 添加到某个加密货币交易所。 + +## 节点设置 + +我们强烈建议在高级计算机/云端设置至少两个节点实例, 立即升级到较新的版本,并随时注意自带的监测工具的服务操作。 + +这样设置可以让您: +- 为 Solana mainnet-beta 集群设置一个可信的网关来获取数据和提交取现交易 +- 完全控制保留历史区块数据的多少 +- 即使某个节点失败仍然保持您的服务可用性 + +Solana 节点需要较高的计算力来处理我们的快速区块和高 TPS 。 关于具体要求,请参阅[硬件建议](../running-validator/validator-reqs.md)。 + +运行一个 api 节点: + +1. [安装 Solana 命令行工具](../cli/install-solana-cli-tools.md) +2. 启动验证节点时至少使用以下参数: + +```bash +solana-validator \ + --ledger \ + --entrypoint \ + --expected-genesis-hash \ + --rpc-port 8899 \ + --no-voting \ + --enable-rpc-transaction-history \ + --limit-ledger-size \ + --trusted-validator \ + --no-untrusted-rpc +``` + +自定义 `--ledger` 到您所需的账本存储位置, `--rpc-port` 到您想要显示的端口。 + +`--entrypoint` and `--experted-genesis-hash` 参数都针对您正在加入的集群。 [主网 Beta 的当前参数](../clusters.md#example-solana-validator-command-line-2) + +`--limit-ledger-size` 参数允许您指定保留节点的多少个账本 [shreds](../terminology.md#shred) 在磁盘上。 如果您没有配置该参数,验证节点将保留整个账本直到磁盘空间满了为止。 保持账本磁盘使用量的默认值小于 500GB。 如果需要,可以通过添加参数到 `--limit-ledger-size` 来增加或减少磁盘的使用。 查看 `solana-validator --help` 来配置 `--limit-ledger-size` 所使用的默认限制值。 关于选择一个普通限制值的更多信息请参看 [这里](https://github.com/solana-labs/solana/blob/583cec922b6107e0f85c7e14cb5e642bc7dfb340/core/src/ledger_cleanup_service.rs#L15-L26). + +指定一个或多个 `--trusted-validator` 参数可以保护您免遭恶意快照的攻击。 [更多关于使用可信验证程序启动的值](../running-validator/validator-start.md#trusted-validators) + +可选参数: + +- `--private-rpc` 防止您的 RPC 端口被其他节点发布 +- `--rpc-bind-address` 允许您指定一个不同的 IP 地址绑定 RPC 端口 + +### 自动重启和监测 + +我们建议将每个节点配置退出时自动重启,以确保尽可能少地丢失数据。 把 Solana 软件运行为一个系统服务是很好的选择。 + +对于监控,我们提供[`solana-watchtower`](https://github.com/solana-labs/solana/blob/master/watchtower/README.md),它可以监视您的验证节点,并且通过 `solana-validator` 检测节点是否不健康。 它可以直接配置 Slack、Telegram 、Discord 或 Twillio 来提醒您。 详情请运行 `solana-watchtower --help`。 + +```bash +solana-watchtower --validator-identity +``` + +#### 新软件发布公告 + +我们经常发布新软件(大约每周一版)。 有时较新的版本包含不兼容的协议调整,这时候需要及时更新软件,以避免出块产生的错误。 + +我们发布的所有类型的官方公告(正常的和安全)都是通过一个叫做[`#mb-annound`](https://discord.com/channels/428295358100013066/669406841830244375) (`mb` 表示 `mainnet-beta`)。 + +就像已质押的验证节点,我们期望任何交易所操作的验证节点在正常版本后的一个或两个工作日内尽早更新。 对于安全相关的信息,可能会采取更紧急的行动。 + +### 账本持续性 + +默认情况下,您的每个节点都通过可信验证节点提供的快照启动。 这个快照反映了区块链当前的状态,但不包含完整的历史帐本。 如果您的一个节点退出并且通过新的快照启动,那么该节点上的账本中可能会出现一段缺失。 为了防止该问题, 将 `--no-snapshot-fetch` 参数添加到您的 `solana-validator` 命令,来接收历史账本数据(而不是快照)。 + +不要在初次启动时通过 `--no-snapshot-fetch` 参数,因为它不可能追溯到创世区块去启动节点。 相反,您需要先启动快照,然后添加 `--no-snapshot-quetch` 参数来重启。 + +重要的一点是需要注意,在任何时候您的节点从网络其他地方可获取的可用历史账本数量都是有限的。 一旦运行,如果验证节点经历了重大故障,它们可能无法跟上网络,需要从可信的验证节点下载新的快照。 这样做的时候,您的验证节点在它的历史账本数据中将出现一个无法填补的空白。 + + +### 最小化验证节点端口风险 + +验证节点要求从所有其他的 Solana 验证程序中打开 UDP 和 TCP 端口传入流量。 虽然这是最有效率的操作模式,我们也强烈推荐,但是可以将验证节点限制为只需要从另外一个 Solana 验证节点流量接入。 + +首先添加 `--restricted-reparir-only-mode` 参数。 这将会让验证节点在受限制的模式下运行,它将不会收到其他验证节点的消息,而是要不断联系其他验证节点获取区块。 验证节点只能使用 *Gossip* 和 *ServeR* ("服务修理") 端口传输 UDP 包到其他验证节点,并且只有在其 *Gossip* 和 *Repair* 端口上接收 UDP 包。 + +*Gossip* 端口是双向的,允许您的验证节点保持与其他集群的联系。 因为Turbine 现在已被禁用,因此您的验证节点需要在 *ServerR* 上传输信息,以便提出修理请求,从网络其余部分获取新区块。 然后您的验证节点将收到其他验证节点在 *Repair* 端口上的维修回应。 + +要进一步限制验证节点只从一个或多个验证器请求区块,您首先确定该验证节点身份的 Pubkey 为每一个 PUBKEY 添加 `--gossip-pull-validator PUBKEY --resurir-validator PUBKEY` 参数。 这将使你的验证节点成为您添加的每个验证节点上的资源流量, 您是可以这样操作的,并且只有在与目标验证节点请求后才能进行。 + +现在您的验证节点只能与特别指出的验证节点通信并且只能在 *Gossip*,*Repair* 和 *ServeR* 端口上通信。 + +## 设置存款账户 + +Solana 帐户不需要任何链上的初始化设置;只要有 SOL 余额,它们就自动出现。 您可以使用任何我们的 [钱包工具](../wallet-guide/cli.md) 生成一个 Solana 密钥,来设置一个交易所存款帐户。 + +我们建议您为每个用户配置一个独特的存款帐户。 + +Solana 帐户在每个 epoch 都收取一次 [ 租金 ](developing/programming-model/accounts.md#rent),但如果它们的 SOL 价值包括两年,就可以免除租金。 想要找到您存款账户的最低免租余额,请查询[`getMinimumBalanceForRentExemption` 端点](developing/clients/jsonrpc-api.md#getminimumbalanceforrentexemption): + +```bash +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getMinimumBalanceForRentExemption","params":[0]}' localhost:8899 + +{"jsonrpc":"2.0","result":890880,"id":1} +``` + +### 离线账户 + +为了提高的安全性,您可能想离线保存一个或多个收藏账户的密钥。 这时候您需要使用我们的 [ 离线方法](../offline-signing.md) 将 SOL 转移到热钱包。 + +## 正在等待充值 + +如果某个用户想 SOL 存入您的交易所,请指示他们发送一笔金额到相应的存款地址。 + +### 区块投票 + +您可以使用 Solana API 节点的 JSON-RPC 服务来跟踪交易所的所有存款帐户,对每个确认的区块进行调查或检查感兴趣的地址。 + +- 要确定哪些区块处于可用状态,请发送 [`getConfirmedBlocks` request](developing/clients/jsonrpc-api.md#getconfirmedblocks),通过您已经处理过的最后一个块作为启动槽参数: + +```bash +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlocks","params":[5]}' localhost:8899 + +{"jsonrpc":"2.0","result":[5,6,8,9,11],"id":1} +``` + +不是每个 Slot 都会出块,所以在整数序列中可能存在缺口。 + +- 对于每个块,可以通过 [`getConfirmedBlock` request](developing/clients/jsonrpc-api.md#getconfirmedblock) 请求其包含的内容: + +```bash +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[5, "json"]}' localhost:8899 + +{ + "jsonrpc": "2.0", + "result": { + "blockhash": "2WcrsKSVANoe6xQHKtCcqNdUpCQPQ3vb6QTgi1dcE2oL", + "parentSlot": 4, + "previousBlockhash": "7ZDoGW83nXgP14vnn9XhGSaGjbuLdLWkQAoUQ7pg6qDZ", + "rewards": [], + "transactions": [ + { + "meta": { + "err": null, + "fee": 5000, + "postBalances": [ + 2033973061360, + 218099990000, + 42000000003 + ], + "preBalances": [ + 2044973066360, + 207099990000, + 42000000003 + ], + "status": { + "Ok": null + } + }, + "transaction": { + "message": { + "accountKeys": [ + "Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX", + "47Sbuv6jL7CViK9F2NMW51aQGhfdpUu7WNvKyH645Rfi", + "11111111111111111111111111111111" + ], + "header": { + "numReadonlySignedAccounts": 0, + "numReadonlyUnsignedAccounts": 1, + "numRequiredSignatures": 1 + }, + "instructions": [ + { + "accounts": [ + 0, + 1 + ], + "data": "3Bxs3zyH82bhpB8j", + "programIdIndex": 2 + } + ], + "recentBlockhash": "7GytRgrWXncJWKhzovVoP9kjfLwoiuDb3cWjpXGnmxWh" + }, + "signatures": [ + "dhjhJp2V2ybQGVfELWM1aZy98guVVsxRCB5KhNiXFjCBMK5KEyzV8smhkVvs3xwkAug31KnpzJpiNPtcD5bG1t6" + ] + } + } + ] + }, + "id": 1 +} +``` + +` 原先余额 ` 和 ` 交易后余额 ` 字段能让您跟踪余额每个账户中的变动,而无需解析整个交易。 他们将每个账户的最初和交易后余额分别列出在 [ lamports ](../terminology.md#lamport) 中,并索引到 `账户` 列表。 例如,您准备充值的地址是 ` 47Sbuv6jL7CViK9F2NMW51aQGhfdpUu7WNvKyH645Rfi `,它表示一笔 218099990000 - 207099990000 = 11000000000 lamports = 11 SOL 的交易。 + +如果需要更多关于交易类型或其他细节的信息,您可以用二进制格式从 RPC 请求区块,然后使用 [Rust SDK](https://github.com/solana-labs/solana) 或 [Javascript SDK](https://github.com/solana-labs/solana-web3.js) 进行解析。 + +### 地址历史 + +您也可以查询特定地址的交易历史记录。 这通常 *不是* 一种追踪您所有插槽的所有存款地址的可行方法, 但可能检查一段时间内的几个账户非常有用。 + +- 向 api 节点发送 [`getConfirmedSignaturesFors2`](developing/clients/jsonrpc-api.md#getconfirmedsignaturesforaddress2) 请求: + +```bash +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedSignaturesForAddress2","params":["6H94zdiaYfRfPfKjYLjyr2VFBg6JHXygy84r3qhc3NsC", {"limit": 3}]}' localhost:8899 + +{ + "jsonrpc": "2.0", + "result": [ + { + "err": null, + "memo": null, + "signature": "35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby", + "slot": 114 + }, + { + "err": null, + "memo": null, + "signature": "4bJdGN8Tt2kLWZ3Fa1dpwPSEkXWWTSszPSf1rRVsCwNjxbbUdwTeiWtmi8soA26YmwnKD4aAxNp8ci1Gjpdv4gsr", + "slot": 112 + }, + { + "err": null, + "memo": null, + "signature": "dhjhJp2V2ybQGVfELWM1aZy98guVVsxRCB5KhNiXFjCBMK5KEyzV8smhkVvs3xwkAug31KnpzJpiNPtcD5bG1t6", + "slot": 108 + } + ], + "id": 1 +} +``` + +- 对于返回的每个签名,发送 [`getConsulmedTransaction`](developing/clients/jsonrpc-api.md#getconfirmedtransaction) 请求来获取交易细节: + +```bash +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedTransaction","params":["dhjhJp2V2ybQGVfELWM1aZy98guVVsxRCB5KhNiXFjCBMK5KEyzV8smhkVvs3xwkAug31KnpzJpiNPtcD5bG1t6", "json"]}' localhost:8899 + +// 结果 +{ + "jsonrpc": "2.0", + "result": { + "slot": 5, + "transaction": { + "message": { + "accountKeys": [ + "Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX", + "47Sbuv6jL7CViK9F2NMW51aQGhfdpUu7WNvKyH645Rfi", + "11111111111111111111111111111111" + ], + "header": { + "numReadonlySignedAccounts": 0, + "numReadonlyUnsignedAccounts": 1, + "numRequiredSignatures": 1 + }, + "instructions": [ + { + "accounts": [ + 0, + 1 + ], + "data": "3Bxs3zyH82bhpB8j", + "programIdIndex": 2 + } + ], + "recentBlockhash": "7GytRgrWXncJWKhzovVoP9kjfLwoiuDb3cWjpXGnmxWh" + }, + "signatures": [ + "dhjhJp2V2ybQGVfELWM1aZy98guVVsxRCB5KhNiXFjCBMK5KEyzV8smhkVvs3xwkAug31KnpzJpiNPtcD5bG1t6" + ] + }, + "meta": { + "err": null, + "fee": 5000, + "postBalances": [ + 2033973061360, + 218099990000, + 42000000003 + ], + "preBalances": [ + 2044973066360, + 207099990000, + 42000000003 + ], + "status": { + "Ok": null + } + } + }, + "id": 1 +} +``` + +## 发送提现请求 + +要满足用户的提款请求, 您必须生成一笔 Solana 转账交易,并将其发送到 API 节点来扩散到集群中。 + +### 同步 + +发送同步传输到 Solana 集群可以让您轻松保证转账的成功并由集群确定最终性。 + +Solana的命令行工具提供了一个用于生成、提交和确认转账交易的简单命令, `solana transfer`。 默认情况下,该方法将等待并跟踪 stderr 的进度,直到集群确认了某笔交易。 如果交易失败,它将报告任何类型的交易错误。 + +```bash +solana transfer --keypair --url http://localhost:8899 +``` + +[Solana Javascript SDK](https://github.com/solana-labs/solana-web3.js) 为 JS 生态提供了类似的方法。 使用 `SystemProgram` 创造一笔转账交易,然后使用 `sendAndConfirmTransaction` 方法提交。 + +### 异步 + +为了更大的灵活性,您可以异步提交提现转账。 在这些情况下,您有责任验证交易的成功性并由集群最终确认。 + +** 请注意:** 每笔交易都包含一个 [ 最新区块哈希 ](developing/programming-model/transactions.md#blockhash-format) 表明它在线。 在某笔提现交易没有被集群确认或最终确定的时候,如果要重新提现,等待这个区块哈希过期是非常 **重要** 的。 否则,你将会面临双花的风险。 更多内容请参见下方 [blockhash expiration](#blockhash-expiration)。 + +首先,使用 [`getFees` 端点](developing/clients/jsonrpc-api.md#getfees) 或 CLI 命令获取最近的区块哈希: + +```bash +solana fees --url http://localhost:8899 +``` + +在命令行工具中,通过 `--no-wait` 参数发送异步传输,使用 `--blockhash` 参数包含您最近的区块哈希: + +```bash +solana transfer --no-wait --blockhash --keypair --url http://localhost:8899 +``` + +您也可以手动化生成、签名和序列化一笔交易,然后用 JSON-RPC [`发送交易` 端点](developing/clients/jsonrpc-api.md#sendtransaction) 将它关闭到某个集群。 + +#### 交易确认 & 最终性 + +使用 [`getSignatureStatuses` JSON-RPC 端点](developing/clients/jsonrpc-api.md#getsignaturestatuses) 获取一批交易的状态。 `确认` 字段报告了自交易处理后,有多少 [已确认区块](../terminology.md#confirmed-block) 。 如果 `confirmations: null`,那么它就是 [已经确认](../terminology.md#finality)。 + +```bash +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getSignatureStatuses", "params":[["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW", "5j7s6NiJS3JAkvgkoc18WVAsiSaci2pxB2A6ueCJP4tprA2TFg9wSyTLeYouxPBJEMzJinENTkpA52YStRW5Dia7"]]}' http://localhost:8899 + +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 82 + }, + "value": [ + { + "slot": 72, + "confirmations": 10, + "err": null, + "status": { + "Ok": null + } + }, + { + "slot": 48, + "confirmations": null, + "err": null, + "status": { + "Ok": null + } + } + ] + }, + "id": 1 +} +``` + +#### 区块哈希过期 + +当您使用 [`getFees` endpoint](developing/clients/jsonrpc-api.md#getfees) 或 `solana fees` 请求您提款交易最近的区块哈希,响应将包括 `lastValidSlot`,有效区块哈希的最后一个插槽。 您可以使用 [`getSlot` query](developing/clients/jsonrpc-api.md#getslot) 检查集群插槽;一旦集群槽大于`lastValidSlot`,那么使用该区块哈希的提现交易永远不会成功。 + +您也可以通过发送一个以区块哈希作为参数 [`getFeeCalculatorForBlockhash`](developing/clients/jsonrpc-api.md#getfeecalculatorforblockhash) 的请求,来再次确认某个区块哈希是否仍然有效。 如果响应值为空,那么该区块哈希已经过期,提现请求就一定不会成功。 + +### 验证用户提供的提款账户地址 + +由于提款是不可逆过程,因此最好在提款确认之前对用户提供的帐户地址进行验证,以防止用户资产意外丢失。 + +Solana 的普通账户地址是一个 256 位 ed25519 公钥的 Base58 编码字符串。 并非所有位图案都是 ed25519 曲线的有效公共密钥, 这样可以确保用户提供的帐户地址至少是正确的 ed25519 公钥。 + +#### Java + +这是验证用户提供的地址为有效 ed25519 公钥的 Java 示例: + +下面的代码例子假设你正在使用 Maven。 + +`pom.xml`: + +```xml + + ... + + spring + https://repo.spring.io/libs-release/ + + + +... + + + ... + + io.github.novacrypto + Base58 + 0.1.3 + + + cafe.cryptography + curve25519-elisabeth + 0.1.0 + + +``` + +```java +import io.github.novacrypto.base58.Base58; +import cafe.cryptography.curve25519.CompressedEdwardsY; + +public class PubkeyValidator +{ + public static boolean verifyPubkey(String userProvidedPubkey) + { + try { + return _verifyPubkeyInternal(userProvidedPubkey); + } catch (Exception e) { + return false; + } + } + + public static boolean _verifyPubkeyInternal(String maybePubkey) throws Exception + { + byte[] bytes = Base58.base58Decode(maybePubkey); + return !(new CompressedEdwardsY(bytes)).decompress().isSmallOrder(); + } +} +``` + +## 支持 SPL 代币标准 + +[SPL 代币](https://spl.solana.com/token) 是在 Solana 区块链上创建和交易包装/合成代币的标准。 + +SPL 代币的工作流程类似于原生 SOL 代币,但本节将讨论它们的几个不同之处。 + +### 代币铸造 + +每种 *类型* 的 SPL 代币都是由一个 *铸造* 账号所产生。 该帐户存储了代币功能的元数据,如供应量、小数点数和对铸造的多种权限。 每个 SPL Token 帐户引用与它铸造相关的字段,并且只能与该种类型的 SPL 代币交互。 + +### 安装 `spl-token` CLI 工具 + +使用 `spl-token` 命令行功能查询和修改 SPL Token 帐户。 本部分提供的示例取决于能否在本地系统安装。 + +`spl-token` 从 Rust [crates.io](https://crates.io/crates/spl-token) 中通过 Rust `cargo` 命令行功能衍生出来的。 最新版本的 `cargo` 可以在 [rustuprers](https://rustup.rs),通过方便的工具安装在您的平台。 一旦 `cargo` 安装完毕, `spl-toke` 可以通过以下命令获得: + +``` +cargo install spl-token-cli +``` + +然后您可以检查已安装的版本进行验证 + +``` +spl-token --version +``` + +输出结果应该类似于 + +```text +spl-token-cli 2.0.1 +``` + +### 创建帐户 + +SPL 代币账户包含了本地系统程序账户所不具备的额外要求: + +1. 在创建 SPL Token 帐户之前,必须先存入一定数量的代币。 代币帐户可以使用 `spl-token create-account` 命令显式创建, 或者 `spl-token transfer --fund-receiving ...` 命令隐式创建。 +1. 在生效期间,SPL Token 帐户必须保持 [rent-exempt](developing/programming-model/accounts.md#rent-exemption) 状态,因此在创建帐户时需要存入少量的原生 SOL 代币。 对于 SPL Token v2 账户,该数量为 0.00203928 SOL(2 039 280 lamports)。 + +#### 命令行 +创建具有以下属性的 SPL 代币帐户: +1. 关联指定的铸造 +1. 由资产账户的密钥所拥有 + +``` +spl-token create-account +``` + +#### 示例: +``` +$ spl-token create-account AkUFCWTXb3w9nY2n6SFJvBV6VwvFUCe4KBMCcgLsa2ir +Creating account 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkV +Signature: 4JsqZEPra2eDTHtHpB4FMWSfk3UgcCVmkKkP7zESZeMrKmFFkDkNd91pKP3vPVVZZPiu5XxyJwS73Vi5WsZL88D7 +``` + +或者创建指定密钥对的 SPL 代币账户: +``` +$ solana-keygen new -o token-account.json +$ spl-token create-account AkUFCWTXb3w9nY2n6SFJvBV6VwvFUCe4KBMCcgLsa2ir token-account.json +Creating account 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkV +Signature: 4JsqZEPra2eDTHtHpB4FMWSfk3UgcCVmkKkP7zESZeMrKmFFkDkNd91pKP3vPVVZZPiu5XxyJwS73Vi5WsZL88D7 +``` + +### 检查账户余额 + +#### 命令行 +``` +spl-token balance +``` + +#### 示例: +``` +$ solana balance 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkV +0 +``` + +### 代币转移 + +发送代币的源账户是包含余额的实际代币账户。 + +但是收款人地址可以是一个普通的钱包帐户。 如果给定钱包关联的代币帐户不存在,那么将在发送交易的时候创建一个地址,条件是 `--fund-receiver` 所提供的参数。 + +#### 命令行 +``` +spl-token transfer --fund-recipient +``` + +#### 示例: +``` +$ spl-token transfer 6B199xxzw3PkAm25hGJpjj3Wj3WNYNHzDAnt1tEqg5BN 1 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkV +发送 1 个代币 + 发送方:6B199xxzw3PkAm25hGJpjj3Wj3WNYNHzDAnt1tEqg5BN + 接收方:6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkV +签名:3R6tsog17QM8KfzbcbdP4aoMfwgo6hBggJDVy7dZPVmH2xbCWjEj31JKD53NzMrf25ChFjY7Uv2dfCDq4mGFFyAj +``` + +### 充值 +因为每个 `(user, mint)` 对需要在链上有一个单独的帐户,所以建议交易所提前创建批量代币帐户,并分配给各个用户。 这些账户都由交易所账号密钥所拥有。 + +存款交易的监控应遵循上面描述的 [block polling](#poll-for-blocks) 方法。 每个新区块应该扫描获得铸造 SPL 代币的成功交易 [Transfer](https://github.com/solana-labs/solana-program-library/blob/096d3d4da51a8f63db5160b126ebc56b26346fc8/token/program/src/instruction.rs#L92) 或 [Transfer2](https://github.com/solana-labs/solana-program-library/blob/096d3d4da51a8f63db5160b126ebc56b26346fc8/token/program/src/instruction.rs#L252) 指令来引用用户帐户,然后查询 [代币账户余额](developing/clients/jsonrpc-api.md#gettokenaccountbalance) 更新。 + +[Considerations](https://github.com/solana-labs/solana/issues/12318) 正在扩展 `preBalance`和`postBalance` 交易状态元数据字段,来把 SPL代币余额转移包括进去。 + +### 提现 +用户提供的提现地址应该是和普通 SOL 提款地址相同。 + +在执行提款 [transfer](#token-transfers) 之前,交易所应检查地址符合 [上文所述](#validating-user-supplied-account-addresses-for-withdrawals) 的规则。 + +从提款地址为正确的铸币确定关联的代币帐户,并将转账发送到该帐户。 请注意关联的代币帐户现在还不存在,因此交易所应该代表用户为该账户提供资金。 对于 SPL Token v2 账户,为提款账户提供的资金额为 0.00203928 SOL (2,039 280 lamports)。 + +用来提现的 `spl-token transfer` 命令模板为: +``` +$ spl-token transfer --fund-recipient +``` + +### 其他考虑因素 + +#### 冻结权限 +出于法规合规性原因,SPL 代币发行实体可以为与铸造相关联的所有帐户选择保留“冻结权限”。 这允许他们按照需要将一个给定帐户的资产 [冻结](https://spl.solana.com/token#freezing-accounts),直到解冻以后才能使用。 如果开放该功能,冻结权限的公钥将在 SPL 代币的铸造账户中注册。 + +## 测试集成 + +请务必先在 Solana devnet 和 testnet [clusters](../clusters.md) 测试完整的工作流,然后再迁移到 mainnet-beta 上。 Devnet 是最开放和最灵活、最理想的初始开发方式,而 testnet 提供了更现实的集群配置。 Devnet 和 testnet 都有一个水龙头,您可以通过运行 `solana airdrop 10` 获取一些用来开发和测试的 devnet 或 testnet 的 SOL 代币。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/introduction.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/introduction.md new file mode 100644 index 0000000000..fa65f70ecb --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/introduction.md @@ -0,0 +1,33 @@ +--- +title: 简介 +--- + +## Solana是什么? + +Solana是一个开源项目,它实现了一个全新的高性能无许可区块链。 Solana基金会位于瑞士日内瓦,维护着开源项目。 + +## 为什么需要Solana? + +如果平均每个交易不超过176个字节,则标准数据库可能每秒可以处理710,000个交易。 中心化数据库还可以使用称为Optimistic Concurrency Control[\[H.T.Kung, J.T.Robinson (1981)\]](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.65.4735)的分布式系统技术来复制自身并保持高可用性,而不会显着损害交易处理速率。 在Solana,我们证明了这些相同的理论极限同样适用于对抗网络上的区块链。 关键点在哪里? 当节点无法彼此信任时,我们找到了一种共享时间的方法。 一旦节点可以相互信任,40年的分布式系统研究经验就可以应用于区块链了! + +> 也许我们的方法与基于超时(timeout) 算法之间最显着的区别是,使用超时会产生一种传统的分布式算法,其中进程异步运行,而我们的方法产生一种全局同步的算法,其中每个进程在同一时刻都执行相同的操作。 我们的方法似乎与分布式处理的整个目的相矛盾,后者旨在允许不同的进程独立运行并执行不同的功能。 但是,如果分布式系统实际上是单个系统,则必须以某种方式同步进程。 从概念上讲,同步流程的最简单方法是让所有流程同时执行相同的操作。 因此,我们的方法用于实现和执行必要同步的内核——例如,确保两个不同的进程不会尝试在同一时间修改文件。 进程可能只花费一小部分时间来执行同步内核;在其余时间里,它们可以独立运行——例如访问不同的文件。 即使在不需要容错的情况下,这也是我们提倡的一种方法。 该方法的基本简单性使其更易于理解系统的精确属性,这对于了解系统的容错能力至关重要。 [\[L.Lamport (1984)\]](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.71.1078) + +此外,令我们惊讶的是,它可以使用从第一天开始就存在于比特币中的一种机制来实现。 比特币功能称为nLocktime,它可用于使用区块高度而不是时间戳记来对交易进行排序。 作为比特币客户端,如果您不信任网络,则可以使用区块高度而不是时间戳。 事实证明,区块高度是密码学界所谓的“可验证延迟功能”的一个实例。 这是一种表示时间已过去的加密安全方法。 在Solana中,我们使用更细粒度的可验证延迟函数SHA 256哈希链来检查并协调共识。 有了它,我们实现了乐观并发控制,现在正朝着每秒710,000个事务的理论极限迈进。 + +## 文件概述 + +Solana文档描述了Solana开源项目,这是一个从头开始大规模构建的区块链。 它们涵盖了Solana可用的原因,使用方法,工作原理以及即使Solana倒闭以后,很长一段时间内它将继续工作。 Solana架构的目标是证明了存在一套软件算法,当结合使用这些算法来实现区块链时,它消除了软件的性能瓶颈,使交易吞吐量与网络带宽成比例扩展。 该架构继续满足适当区块链的所有三个理想特性:可扩展、安全性和去中心化。 + +该体系结构描述了标准千兆位网络上每秒71万笔交易 \(tps\) 的理论上限,而40GB上每秒2840万tps的交易上限。 此外,该体系结构支持安全,并发地执行以通用编程语言(例如C或Rust)编写的程序。 + +## 什么是 Solana 集群? + +群集是一组可以协同工作的计算机,可以从外部将其视为单个系统。 Solana集群是一组相互独立的计算机,这些计算机一起工作(有时互相冲突),以验证用户提交的不可信程序输出。 只要用户希望及时保留事件的不变记录或这些事件的程序解释,就可以利用Solana集群。 一种用途是跟踪哪些计算机做了有意义的工作来保持群集运行。 另一个用途可能是跟踪对现实世界资产的拥有权。 在每种情况下,集群都会生成一个称为账本的事件记录。 它将在群集的整个生命周期内保留。 只要世界上某个地方的某人维护了的副本,其程序的输出\(可能包含谁拥有什么的记录\) 将永远是可复制的,而与发起它的组织无关。 + +## 什么是SOL? + +SOL是Solana原生代币的名称,可以将其传递给Solana集群中的节点,以换取运行链上程序或验证其输出。 系统可以执行分数SOL的微支付,称为_lamports_。 它们的名称是为了纪念Solana的最大技术影响力[Leslie Lamport](https://en.wikipedia.org/wiki/Leslie_Lamport)。 1 Lamport的值为0.000000001 SOL。 + +## 免责声明 + +本项目中描述的所有索赔、内容、设计、算法、预估、路线图、规格和性能度量均由作者尽力而为。 读者应检查并验证其准确性和真实性。 此外,该项目中的任何内容都不构成投资的行为。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/offline-signing.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/offline-signing.md new file mode 100644 index 0000000000..fa82f9baed --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/offline-signing.md @@ -0,0 +1,140 @@ +--- +title: 离线交易签名 +--- + +一些安全模型要求保留签名密钥,因此签名过程与交易创建和网络广播分开。 示例包括: + +- 从地理位置不同的签名者收集的签名在[多签名方案](cli/usage.md#multiple-witnesses) +- 使用 [气隙(airgapped)](https://en.wikipedia.org/wiki/Air_gap_(networking))签名设备来签名交易 + +本文档介绍了如何使用Solana的CLI分别签名和提交交易。 + +## 支持离线签名的命令 + +当前,有以下命令支持离线签名: + +- [`创建质押账户`](cli/usage.md#solana-create-stake-account) +- [`停用质押`](cli/usage.md#solana-deactivate-stake) +- [`委托质押`](cli/usage.md#solana-delegate-stake) +- [`拆分质押`](cli/usage.md#solana-split-stake) +- [`质押授权`](cli/usage.md#solana-stake-authorize) +- [`设置质押锁定`](cli/usage.md#solana-stake-set-lockup) +- [`转账`](cli/usage.md#solana-transfer) +- [`提现质押`](cli/usage.md#solana-withdraw-stake) + +## 离线签名交易 + +要离线签署交易,请在命令行上传递以下参数 + +1. `--sign-only`,阻止客户端将签名的交易提交到网络。 相反,pubkey/签名对被打印到stdout。 +2. `--blockhash BASE58_HASH`,允许调用者指定用于填写交易的 `最近的区块哈希` 字段。 这可以满足一些目的。例如: _ 取消连接到网络的需要,并通过RPC 查询最近的区块哈希 _ 让签名者能够在多个签名中协调区块哈希方案 + +### 示例:离线签名付款 + +命令 + +```bash +solana@offline$ solana pay --sign-only --blockhash 5Tx8F3jgSHx21CbtjwmdaKPLM5tWmreWAnPrbqHomSJF \ + recipient-keypair.json 1 +``` + +输出 + +```text + +Blockhash: 5Tx8F3jgSHx21CbtjwmdaKPLM5tWmreWAnPrbqHomSJF +Signers (Pubkey=Signature): + FhtzLVsmcV7S5XqGD79ErgoseCLhZYmEZnz9kQg1Rp7j=4vC38p4bz7XyiXrk6HtaooUqwxTWKocf45cstASGtmrD398biNJnmTcUCVEojE7wVQvgdYbjHJqRFZPpzfCQpmUN + +{"blockhash":"5Tx8F3jgSHx21CbtjwmdaKPLM5tWmreWAnPrbqHomSJF","signers":["FhtzLVsmcV7S5XqGD79ErgoseCLhZYmEZnz9kQg1Rp7j=4vC38p4bz7XyiXrk6HtaooUqwxTWKocf45cstASGtmrD398biNJnmTcUCVEojE7wVQvgdYbjHJqRFZPpzfCQpmUN"]}' +``` + +## 将离线签名交易提交到网络 + +若要提交已离线签名的交易,请在命令行传入下面的参数 + +1. `--blockhash BASE58_HASH`,必须与用于签名的区块哈希值相同 +2. `--signer BASE58_PUBKEY=BASE58_SIGNATURE`,离线签名者中的一个。 这直接包含在交易中的pubkey(s) 签名,而不用任何本地秘钥对它进行签名 + +### 示例:提交离线已签名付款 + +命令 + +```bash +solana@online$ solana pay --blockhash 5Tx8F3jgSHx21CbtjwmdaKPLM5tWmreWAnPrbqHomSJF \ + --signer FhtzLVsmcV7S5XqGD79ErgoseCLhZYmEZnz9kQg1Rp7j=4vC38p4bz7XyiXrk6HtaooUqwxTWKocf45cstASGtmrD398biNJnmTcUCVEojE7wVQvgdYbjHJqRFZPpzfCQpmUN + recipient-keypair.json 1 +``` + +输出 + +```text +4vC38p4bz7XyiXrk6HtaooUqwxTWKocf45cstASGtmrD398biNJnmTcUCVEojE7wVQvgdYbjHJqRFZPpzfCQpmUN +``` + +## 多个会话的离线签名 + +离线签名也可以在多个会话中进行。 在这种情况下,请为每个角色传递缺席签名者的公钥。 所有指定但未生成签名的发布密钥将在离线签名输出中列出为不存在 + +### 示例:通过两个离线签名会话进行传输 + +命令(离线会话 #1) + +```text +solana@offline1$ solana transfer Fdri24WUGtrCXZ55nXiewAj6RM18hRHPGAjZk3o6vBut 10 \ + --blockhash 7ALDjLv56a8f6sH6upAZALQKkXyjAwwENH9GomyM8Dbc \ + --sign-only \ + --keypair fee_payer.json \ + --from 674RgFMgdqdRoVtMqSBg7mHFbrrNm1h1r721H1ZMquHL +``` + +输出 (离线会话 #1) + +```text +Blockhash: 7ALDjLv56a8f6sH6upAZALQKkXyjAwwENH9GomyM8Dbc +Signers (Pubkey=Signature): + 3bo5YiRagwmRikuH6H1d2gkKef5nFZXE3gJeoHxJbPjy=ohGKvpRC46jAduwU9NW8tP91JkCT5r8Mo67Ysnid4zc76tiiV1Ho6jv3BKFSbBcr2NcPPCarmfTLSkTHsJCtdYi +Absent Signers (Pubkey): + 674RgFMgdqdRoVtMqSBg7mHFbrrNm1h1r721H1ZMquHL +``` + +命令(离线会话 #2) + +```text +solana@offline2$ solana transfer Fdri24WUGtrCXZ55nXiewAj6RM18hRHPGAjZk3o6vBut 10 \ + --blockhash 7ALDjLv56a8f6sH6upAZALQKkXyjAwwENH9GomyM8Dbc \ + --sign-only \ + --keypair from.json \ + --fee-payer 3bo5YiRagwmRikuH6H1d2gkKef5nFZXE3gJeoHxJbPjy +``` + +输出 (离线会话 #2) + +```text +Blockhash: 7ALDjLv56a8f6sH6upAZALQKkXyjAwwENH9GomyM8Dbc +Signers (Pubkey=Signature): + 674RgFMgdqdRoVtMqSBg7mHFbrrNm1h1r721H1ZMquHL=3vJtnba4dKQmEAieAekC1rJnPUndBcpvqRPRMoPWqhLEMCty2SdUxt2yvC1wQW6wVUa5putZMt6kdwCaTv8gk7sQ +Absent Signers (Pubkey): + 3bo5YiRagwmRikuH6H1d2gkKef5nFZXE3gJeoHxJbPjy +``` + +命令(在线提交) + +```text +solana@online$ solana transfer Fdri24WUGtrCXZ55nXiewAj6RM18hRHPGAjZk3o6vBut 10 \ + --blockhash 7ALDjLv56a8f6sH6upAZALQKkXyjAwwENH9GomyM8Dbc \ + --from 674RgFMgdqdRoVtMqSBg7mHFbrrNm1h1r721H1ZMquHL \ + --signer 674RgFMgdqdRoVtMqSBg7mHFbrrNm1h1r721H1ZMquHL=3vJtnba4dKQmEAieAekC1rJnPUndBcpvqRPRMoPWqhLEMCty2SdUxt2yvC1wQW6wVUa5putZMt6kdwCaTv8gk7sQ \ + --fee-payer 3bo5YiRagwmRikuH6H1d2gkKef5nFZXE3gJeoHxJbPjy \ + --signer 3bo5YiRagwmRikuH6H1d2gkKef5nFZXE3gJeoHxJbPjy=ohGKvpRC46jAduwU9NW8tP91JkCT5r8Mo67Ysnid4zc76tiiV1Ho6jv3BKFSbBcr2NcPPCarmfTLSkTHsJCtdYi +``` + +输出 (在线提交) + +```text +ohGKvpRC46jAduwU9NW8tP91JkCT5r8Mo67Ysnid4zc76tiiV1Ho6jv3BKFSbBcr2NcPPCarmfTLSkTHsJCtdYi +``` + +## 购买更多时间来签名 + +通常,Solana交易必须由网络在其`recent_blockhash`字段中距区块哈希值数个插槽内进行签名并接受(在撰写本文时约为2分钟)。 如果您的签名过程花费的时间超过此时间,则[Durable Transaction Nonce](offline-signing/durable-nonce.md) 可以为您提供所需的额外时间。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/offline-signing/durable-nonce.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/offline-signing/durable-nonce.md new file mode 100644 index 0000000000..dc6234ccd9 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/offline-signing/durable-nonce.md @@ -0,0 +1,226 @@ +--- +title: 持久交易随机数(Nonces) +--- + +持久交易随机数是一个机制,它可以绕过交易典型的个短寿期 [`recent_blockhash`](developing/programming-model/transactions.md#recent-blockhash)。 这些方案是作为Solana方案实施的,其机制详见 [proposal](../implemented-proposals/durable-tx-nonces.md)。 + +## 使用示例 + +持久的 nonce CLI 命令的详细使用情况可在 [CLI 引用](../cli/usage.md) 中找到。 + +### Nonce 授权 + +可以将对临时帐户的权限分配给另一个帐户。 这样,新授权机构将继承先前的授权机构(包括帐户创建者)对临时帐户的完全控制权。 通过此功能,可以创建更复杂的帐户的所有权安排以及与密钥对无关的派生帐户地址。 `--nonce-authority ` 参数用于指定此帐户,并且受以下命令: + +- `create-nonce-account` +- `new-nonce` +- `withdraw-from-nonce-account` +- `authorize-nonce-account` + +### Nonce 帐户创建 + +持久性交易随机数功能使用一个帐户来存储下一个随机数值。 持久的现时帐户必须为[免租](../implemented-proposals/rent.md#two-tiered-rent-regime),因此需要最低余额才能实现此目的。 + +通过首次生成一个新的密钥对,然后在链上创建该帐户来创建一个 nonce 帐户。 + +- 命令 + +```bash +solana-keygen new -o nonce-keypair.json +solana create-nonce-account nonce-keypair.json 1 +``` + +- 输出 + +```text +2SymGjGV4ksPdpbaqWFiDoBz8okvtiik4KE9cnMQgRHRLySSdZ6jrEcpPifW4xUpp4z66XM9d9wM48sA7peG2XL +``` + +> 要保持密钥对完全离线,请使用 [纸钱包](wallet-guide/paper-wallet.md) 密钥生成 [指令](wallet-guide/paper-wallet.md#seed-phrase-generation) + +> [完整使用文档](../cli/usage.md#solana-create-nonce-account) + +### 查询存储Nonce值 + +创建持久的随机数交易需要在签名和提交时将存储的随机数值作为值传递给`--blockhash`参数。 使用以下方法获取当前存储的当前值: + +- 命令 + +```bash +solana nonce none-non-keypair.json +``` + +- 输出 + +```text +8GRipryfxcsxN8mAGjy8zbFo9ezaUsh47TsPzmZbuytU +``` + +> [完整使用文档](../cli/usage.md#solana-get-nonce) + +### 提升存储Nonce值 + +尽管通常不需要在更有用的交易之外进行存储,但存储的当前值可以通过以下方式获取: + +- 命令 + +```bash +solana new-nonce none-non-keypair.json +``` + +- 输出 + +```text +44jYe1yPKrjuYDmoFTdgPjg8LFpYyh1PFKJqm5SC1PiSyAL8iw1bhadcAX1SL7KDmREEkmHpYvreKoNv6fZgfvUK +``` + +> [完整使用文档](../cli/usage.md#solana-new-nonce) + +### 显示Nonce账户 + +以更人性化的格式检查nonce 帐户 + +- 命令 + +```bash +solana non-account non-ceypair.json +``` + +- 输出 + +```text +balance: 0.5 SOL +minimum balance required: 0.00136416 SOL +nonce: DZar6t2EaCFQTbUP4DHKwZ1wT8gCPW2aRfkVWhydkBvS +``` + +> [完整使用文档](../cli/usage.md#solana-nonce-account) + +### 从Nonce帐号提取资产 + +通过以下方式从 nonce 帐户提取资产 + +- 命令 + +```bash +solana withdraw-from-nonce-account nonce-keypair.json ~/.config/solana/id.json 0.5 +``` + +- 输出 + +```text +3foNy1SBqwXSsfSfTdmYKDuhnVheRnKXpoPySiUDBVeDEs6iMVokgqm7AqfTjbk7QBE8mqomvMUMNQhtdMvFLide +``` + +> 通过提取全部余额关闭nonce账户 + +> [完整使用文档](../cli/usage.md#solana-withdraw-from-nonce-account) + +### 为Nonce账户分配新的授权 + +创建后重新分配 nonce 帐户的授权 + +- 命令 + +```bash +solana authorize-non-account non-keypair.json nonce-authority.json +``` + +- 输出 + +```text +3F9cg4zN9wHxLGx4c3cUKmqpej4oa67QbALmChsJbfxTgTffRiL3iUehVhR9wQmWgPua66jPuAYeL1K2pYYjbNoT +``` + +> [完整使用文档](../cli/usage.md#solana-authorize-nonce-account) + +## 支持持久Nonce的其他命令 + +要将持久随机数与其他CLI子命令一起使用,必须支持两个参数。 + +- `--nonce`,指定帐户存储 nonce 值 +- `--nonce-authority`,指定一个可选的 [nonce authority](#nonce-authority) + +到目前为止,以下子命令已接受此处理 + +- [`支付`](../cli/usage.md#solana-pay) +- [`委托质押`](../cli/usage.md#solana-delegate-stake) +- [`停用质押`](../cli/usage.md#solana-deactivate-stake) + +### 使用持久Nonce的支付示例 + +在这里,我们演示了Alice使用持久 nonce 向Bob 1 SOL支付的费用。 对于支持持久随机数的所有子命令,该过程相同 + +#### - 创建帐户 + +首先,我们需要为Alice、Alice的none和Bob准备一些账户 + +```bash +$ solana-keygen new -o alice.json +$ solana-keygen new -o nonce.json +$ solana-keygen new -o bob.json +``` + +#### - Alice账户充值 + +Alice 需要一些资产来创建一个 nonce 帐户并发送给 Bob。 空投一些SOL给她 + +```bash +$ solana airdrop -k alice.json 10 +10 SOL +``` + +#### - 创建 Alice 的 nonce 帐户 + +现在Alice需要一个nonce 帐户。 创建一个 + +> 这里没有单独的 [nonce authority](#nonce-authority) 被使用,所以 `alice.json` 对nonce 帐户拥有完全的权限 + +```bash +$ solana create-nonce-account -k alice.json nonce.json 1 +3KPZr96BTsL3hqera9up82KAU462Gz31xjqJ6ehuAjF935Yf8i1kmfEbo6SVbNaACKE5z6gySrNjVRvmS8DcPuwV +``` + +#### - 支付给 Bob 的首次失败尝试 + +Alice 试图为支付给 Bob,但签名需要太长时间。 指定的区块哈希已经过期,导致交易失败 + +```bash +$ solana pay -k alice.json --blockhash expiredDTaxfagttWjQweib42b6ZHADSx94Tw8gHx3W7 bob.json 1 +[2020-01-02T18:48:28.462911000Z ERROR solana_cli::cli] Io(Custom { kind: Other, error: "Transaction \"33gQQaoPc9jWePMvDAeyJpcnSPiGUAdtVg8zREWv4GiKjkcGNufgpcbFyRKRrA25NkgjZySEeKue5rawyeH5TzsV\" failed: None" }) +Error: Io(Custom { kind: Other, error: "Transaction \"33gQQaoPc9jWePMvDAeyJpcnSPiGUAdtVg8zREWv4GiKjkcGNufgpcbFyRKRrA25NkgjZySEeKue5rawyeH5TzsV\" failed: None" }) +``` + +#### - 用 Nonce 来补救! + +Alice 重试交易,这次指定她的nonce账户和存储在那里的区块哈希。 + +> 记住,`alice.json` 是这个示例中的 [nonce 授权](#nonce-authority) + +```bash +$ solana nonce-account nonce.json +balance: 1 SOL +minimum balance required: 0.00136416 SOL +nonce: F7vmkY3DTaxfagttWjQweib42b6ZHADSx94Tw8gHx3W7 +``` + +```bash +$ solana pay -k alice.json --blockhash F7vmkY3DTaxfagtWjQweib42b6ZHADSx94Tw8gHx3W7 --nonce nonce.json bob.json 1 +HR1368UKHVZyenmH7yVz5sBAijV6XAPeWbEiXEGVYQorRMcoijeNAbzZqEZiH8cDB8tk65ckeegFjK8dHwNFgQ +``` + +#### - 成功了! + +交易成功! Bob 从 Alice 那里收到1个SOL,并且Alice存储的nonce更新到了一个新的值 + +```bash +$ solana balance -k bob.json +1 SOL +``` + +```bash +$ solana nonce-account nonce.json +balance: 1 SOL +minimum balance required: 0.00136416 SOL +nonce: 6bjroqDcZgTv6Vavhqf81oBHTv3aMnX19UTB51YhAZnN +``` diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/accepted-design-proposals.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/accepted-design-proposals.md new file mode 100644 index 0000000000..2f52dd3f26 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/accepted-design-proposals.md @@ -0,0 +1,5 @@ +--- +title: 已接受的提案 +--- + +以下架构建议已被Solana团队接受,但尚未完全实施。 提案可以按所描述的方式实施,也可以随着设计中的问题变得明显而采用其他方式实施,或者根本不实施。 如果实施,则提案将移至[已实施的提案](../implemented-proposals/implemented-proposals.md),并将详细信息添加到相关文档。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/bankless-leader.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/bankless-leader.md new file mode 100644 index 0000000000..25485f86c5 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/bankless-leader.md @@ -0,0 +1,57 @@ +--- +title: 见证领导人 +--- + +见证领导人做较少的工作便能产生有效的区块。 其任务是处理区块交易,对有效交易进行分类和过滤,将它们排列成条目,并广播每一个单元条目。 每个验证者只需要重新组装块并重新审查格式正确的条目即可。 见证领导人在执行任何存储区之前,执行的内存工作要比每个验证者处理的交易多3倍。 + +## 基本原理 + +正常的验证者需要进行2次加载和2次存储。 有了这个见证领导人,只需要1个负载即可。 因此在生成该区块之前,验证者的工作量要少4倍。 存储操作可能比读取操作更昂贵。 + +当重新审查阶段开始处理相同的交易时,可以审查历史证明的有效性,并且所有条目对于并行执行都是安全的。 已被加载以生成该块的费用帐户可能仍在内存中,因此额外的负载应处于预热状态,并且成本可能会平摊。 + +## 费用账户 + +[费用账户](../terminology.md#fee_account) 支付的交易费用被包括在区块中。 领导者仅需要验证费用帐户是否有余额来支付费用。 + +## 余额缓存 + +在领导者连续出块的持续时间内,领导者为所有已处理的费用帐户创建一个临时余额缓存。 缓存是从公钥到"Lamport"的映射。 + +在第一个程序段开始时,余额缓存为空。 在最后一个区块的末尾,缓存将被销毁。 + +在整个缓存期间,余额缓存查找必须引用相同的基叉。 在区块与区块交界处,可以在重播阶段完成对前一个块的验证之后,将缓存与基叉一起重置。 + +## 余额检查 + +在进行余额检查之前,领导者会验证交易中的所有签名。 + +1. 确认帐户未使用且区块哈希有效。 +2. 检查收费帐户是否存在于高速缓存中,或从"accounts_db"加载帐户并将"Lamport"余额存储在高速缓存中。 +3. 如果余额少于费用,请取消交易。 +4. 从余额中减去费用。 +5. 对于交易中的所有属于信用借记并被指示引用的密钥,将其余额在缓存中减少为0。 帐户费用被声明为贷方借方,但是只要未在任何指令中使用该帐户费用,其余额就不会减少为0。 + +## 领导者重播 + +领导者将需要重新广告播区块,作为标准重播阶段操作的一部分。 + +## 带连续区块的领导者重播 + +可以安排一个领导者连续生产多个块。 在那种情况下,领导者可能会在广播第一个区块的重播阶段时产生下一个区块。 + +领导者完成重播阶段后,可以通过清除余额缓存来重置余额缓存,并重新设置缓存,该缓存可以在下一个块中变为活动状态。 + +## 重置余额缓存 + +1. 在区块的开头,如果未初始化余额缓存,则将余额缓存的基叉设置为区块的父代,并创建一个空缓存。 +2. 如果缓存已初始化,请检查区块的父级是否有一个新的冻结账本,该冻结账本比余额缓存的当前基叉要新。 +3. 如果存在比缓存的基本派生更新的父代,请将缓存重置为父代。 + +## 对客户端的影响 + +相同的费用帐户可以在同一区块中多次重复使用,直到指令将其用作贷方借方一次为止。 + +每秒传输大量交易的客户应使用专用的费用帐户,该费用帐户在任何指令中均不得用作贷方借方。 + +一旦将帐户费用用作贷方借方,它将无法进行余额检查,直到重置余额缓存为止。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/block-confirmation.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/block-confirmation.md new file mode 100644 index 0000000000..6090f904c5 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/block-confirmation.md @@ -0,0 +1,45 @@ +--- +title: 区块确认 +--- + +验证节点对历史证明哈希投票有两个目的。 首先,投票表明它认为该账本在该时间点之前是有效的。 其次,由于在给定的高度上可能存在许多有效的分叉,因此投票也表示对该分叉的排他性支持。 本文档仅描述前者。 后者在 [Tower BFT](../implemented-proposals/tower-bft.md) 中进行了描述。 + +## 当前设计 + +要开始投票,验证节点首先注册一个帐户,投票将发送到该帐户。 然后,它将投票发送到该帐户。 投票包含正在投票的块的刻度高度。 该帐户存储32个最高高度。 + +### 面临的问题 + +- 只有验证节点知道如何直接找到自己的选票。 + + 其他组件,例如计算确认时间的组件,需要放入验证节点代码中。 验证节点代码向银行查询投票程序拥有的所有帐户。 + +- 投票选票不包含历史证明哈希。 验证节点仅投票表明它已观察到某个高度的任意块。 + +- 投票选票不包含验证节点状态的哈希值。 没有该哈希值,就没有证据表明验证节点执行了交易并确认没有重复消费。 + +## 拟定设计 + +### 初始状态无跨区块 + +在生成区块的那一刻,领导者应向分类账中添加一个新区块交易,其中包含代表验证奖励的多个代币。 它实际上是一个增量的多重签名事务,它将代币从矿池发送到验证节点。 该帐户应分配足够的空间来收集实现多数票所需的票数。 当验证节点观察到新区块交易时,它可以选择提交包含其账本状态(验证节点状态) 的哈希值的投票。 帐户获得足够的票数后,投票程序应将代币分配给验证节点,这将导致帐户被删除。 + +#### 日志确认时间 + +账本需要知道投票方案。 每次交易后,应该检查它是否属于一个投票交易,如果是,就需要检查该帐户的状态。 如果交易通过绝大多数实现了,它应该记录提交NewBlock交易以来的时间。 + +### 最终确认和付款 + +[Tower BFT](../implemented-proposals/tower-bft.md) 是拟议的分叉选择算法。 它提议将付给矿工的款项推迟到 _堆栈_ 的验证节点投票达到一定深度, 通过这样来防止回滚。 因此,投票程序可能会实现 Tower BFT 。 投票指令需要引用一个全局Tower帐户,以便它能够跟踪交叉区块状态。 + +## 难点 + +### 链上投票 + +使用程序和帐户来实现这一点有点乏味。 最难的部分是弄清楚要在新区块中分配多少空间。 这两个变量是这些验证程序的 _活动集_ 和质押。 如果我们在提交新区块时计算活动集,则预先知道要为其分配空间的验证节点的数量。 但是,如果我们允许新的验证节点对旧块进行投票,那么我们需要一种动态分配空间的方法。 + +从本质上讲,如果领导者在新区块时缓存股份,则投票程序在处理投票时无需与银行进行交互。 如果我们不这样做,那么我们可以选择允许质押浮动,直到提交投票为止。 可以想像的是,验证节点可以引用其自己的质押帐户,但这将是当前帐户值,而不是最后确定的账本状态的帐户值。 账本目前不提供从特定时间点引用帐户的方法。 + +### 投票对前几个区块的影响 + +对一个高度进行投票是否意味着对该分叉的所有较低高度的区块进行投票? 如果是这样,我们将需要一种方法来查找尚未达到绝大多数的所有区块的账户。 如果不是,验证节点可以将投票明确地发送到所有区块以获得区块奖励。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/cluster-test-framework.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/cluster-test-framework.md new file mode 100644 index 0000000000..5f95313097 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/cluster-test-framework.md @@ -0,0 +1,103 @@ +--- +title: 群集测试框架 +--- + +本文档提出了集群测试框架\(CTF\)。 CTF 是一个测试工具,它对一个当地、程序中或已部署的集群进行测试。 + +## 激励措施 + +CTF 的目标是提供一个不论该组部署在何处和如何部署的情况下编写检验报告的框架。 这些试验可以根据部署的集群进行回归测试,从而核查部署情况。 这些测试的重点在于集群稳定性、共识、容错性和 API 稳定性。 + +测试用于验证单个错误或场景,并且写入最少接触测试的内部管道数量。 + +## 设计概览 + +测试提供了一个切入点,它是一个 `contact_info::ContactInfo` 结构和已经有金额的密钥对。 + +集群中的每个节点在启动时都已经配置 `validator::ValidatorConfig`。 在启动时,该配置指定了测试所需的额外集群配置。 当集群已经运行或处于数据中心时,集群应当与配置一起启动。 + +一旦启动后,测试将通过 gossip 入口点发现集群,并通过验证节点 RPC 配置任何运行状况。 + +## 测试接口 + +每次 CTF 测试都从一个模糊的切入点和一个有资金的密钥对开始。 试验不应取决于该群集的部署方式,并且应该通过公开的接口使用所有的集群功能。 + +```text +use crate::contact_info::ContactInfo; +use solana_sdk::signature::{Keypair, Signer}; +pub fn test_this_behavior( + entry_point_info: &ContactInfo, + funding_keypair: &Keypair, + num_nodes: usize, +) +``` + +## 群集发现 + +在测试开始时,集群已经建立并且完全连接。 测试可以在几秒钟内发现大多数可用的节点。 + +```text +use crate::gossip_service::discover_nodes; + +// 在几秒钟之内发现集群。 +let cluster_nodes = discover_nodes(&entry_point_info, num_nodes); +``` + +## 集群配置 + +为了启用特定场景,需要通过特殊配置启动集群。 这些配置可以在 `validator::ValidatorConfig` 中查看。 + +例如: + +```text +let mut validator_config = ValidatorConfig::default(); +validator_config.rpc_config.enable_validator_exit = true; +let local = LocalCluster::new_with_config( + num_nodes, + 10_000, + 100, + &validator_config + ); +``` + +## 如何设计一个新测试 + +例如,有一个错误表示,当集群被无效散播的 gossip 节点挟持时,集群会失败。 我们的 gossip 库和协议可能会改变,但集群必须保持应对无效散播节点的能力。 + +配置 RPC 服务: + +```text +let mut validator_config = ValidatorConfig::default(); +validator_config.rpc_config.enable_rpc_gossip_push = true; +validator_config.rpc_config.enable_rpc_gossip_refresh_active_set = true; +``` + +连接 RPP 并写入一个新测试: + +```text +pub fn test_large_invalid_gossip_nodes( + entry_point_info: &ContactInfo, + funding_keypair: &Keypair, + num_nodes: usize, +) { + let cluster = discover_nodes(&entry_point_info, num_nodes); + + // 攻击集群。 + let client = create_client(entry_point_info.client_facing_addr(), VALIDATOR_PORT_RANGE); + for _ in 0..(num_nodes * 100) { + client.gossip_push( + cluster_info::invalid_contact_info() + ); + } + sleep(Durration::from_millis(1000)); + + // 强迫在线节点结合进行重启。 + for node in &cluster { + let client = create_client(node.client_facing_addr(), VALIDATOR_PORT_RANGE); + client.gossip_refresh_active_set(); + } + + // 验证该笔交易仍然有效。 + verify_spends(&cluster); +} +``` diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/embedding-move.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/embedding-move.md new file mode 100644 index 0000000000..19503b6180 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/embedding-move.md @@ -0,0 +1,37 @@ +--- +title: 嵌入Move编程语言 +--- + +## 面临的问题 + +Solana使开发人员能够使用通用编程语言(例如C或Rust)编写链上程序,但这些程序包含特定于Solana的机制。 例如,没有其他区块链要求开发人员使用`process_instruction(KeyedAccounts)`函数创建Rust模块。 如果可以,Solana应该为应用程序开发者提供更多可移植的选项。 + +直到最近,还没有流行的区块链提供一种可以揭示Solana大规模并行[runtime](../validator/runtime.md)价值的语言。 例如,Solidity合约不会将对共享数据的引用与合约代码分开,因此需要顺序执行以确保确定性行为。 在实践中,我们看到最积极优化的基于EVM的区块链似乎都达到了约1,200 TPS的峰值——但这只是Solana能做到的冰山一角。 另一方面,Libra项目设计了一种称为Move的链上编程语言,该语言更适合于并行执行。 像Solana的runtime一样,Move程序依赖于帐户的所有共享状态。 + +Solana的runtime和Libra的Move VM之间最大的设计差异是它们如何管理模块之间的安全调用。 Solana采用操作系统方法,而Libra采用特定领域语言方法。 在runtime中,模块必须捕获回到runtime中,以确保调用方的模块未写入被调用方拥有的数据。 同样,当被调用方完成操作时,它必须再次陷阱回到runtime,以确保被调用方未写入调用方拥有的数据。 另一方面,Move包含一个高级类型的系统,该系统允许其字节码验证程序运行这些检查。 由于可以验证Move字节码,因此在链上加载模块时,只需支付一次验证费用。 在runtime中,每笔交易在模块之间交叉时都要支付费用。 从本质上讲,这种区别类似于动态类型的语言(如Python)与静态类型的语言(如Java)之间的差异。 Solana的runtime允许使用通用编程语言编写应用程序,但这在程序之间跳转时会带来runtime检查的费用。 + +该提议尝试定义一种嵌入Move VM的方式,从而实现: + +- 跨模块调用中,Move不需要runtime的跨程序 + + 跨程序runtime检查 + +- Move程序可以利用其他Solana程序中的功能,反之 + + 亦然 + +- Solana的runtime并行性暴露于批量Move和non-Move中的 + + 交易 + +## 拟定的解决方案 + +### 将Move VM作为Solana加载器 + +Move VM应该作为Solana加载器嵌入在标识符`MOVE_PROGRAM_ID`下,以便可以将Move模块标记为`可执行的`,而VM是其`所有者`。 这将允许模块加载模块依赖性,支持并行执行Move脚本。 + +Move模块拥有的所有数据帐户必须将其所有者设置为加载程序`MOVE_PROGRAM_ID`。 由于Move模块以与Solana程序封装其帐户相同的方式封装其帐户数据,因此Move模块所有者应嵌入在帐户数据中。 Runtime将授予对Move VM的写访问权限,而Move将授予对模块帐户的访问权限。 + +### 与Solana程序交互 + +要在非Move程序中调用指令,Solana需要通过`process_instruction()`系统调用来扩展MoveVM。 它和Rust BPF程序的`process_instruction()`方法一样。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/interchain-transaction-verification.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/interchain-transaction-verification.md new file mode 100644 index 0000000000..0bf02ec1b3 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/interchain-transaction-verification.md @@ -0,0 +1,105 @@ +--- +title: 跨链之间交易验证 +--- + +## 面临的问题 + +链间应用程序对于数字资产生态系统而言并不是新事物。 实际上,就用户和数量而言,即使是较小的集中式交换机也绝对使所有组合在一起的单链应用程序相形见绌。 他们估值巨大,并花费了数年时间为众多最终用户有效地优化了其核心产品。 但是,它们的基本都要求用户单方面信任其机制,通常很少或根本没有追索权或对意外损失的保护。 这导致更广泛的数字资产生态沿网络断裂,因为互操作性解决方案通常具有以下特点: + +- 技术复杂,无法全面实施 +- 网络规模激励机制不稳定 +- 要求质押者之间保持一致和高级别合作 + +## 拟定的解决方案 + +简单付款验证\(SPV\) 是大多数主要区块链网络上的轻客户端使用的一系列不同方法的通用术语,用于验证网络状态的各个方面,而无需完全存储和维护链本身的负担。 在大多数情况下,这意味着要依靠某种哈希树的形式,通过与该区块标头中的根哈希值或等效值进行比较,来证明某个交易中存在给定交易的证据。 这允许轻量级客户端或钱包本身就链上事件达到概率的确定性级别,而对网络节点的信任度要求最低。 + +传统上,这些证明的组装和验证过程是由节点,钱包或其他客户端在链下执行的,但它也为链间状态验证提供了一种潜在的机制。 但是,通过将验证SPV证明作为智能合约在链上的功能转移到一边,同时又利用了区块链固有的存储属性,有可能构建一个系统来以编程方式检测和验证其他网络上的交易,而无需涉及任何类型的受信任预言机或复杂的多阶段共识机制。 此概念可广泛应用于具有SPV机制的任何网络,甚至可以在其他智能合约平台上双向操作,从而开辟了廉价、快速链间价值转移的可能性,而无需依赖抵押品,哈希锁或受信任的中介机构。 + +选择利用所有主要区块链已经通用的,建立良好且发展稳定的机制,可以使基于SPV的互操作性解决方案比精心设计的多阶段方法要简单得多。 为此,他们无需广泛同意的跨链通信标准,也不需要大型的多方组织来编写它们,而是支持一套离散的基于合约的服务,这些服务可以由主叫合约通过通用的抽象格式协议轻松地使用。 这将为广泛的应用程序和合约奠定基础,这些应用和合约能够在多样化的平台和每个成长中的平台生态中相互操作。 + +## 术语 + +SPV程序 - 链间SPV系统的面向客户端的界面,管理参与者的角色。 SPV引擎 - 验证交易证明,为SPV程序的子集。 客户 - SPV程序的调用者,通常是另一个solana合约。 证明者 - 生成交易证明并将其提交给SPV程序的一方。 交易证明 - 由Provers创建,包含商业证明,交易和区块头参考。 Merkle证明 - 基本的SPV证明,用于验证特定区块中交易的存在。 区块头 - 表示给定区块的基本参数和相对位置。 证明请求 - 客户下达的由证明人验证(一笔或多笔) 交易的订单。 区块头存储 - 一种数据结构,用于存储和引用证明中区块头的范围。 客户请求 - 从客户到SPV程序的交易,以触发创建证明请求。 子帐户 - 另一个合约帐户拥有的Solana帐户,没有自己的私钥。 + +## 服务 + +SPV程序通过部署在Solana网络上的合约形式运行,并维护着SPV证明的公开市场,允许任何一方提交证明请求以及根据请求进行验证。 在任何给定时间,将有多个SPV程序实例处于活动状态,每个连接的外部网络至少有一个实例,并且每个网络可能有多个实例。 SPV程序实例的高级API和功能集将相对一致,并且货币平台\(Bitcoin, Litecoin\) 和智能合约平台之间会有一些差异,这是由于可以验证网络状态的变化,而不仅仅是交易本身。 在任何情况下,无论使用哪种网络,SPV程序都依赖于称为SPV引擎的内部组件,以提供对实际SPV证明的无状态验证,并以此为基础构建面向高级客户端的功能和api。 SPV引擎需要针对特定网络实施,但支持执行该实施并将其放入标准SPV程序中进行部署的任何团队,都可以轻松扩展较大的链间生态。 + +在Proof Request中,请求者被称为程序客户端, 在大多数情况下,如果不是所有情况下都是另一份Solana合约。 客户可以选择提交与特定交易有关的请求,也可以选择更广泛的过滤器,该过滤器可以应用于交易的一系列参数中的任何一个,包括其输入,输出和金额。 例如,客户可以在一定时间后提交从给定地址A发送到地址B且金额为X的任何交易的请求。 此结构可用于多种应用程序,例如在原子交换的情况下验证特定的预期付款或检测贷款的抵押资产的变动。 + +提交客户请求后,假设已成功验证该请求,则SPV程序将创建一个证明请求帐户,以跟踪请求的进度。 证明者使用该帐户指定他们打算填写其提交以供验证的证明的请求,这时SPV程序会验证这些证明,如果成功,则将其保存到请求帐户的账户数据中。 客户可以通过查询请求帐户的帐户数据来监视其请求的状态,并查看所有适用的交易以及其证明。 在以后的迭代中,如果得到Solana的支持,则可以通过合约发布事件来简化此过程,而不需要如上所述的投票过程。 + +## 执行情况 + +Solana链间SPV机制由以下组件和参与者组成: + +### SPV 引擎 + +部署在Solana上的合约,可以为呼叫者无状态验证SPV证明。 它需要以下参数来验证: + +- 与程序关联的区块链格式正确的SPV证明 +- 引用相关的(一个或多个) 区块头来比较这个证明和 +- 验证交易的必要参数 + + 如果成功验证了相关证明,则SPV程序将保存证明 + + 验证到请求帐户中,调用者可以将其保存到 + + 其帐户数据或根据需要进行其他处理。 SPV程序也暴露在 + + 表示和验证标头的实用程序和结构, + + 逐个链地进行交易,哈希等。 + +### SPV 程序 + +部署在Solana上的合约,用于协调和中介客户与证明者之间的交互,并管理请求、标头、证明等的验证。 这是客户合约访问链间的主要访问点。 SPV机制。 它提供以下核心功能: + +- 提交证明请求 - 允许客户提出特定证明或一组证明的请求 +- 取消证明请求 - 允许客户使待处理请求无效 +- 填写证明请求 - 由证明人提交与给定证明请求相对应的证明,用于验证 + + SPV程序会维护有效的待处理证明的公开列表 + + 向其证明者的利益请求其帐户数据, + + 监督者对此进行监视并将对目标请求的引用及其提交的证据括起来。 + +### 证明请求 + +客户端发送到SPV引擎的消息,表示请求特定交易或一组交易的证明。 证明请求可以通过其哈希值手动指定特定交易,也可以选择提交与多个交易或交易类别匹配的过滤器。 例如,匹配“从地址xxx到地址yyy的任何交易”的过滤器可用于检测债务的支付或链间合约的结算。 同样,与“来自地址xxx的任何交易”相匹配的过滤器可以由贷款或合成代币铸造合约使用,以监视抵押品的变化并对变化做出反应。 证明请求是有偿发送的,一旦与请求相匹配的证明经过验证,SPV引擎合约会将其支付给合适的证明者。 + +### 请求表 + +可供证明者填写或客户取消有效的、开放的验证请求的公开列表。 大致类似于交易所中的订单簿,但具有单一类型的列表,而不是两个分开的双方。 它存储在SPV程序的帐户数据中。 + +### 证明 + +所涉及的区块链中存在给定交易的证明。 证明包括实际的Merkle证明和对有效顺序块头链的(一个或多个) 引用。 它们是由证明者根据SPV程序请求书上托管的可公开获得的证明请求的规范构造和提交的。 验证后,它们将保存到相关证明请求的帐户数据中,客户可以使用该数据来监视请求的状态。 + +### 客户 + +交易证明请求的发起者。 客户通常会成为其他合约,作为应用程序或特定金融产品(如贷款、掉期、托管等)的组成部分。 在任何给定的验证过程周期中,客户最初都会提交一个ClientRequest,传达参数和费用,如果成功通过验证,则结果是通过SPV程序创建证明请求帐户。 客户也可以提交一个取消请求,该取消请求引用了一个有效的证明请求,表示无效的证明。 + +### Prover(证明者) + +填写Proof Request请求的提交人。 证明者监视SPV程序的请求书中是否有未决的证明请求,并生成匹配的证明,然后将其提交给SPV程序进行验证。 如果证据被接受,则与咨询中的Proof Request相关的费用将支付给证明者。 证明者通常充当Solana区块节点,它们也可以访问比特币节点,用于构造证明和访问区块头。 + +### 区块头存储 + +一种基于帐户的数据结构,用于维护头部区块,以便通过引用区块头部存储帐户,将其包含在提交的证明中。 区块头存储可以由独立的实体维护,因为标头区块链验证是SPV程序证明验证机制的组成部分。 请求证明所支付的费用在默认证明的提交者和提交证明中引用的标头存储之间分配。 由于当前无法增加已经分配的帐户数据容量,因此用例需要一种可以无限增长而无需重新平衡的数据结构。 子帐户是SPV程序拥有的帐户,没有其自己的私钥,这些私钥用于通过将区块头分配到其帐户数据来进行存储。 采用多种可能的办法来实施标头存储是可行的: + +将区块头存储在由公共地址索引的程序子账户中: + +- 每个子账户都有一个头部指针,且有一个公钥匹配的区块哈希 +- 每次验证需要与确认相同数量的帐户数据 +- 通过最大交易数据上限来限制确认数量\(15-20\) +- 单个区块头在网络范围内不重复 + +多个子帐户存储标头的链接列表: + +- 维护存储帐户的顺序索引,每个存储帐户有多个标头 +- 最多进行2次帐户数据查询,以进行大于>99.9%的验证(大多数情况下为1) +- 紧凑的顺序数据地址格式,允许任意数量的确认和快速查找 +- 促进网络范围内的区块标头复制效率低下问题 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/ledger-replication-to-implement.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/ledger-replication-to-implement.md new file mode 100644 index 0000000000..614584fc59 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/ledger-replication-to-implement.md @@ -0,0 +1,411 @@ +--- +title: 账本复制 +--- + +注意:此账本复制解决方案已部分实施,但尚未完成。 为了防止未使用代码的安全风险,https://github.com/solana-labs/solana/pull/9992 删除了部分实现。 本设计文档的第一部分反映了账本复制的已实现部分。 [本章节的第二部分](#ledger-replication-not-implemented) 描述了解决方案中尚未实现的部分。 + +## 复制证明 + +在1gbps的网络上满负荷运行时,solana每年将产生4PB的数据。 为了防止网络过于集中在存储完整数据库的验证节点,该协议提出了一种挖掘节点为数据片段提供存储容量的方法。 + +复制证明的基本思想为 CBC 加密,使用公共对称密钥加密数据集,然后对加密的数据集进行哈希处理。 原始方法的主要问题在于,不诚实的存储节点会流式传输加密,对数据进行哈希处理时将其删除。 一种简单的解决方案是根据带符号的PoH值定期重新生成哈希。 这确保了在生成证明期间所有数据都存在,并且还要求验证节点拥有完整的加密数据,以验证每个身份的每个证明。 因此,验证所需的空间为 `number_of_proofs*data_size`。 + +## 使用 PoH 进行优化 + +我们对这种方法的改进是随机取样加密区段,这样比加密算法本身还快, 并将这些采样的哈希值记录到PoH账本中。 因此,每个 PoRep 片段保持完全相同的顺序,并且验证可以在单个批次中流传输数据,验证所有的证明。 这样,我们可以同时验证多个证明,每个证明都在其自己的 CUDA 内核上。 验证所需的总空间为`1_ledger_segment + 2_cbc_blocks * number_of_identities`,核心计数等于`number_of_identities`。 我们使用 64 字节的缓存 CBC 区块大小。 + +## 网络 + +PoRep 验证节点与验证交易的验证节点相同。 如果归档器可以证明验证节点验证了伪造的 PoRep,那么验证节点就不会收到该存储 epoch 的奖励。 + +归档器(Archiver)是专门的_轻客户端_。 他们下载一部分账本\(也称为 Segment\) 并存储起来,同时提供存储账本的PoRep。 对于每个经过验证的 PoRep 归档器,均可从矿池中获得 sol 奖励。 + +## 约束因素 + +我们面临以下的限制: + +- 验证需要生成 CBC 区块。 对于同一数据集的每个身份, + + 它就需要 2 个区块和 1 个 CUDA 内核。 这样, + + 许多身份可以一次性将这些证据 + + 添加到批处理中同一数据集验证的身份。 + +- 验证节点将随机抽取一组存储证明, + + 来证明他们可以处理,并且只有那些选择的证明创建者 + + 才能获得奖励。 只要验证节点的硬件配置成功,它就可以运行基准测试 + + 进行更改以确定可以验证存储证明的速率。 + +## 验证和复制协议 + +### 常量 + +1. SLOTS_PER_SEGMENT:账本数据段的插槽数。 . + + 此存档器的存储单位。 + +2. NUM_KEY_ROTATION_SEGMENTS:归档器之后的段数 + + 重新生成其加密密钥并选择要存储的新数据集。 + +3. NUM_STORAGE_PROOFS:存储证明所需的存储证明数量 + + 成功获得了奖励。 + +4. RATIO_OF_FAKE_PROFS:存储的伪造证明与真实证明的比率 + + 挖矿证明要求必须包含有效的奖励。 + +5. NUM_STORAGE_SAMPLES:存储挖掘所需的样本数证明。 + + . + +6. NUM_CHACHA_ROUNDS:执行生成加密状态的数量。 + + . + +7. NUM_SLOTS_PER_TURN:定义单个存储epoch或 PoRep “回转” + + 的插槽数。 + +### 验证节点行为 + +1. 验证节点加入网络,并开始在每个存储epoch/变化边界中 + + 寻找归档器帐户。 + +2. 每一轮,验证程序在边界处签名 PoH 值并使用该签名 + + 从 epoch 边界中找到的每个存储帐户中随机选择要验证的证据。 + + 此签名的值也将提交到验证节点的存储帐户,并将由 + + 归档器在稍后阶段进行交叉验证。 + +3. 验证节点在每个 `NUM_SLOTS_PER_TURN` 插槽中公布 PoH 值。 这个值 + + 也可以通过RPC接口提供给存档器。 + +4. 对于给定的 N 轮,所有验证都将被锁定,直到 N+3 轮(间隔为 2 轮/epoch) 为止。 + + 此时,该epoch中的所有验证都可用于奖励收集。 + +5. 在两次转换之间将标记任何不正确的验证。 + +### 归档器行为 + +1. 由于存档器有点像轻量级客户端,因此不会下载所有的账本数据, + + 他们必须依靠其他验证节点和归档器来获取信息。 + + 尽管给定的验证节点可能是恶意软件,也可能不是恶意软件, + + 并且给出的信息不正确,除了拥有存档器会做额外的浪费工作。 + + . 对于许多操作,许多选项取决于 + + 归档器的偏离程度: + + - \(a\) 归档器可以要求验证节点 + - \(b\) 归档器可以询问多个验证节点 + - \(c\) 归档器可以询问其他归档器 + - \(d\) 存档器可以订阅完整的事务流并生成信息 + + \(假定插槽已经是最新的\) + + - \(e\) 归档器可以订阅一个简短的交易流 + + \(假定插槽已经是最新的\) + +2. 归档器使用其插槽获取与最后一个epoch相对应的PoH哈希。 +3. 归档器使用其密钥对对PoH哈希进行签名。 该签名是种子, + + 用于选择要复制的段以及加密密钥。 . + + 存档器使用插槽修改签名以获取要分段的部分复制。 + + . + +4. 归档器通过询问对等验证节点和归档器。 + + . 参见6.5。 + +5. 然后,归档程序使用chacha算法用密钥对该段进行加密。 + + 在CBC模式下,加密方式为`NUM_CHACHA_ROUNDS`。 + +6. 存档器使用签名的最近PoH值初始化种子。 + + . + +7. 归档程序会在以下范围内生成`NUM_STORAGE_SAMPLES`个样本条目, + + 并使用sha256对加密的段分别采样32个字节偏移值。 + + . 采样状态应该比生成加密的状态更快。 + + . + +8. 存档器发送包含其sha状态的PoRep证明交易在采样操作结束时, + + 将其种子和用于采样的样本当前的领导者, + + 并将其放到账本中。 + +9. 在给定的epoch中,归档器应针对同一段提交许多证明 + + 并且基于`RATIO_OF_FAKE_PROOFS`,其中一些证明必须是伪造的。 + +10. 当PoRep游戏进入下一epoch时, + + 归档器必须提交一个在最后一轮交易中戴上伪造的mask。 这笔交易 + + 将定义对归档器和验证节点的奖励。 + +11. 最后对于一个轮 N,随着PoRep游戏进入 N+3 轮, + + 归档器的证明将计入其奖励。 + +### PoRep 游戏(Game) + +复制证明游戏有四个主要阶段。 对于每一“轮”,都有多个 PoRep 游戏,但每个游戏处于不同的阶段。 + +PoRep 游戏的四个阶段如下: + +1. 证明提交阶段 + - 归档器:在此阶段提交尽可能多的证明 + - 验证节点:无操作 +2. 验证阶段 + - 存档器:无操作 + - 验证节点:选择归档器并从上一轮验证他们的证明 +3. 证明挑战阶段 + - 归档器:提交带有证明理由的证明蒙版(对于2轮前提交的伪造证明) + - 验证节点:无操作 +4. 奖励收集阶段 + - 归档器:收集3轮前的奖励 + - 验证节点:3轮之前收集奖励 + +对于PoRep游戏的每一轮,验证节点和归档器都会评估每个阶段。 这些阶段作为独立的事务在存储程序上运行。 + +### 找出谁有账本的给定区块 + +1. 验证节点监视PoRep游戏中的变化,并查看植根的账本 + + 依次寻找任何证明的边界。 + +2. 验证节点维护账本段和相应的归档器公共密钥的映射。 + + 当验证节点处理段的归档器的证明时,映射将更新。 + + 验证节点提供了一个RPC接口来访问此映射。 使用此API, + + 客户端可以将段映射到归档器的网络地址(通过cluster_info表进行关联)。 + + 然后,客户端可以将修复请求发送到存档器以检索段。 + +3. 验证节点需要每N轮使此列表无效。 + +## 女巫攻击 + +对于任何随机种子,我们强迫所有人使用从轮次边界处的PoH哈希派生的签名。 每个人都使用相同的计数,因此每个参与者都签名相同的PoH哈希。 然后,每个签名都加密绑定到密钥对,这可以防止领导者根据超过1个身份的结果值进行挖矿。 + +由于除了加密身份之外,还有更多的客户端身份,因此我们需要为多个客户端分配奖励,并防止Sybil攻击生成许多客户端来获取相同的数据块。 为了保持BFT,我们要避免单个实体存储账本某一个区块的所有副本。 + +我们对此的解决方案是强制客户端继续使用相同的身份。 如果第一轮用于获取许多客户端身份的相同区块,则第二轮对相同客户端身份强制重新分配签名,从而强制重新分配PoRep身份和块。 因此,要获得对归档器的奖励,需要免费存储第一个区块,并且网络可以奖励长期存在的客户端身份,而不是奖励一个新身份。 + +## 验证节点攻击 + +- 如果验证节点批准了伪造的证明,则归档器可以通过以下方式轻松地将其剔除: + + 显示哈希的初始状态。 + +- 挖矿如果验证节点将真实证明标记为伪造, + + 则无法进行链上计算区分谁是正确的。 奖励必须依赖于多个验证节点, + + 以阻止不良演员和归档器获得被拒绝的奖励。 + +- 挖矿验证程序本身会窃取挖矿证明结果。 证明是推导的来自归档器的签名, + + 因为验证节点 + + 不知道用于生成加密密钥的私钥, + + 它不能是证明本身。 + +## 奖励措施 + +伪造证明的生成非常容易,但难以验证。 因此,由归档器生成的PoRep证明交易可能需要比正常交易更高的费用,才能代表验证节点所需的计算成本。 + +为了从存储挖矿中获得奖励,还需要一定比例的伪造证据。 + +## 注意事项 + +- 通过使用PoH,我们可以减少PoRep验证的费用,实际上 + + 使验证全局数据集的大量证明变得可行。 + +- 我们可以通过强制每个人都签名相同的PoH哈希和 + + 使用签名作为种子 + +- 验证节点和归档器之间的博弈超过随机块和随机数 + + 加密身份和随机数据样本。 随机化的目标是 + + 防止共谋组在数据或验证上重叠。 + +- 存档客户通过提交伪造的证明来寻找懒惰的验证节点 + + 他们可以证明是假的。 + +- 为了防御试图存储同一区块的Sybil客户身份, + + 我们强迫客户在获得奖励之前先进行多轮存储。 + +- 验证节点还应通过验证提交的存储证明而获得奖励 + + 作为存储账本的诱因。 他们只能验证证明,如果他们 + + 正在存储一部分该账本。 + +# 账本复制未实现部分 + +复制行为尚未实现的部分。 + +## 存储 epoch + +存储时期应为插槽数,这将导致生成大约100GB1TB的账本,以供归档器存储。 当给定的分叉极有可能无法回滚时,归档器将开始存储账本。 + +## 验证节点行为 + +1. 每个NUM_KEY_ROTATION_TICKS也会验证从以下位置收到的样本 + + 归档器。 它在那时签署PoH哈希并使用以下内容以签名为输入的算法: + + . + + - 签名的第一个字节的低5位将创建一个索引签名的另一个起始字节。 + + . + + - 验证节点然后查看存储证明集,其中从低字节开始的证明的sha状态向量完全匹配与所选的签名字节。 + + . + + () + + - 如果证明集大于验证节点可以处理的范围,则证明在签名中增加到匹配2个字节。 + + . + + - 验证程序将继续增加匹配字节的数量, + + 直到出现找到了可行的集合。 + + - 然后创建有效证明和伪造证明的掩码, + + 并将其发送给领导人。 这是一个存储证明确认交易。 + +2. 在NUM_SECONDS_STORAGE_LOCKOUT秒的锁定期后, + + 验证节点然后提交存储证明索赔交易, + + 然后导致如果没有发现挑战的证据, + + 则分配存储奖励验证节点和归档器参与证明。 + +## 归档器行为 + +1. 然后,存档器生成另一组偏移量,它会提供一个伪造的偏移量。 + + . 提供种子的哈希结果可以证明它是伪造的。 + + . + + - 伪造证明应包括 PoH 签名的归档器哈希价值。 + + . 这样,当归档器揭露虚假证据时,就可以在链上验证。 + + . + +2. 归档器监视账本,如果发现集成了伪造的证明, + + 它将创建一个挑战交易并将其提交给当前的领导者。 . + + 这事务处理证明验证节点错误地验证了伪造的存储证明。 + + 归档器得到奖励,验证节点的质押余额被罚没或冻结。 + + . + +## 存储合约逻辑证明 + +每个存档器和验证节点将拥有自己的存储帐户。 验证节点的帐户将与他们的投票帐户类似,而不是其八卦 id。 这些应作为两个程序实现,一个程序将验证程序作为密钥签名者,另一个程序作为存档程序。 这样,当程序引用其他帐户时,他们可以检查程序ID,以确保该程序是他们正在引用的验证节点或归档器帐户。 + +### SubmitMiningProof + +```text +SubmitMiningProof { + slot: u64, + sha_state: Hash, + signature: Signature, +}; +keys = [archiver_keypair] +``` + +归档器在为特定的哈希值挖掘其存储的账本数据后创建这些文件。 该插槽是它们要存储的账本段的末尾插槽,使用哈希函数对归档器的结果进行sha_state声明,以对其加密的账本段进行采样。 签名是在他们为当前存储时期签名PoH值时创建的签名。 当前存储纪元的证明清单应保存在帐户状态,然后在纪元过去时转移到上一个纪元的证明清单。 在给定的存储时间段内,给定的归档器应仅提交一个分段的证明。 + +该程序应具有一个插槽列表,这些插槽是有效的存储挖矿插槽。 应当通过跟踪作为根目录的插槽的插槽来维护此列表,在这些插槽中,网络的重要部分已经投票,具有较高的锁定值(可能是32投票权的旧版本)。 每个SLOTS_PER_SEGMENT个插槽数都将添加到该集合中。 程序应检查插槽是否在此集中。 可以通过接收AdvertiseStorageRecentBlockHash并检查其bank/TowerBFT状态来维护该集。 + +该程序应该对签名,来自事务提交者的公钥以及先前存储纪元PoH值的消息进行签名验证检查。 + +### ProofValidation + +```text +ProofValidation { + proof_mask: Vec, +} +keys = [validator_keypair, archiver_keypair(s) (unsigned)] +``` + +验证节点将提交此交易,以表明给定细分的一组证明是有效/无效或在验证节点未查看的情况下被跳过。 应该在密钥中引用它所查看的归档器的密钥对,以便程序逻辑可以转到这些帐户,并查看证明是在前一个时期生成的。 应验证存储证明的采样,以确保验证节点根据采样的验证节点行为中概述的逻辑跳过正确的证明。 + +随附的存档器密钥将指示正在引用的存储样本;应该对照所引用的归档器帐户中的一组存储证明来验证proof_mask的长度,并且应与所述归档器(多个) 帐户状态下在先前存储时期中提交的证明数量相匹配。 + +### ClaimStorageReward + +```text +ClaimStorageReward { +} +keys = [validator_keypair or archiver_keypair, validator/archiver_keypairs (unsigned)] +``` + +归档器和验证节点将使用此事务从程序状态获取已支付的令牌,在该程序状态中,SubmitStorageProof,ProofValidation和ChallengeProofValidation处于已提交并验证了证明的状态,并且没有ChallengeProofValidations引用这些证明。 对于验证节点,它应该在相关纪元中引用已验证其证据的存档器密钥对。 对于归档器,它应该引用已验证并希望获得奖励的验证节点密钥对。 + +### ChallengeProofValidation + +```text +ChallengeProofValidation { + proof_index: u64, + hash_seed_value: Vec, +} +keys = [archiver_keypair, validator_keypair] +``` + +此事务用于捕获没有进行验证工作的懒惰验证节点。 当看到验证节点批准了假的SubmitMiningProof事务时,归档器将提交此事务。 由于存档器是轻量级客户端,而不是查看整个区块链,因此可能必须通过RPC调用向验证节点或一组验证节点询问此信息,以获取上一个存储时期中某个段的所有ProofValidation。 该程序将查看验证节点帐户状态,查看是否在上一个存储纪元中提交了ProofValidation并对hash_seed_value进行哈希处理,并看到哈希值与SubmitMiningProof事务匹配,并且验证节点将其标记为有效。 如果是这样,那么它将把挑战保存到其状态下的挑战列表中。 + +### AdvertiseStorageRecentBlockhash + +```text +AdvertiseStorageRecentBlockhash { + hash: Hash, + slot: u64, +} +``` + +验证节点和归档器将提交此消息,以指示新的存储纪元已经过去,并且作为当前的存储证据现在应作为前一个纪元的存储证明。 其他事务应检查,来确保在当前的区块链状态下,它们所引用的纪元是正确的。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/optimistic-confirmation-and-slashing.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/optimistic-confirmation-and-slashing.md new file mode 100644 index 0000000000..022f8830d3 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/optimistic-confirmation-and-slashing.md @@ -0,0 +1,35 @@ +--- +title: 乐观确认与罚没 +--- + +乐观确认的进展可以在这里追踪 + +https://github.com/solana-labs/solana/projects/52 + +5月底,mainnetbeta移至1.1版本,而testnet移至1.2版本。 在1.2版本中,只要至少不超过4.66%的验证节点作恶,testnet就能获得乐观的终结性。 应用程序可以假设,在八卦中观察到的超过 2/3 的投票确认了某个区块,或者至少有4.66%的网络违反了该协议。 + +## 工作原理 + +一般的想法是,验证节点必须在最后一次分叉之后继续投票,除非验证节点可以构造证明其当前分叉可能未达到最终确定性的证据。 验证节点构造此证明的方式是通过收集所有分叉,但不包括他们自己分叉的投票。 如果有效投票集代表了该时代的质押权重的 1/3+X,则验证节点当前的分叉可能无法达到超过 2/3 的最终性。 验证节点对证据进行哈希处理(创建证人),并将其投票提交给替代分叉。 但是,如果同一个区块获得超过 2/3 的投票,则任何验证节点都不可能构造该证明,因此,没有验证节点能够切换分叉,并且将最终确定该区块。 + +## 权衡 + +安全阈值为 1/3+X,其中 X 表示在违反协议的情况下将被罚没的最低抵押金额。 折衷方案是,最坏情况下的活性降低了两倍。 如果超过 1/3-2X 的网络不可用,则网络可能会停止,并且仅在网络恢复到故障节点的 1/3-2X 以下才恢复确认区块。 到目前为止,我们还没有发现主网、cosmos或tezos遭受巨大的不可用性影响。 对于主要由高可用性系统组成的网络而言,这似乎不太可能。 当前,我们将阈值百分比设置为 4.66%,这意味着如果 23.68% 的网络失败,则网络可能会停止出块。 对于我们高可用性系统网络而言,可用性下降似乎不存在 23.68% 的联系。 1:10^12 的概率假设有五个 4.7% 的抵押节点的正常运行时间为 0.995。 + +## 安全性 + +每个插槽的长期平均票数为 670,000,000票/12,000,000插槽,即 64 个投票验证节点中的 55 个。 这包括由于出块节点故障而丢失的区块。 当客户端观察到 55/64 或约 86% 的概率确认区块后,可以预期必须约 24% 或`(86-66,666.. +4,666..%)` 的网络遭受罚没才会导致该区块无法完全确认最终性。 + +## 为什么选择Solana? + +这种方法也可以在其他网络上实施,但是在Solana实现的复杂性大大降低了,因为我们的投票有一个可证明的基于VDF超时。 尚不清楚是否可以在对时间假设较弱的网络中轻松构建切换证明。 + +## 罚没路线图 + +罚没是一个困难的问题,当网络的目标是使延迟尽可能短时,它就变得更加困难。 在针对延迟进行优化时,折衷尤为明显。 例如,理想情况下,验证节点应该在内存已同步到磁盘之前进行投票并传播其投票,这意味着本地状态损坏的风险要高得多。 + +从根本上讲,我们的罚没目标是在节点恶意尝试违反安全规则的情况下罚没100%,在常规操作期间罚没0%。 我们的目标是首先实施罚没证明,而不进行任何自动罚没。 + +目前,为了定期达成共识,在违反安全规定后,网络将停止。 我们可以分析数据并找出谁负责,并建议重新启动后进行罚没。 乐观conf将使用类似的方法。 乐观的conf安全违规很容易观察到,但是在正常情况下,乐观确认的安全违规可能不会阻止网络。 一旦观察到违规,验证节点将在下一个时期冻结受影响的股份,如果违规需要罚没,则将决定下一次升级。 + +从长远来看,如果证明存在乐观的安全违规行为,交易应该能够收回罚没的抵押品。 在那种情况下,每个区块都由网络有效地保护。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/optimistic_confirmation.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/optimistic_confirmation.md new file mode 100644 index 0000000000..bd9de07399 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/optimistic_confirmation.md @@ -0,0 +1,296 @@ +--- +title: 乐观确认 +--- + +## 原理 + +`vote(X, S)`-投票将增加“参考”位,`X`这是该验证节点通过切换证明,投票通过的分叉的**最新**祖先。 只要验证节点进行的连续投票都是彼此相同的,`X`应该用于所有的这些投票。 验证节点对一个插槽`s`进行投票时,它不是前一个的后代,`X`将设置为新的插槽`s`。 所有投票将采用以下`vote(X, S)`的形式,其中`S`为插槽等待投票的排序列表`(s, s.lockout)`。 + +对于一个投票`vote(X, S)`,让`S.last==vote.last`成为最后一个插槽`S`。 + +现在,我们定义一些“乐观罚没”的罚没条件。 直觉描述如下: + +- `直觉`: 如果验证节点提交 `voite(X, S)`,同一个验证节点不应该在一个不同的分叉上投票(这个分叉有“重叠”。) 更具体而言,这个验证程序不应该再投另一个票`voite(X', S')` 范围 `[X, S.` 与范围重叠 `[X', S'.last]`, `X != X'`,如下所示: + +```text + +-------+ + | | + +---------+ +--------+ + | | | | + | +-------+ | + | | + | | + | | + +---+---+ | + | | | + X | | | + | | | + +---+---+ | + | | + | +---+---+ + | | | + | | | X' + | | | + | +---+---+ + | | + | | + | | + | | + | +---+---+ + | | | + | | | S'.last + | | | + | +-------+ + | + +---+---+ + | | + s | | + | | + +---+---+ + | + | + | + | + +---+---+ + | | + S.last | | + | | + +-------+ +``` + +(可选票的示例(X', S') 和选票(X, S)) + +在上图中,请注意,对`S.last`的投票必须在对`S'.last`的投票之后发送(由于锁定,较高的投票必须在以后发送)。 因此,投票顺序必须是: `X ... S'.last ... S.last`。 这意味着在对`S'.last`进行投票后,验证节点必须已在某个插槽`s > S'.last > X`上切换回了另一个分叉。 因此,对`S.last`的投票应该使用`s`作为“参考点”,而不是`X`,因为那是分叉上的最后一个“开关”。 + +为了实现这一点,我们定义了“乐观罚没”的罚没条件。 给定两个不同的投票 `voite(X, S)`和 `voite(X, S)`,经过同一个验证程序的投票必须满足: + +- `X <= S.last`, `X' <= S'.last` +- `S` 中所有的 `s` 都是彼此的祖先/后代,`S'` 中的所有 `s'` 都是同伴/同辈。 +- +- `X == X'` 暗示 `S` 是 `S'` 父级,或者 `S'` 是 `S` 的父级 +- `X' > X` 意味着 `X' > S.last` 和 `S'.last > S.last` 所有 `s` 在 `S` 之中,`s + lockout(s) < X'` +- `X > X'` 意味着 `X > S.last` 和 `S.last > S'.last` 所有 `s` 在 `S'`之中,`s + lockout(s) < X` + +(最后两个规则意味着范围不能重叠):否则,验证程序将被罚没。 + +`范围(投票)` - 投票 `v = vote(X, S)`, 定义 `Range(v)` 为插槽 `[X, S.last]`的范围。 + +`SP(old_vote,new_vote)`-这是验证节点最新投票`old_vote`的“切换证明”。 每当验证节点切换其参考位(请参见上面的投票部分) 时,此类证明都是必需的。 切换证明包括对`old_vote`的引用,因此存在`old_vote`的范围是什么的记录(以使该范围内的其他冲突开关可被罚没)。 这样的开关仍必须遵守锁定条件。 + +交换证明表明,网络的`> 1/3`被锁定在`old_vote.last`插槽中。 + +证明是元素`(validator_id,validator_vote(X,S))`的列表,其中: + +1. 所有验证节点ID的质押总和`> 1/3` + +2. 对于每 `(validator_id, validator_voite(X, S))`,在 `S` 中存在一些插槽 `s` 其中: _ a.`s` 不是两者的共同祖先 `validator_vote.last` 和 `vote.last` 和 `new_vote.last`。 _ b. `s` 不是 `validator_voote.last` 的后代。 \* c. `s + s.lockout() >= old_vote.last` (隐含着验证节点仍然被锁定在`old_vote.last`的`s` 插槽)。 + +在没有有效切换证明的情况下切换分叉是可罚没的。 + +## 定义: + +乐观确认 - 如果一个模块 `B` 已经实现"乐观确认",假如 `>2/3` 质押以投票方式投票 `v`,其中 `Range(v)` 对每个这样的 `v` 包括 `B.slot`。 + +已完成 - 如果至少有一个正确的验证节点已植入 `B` 或是 `B` 的后代,那么就说区块 `B` 已经完成。 + +已恢复 - 如果另一个 `B'` 不是 `B` 的父级或后代,则说区块 `B`已恢复。 + +## 保障: + +除非至少罚没了一个验证节点,否则已经达成乐观确认的区块`B`将不会恢复。 + +## 证明: + +假定是出于矛盾, 一个区块 `B` 已经在某些槽位 `B + n`对于某些 `n`实现了`乐观确认` 并且: + +- 另一个区块 `B'` 不是已经完成的区块 `B `的父级或后代。 +- 没有验证节点违反任何罚没条件。 + +由 `乐观确认`的定义,意味着 `> 2/3` 验证程序中的每一个都显示了一些投票 `v` 表单 `Vote(X, S)` `X <= B <= v.last`。 称这组验证节点为 `乐观验证节点`。 + +现在给定 `乐观验证节点`的一个验证节点 `v` ,有`v`, `Vote(X, S)` 和 `Vote(X', S')`的两个投票,其中 `X <= B <= S.last` 和 `X' <= B <= S'.last`,然后 `X == X'` 否则违反了“乐观罚没”条件(每次投票的“幅度”会重叠在 `B`)。 + +因此,将`乐观投票`定义为`乐观验证节点`做出的一组投票,其中,对于每个乐观验证节点`v`而言,集合中包括的`v`做出的投票就是`最大`投票`(X, S)`,在满足`X <= B <= S.last` 的`v`做出的任何投票中,具有最高的`S.last`。 因为我们从上方知道`X`对由`v`做出的所有此类投票都是唯一的,所以我们知道有如此独特的对`maximal`进行的投票。 + +### 引理 1: + +`声明:`给出了由`乐观验证节点`集中的验证节点`V`做出的`Vote(X, S)`投票,而`S`包含了针对`s`插槽表决,其中: + +- `s + s.lockout > B`, +- `s` 不是 `B` 的前辈或后代, + +那么 `X > B` + +```text + +-------+ + | | + +---------+ +--------+ + | | | | + | +-------+ | + | | + | | + | | + | +---+---+ + | | | + | | | X' + | | | + | +---+---+ + | | + | | + | +---+---+ + | | | + | | | B (Optimistically Confirmed) + | | | + | +---+---+ + | | + | | + | | + | +---+---+ + | | | + | | | S'.last + | | | + | +-------+ + | + +---+---+ + | | + X | | + | | + +---+---+ + | + | + | + | + | + | + +---+---+ + | | + S.last | | + | | + +---+---+ + | + | + | + | + +---+---+ + | | + s + s.lockout | | + +-------+ +``` + +`证明`: 假定为了与验证节点 `V` 从设置的“乐观验证节点”进行了这样一次投票 `Voite(X, S)` 其中 `S` 包含对一个插槽的投票,`s` 不是 `B` 的一个父辈或后代,其中 s`s + s.lockout > B`, 但是 `X <= B`。 + +令`Vote(X', S')`为验证节点`V`所做的`乐观投票`集合中的投票。 根据该集合的定义(所有选票均乐观地确认为`B`),`X' <= B <= S'.last` (请参见上图)。 + +这意味着,因为假定它在 `X <= B`,然后在 `X <= B`上,所以根据罚没规则, `X == X'` or `X < X'`(否则会重叠范围`(X', S'.last)`)。 + +`Case X == X'`: + +考虑 `s`。 我们知道 `s != X` ,因为它假定 `s` 不是`B`的一个祖先或后代 , `X` 是 `B` 的祖先。 因为 `S'.last` 是 `B`的后代,意味着 `s` 也不是`S.last`的祖先或后代。 然后因为 `S.last` 来自 `s`,然后又 `S.last` 不能是 `S.last`的祖先或后代。 这意味着根据"乐观罚没"规则,`X != X` 。 + +`Case X < X'`: + +直觉上,这意味着 `Vote(X, S)` 是在 `Vote(X, S)`之前发生的。 + +根据上述假设, `s + s.lockout > B > X'`。 因为`s`不是`X'`的祖先,所以当此验证节点首次尝试以`Vote(X', S'')`的形式向`X'`提交切换表决时,将违反锁定。 + +由于这些情况均不成立,因此该假设必定无效,并且假设已得到证明。 + +### 引理 2: + +回想一下,`B'`是在与乐观地确认的`B`区块不同的分叉上最终确定的区块。 + +`声明`: 任何投票 `Vote(X, S)` 在 `乐观投票` 集合中必须为 `B' > X` + +```text + +-------+ + | | + +--------+ +---------+ + | | | | + | +-------+ | + | | + | | + | | + | +---+---+ + | | | + | | | X + | | | + | +---+---+ + | | + | | + | +---+---+ + | | | + | | | B (Optimistically Confirmed) + | | | + | +---+---+ + | | + | | + | | + | +---+---+ + | | | + | | | S.last + | | | + | +-------+ + | + +---+---+ + | | + B'(Finalized) | | + | | + +-------+ +``` + +`证明`: 让 `Vote(X, S)` 在 `乐观投票` 集合中的一次投票。 然后按定义,给出"最佳确认" 区块 `B`, `X <= B <= S.last`。 + +因为 `X` 是 `B`的父类,并且 `B'` 不是 `B`,那么: + +- `B' != X` +- `B'` 不是 `X` 的父类 + +现在请考虑是否 `B'` < `X`: + +`Case B' < X`: 我们会证明这样是违反锁定的。 从上面我们知道 `B'` 不是 `X` 的父级。 从上面我们知道`B‘`不是`X`的父代。然后,因为`B'`是根植的,所以验证节点不应该能够对不是来自区块`B'`的更高插槽`X`进行投票。 + +### 安全性证明: + +现在,我们旨在显示`乐观验证节点`集合中至少有一个验证节点违反了罚没的规则。 + +首先要注意的是,为了使`B'`已经植入根目录,必须有`> 2/3`的质押对`B'`或`B'`的后代进行投票。 假设`乐观验证节点`集还包含`> 2/3`的质押验证节点,则得出`> 1/3`的质押验证节点: + +- 根植于 `B'` 或 `B`的后代 +- 也提交了一个表 `Vote(X, S) ` 的投票 `v`,其中 `X <= B <= v.last`。 + +让 `Delinquent` 设置为符合以上标准的验证集。 + +根据定义,为了根植于 `B'`, 每个验证节点 `V` 在 `Delinquent` 都必须对表单进行一些"切换投票" `Vote(X_v, S_v)`,其中: + +- `S_v.last > B'` +- `S_v.last` 是 `B'` 的后代,因此它不能是 `B` 的后代。 +- 因为 `S_v.last` 不是 `B` 的后代, 然后 `X_v` 不能是 `B` 的后代或祖先。 + +根据定义,这个过时的验证人`V`还在`乐观投票`中进行了 `Vote(X, S)`,其中根据该集合的定义(经过乐观确认的`B`),我们知道 `S.last >= B >= X`。 + +通过`引理2`,我们知道 `B' > X`,以及上文的 `S_v.last > B'`,所以`S_v.last > X`。 因为 `X_v != X` (不能从上方成为`B`的后代或祖先),那么根据罚没规则,我们知道 `X_v > S.last`。 上面有 `S.last >= B >= X` ,因此对于所有这样的切换投票,有 `X_v > B`。 + +现在按顺序排列所有这些切换投票,假设`V`是`乐观验证节点`中的验证节点,该它首先提交这样的切换投票`Vote(X', S')`,其中 `X' > B`。 我们知道存在这样的验证节点,因为从上面知道所有违规验证节点都必须提交这样的投票,并且违规验证节点是`乐观验证节点`的子集。 + +令`Vote(X, S)`为验证节点`V`(最大化`S.last`)在`乐观投票`中的唯一投票。 + +给定`Vote(X, S)`,因为 `X' > B >= X`,然后给出 `X' > X`,因此按照“乐观罚没”规则,得出 `X' > S.last`。 + +为了对 `X'` 执行这样的“切换投票”,切换证明 `SP(Vote(X, S), Vote(X', S'))` 必须显示 `> 1/3` 的质押锁定此验证节点的最新投票`S.last`。 将此 `>1/3` 与`乐观投票者`集合中的一组验证节点的质押 `>1/3` 这个事实结合,就意味着`乐观投票者`中至少有一个乐观验证节点`W`。集合必须已提交投票(回顾切换证明的定义),验证节点`V`的插槽`X'`的切换证明中包含的`Vote(X_w, S_w)`,其中`S_w`包含了一个插槽`s`,所以有: + +- `s` 不是 `S.last` 和 `X'` 的共同祖先 +- `s` 不是 `S.last` 的后代。 +- `s' + s'.lockout > S.last` + +因为 `B` 是 `S.last`的祖先,那么下面也是真的: + +- `s` 不是 `B` 和 `X'` 的共同祖先 +- `s' + s'.lockout > B` + +包含在 `V` 的切换证明中。 + +现在,由于`W`也是`乐观投票者`的成员,因此由上面的`引理1`决定,由`W`投票,即 `Vote(X_w, S_w)`,其中`S_w`包含对插槽`s`的投票,其中 `s + s.lockout > B`,并且`s`不是`B`的祖先,那么 `X_w > B`。 + +因为验证节点`V`在其为`X'`插槽进行切换的证明中包括了投票`Vote(X_w, S_w)`,所以隐含了验证节点`V'`在投票给 vote `Vote(X_w, S_w)` **之前**,`V` 就对插槽 `X'` 进行了 `Vote(X', S')` 投票。 + +但这是一个矛盾,因为我们选择 `Vote(X', S')`作为`乐观投票者`集合中任何验证节点的第一票,其中 `X' > B` 且`X'`不是`B`的后代。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/program-instruction-macro.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/program-instruction-macro.md new file mode 100644 index 0000000000..03095f6523 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/program-instruction-macro.md @@ -0,0 +1,196 @@ +# 程序指令宏 + +## 面临的问题 + +当前,检查链上交易需要依赖于客户端的、特定语言的解码库来解析指令。 如果 rpc 方法可以返回解码后的指令详细信息,那么这些自定义解决方案就没有必要了。 + +我们可以使用程序的指令枚举来反序列化指令数据,但是将帐户密钥列表解码为人类可读的标识符需要手动解析。 我们当前的说明枚举具有该帐户信息,但仅针对变体文档。 + +同样,我们拥有指令构造函数,该函数几乎复制了枚举中的所有信息,但是由于帐户引用列表在代码注释中,因此无法从枚举定义中生成该构造函数。 + +另外,由于没有确保一致性的机制,说明文档在不同的实现方式中可能会有所不同。 + +## 拟定的解决方案 + +将数据从代码注释移到属性,以便可以生成构造函数,并包括枚举定义中的所有文档。 + +这是使用新帐户格式的指令枚举示例: + +```rust,ignore +#[instructions(test_program::id())] +pub enum TestInstruction { + /// 转移 lamports + #[accounts( + from_account(SIGNER, WRITABLE, desc = "Funding account"), + to_account(WRITABLE, desc = "Recipient account"), + )] + Transfer { + lamports: u64, + }, + + /// 提供 N 个所需签名中的 M + #[accounts( + data_account(WRITABLE, desc = "Data account"), + signers(SIGNER, multiple, desc = "Signer"), + )] + Multisig, + + /// 消耗一个存储的nonce,用一个继承来代替 + #[accounts( + nonce_account(SIGNER, WRITABLE, desc = "Nonce account"), + recent_blockhashes_sysvar(desc = "RecentBlockhashes sysvar"), + nonce_authority(SIGNER, optional, desc = "Nonce authority"), + )] + AdvanceNonceAccount, +} +``` + +用文档生成的 TestInstruction 示例: +```rust,ignore +pub enum TestInstruction { + /// 转移 lamports + /// + /// * 此操作需要的账户: + /// 0。 `[WRITABLE, SIGNER]` Funding account + /// 1. `[WRITABLE]` Recipient account + Transfer { + lamports: u64, + }, + + /// 提供 N 个所需签名中的 M + /// + /// * 此操作需要的账户: + /// 0。 `[WRITABLE]` Data account + /// * (Multiple) `[SIGNER]` Signers + Multisig, + + /// Consumes a stored nonce, replacing it with a successor + /// + /// * Accounts expected by this instruction: + /// 0. `[WRITABLE, SIGNER]` Nonce account + /// 1. `[]` RecentBlockhashes sysvar + /// 2. (Optional) `[SIGNER]` Nonce authority + AdvanceNonceAccount, +} +``` + +生成的构造器: +```rust,ignore +/// Transfer lamports +/// +/// * `from_account` - `[WRITABLE, SIGNER]` Funding account +/// * `to_account` - `[WRITABLE]` Recipient account +pub fn transfer(from_account: Pubkey, to_account: Pubkey, lamports: u64) -> Instruction { + let account_metas = vec![ + AccountMeta::new(from_pubkey, true), + AccountMeta::new(to_pubkey, false), + ]; + Instruction::new( + test_program::id(), + &SystemInstruction::Transfer { lamports }, + account_metas, + ) +} + +/// Provide M of N required signatures +/// +/// * `data_account` - `[WRITABLE]` Data account +/// * `signers` - (Multiple) `[SIGNER]` Signers +pub fn multisig(data_account: Pubkey, signers: &[Pubkey]) -> Instruction { + let mut account_metas = vec![ + AccountMeta::new(nonce_pubkey, false), + ]; + for pubkey in signers.iter() { + account_metas.push(AccountMeta::new_readonly(pubkey, true)); + } + + Instruction::new( + test_program::id(), + &TestInstruction::Multisig, + account_metas, + ) +} + +/// Consumes a stored nonce, replacing it with a successor +/// +/// * nonce_account - `[WRITABLE, SIGNER]` Nonce account +/// * recent_blockhashes_sysvar - `[]` RecentBlockhashes sysvar +/// * nonce_authority - (Optional) `[SIGNER]` Nonce authority +pub fn advance_nonce_account( + nonce_account: Pubkey, + recent_blockhashes_sysvar: Pubkey, + nonce_authority: Option, +) -> Instruction { + let mut account_metas = vec![ + AccountMeta::new(nonce_account, false), + AccountMeta::new_readonly(recent_blockhashes_sysvar, false), + ]; + if let Some(pubkey) = authorized_pubkey { + account_metas.push(AccountMeta::new_readonly*nonce_authority, true)); + } + Instruction::new( + test_program::id(), + &TestInstruction::AdvanceNonceAccount, + account_metas, + ) +} + +``` + +生成的 TestInstructionVerbose 枚举: + +```rust,ignore +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub enum TestInstruction { + /// Transfer lamports + Transfer { + /// Funding account + funding_account: u8 + + /// Recipient account + recipient_account: u8 + + lamports: u64, + }, + + /// Provide M of N required signatures + Multisig { + data_account: u8, + signers: Vec, + }, + + /// Consumes a stored nonce, replacing it with a successor + AdvanceNonceAccount { + nonce_account: u8, + recent_blockhashes_sysvar: u8, + nonce_authority: Option, + } +} + +impl TestInstructionVerbose { + pub fn from_instruction(instruction: TestInstruction, account_keys: Vec) -> Self { + match instruction { + TestInstruction::Transfer { lamports } => TestInstructionVerbose::Transfer { + funding_account: account_keys[0], + recipient_account: account_keys[1], + lamports, + } + TestInstruction::Multisig => TestInstructionVerbose::Multisig { + data_account: account_keys[0], + signers: account_keys[1..], + } + TestInstruction::AdvanceNonceAccount => TestInstructionVerbose::AdvanceNonceAccount { + nonce_account: account_keys[0], + recent_blockhashes_sysvar: account_keys[1], + nonce_authority: &account_keys.get(2), + } + } + } +} + +``` + +## 考虑因素 + +1. **命名字段(Named fields)** - 由于生成的Verbose枚举使用命名字段构造变量,因此原始指令变量中的所有未命名字段都需要生成名称。 这样,如果将所有Instruction枚举字段都转换为命名类型而不是未命名元组,就会更加直接。 无论如何,这似乎都是值得的,因为它可以为变体增加更多的精度并启用真实文档(因此开发人员不必[这样做](https://github.com/solana-labs/solana/blob/3aab13a1679ba2b7846d9ba39b04a52f2017d3e0/sdk/src/system_instruction.rs#L140)。它会在我们当前的代码库中造成一点混乱,但不会太严重。 +2. **可变帐户列表(Variable account lists)** - 这种方法为可变帐户列表提供了两个选项。 首先是添加可选帐户,并使用`optional`关键字进行标记。 但是,当前每条指令仅支持一个可选帐户。 需要在指令中添加其他数据以支持乘数,从而能够在包含一些但不是全部时识别存在的帐户。 其次,可以将具有相同功能的帐户作为一个集合添加,并以关键字`multiple`标记。 与可选帐户一样,每条指令仅支持一个多帐户集(并且可选和多个帐户可能不共存)。 可能需要将逻辑弄清楚帐户顺序/表示形式的,不能由`可选`或`多个`容纳的更复杂的指令,可能应该做成单独的指令。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/rip-curl.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/rip-curl.md new file mode 100644 index 0000000000..015bdbe991 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/rip-curl.md @@ -0,0 +1,33 @@ +# RiP Curl:低延迟,面向事务的RPC + +## 面临的问题 + +创建Solana的初始RPC实现是为了让用户确认最近刚发送到集群的交易。 在设计时就考虑到了它的内存使用情况,因此任何验证节点都应该能够支持API,而不必担心DoS攻击。 + +后来,使用相同的API来支持Solana浏览器变得很必要。 原始设计仅支持几分钟的历史记录,因此我们将其更改为改为将事务状态存储在本地RocksDB实例中,并提供长达几天的历史记录。 然后,我们通过BigTable将其扩展到六个月。 + +每次修改都让API变得更适合于提供静态内容的应用程序,并且对交易处理的吸引力降低了。 客户轮询交易状态而不是被通知,会给人一种错误的印象,即确认时间更长。 此外,客户可以轮询的内容是有限的,这会阻止他们做出合理的实时决策,例如,一旦特定的、受信任的验证者对其进行投票,便确认了交易。 + +## 拟定的解决方案 + +基于验证者的ReplayStage,构建一个网络友好、面向事务的流式API。 + +改善客户体验: + +* 直接从WebAssembly应用程序支持连接。 +* 可以实时向客户通知确认进度,包括投票和投票者质押权重。 +* 当占比最重的分叉发生变化,如果它会影响交易确认计数,则会通知客户。 + +对验证节点的支持更加简单: + +* 每个验证节点支持一定数量的并发连接,否则没有明显的资源限制。 +* 交易状态永远不会存储在内存中,因此无法进行轮询。 +* 签名仅存储在内存中,直到所需的承诺级别或直到区块哈希过期为止(以较晚的日期为准)。 + +工作原理: + +1. 客户端使用可靠的通信通道(例如Web socket)连接到验证节点。 +2. 验证节点使用ReplayStage注册签名。 +3. 验证程序将交易发送到Gulf Stream,并重试所有已知的派生,直到区块哈希过期(直到仅在最长的分叉上接受交易为止)。 如果区块哈希过期,则签名未注册,通知客户端,并关闭连接。 +4. 当ReplayStage检测到影响交易状态的事件时,它将实时通知客户端。 +5. 确认交易已植根后 (`CommitmentLevel::Max`),签名则未注册,服务器关闭上游通道。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/rust-clients.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/rust-clients.md new file mode 100644 index 0000000000..8b07c3bb13 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/rust-clients.md @@ -0,0 +1,31 @@ +--- +title: Rust 客户端 +--- + +## 面临的问题 + +诸如Bench-tps之类的高级测试是根据`客户端`特征编写的。 将这些测试作为测试套件的一部分执行时,我们将使用低级的`BankClient`实现。 当需要对集群运行相同的测试时,我们使用`ThinClient(轻客户端)`实现。 这种方法的问题在于,它意味着该特性将不断扩展,从而包括新的实用程序功能,并且其所有实现都需要添加新功能。 通过将面向用户的对象与抽象化网络接口的特征分离,我们可以扩展面向用户的对象,以包括各种有用的功能,例如RpcClient的“spinner”,而无需担心扩展特征及其实现。 + +## 拟定的解决方案 + +代替实现`客户端`特征,应使用其实现来构造`ThinClient`。 这样,当前具有`客户端`特征的所有实用程序功能都可以移至`ThinClient`中。 然后,`ThinClient`可以移至`solana-sdk`中,因为它的所有网络相关性都在`Client`的实现中。 然后,我们将添加一个名为`Client`的新实现,称为`ClusterClient`,并将其存在于`ThinClient`当前所在的`Solana-client`工具箱中。 + +重组之后,任何需要客户端的代码都将以`ThinClient`的形式编写。 在单元测试中,将使用`ThinClient`调用该功能,而`main()`函数、基准测试和集成测试将通过`ThinClient`调用该功能。 + +如果更高级别的组件需要比`BankClient`能够实现的功能更广,则应按照与此处所述相同的模式,通过实现第二个特征的第二个对象来实现。 + +### 错误处理 + +`客户端`应使用现有的`TransportError`枚举来进行错误处理,除了`Custom(String)`字段应更改为`Custom(Box)`。 + +### 实施战略 + +1. 在`solana-sdk`、`RpcClientTng`中添加新对象,其中`Tng`后缀是临时的,代表“TheNextGeneration” +2. 用`SyncClient`的实现来初始化`RpcClientTng`。 +3. 将新对象添加到`solana-sdk`、`ThinClientTng`中;使用`RpcClientTng`和`AsyncClient`实现对其进行初始化 +4. 将所有单元测试从`BankClient`移至`ThinClientTng` +5. 添加`ClusterClient` +6. 将`ThinClient`用户移到`ThinClientTng` +7. 删除`ThinClient`并将`ThinClientTng`重命名为`ThinClient` +8. 将`RpcClient`用户移到新的`ThinClient` +9. 删除`RpcClient`并将`RpcClientTng`重命名为`RpcClient` diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/simple-payment-and-state-verification.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/simple-payment-and-state-verification.md new file mode 100644 index 0000000000..c116dbe7d6 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/simple-payment-and-state-verification.md @@ -0,0 +1,151 @@ +--- +title: 简单支付和状态验证 +--- + +让资源不足的客户端轻松加入Solana集群通常很有帮助。 无论是参与经济活动还是合约执行活动,验证客户活动已经被网络接受通常都很昂贵。 该提案提出了一种机制,使此类客户可以以最小的资源支出和信任第三方来确认其行为已提交到账本状态。 + +## 一种简单的方法 + +验证节点会在短时间内存储最近确认的交易的签名,以确保不会多次处理它们。 验证节点提供了一个JSONRPC端点,客户端可以使用它来查询集群(如果最近处理了事务)。 验证节点还提供PubSub通知,从而当验证节点观察到给定签名时,客户端将进行注册并进行通知。 虽然这两种机制允许客户验证付款,但它们并不是证明,并且完全依赖验证节点。 + +我们将描述一种使用Merkle证明将验证节点的响应锚定在账本中的方式来最小化这种信任的方法,使客户端可以自己确认足够数量的验证节点已确认交易。 它要求多个验证节点证明进一步降低了对验证节点的信任,因为这个过程增加了折衷其他几个网络参与者的技术和经济难度。 + +## 轻量级客户端 + +“轻量级客户端”是群集参与者,它本身并不运行验证程序。 该轻客户端提供比信任远程验证节点更高的安全级别,而它本身无需花费大量资源来验证账本。 + +验证程序不是直接向轻量客户端提供交易签名,而是从感兴趣的交易到包含区块中所有交易的Merkle树的根生成Merkle证明。 此Merkle根存储在账本条目中,该条目由验证节点投票,提供共识合法性。 轻客户端的额外安全性级别取决于轻客户端认为是集群涉及的一组初始规范验证节点。 随着该设置的更改,客户端可以使用[收据](simple-payment-and-state-verification.md#receipts)更新其内部的已知验证节点集。 对于大量的委托质押,这可能比较具有挑战性。 + +出于性能原因,验证节点本身可能希望使用轻客户端API。 例如,在验证节点的初始启动期间,验证节点可以使用状态提供的集群提供的检查点,并通过收据进行验证。 + +## 收据(Receipts) + +收据是证明的最低限度的证明;交易已包含在一个区块中,该区块已由客户的一组首选验证程序进行了投票,并且投票已达到所需的确认深度。 + +### 包含证明的交易 + +包含证明的交易是一种数据结构,其中它包含了从 Entry-Merkle 到 Block-Merkle 的交易的 Merkle 路径,该路径包含在带有所需验证节点票证的 Bank-Hash中。 来自 Bank-Hash 的包含后续验证节点投票的 PoH 条目的区块链是确认的证明。 + +#### 交易 Merkle + +Entry-Merkle 是 Merkle根,包括了给定条目中按签名排序的所有交易。 条目中的每个交易都已经在这里进行了合并:https://github.com/solana-labs/solana/blob/b6bfed64cb159ee67bb6bdbaefc7f833bbed3563/ledger/src/entry.rs#L205。 这意味着我们可以显示条目`E`中包含了交易`T`。 + +Block-Merkle 是在该块中排序的所有 Entry-Merkles 的 Merkle 根。 + +![区块 Merkle 图](/img/spv-block-merkle.svg) + +这两个 Merkle 证明结合起来证明了交易`T`包含在具有银行哈希`B`的区块中。 + +帐户哈希是在当前插槽内修改的每个帐户的状态哈希的组合哈希。 + +收据必须具有交易状态,因为状态收据是针对该区块构造的。 处于同一状态的两笔交易可能会出现在这个区块中,因此,无法仅从该状态推断出提交到账本的交易修改状态是成功还是失败了。 可能不需要对完整的状态代码进行编码,而只需对单个状态位进行编码即可指示交易成功。 + +当前,尚未实现 Block-Merkle,因此要验证 `E` 是具有银行哈希 `B` 区块中的条目,我们需要在该区块中提供所有条目哈希。 理想情况下,可以采用 Block-Merkle 来实现,但这种方法效率很低。 + +#### 区块头 +为了验证包含证明的交易,轻客户端需要能够推断网络中分支的拓扑。 + +更具体地说,轻客户端将需要跟踪传入的区块头,以便给定块`A`和`B`的两个银行哈希,他们可以确定`A`是否为`B`的祖先(下文的`乐观确认证明`章节有详细解释)。 区块头的内容是计算银行哈希值所必需的字段。 + +Bank-Hash 是上面 `Transaction Merkle` 章节所述的 Block-Merkle 和 Accounts-Hash 串联的哈希。 + +![银行哈希图](/img/spv-bank-hash.svg) + +代码: + +https://github.com/solana-labs/solana/blob/b6bfed64cb159ee67b6bdbdbaefc7f833bbbed3563/runtime/src/bank.rs#L3468-L3473 + +``` + let mut hash = hashv(&[ + // 父块的 bank hash + self.parent_hash.as_ref(), + // 所有修改账号的哈希值 + accounts_delta_hash.hash.as_ref(), + // 该区块处理的所有签名数量 + &signature_count_buf, + // 该区块的上一次 PoH 哈希值 + self.last_blockhash().as_ref(), + ]); +``` + +在验证程序的重播逻辑中沿现有流逻辑来实现是一种好方法:https://github.com/solana-labs/solana/blob/b6bfed64cb159ee67b6bb6bdbaefc7f833bbbbed3563/core/src/replay_stage.rs#L1092-L1096 + +#### 乐观确认证明 + +目前前,通过监听八卦和重播管道的侦听器可以检测到投票的乐观确认:https://github.com/solana-labs/solana/blob/b6bfed64cb159ee67bb6bdbaefc7f833bbed3563/core/src/cluster_info_vote_listener.rs#L604-L614。 + +每次投票都是一项签名交易,其中包括验证节点投票的区块银行哈希值,即上面的`Transaction Merkle`部分的`B`。 一旦网络的某个阈值`T`已对一个区块进行投票,就认为该区块是乐观确定的。 需要由这组`T`验证节点的投票才能证明乐观确认了带有银行哈希`B`的区块。 + +但是,除了某些元数据以外,已签名的投票本身当前未存储在任何地方,因此无法按需检索它们。 这些投票可能需要保留在Rocksdb数据库中,并通过`(Slot, Hash, Pubkey)`键进行索引,该键代表投票的位置,投票的银行哈希值以及负责投票的投票帐户pubkey。 + +这样就可以通过扩展现有的签名订阅逻辑,通过 RPC 向订户提供交易处理和乐观确认证明。 当检测到乐观确认时,已经通知了订阅“SingleGossip”确认级别的客户,可以提供一个标志来指示上述两个证明也应该返回。 + +要注意的一点是,对`B`进行乐观确认还意味着对`B`的所有祖先区块进行了乐观确认,而且并不是所有的区块都被乐观确认。 + +``` + +B -> B' + +``` + +因此在上面的示例中,如果乐观确认了区块`B'`,那么`B`也一样。 因此,如果交易在区块`B`中,则证明中的交易合并将针对区块`B`,但是在证明中的投票将针对区块`B'`。 这就是上文所说的`区块头`章节中的头部非常重要的原因,客户端需要验证`B`确实是`B'`的祖先。 + +#### 质押分配证明 + +一旦获得了上面的交易提示和乐观确认证明,客户就可以验证交易`T`是否在具有银行哈希的区块`B`被乐观确认。 最后一个遗漏的点是如何验证上述乐观证明中的票数实际上构成了为维护“乐观确认”的安全保证所必需的质押有效百分比`T`。 + +解决此问题的一种方法可能是,在每个质押设置发生变化的 epoch,将所有质押写入系统帐户,然后让验证程序订阅该系统帐户。 接着完整的节点可以提供Merkle证明系统帐户状态在某个区块`B`中已更新,然后表明该区块`B`被乐观确认/扎根。 + +### 账户状态验证 + +可以通过向集群提交带有 **_TBD_** 指令的交易来验证帐户的状态(余额或其他数据)。 然后,客户可以使用[包含证明的交易](#transaction-inclusion-proof)来验证群集是否同意该帐户已达到预期状态。 + +### 验证节点投票 + +领导者应将验证节点的投票按质押权重合并为一个条目。 这将减少创建收据所需的条目数量。 + +### 条目链 + +一个收据具有从付款或状态 Merkle Path 根到连续验证票列表的 PoH 链接。 + +它包含以下内容: + +- Transaction -> Entry-Merkle -> Block-Merkle -> Bank-Hash + +以及 PoH 条目的矢量: + +- 验证节点投票条目 +- 滴答 +- 轻量级条目 + +```text +/// 此条目定义跳过交易,仅包含 +/// 用于修改 PoH 交易的哈希。 +LightEntry { + /// 从上一个 Entry ID 以来的哈希数量。 + pub num_hashes: u64, + /// 从上一个 Entry ID 以来的 SHA-256 hash `num_hashes`。 + hash: Hash, + /// 编码到条目中的交易的 Merkle 根。 + entry_hash: Hash, +} +``` + +轻量级条目是从 Entries 重构的,它仅显示混合到 PoH 哈希中的 Merkle Root 条目,而不是完整的交易集。 + +客户端不需要开始投票状态。 [分叉选择](../implemented-proposals/tower-bft.md)算法的定义为,只有在交易之后出现的投票才能为交易提供最终性,并且最终性与起始状态无关。 + +### 验证 + +轻客户端知道绝大多数设置验证节点的轻客户端可以通过遵循 PoH 链的 Merkle 路径来验证收据。 Block-Merkle 是 Merkle 根,将出现在条目中包含的投票中。 轻客户端可以模拟连续投票的[分叉选择](../implemented-proposals/tower-bft.md),并验证收据已确认为所需的锁定阈值。 + +### 综合状态 + +综合状态应与银行生成的状态一起计算到银行哈希中。 + +例如: + +- Epoch验证节点帐户及其质押和权重。 +- 计算费率。 + +这些值应在银行哈希中有一个条目。 它们在已知帐户中,因此具有一个哈希连接的索引。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/slashing.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/slashing.md new file mode 100644 index 0000000000..80a2a56b19 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/slashing.md @@ -0,0 +1,35 @@ +--- +title: 罚没规则 +--- + +与工作量证明(PoW\) 不同的是,PoS系统在出块/投票时已经付出了链下的资本支出,因此需要一个风险资本来防止多链投票的逻辑/最佳策略。 我们打算实施严格的规则,如果这些规则被破坏,将导致某些违规验证节点的质押从流通中删除。 考虑到PoH数据结构的排序属性,我们认为可以将罚没规则简化为每个投票分配的投票锁定时间。 + +举例说明 每个投票都有一个关联的锁定时间\(PoH持续时间\),表示来自该验证节点的任何其他投票的持续时间必须在包含原始投票的PoH中,或者该验证节点的部分质押是可罚没的。 该持续时间是初始投票PoH计数和所有其他投票PoH计数的函数。 它可能采用以下形式: + +```text +Lockouti\(PoHi, PoHj\) = PoHj + K \* exp\(\(PoHj - PoHi\) / K\) +``` + +其中PoHi是要应用锁定的投票的高度,而PoHj是同一分叉上当前投票的高度。 如果验证节点对任何PoHk上的不同PoH分支(其中 k > j > i 和 PoHk < Lockout\(PoHi, PoHj\))进行投票,则该验证节点的部分质押有被罚没的风险。 + +除了上述功能形式锁定之外,早期实现还可以基于先进先出(FIFO) 数据结构和类似以下逻辑的数值: + +- 每个有效验证节点拥有32票的FIFO队列 +- 将新的投票推入队列\(`push_front`\) 的顶部 +- 过期的选票弹出顶部\(`pop_front`\) +- 将选票推入队列时,每个排队选票的锁定都会加倍 +- 如果`queue.len() > 32`,则从队列后面删除投票 +- 应该存储从队列后面移走的最早和最新的高度 + +可能会向任何证明已违反PoH罚没条件的节点提供一定百分比的罚没报酬。 + +### 部分罚没 + +在到目前为止描述的模式中,当验证节点对给定的PoH流进行投票时,他们将在投票锁定的时间内提交到该分叉。 一个悬而未决的问题是,如果认为处罚对于诚实的错误或轻率的行为过于严厉,验证节点是否会犹豫对可用的分叉进行投票。 + +解决此问题的一种方法是实施部分罚没,根据以下任何一种情况进行一部分罚没: + +1. 验证节点在总验证节点池中所占的比例,在同一时间段\(alaCasper\) +2. 自投票开始以来的时间量(例如,随着时间的推移,可存入的总金额线性增加的百分比),或两种都有。 + +这是目前正在探索的领域。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/snapshot-verification.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/snapshot-verification.md new file mode 100644 index 0000000000..861fd43c52 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/snapshot-verification.md @@ -0,0 +1,11 @@ +--- +title: 快照验证 +--- + +## 面临的问题 + +已实现帐户状态的快照验证,但是用于验证的快照转账哈希是伪造的。 + +## 解决方案 + +在验证节点处理交易从快照赶上群集时,请使用传入的投票交易和承诺计算器来确认群集确实正在建立在快照的转账哈希。 达到阈值承诺水平后,将快照视为有效并开始投票。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/tick-verification.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/tick-verification.md new file mode 100644 index 0000000000..346f0c90fa --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/tick-verification.md @@ -0,0 +1,43 @@ +--- +title: 时钟验证(Tick Verification) +--- + +这样可以设计插槽中的刻度线的标准和验证。 它还描述了错误处理和罚没条件,包括系统如何处理不满足这些要求的传输。 + +# 插槽结构 + +每个插槽必须包含一个预期的`ticks_per_slot`滴答次数。 插槽中的最后一个碎片必须仅包含最后一次滴答,而不能包含其他任何内容。 领导者还必须用`LAST_SHRED_IN_SLOT`标志标记包含最后一次滴答的碎片。 在滴答之间,必须有`hashes_per_tick`个哈希值。 + +# 处理不良传播 + +恶意传输`T`的处理方式有两种: + +1. 如果领导者可以为同一个插槽生成一些错误的传输`T`以及一些替代传输`T‘`,而不会违反重复传输的任何罚没规则(例如,如果`T‘`是`T`的子集),则群集必须处理两种传输均处于活动状态的可能性。 + +因此,这意味着我们无法将错误的传输`T`标记为已死,因为集群可能已就`T‘`达成共识。 这些案件需要严厉的证据来惩治这种不良行为。 + +2. 否则,我们可以简单地将插槽标记为已死且无法播放。 根据可行性,罚没可能是必要的,也可能不是必要的。 + +# Blockstore 接收碎片 + +当 blockstore 收到一个新的碎片`s`,有两个实例: + +1. 将`s`标记为`LAST_SHRED_IN_SLOT`,然后检查该存储区中是否存在用于此插槽的碎片`s‘`,其中`s'.index > s.index`。如果是,则将`s`和`s‘`一起构成罚没的证明。 + +2. Blockstore已经收到一个标记为`LAST_SHRED_IN_SLOT`的带有索引`i`的碎片`s'`。 如果`s.index > i`,则`s`和`s'`一起构成一个罚没证明。 在这种情况下,blockstore也不会插入`s`。 + +3. 相同索引的重复碎片将被忽略。 相同索引的不可重复的碎片是一个可罚没的条件。 有关这种情况的详细信息,请参见`领导者重复区块罚没`章节。 + +# 重播和验证滴答 + +1. 重播阶段的重播来自blockstore的条目,它跟踪每个插槽中已观察到的滴答数量,并确认在各个标记之间有`hashes_per_tick`个哈希值。 在播放完最后一个碎片的滴答之后,重播阶段会检查滴答的总数。 + +失败场景1:如果有两个连续的滴答,其间的哈希数为`!=Hashes_per_tick`,则将此插槽标记为无效。 + +失败情况2:如果滴答数量等于 != `ticks_per_slot`,则将插槽标记为无效。 + +失败情况3:如果滴答的数量达到`ticks_per_slot`,但我们仍未看到`LAST_SHRED_IN_SLOT`,则将此插槽标记为无效。 + +2. 当ReplayStage达到标记为最后一个碎片时,它将检查这个碎片是否为一次滴答。 + +失败情况:如果带有`LAST_SHRED_IN_SLOT`标志的带符号碎片无法反序列化为滴答(无法反序列化或反序列化为条目),则将此插槽标记为无效。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/validator-proposal.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/validator-proposal.md new file mode 100644 index 0000000000..70554f61c5 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/validator-proposal.md @@ -0,0 +1,29 @@ +--- +title: 验证节点 +--- + +## 历史 + +当我们首次启动Solana时,目标是降低TPS索赔的风险。 我们知道,在乐观并发控制和领导者在位时间太长之间,PoS共识并不是TPS的最大风险。 这是基于GPU的签名验证、软件流水线和并发银行业务。 因此,TPU诞生了。 在达到100kTPS之后,我们将团队划分出一个小组,争取突破710k TPS,另一小组则巩固验证程序管道。 因此,TVU诞生了。 当前的体系结构是按顺序和项目优先级进行增量开发的结果。 这并不反映我们曾经认为这些技术最为优雅的表现。 在领导者轮换的背景下,领导者与验证之间的明显区别变得模糊。 + +## 验证与领导之间的差异 + +管道之间的根本区别在于存在PoH的时间。 作为领导者的角色,我们处理交易,删除不良交易,然后用PoH哈希标记结果。 作为验证节点的角色,我们验证哈希,将其剥离并以完全相同的方式处理事务。 唯一的区别是,如果验证者看到错误的交易,不能像领导者一样简单地将其删除,因为这会导致PoH哈希发生变化。 相反,它拒绝整个区块。 流水线之间的另一个区别是银行交易_后_会发生的事情。 领导者将条目广播到下游验证节点,而验证节点已经在RetransmitStage中完成了此操作,这是确认时间的最优化。 另一方面,验证管道还有最后一步。 每当处理完一个区块后,它都需要权衡它所观察到的任何分支,并可能投一票,如果这样,则将其PoH哈希值重置为刚投票的块哈希值。 + +## 拟定设计 + +我们解开了许多抽象层,并构建了一个管道,只要验证者的ID在领导者时间表中显示,就可以切换领导者模式。 + +![验证节点区块图](/img/validator-proposal.svg) + +## 显著的变化 + +- TPU之外提升FetchStage和BroadcastStage +- BankForks更名为Banktree +- TPU转移到名为solana-tpu的新工具箱。 +- TPU的BankingStage吸收了ReplayStage +- TVU消失了 +- 新的修复阶段吸收了碎片获取阶段和修复请求 +- JSONRPC服务是可选的-用于调试。 相反,它应该是单独的`solana-blockstreamer`可执行文件的一部分。 +- 新的MulticastStage吸收了RetransmitStage的重发部分 +- Blockstore下游的MulticastStage diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/vote-signing-to-implement.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/vote-signing-to-implement.md new file mode 100644 index 0000000000..7767392682 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/proposals/vote-signing-to-implement.md @@ -0,0 +1,116 @@ +--- +title: 安全投票签名 +--- + +## 安全投票签名 + +此设计描述了其他投票签名行为,它将使该过程更加安全。 + +当前,Solana实现了一项投票签名服务,该服务会评估每个投票,以确保它不违反罚没的条件。 取决于硬件平台功能,该服务可能稍微不同。 特别是,它可以与安全区域 \(例如SGX\) 结合使用。 Enclave 可以生成非对称密钥,为用户\(不受信任的\) 代码公开API以签名投票交易,同时将投票签名私钥保留在其受保护的内存中。 + +以下各节概述了此体系结构的工作方式: + +### 消息流 + +1. 节点在启动时初始化enclave + + - 快速生成非对称密钥,并将公钥返回给 + + 节点 + + - 密钥对是短暂的。 节点启动时会生成一个新的密钥对。 一个 + + 新的密钥对也可能会在运行时 + + 根据待确定的密钥对进行生成标准。 + + - Enclave 将其证明报告返回给节点 + +2. 节点执行enclave 的证明\(例如使用Intel的IAS API\) + + - 节点确保Secure Enclave在TPM上运行 + + 并且是由受信方签名 + +3. 节点的质押者授予临时密钥许可以使用其质押。 + + 这一过程有待确定。 + +4. 节点的不受信任的非安全区软件调用受信任的安全区软件 + + 使用其界面来签名交易和其他数据。 + + - 在投票表决的情况下,节点需要验证PoH。 PoH验证 + + 是签名不可或缺的一部分。 Enclave 会 + + 在签名投票之前提供一些可验证的数据来进行检查。 + + - 确定在不受信任的空间中生成可验证数据的过程 + +### PoH 验证 + +1. 当节点对条目`X`投票时,存在一个锁定期`N`,因为 + + 它无法在其历史记录中不包含`X`的分叉上投票。 + +2. 每次节点对`X`的导数投票时,让它为`X+y`,则 + + 锁定`X`的周期增加了`F`因子\(即持续时间节点无法对 + + 不包含`X`增加的分叉进行投票\)。 + + - `X+y`的锁定期仍为`N`,直到节点再次投票为止。 + +3. 锁定期的增加上限为\(例如,系数`F`最大为 + + 32\)。 + +4. 签名区域不得签名违反该政策的投票。 这个方法 + + 意味着 + + - 快速初始化为`N`、`F`和`因子上限`。 + - Enclave存储 `因子上限` 节点上的条目 ID 数量 + + 先前投票 + + - 的签名请求包含新投票的条目ID + - Enclave验证新投票的条目ID是否在正确的分叉上 + + \(遵循上述规则 \#1 和 \#2 \) + +### 祖先验证 + +这是另一种验证投票分叉的方法,尽管这种方法不太确定。 1. 验证节点在集群中维护一个活动节点集 2. 观察上一个投票周期活动集中的投票 3. 存储每个节点投票的祖先/上一次滴答 4. 发送新的投票请求进行投票签名服务 + +- 它包括来自活动集中节点的先前投票及其 + + 对应的祖先 + + 1. 签名人检查先前的投票是否包含来自验证节点的投票, + + 并且投票祖先与大多数节点匹配 + +- 如果检查成功,它将签名新的投票 +- 如果检查不成功,则断言\(引发某种报错\) + +前提是验证节点最多可以被伪装一次,对不正确的数据进行投票。 如果有人劫持了验证节点并提交了对虚假数据的投票请求,那么该投票将不会包含在PoH中(因为它将被集群拒绝)。 验证节点下一次发送签名请求的签名时,签名服务将检测到验证节点的最后一票丢失了(作为 + +## 见上文第5点的一部分\)。 + +### 分叉确定 + +由于速度太快无法处理PoH,因此无法直接知道已提交验证节点投票的分叉历史。 每个enclave都应使用当前的公开密钥的_活跃集_来启动。 验证节点应提交其当前投票以及在其先前投票中观察到的活动集\(包括自身\) 的投票。 这样,enclave可以在验证节点上次投票的同时进行投票,从而对分叉进行投票。 验证节点最初提交的投票是不可能的,因为它没有‘上一个’插槽供参考。 为了解决这个问题,应该暂时冻结投票,直到第二次投票提交为止,在初始投票的高度,其中包含活动集中的投票及其自身的投票。 + +### Enclave 配置 + +质押的客户端应该是可配置的,以防止对不活跃的分叉进行投票。 该机制应该使用客户端的已知活动集`N_active`以及阈值投票`N_vote`和阈值深度`N_depth`来确定是否继续对提交的分叉进行投票。 此配置应采用这样的一种规则,以便客户端仅在`N_depth`观察到超过`N_vote`的情况下才对分叉进行投票。 实际上,这代表客户端确认它已经观察到一定深度的提交分叉的经济最终性,如果该分叉最终没有被使用,则额外的投票将需要锁定一段不必要的时间。 + +### 难点 + +1. 第一代可验证数据在不受信任的空间中 + + 用于PoH验证区块。 + +2. 需要将质押临时授权密钥的基础设施。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator.md new file mode 100644 index 0000000000..5b5caedfc3 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator.md @@ -0,0 +1,7 @@ +--- +title: 运行一个验证节点 +--- + +本节介绍了如何运行一个 Solana 验证节点。 + +有几个可以连接的集群,请参看 [选择一个集群](cli/choose-a-cluster.md) 来大致了解每个集群。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/restart-cluster.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/restart-cluster.md new file mode 100644 index 0000000000..31ecc8d153 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/restart-cluster.md @@ -0,0 +1,81 @@ +## 重新启动集群 + +### 步骤1。 确定集群将在以下位置重新启动的插槽 + + +乐观确认的最高插槽是开始的最佳插槽,可通过查找[这里](https://github.com/solana-labs/solana/blob/0264147d42d506fb888f5c4c021a998e231a3e74/core/src/optimistic_confirmation_verifier.rs#L71)的性能指标数据。 否则,请使用最后一个根。 + +调用这个插槽 `SLOT_X` + +### 步骤2。 停止(一个或多个) 验证节点 + +### 步骤3。 安装新的solana版本 + +### 步骤4。 在插槽`SLOT_X`上为插槽`SLOT_X`的硬分叉创建一个新的快照。 + +```bash +$ solana-ledger-tool -l ledger create-snapshot SLOT_X ledger --硬分叉 SLOT_X +``` + +现在,账本目录应包含一个新的快照。 `solana-ledger-tool-create-snapshot` 也会输出新的碎片版本和bank哈希值,分别调用 NEW\_SHRED\_VERSION 和 NEW\_BANK\_HASH。 + +调整验证节点的参数: + +```bash + --wait-for-supermajority SLOT_X + --expected-bank-hash NEW_BANK_HASH +``` + +然后重新启动验证节点。 + +使用日志确认验证程序已启动,并且现在处于`SLOT_X`的等待模式,正在等待绝大多数投票。 + +### 步骤5。 在 Discord 上宣布重启: + +在#announcements 频道发布如下内容(酌情调整文本): + +> Hi @Validators, +> +> We've released v1.1.12 and are ready to get testnet back up again. +> +> Steps: 1. Install the v1.1.12 release: https://github.com/solana-labs/solana/releases/tag/v1.1.12 2. a. Preferred method, start from your local ledger with: +> +> ```bash +solana-validator + --wait-for-supermajority SLOT_X # <-- NEW! IMPORTANT! REMOVE AFTER THIS RESTART + --expected-bank-hash NEW_BANK_HASH # <-- NEW! IMPORTANT! REMOVE AFTER THIS RESTART + --hard-fork SLOT_X # <-- NEW! IMPORTANT! REMOVE AFTER THIS RESTART + --no-snapshot-fetch # <-- NEW! IMPORTANT! REMOVE AFTER THIS RESTART + --entrypoint entrypoint.testnet.solana.com:8001 + --trusted-validator 5D1fNXzvv5NjV1ysLjirC4WY92RNsVH18vjmcszZd8on + --expected-genesis-hash 4uhcVJyU9pJkvQyS88uRDiswHXSCkY3zQawwpjk2NsNY + --no-untrusted-rpc + --limit-ledger-size + ... # <-- your other --identity/--vote-account/etc arguments +``` + +b. If your validator doesn't have ledger up to slot SLOT_X or if you have deleted your ledger, have it instead download a snapshot with: + +```bash +solana-validator + --wait-for-supermajority SLOT_X # <-- NEW! IMPORTANT! REMOVE AFTER THIS RESTART + --expected-bank-hash NEW_BANK_HASH # <-- NEW! IMPORTANT! REMOVE AFTER THIS RESTART + --entrypoint entrypoint.testnet.solana.com:8001 + --trusted-validator 5D1fNXzvv5NjV1ysLjirC4WY92RNsVH18vjmcszZd8on + --expected-genesis-hash 4uhcVJyU9pJkvQyS88uRDiswHXSCkY3zQawwpjk2NsNY + --no-untrusted-rpc + --limit-ledger-size + ... # <-- your other --identity/--vote-account/etc arguments +``` + + You can check for which slots your ledger has with: `solana-ledger-tool -l path/to/ledger bounds` + +3. 等待80%的质押在线 + +要确认您已经正确重新启动验证程序并且在等待80%质押: a。 查找八卦日志消息中`可见的N%活跃质押` b. 通过RPC询问它在哪个插槽上:`solana --url http://127.0.0.1:8899 slot`。 它应该返回`SLOT_X`,直到我们获得80%的质押 + +感谢! + +### 步骤7。 等待并关注最新消息 + +重新启动验证器时,请对其进行监视。 回答疑问,帮助其他同伴, diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/validator-info.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/validator-info.md new file mode 100644 index 0000000000..789e4660cc --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/validator-info.md @@ -0,0 +1,61 @@ +--- +title: 发布验证者信息 +--- + +您可以将验证者信息发布到链上,以使其对其他用户公开可见。 + +## 运行solana validator-info + +运行solana CLI来获取一个验证者信息帐户: + +```bash +solana validator-info publish --keypair ~/validator-keypair.json +``` + +关于VALIDATOR_INFO_ARGS可选字段的详细信息: + +```bash +solana validator-info publish --help +``` + +## 示例命令 + +发布命令示例: + +```bash +solana validator-info publish "Elvis Validator" -n elvis -w "https://elvis-validates.com" +``` + +示例查询命令: + +```bash +solana validator-info get +``` + +输出为 + +```text +Validator info from 8WdJvDz6obhADdxpGCiJKZsDYwTLNEDFizayqziDc9ah + Validator pubkey: 6dMH3u76qZ7XG4bVboVRnBHR2FfrxEqTTTyj4xmyDMWo + Info: {"keybaseUsername":"elvis","name":"Elvis Validator","website":"https://elvis-validates.com"} +``` + +## 密钥库 + +包括Keybase用户名,客户端应用程序\(例如Solana Network Explorer \) 可以自动引入您的验证节点公共配置文件,包括密码证明,品牌标识等。 要将验证器公钥与Keybase连接: + +1. 加入[https://keybase.io/](https://keybase.io/)并填写您的验证节点个人资料 +2. 将您的验证节点**身份pubkey**添加到Keybase: + + - 在本地计算机上创建一个名为`validator-`的空文件。 + - 在“密钥库”中,导航到“文件”,然后将您的pubkey文件上传到 + + 公用文件夹中的`solana`子目录:`/keybase/public//solana` + + - 要检查您的公钥,请确保您可以成功浏览到 + + `https://keybase.pub//solana/validator-` + +3. 使用Keybase用户名添加或更新您的`solana Validator-info`。 然后 + + CLI将验证`validator-`文件 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/validator-monitor.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/validator-monitor.md new file mode 100644 index 0000000000..7c45fbc102 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/validator-monitor.md @@ -0,0 +1,42 @@ +--- +title: 监控验证节点 +--- + +## 检查 Gossip + +通过运行以下命令,确认您的验证节点的IP地址和**身份pubkey**在八卦网络中处于可见状态: + +```bash +solana-gossip spy --entrypoint devnet.solana.com:8001 +``` + +## 检查余额 + +当您的验证节点提交选票时,您的帐户余额应减少交易费用,而在担任领导者后,您的帐户余额应增加。 通过`lamports`进行更详细的观察: + +```bash +solana balance --lamports +``` + +## 检查投票活动 + +`solana vote-account`命令可以显示验证者最近的投票活动: + +```bash +solana vote-account ~/vote-account-keypair.json +``` + +## 获取集群信息 + +有几个有用的JSON-RPC端点,用于监视集群上的验证节点以及集群的运行状况: + +```bash +#与solana-gossip相似,您应该在集群节点列表中看到您的验证节点 +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getClusterNodes"}' http://devnet.solana.com +# 如果您的验证节点进行了正确的投票,那么它应该出现在“当前”投票帐户列表中。 如果已经质押,那么`stake` 应当为 > 0 +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getVoteAccounts"}' http://devnet.solana.com +# 返回当前的领导者安排表 +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getLeaderSchedule"}' http://devnet.solana.com +# 返回当前 epoch 的信息 slotIndex 应该在随后的调用中获得进展。 +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getEpochInfo"}' http://devnet.solana.com +``` diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/validator-reqs.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/validator-reqs.md new file mode 100644 index 0000000000..163ca3f496 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/validator-reqs.md @@ -0,0 +1,64 @@ +--- +title: 验证节点要求 +--- + +## 硬件 + +- CPU 推荐 + - 我们建议使用尽可能多的内核。 AMD Threadripper或Intel服务器\(Xeon\) CPU都很好。 + - 我们建议您使用AMD Threadripper,因为与英特尔相比,您可以获得更多的并行内核。 + - 与同等的英特尔产品相比,Threadripper还具有每核成本优势和更多的PCIe通道。 PoH\(历史证明\) 基于sha256,并且Threadripper还支持sha256硬件指令。 +- 验证节点的SSD规则I/O样式\(SATA vs NVMe/M.2\) + - 最低配置示例 - Samsung 860 Evo 2TB + - 中等配置示例 - Samsung 860 Evo 4TB + - 高端配置示例 - Samsung 860 Evo 4TB +- GPU + - 虽然纯CPU的节点可能能够跟上初始的空闲网络,但是一旦事务吞吐量增加,就将需要GPU。 + - 什么类型的 GPU ? + - 我们建议使用Nvidia Turing和volta系列GPU(从1660ti到2080ti系列用户级GPU或Tesla系列服务器GPU)。 + - 我们目前不支持OpenCL,因此不支持AMD GPU。 我们对移植Solana到OpenCL设有一项奖励。 有兴趣? [请查看我们的GitHub。](https://github.com/solana-labs/solana) +- 电源消耗 + - 运行AMD Threadripper 3950x和2x 2080Ti GPU的验证器节点,其功耗大约为800-1000W。 + +### 预配置设置 + +以下是我们关于低、中、高端机器规格的建议: + +| | 低端配置 | 中等配置 | 高端配置 | 注意事项 | +|:----------- |:------------------- |:---------------------- |:---------------------- |:-------------------------------------- | +| CPU | AMD Ryzen 3950x | AMD Threadripper 3960x | AMD Threadripper 3990x | 考虑设立一个能够使用10Gb的主板,尽可能多地配备PCIe通道和m.2插槽。 | +| RAM | 32GB | 64GB | 128GB | | +| Ledger 驱动器 | Samsung 860 Evo 2TB | Samsung 860 Evo 4TB | Samsung 860 Evo 4TB | 或等效的 SSD | +| 账户驱动\(s\) | 无 | Samsung 970 Pro 1TB | 2x Samsung 970 Pro 1TB | | +| GPU | Nvidia 1660ti | Nvidia 2080 Ti | 2x Nvidia 2080 Ti | Linux 平台支持的任何 Cuda 的 GPU。 | + +## 云平台虚拟机 + +虽然您可以在云计算平台上运行验证节点,但从长远来看它可能并不具有成本效益。 + +但是,在VM实例上运行非投票api节点,来供您自己内部使用可能会很方便。 该用例包括在Solana上构建的交易所和服务。 + +实际上,官方mainnet-beta API节点当前(2020年10月) 在具有2048 GB SSD的 GCE `n1-standard-32`(32 vCPU,120 GB内存) 实例上运行。 + +对于其他云平台,请选择具有类似规格的实例类型。 + +并且还要注意,出口互联网流量使用可能会很高,尤其是运行质押验证程序的情况。 + +## Docker + +我们不建议在Docker内部为活动集群(包括mainnet-beta) 运行验证程序,并且通常也不支持这个功能。 除非特别配置,否则这是由于担心一般docker的容器化开销和导致的性能下降。 + +我们仅将docker用于开发目的。 + +## 软件设置 + +- 我们在Ubuntu 04/18上进行开发和运行。 在Ubuntu 04/16上运行时,某些用户会遇到一些问题 +- 请参阅 [安装Solana](../cli/install-solana-cli-tools.md) 以获取当前的 Solana 软件版本。 + +请确保所使用的计算机不在本地NAT后面,以避免NAT遍历问题。 云托管的机器效果最好。 **请确保8000到10000的IP端口没有被禁止,来让网络实现进出通信。** 关于寄宿网络端口转发的更多信息,请参阅 [这个文档](http://www.mcs.sdsmt.edu/lpyeatt/courses/314/PortForwardingSetup.pdf)。 + +预构建的二进制文件是在 Linux x86_64 \(推荐Ubuntu 18.04\)。 MacOS 或 WSL 用户可以从源代码构建。 + +## GPU 要求 + +要在您的系统上使用GPU,必须使用CUDA。 发布的 Solana 二进制文件是通过 [CUDA Toolkit 10.1 update 1](https://developer.nvidia.com/cuda-toolkit-archive) 在 Ubuntu 18.04 上构建的。 如果您的机器使用了不同的 CUDA,那么您将需要从源代码进行重建。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/validator-stake.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/validator-stake.md new file mode 100644 index 0000000000..96d131d1fc --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/validator-stake.md @@ -0,0 +1,103 @@ +--- +title: 质押 +--- + +** 在默认情况下,您的验证节点是没有质押的。** 这意味着无法当选领导者。 + +## 监测更新 + +如果要委托质押,首先请确保您的验证程序正在运行,并且跟上集群。 验证节点启动后,可能需要一些时间来跟上。 请使用 `catchup` 命令来监控该过程: + +```bash +solana catchup ~/validator-keypair.json +``` + +在验证节点跟上之前,它无法成功投票,因此也无法委托质押。 + +另外,如果集群插槽速度比您的快,那么你很可能永远都跟不上最新状态。 这通常意味着您的验证节点与群集其余部分之间出现某种网络问题。 + +## 创建质押密钥 + +如果还没有质押密钥,那么您需要新创建一个。 如果你完成了这个步骤,那么在 Solana 运行目录中将出现 “validator-stake-keypair.json”。 + +```bash +solana-keygen new -o ~/validator-stake-keypair.json +``` + +## 委托您的质押 + +在首先创建质押帐户之前,现在先把 1 SOL 委托给您的验证节点: + +```bash +solana create-stake-account ~/validator-stake-keypair.json 1 +``` + +然后将这个质押委托给您的验证节点: + +```bash +solana delegate-stake ~/validator-stake-keypair.json ~/vote-account-keypair.json +``` + +> 不要委托您剩余的 SOL,因为验证程序需要用这些代币进行投票。 + +任何时候都可以使用相同的命令将质押重新委托到另一个节点,但每个 epoch 只能够换一次: + +```bash +solana delegate-stake ~/validator-stake-keypair.json ~/some-other-vote-account-keypair.json +``` + +假设节点正在投票,现在您已经开始运行并产生验证节点奖励。 在每个 epoch 结束阶段,奖励会自动进行发放。 + +根据投票帐户中设置的佣金率,所赚取的lamports奖励将在您的质押帐户和投票帐户之间分配。 奖励只能在验证节点启动并运行时获得。 此外,验证节点一旦投入,便成为网络的重要组成部分。 为了安全地从网络中删除验证节点,请先停用其质押。 + +在每个时段的末尾,验证程序都将发送投票交易。 这些投票交易由验证者的身份帐户中的lamports支付。 + +这是正常交易,因此将收取标准交易费。 交易费用范围由创世区块定义。 实际费用将根据交易量而变动。 您可以在提交交易之前通过[RPC API “getRecentBlockhash”](developing/clients/jsonrpc-api.md#getrecentblockhash)确定当前费用。 + +点击这里了解更多关于 [交易费的信息](../implemented-proposals/transaction-fees.md)。 + +## 验证节点预热 + +为了抵制对共识的各种攻击,新的质押委托需要经过一个[预热](/staking/stake-accounts#delegation-warmup-and-cooldown)阶段。 + +在预热期间,您可以通过以下命令来监控一个验证节点的委托: + +- 查看您的投票账户:`solana vote-account - keypair.json`,这将显示验证节点提交给网络的所有投票的当前状态。 +- 查看您的质押账户、委托偏好以及您的质押细节:`solana stock-account ~/validator-stake-keypair.json` +- `Solana validators` 显示当前所有验证程序的活跃质押,包括您的 +- `solana stake-history` 展示了最近epochs中预热和冷却的历史 +- 在您的验证节点查找日志消息,指明您的下一位领导者插槽:`[2019-09-27T20:16:00.319721164Z INFO solana_core:::replay_stage] 投票并在出块高度重置PoH####。 我的下一个领导者插槽是 ####` +- 质押预热完毕后,您可以通过运行 `solana validators` 来看到验证程序中列出的一个质押余额。 + +## 监视您质押的验证节点 + +确认你的验证节点变成了一个 [领导者](../terminology.md#leader) + +- 在您的验证节点被追上后,使用`solanabalance`命令来监控收入,因为您的验证人被选为领导者并收取交易费用 +- Solana节点提供了许多有用的JSON-RPC方法,来返回有关网络和验证节点参与的信息。 通过使用curl\(或您选择的另一个http客户端) 发出请求,并在JSON-RPC格式的数据中指定所需的方法。 例如: + +```bash + // 请求 + curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getEpochInfo"}' http://localhost:8899 + + // 结果 + {"jsonrpc":"2.0","result":{"epoch":3,"slotIndex":126,"slotsInEpoch":256},"id":1} +``` + +有用的 JSON RPC 方法: + +- `getEpochInfo`[一个纪元](../terminology.md#epoch) 是一段时间,即 [slots](../terminology.md#slot)的数量,一个 [领导者计划](../terminology.md#leader-schedule) 在这个期间有效。 这将告诉你当前的epoch以及集群经过了多长时间。 +- `getVoteAccounts` 这将告诉您,目前验证程序有多少活跃的质押。 验证节点的质押百分比是在epoch刚开始时激活的。 您可以 [在这里](../cluster/stake-delegation-and-rewards.md) 了解更多关于Solana质押的信息。 +- `getLeaderSchedule` 在任何时候,网络只需要一个验证节点来生成账本条目。 目前被选定生成账本条目的 [验证节点](../cluster/leader-rotation.md#leader-rotation) 被称为“领导者”。 这将返回当前激活质押的完整领导者时间表\(按插槽来算\) ,身份公钥将在此处显示一次或多次。 + +## 停用质押 + +在从集群中分离验证节点之前,应通过运行以下命令停用先前委托的质押: + +```bash +solana deactivate-stake ~/validator-stake-keypair.json +``` + +质押不会立即停用,而是类似于预热的方式先进行冷却。 您的验证程序应在冷却时保持在群集上。 在冷却的同时,您的质押将继续获得奖励。 只有在质押冷却之后,才能安全关闭验证节点或从网络中撤出。 冷却时间可能需要几个epoch,具体取决于活跃质押及其规模。 + +请注意,质押帐户只能使用一次,所以在停用后, 使用CLI客户端的 `withdraw-stake` 命令来恢复先前有质押的份额。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/validator-start.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/validator-start.md new file mode 100644 index 0000000000..44c1beb16a --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/running-validator/validator-start.md @@ -0,0 +1,353 @@ +--- +title: 启动验证程序 +--- + +## 配置 Solana CLI + +Solana cli包含`get`和`set`配置命令,可自动为cli命令设置`--url`参数。 例如: + +```bash +solana config set --url http://devnet.solana.com +``` + +尽管本节演示了如何连接到Devnet群集,但其他的[Solana群集](../clusters.md)步骤与此类似。 + +## 确认集群可以访问 + +在附加验证节点之前,通过获取事务计数来明确检查集群是否可被您的机器访问: + +```bash +solana 交易数统计 +``` + +查看 [性能展板](https://metrics.solana.com:3000/d/monitor/cluster-telemetry) 来了解集群活动的细节。 + +## 确认您的安装程序 + +尝试运行以下命令以加入八卦网络并查看集群中的所有其他节点: + +```bash +solana-gossip spy --entrypoint devnet.solana.com/8001 +# 按^C 退出 +``` + +## 启用 CUDA + +如果您的机器安装了 CUDA 的 GPU \(Linux-only currently\),请将 `--cuda` 参数包含到 `solana-validator`。 + +当您的验证程序启动后,请查找以下日志消息来确认CUDA已启用: `"[ solana::validator] CUDA is enabled"` + +## 系统调试 + +### Linux 系统 +#### 自动模式 +Solana代码库有一个守护程序,用于调整系统设置以优化性能(即通过增加OS UDP缓冲区和文件映射限制)。 + +守护进程(`solana-sys-tuner`) 已包含在solana二进制版本中。 在每次软件升级之后,在重新启动验证节点*之前*进行重新启动,以确保配置了系统建议的最新设置。 要运行它: + +运行: + +```bash +sudo solana-sys-tuner --user $(whoami) > sys-tuner.log 2>&1 & +``` + +#### 手动模式 +如果希望自己管理系统设置,您可以使用以下命令。 + +##### **增加UDP缓冲区** +```bash +sudo bash -c "cat >/etc/sysctl.d/20-solana-udp-buffers.conf </etc/sysctl.d/20-solana-mmaps.conf </etc/security/limits.d/90-solana-nofiles.conf < 注意:"validator-keypair.json"文件也是您的 \(ed25519\) 私钥。 + +### 纸钱包身份 + +您可以为身份文件创建一个纸钱包,而不用将密钥对文件写入到磁盘: + +```bash +solana-keygen new --no-outfile +``` + +现在可以通过运行以下操作查看相应的身份公钥: + +```bash +solana-keygen pubkey ASK +``` + +然后输入您的种子短语。 + +查看 [纸钱包使用](../wallet-guide/paper-wallet.md) 获取更多信息。 + +--- + +### 虚拟密钥 + +您可以使用solana-keygen生成一个自定义的虚拟密钥。 例如: + +```bash +solana-keygen grind --starts-with e1v1s:1 +``` + +根据请求的字符串,可能需要几天时间才能匹配... + +--- + +您的验证节点身份密钥独特识别了您在网络中的验证节点。 **备份此信息至关重要。** + +如果您不备份此信息,那么如果您无法访问验证节点的话,将无法对其进行恢复。 如果发生这种情况,您将失去SOL TOO的奖励。 + +要备份您的验证节点识别密钥, **请备份您的"validator-keypair.json" 文件或种子短语到一个安全位置。** + +## 更多 Solana CLI 配置 + +现在您有了密钥对,将solana配置设置为对以下所有命令使用验证节点密钥对: + +```bash +solana config set --keypair ~/validator-keypair.json +``` + +您应该看到以下输出: + +```text +Wallet Config Updated: /home/solana/.config/solana/wallet/config.yml +* url: http://devnet.solana.com +* keypair: /home/solana/validator-keypair.json +``` + +## 空投 & 检查验证节点账户余额 + +空投自己一些SOL即可开始使用: + +```bash +solana airdrop 10 +``` + +请注意,空投只能在Devnet和Testnet上使用。 每次请求都限制在 10 个 SOL。 + +要查看您当前的余额: + +```text +solana balance +``` + +或查看更详细的信息: + +```text +solana balance --lamports +``` + +在这里阅读更多关于 [SOL与lamports 之间的差异](../introduction.md#what-are-sols)。 + +## 创建一个投票账户 + +如果您还没有进行这一步,请创建一个投票帐户密钥对并在网络上创建该投票帐户。 如果完成了此步骤,则应该在Solana运行时目录中看到“ vote-account-keypair.json”: + +```bash +solana-keygen new -o ~/vote-account-keypair.json +``` + +以下命令可用于使用所有在区块链上创建投票帐户的默认选项: + +```bash +solana create-vote-account ~/vote-account-keypair.json ~/validator-keypair.json +``` + +阅读更多关于 [创建和管理一个投票账户](vote-accounts.md)的信息。 + +## 可信的验证程序 + +如果您知道并信任其他验证节点节点,则可以在命令行中使用`solana-validator`的参数`--trusted-validator`来指定。 您可以通过重复参数`--trusted-validator --trusted-validator `来指定多个。 这有两种作用,一种是当验证节点使用`--no-untrusted-rpc`引导时,它只会询问那组受信任的节点来下载创世区块和快照数据。 另一个是结合`--halt-on-trusted-validator-hash-mismatch`选项,它将监视八卦上其他受信任节点的整个帐户状态的merkle根哈希,如果哈希有任何不匹配,验证节点将停止该节点,以防止验证节点投票或处理可能不正确的状态值。 目前,验证节点在其上发布哈希的插槽已与快照间隔绑定。 为了使该功能生效,应将可信集中的所有验证节点设置为相同的快照间隔值或相同的倍数。 + +我们强烈建议您使用这些选项来防止恶意快照状态下载或帐户状态差异。 + +## 连接您的验证节点 + +通过运行以下命令连接到集群: + +```bash +solana-validator \ + --identity ~/validator-keypair.json \ + --vote-account ~/vote-account-keypair.json \ + --ledger ~/validator-ledger \ + --rpc-port 8899 \ + --entrypoint devnet.solana.com:8001 \ + --limit-ledger-size \ + --log ~/solana-validator.log +``` + +要强制验证日志记录到控制台,请添加 `--log -` 参数,否则验证程序将自动登录到一个文件。 + +> 注意:您可以使用 [纸钱包种子短语](../wallet-guide/paper-wallet.md) 用于您的 `--identity` 和/或 `--authorized-panitor` 密钥对。 要使用这些参数,请将各自的参数作为 `solana-validator --idential ASK ... --authorized-lister ASK ...` 并且您将会收到 输入您的种子短语和可选密码的提示。 + +通过打开一个新终端并运行以下命令来确认连接到网络的验证节点: + +```bash +solana-gossip spy --entrypoint devnet.solana.com:8001 +``` + +如果您的验证节点已连接,其公钥和IP地址将出现在列表中。 + +### 控制本地网络端口分配 + +默认情况下,验证节点将在8000-1000范围内动态选择可用的网络端口,可能会覆盖 `--dynamic-port-range`。 例如: `solana-validator --dynamic-port-range 11000-110...` 将限制验证节点到 11000-11010 端口。 + +### 限制账本大小以节省磁盘空间 +`--limit-ledger-size` 参数允许您指定磁盘保留多少个账本[碎片](../terminology.md#shred)。 如果您没有配置该参数,验证节点将保留整个账本直到磁盘空间满了为止。 + +保持账本磁盘使用量的默认值小于 500GB。 如果需要,可以通过添加参数到 `--limit-ledger-size` 来增加或减少磁盘的使用。 查看 `solana-validator --help` 来配置 `--limit-ledger-size` 所使用的默认限制值。 关于选择一个普通限制值的更多信息请参看 [这里](https://github.com/solana-labs/solana/blob/583cec922b6107e0f85c7e14cb5e642bc7dfb340/core/src/ledger_cleanup_service.rs#L15-L26)。 + +### 系统单位 +将验证程序作为系统单元运行是管理后台运行的一种简单方法。 + +假定您的机器上有一个名为 `sol` 的用户,通过以下命令来创建 `/etc/systemd/system/sol.service` 文件: +``` +[Unit] +Description=Solana Validator +After=network.target +Wants=solana-sys-tuner.service +StartLimitIntervalSec=0 + +[Service] +Type=simple +Restart=always +RestartSec=1 +User=sol +LimitNOFILE=500000 +LogRateLimitIntervalSec=0 +Environment="PATH=/bin:/usr/bin:/home/sol/.local/share/solana/install/active_release/bin" +ExecStart=/home/sol/bin/validator.sh + +[Install] +WantedBy=multi-user.target +``` + +现在创建 `/home/sol/bin/validator.sh` 来包含 `solana-validator` 所需的命令行。 确保运行 `/home/sol/bin/validator.sh` 来手动启动验证程序。 别忘了将其标记为 `chmod +x /home/sol/bin/validator.sh` + +开启服务: +```bash +$ sudo systemctl enable --now sol +``` + +### 日志 +#### 日志输出调整 + +验证节点导出到日志的消息可以由 `RUST_LOG` 环境变量控制。 在 [文档](https://docs.rs/env_logger/latest/env_logger/#enabling-logging)中也可以找到详细的 Rust crate `env_logger` 信息。 + +请注意,如果减少日志记录输出,则可能难以调试以后遇到的问题。 如果需要团队的支持,则任何变更都必须恢复,并且在提供帮助之前应重现问题。 + +#### 日志切换 + +由 `--log ~/solana-validator.log`指定的验证器日志文件会随着时间的推移变得很大,因此建议配置日志切换。 + +验证节点在收到`USR1`信号时将重新打开其信号,该信号是启用日志切换的基本原语。 + +#### 使用日志切换 + +`logrotate`的一个示例设置中,它假定验证节点作为名为`sol.service`的系统服务运行,并在/home/sol/solana-validator.log中写入日志文件: +```bash +# 设置日志切换 + +cat > logrotate.sol < 注意:“validator-keypair.json”文件也是您的 \(ed25519\) 私钥。 + +验证节点身份密钥独特识别了您在网络中的验证节点。 **备份此信息至关重要。** + +如果您不备份此信息,那么如果您无法访问验证节点的话,将无法对其进行恢复。 如果发生这种情况,您将失去SOL TOO的奖励。 + +要备份您的验证节点识别密钥, **请备份您的"validator-keypair.json" 文件到一个安全位置。** + +## 将您的Solana公钥链接到Keybase帐户 + +您必须将Solana pubkey链接到Keybase.io帐户。 以下说明介绍了如何通过在服务器上安装Keybase来执行此操作。 + +1. 在您的机器上安装[Keybase](https://keybase.io/download)。 +2. 登录到服务器上的Keybase帐户。 如果您还没有Keybase帐户,请先创建一个。 以下是基本的[Keybase CLI命令列表](https://keybase.io/docs/command_line/basics)。 +3. 在公用文件夹中创建一个Solana目录:`mkdir /keybase/public//solana` +4. 在Keybase公共文件夹中按以下格式创建一个空文件,来发布验证者的身份公共密钥:`/keybase/public//solana/validator-`。 例如: + + ```bash + touch /keybase/public//solana/validator- + ``` + +5. 要检查公钥是否已成功发布,请确保您在 `https://keybase.pub//solana/validator-` 看到它。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/participation/validator-technical-requirements.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/participation/validator-technical-requirements.md new file mode 100644 index 0000000000..388edfa685 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/participation/validator-technical-requirements.md @@ -0,0 +1,11 @@ +--- +title: 运行验证节点的要求 +--- + +## 硬件 + +请参考 [建议的硬件配置](../../running-validator/validator-reqs.md)。 + +## 软件 + +- 我们在Ubuntu 04/18上进行开发和运行。 在Ubuntu 04/16上运行时,某些用户会遇到一些问题 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/README.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/README.md new file mode 100644 index 0000000000..6dbeaf5bc3 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/README.md @@ -0,0 +1 @@ +# 注册 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/confidentiality.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/confidentiality.md new file mode 100644 index 0000000000..86dec13287 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/confidentiality.md @@ -0,0 +1,7 @@ +--- +title: 保密规定 +--- + +请参看****第 8 章[** TOUR DE SOL 参与规则的 **](https://drive.google.com/file/d/15ueLG6VJoQ5Hx4rnpjFeuL3pG5DbrBbE/view) ** 保密规定。** + +Solana 无意在 Tour de SOL 共享任何机密信息。 我们将会通过口头、电子邮件等方式将信息分享出去。 除非明确地调出信息,否则不应将信息视为机密信息,我们欢迎您的分享。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/how-to-register.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/how-to-register.md new file mode 100644 index 0000000000..20b8d8a902 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/how-to-register.md @@ -0,0 +1,25 @@ +--- +title: 如何注册 +--- + +#### 1) 注册表 + +[请在此提交注册表](https://forms.gle/gQYLozj5u7yKU3HG6) + +#### 2) KYC/AML(通过 Coinlist) + +[请在这里注册 KYC/AML + 参与协议](https://tsm.coinlist.co/solana-staking) + +_如果您先前已经完成了 SLP 或 TdS 的 KYC/AML,那么同一个实体/个人就不需要这个步骤了。 我们不接受美国 实体或个人。_ + +#### 3) 加入我们的Discord + +所有 Tour de SOL 验证程序**都需要**加入,因为这是我们的主要通信渠道:https://discord.gg/N3mqAfa + +### 下一步 + +- 查看我们的文档来熟悉如何[运行一个验证节点](../../running-validator.md) + +- 完成注册后,您将收到一封电子邮件,说明您要完成了注册流程。 + +- 在 Discord 上相见! diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/rewards.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/rewards.md new file mode 100644 index 0000000000..653dc85095 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/rewards.md @@ -0,0 +1,29 @@ +--- +title: 奖励 +--- + +## 奖励计算 + +奖励将根据 [论坛的这个帖子](https://forums.solana.com/t/tour-de-sol-stage-1-preliminary-compensation-design/79) 和 [这个表格](https://docs.google.com/spreadsheets/d/11puBSw2THdO4wU-uyDEic-D03jg4ZAooVpcZU0w_4gI/edit#gid=218406032) 中描述的奖励规则来计算。 + +另外请查看 [TOUR DE SOL 参与条款](https://drive.google.com/file/d/15ueLG6VJoQ5Hx4rnpjFeuL3pG5DbrBbE/view) 中的“2\(f\) Tour de Sol 详情”,来了解更多奖励详情。 + +## 领取奖励的要求 + +参与者必须已经签署 Tour de SOL 参与协议,并通过 CoinList 平台以个人身份通过KYC/AML,并在参加之前填写了W-8 BEN或W-9纳税表格\(取决于您的居住地\) 来参与到 Tour 中。 完成注册后,参与者可以参加到任何一个和所有的阶段。 最终注册日期将分阶段公开宣布。 + +最后,参与者必须签署Solana的标准[代币协议](https://drive.google.com/open?id=1O4cEUZzeSNoVcncbHcEegAqPgjT-7hcy)。 代币协议将在奖励发放日期之前由Solana提供。 + +另外请参阅 [TOUR DE SOL 参与条款](https://drive.google.com/file/d/15ueLG6VJoQ5Hx4rnpjFeuL3pG5DbrBbE/view) 中的“2\(i\) & 2\(j\) Tour de Sol 详情”部分,了解与领取奖励有关的更多详情。 + +## 税务要求 + +参与者正在与Solana签订服务协议,并获得与服务相关的酌情奖励。 他们不被视为公司的全职员工,因此如果适用的话,Solana会收集W-9和W-8 BEN表格以支持纳税报告义务。 Solana建议参与者咨询税务会计师,以了解任何潜在的税务要求。 + +此外,如 [TOUR DE SOL 参与条款](https://drive.google.com/file/d/15ueLG6VJoQ5Hx4rnpjFeuL3pG5DbrBbE/view) 第2i、2k和10c节所述: + +> 2i - 要获得任何SOL奖励,参与者必须签署公司的SOL奖励协议标准格式,其中包括作为SOL奖励发行的管理SOL所有权和使用的条款和条件,包括但不限于适用的锁定证券法、黑名单日期和纳税报告信息要求。 + +> 2k - 要获得任何SOL奖励,入围者必须签署公司的SOL奖励协议标准格式,其中包括作为SOL奖励发行的用于管理SOL所有权和使用的条款和条件,包括但不限于适用的锁定证券法、黑名单日期和纳税报告信息要求。 + +> 10c - 您有责任遵守适用于任何协议的交易的所有法律和法规,包括但不限于《商品交易法》以及美国 商品期货交易委员会\(“CFTC”\)颁布的法规,美国 证券交易委员会\(“SEC”\) 颁布的联邦证券法律和法规以及适用于您从公司收取的任何报酬的税法。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/terms-of-participation.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/terms-of-participation.md new file mode 100644 index 0000000000..320bdea36c --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/terms-of-participation.md @@ -0,0 +1,5 @@ +--- +title: 参与条款 +--- + +详情请查看官方 [TOUR DE SOL 参与条款](https://drive.google.com/a/solana.com/file/d/15ueLG6VJoQ5Hx4rnpjFeuL3pG5DbrBbE/view?usp=sharing)。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/validator-registration-and-rewards-faq.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/validator-registration-and-rewards-faq.md new file mode 100644 index 0000000000..5aa0df3cf3 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/registration/validator-registration-and-rewards-faq.md @@ -0,0 +1,53 @@ +--- +title: 注册常见问题 +--- + +对于任何参与问题,[TOUR DE SOL 参与条款](https://drive.google.com/a/solana.com/file/d/15ueLG6VJoQ5Hx4rnpjFeuL3pG5DbrBbE/view?usp=sharing) 都应被视为权威资料。 + +## 注册是强制性的吗? + +是的。 注册是强制的。 注册正在进行中, 我们每月主办为期一个月的 Tour de SOL,新的参加者需要等到下一阶段开始时才能进入。 [注册信息在这里](how-to-register.md)。 + +## 谁有资格参加? + +详情请见 [TOUR DE SOL Participation terms](https://drive.google.com/a/solana.com/file/d/15ueLG6VJoQ5Hx4rnpjFeuL3pG5DbrBbE/view?usp=sharing) 的“参与资格 1;KYC 要求”。 + +## 我是否必须完成KYC/AML认证才能参与? + +是的。 完成KYC/AML是强制性的。 如果你在第一阶段前没有完成这个进程,你就无法参加到 Tour de SOL。 + +我们已经与 Coinlist 合作管理 Tour de SOL 的 KYC/AML。 您可以在这里找到 [参与教程](https://docs.google.com/presentation/d/1gz8e34piUzzwzCMKwVrKKbZiPXV64Uq2-Izt4-VcMR4/),[在这里完成认证](https://docs.google.com/presentation/d/1gz8e34piUzzwzCMKwVrKKbZiPXV64Uq2-Izt4-VcMR4/edit#slide=id.g5dff17f5e5_0_44)。 + +## 我作为 Tour de Sol 参与者的责任是什么? + +详情请查看 [TOR DE SOL 参与条款中](https://drive.google.com/file/d/15ueLG6VJoQ5Hx4rnpjFeuL3pG5DbrBbE/view) 的“2c Tour de SOL详情”。 + +### 如何计算“Tour de Sol 活跃 Tour 事件时间的 50%”责任? + +为了有资格在给定阶段获得奖励,验证者必须在该阶段 >= 50%的位置中提交投票。 + +如果验证者无法为某个阶段提交 >= 50%的投票,但仍然认为他们应该在该阶段获得奖励,那么他们可以向Solana提出重新考虑的请求。 + +## Tour de Sol 测试代币与 Solana 主网代币之间是否有关系? + +没有。 详情请查看 [TOR DE SOL 参与条款中](https://drive.google.com/file/d/15ueLG6VJoQ5Hx4rnpjFeuL3pG5DbrBbE/view) 的“2d Tour de SOL Details”。 + +## 验证节点会被取消 Tour de Sol 资格吗? + +会的。 如果某个验证节点从事违禁行为和/或未能提供上述第\#4点所述的最低限度服务,那么它将被取消资格。 + +另见 [ TOUR DE SOL 参与条款](https://drive.google.com/file/d/15ueLG6VJoQ5Hx4rnpjFeuL3pG5DbrBbE/view) 的“4 违禁行为”,来详细地查看违禁行为。 + +### 更多关于违禁行为的问题: + +#### 如“ 4 禁止行为”一节所述,有在居住地管辖范围以外的其他管辖区提供 Tour 服务的例子吗? 是否意味着服务器必须放在我居住地的管辖范围内? + +不是的。 服务器可以位于与参与者的居住地不同的其他管辖区中。 签署[TOUR DE SOL 参与条款](https://drive.google.com/file/d/15ueLG6VJoQ5Hx4rnpjFeuL3pG5DbrBbE/view)后,参与者已同意:如果居住在美国,他们就在美国提供服务;如果不在美国境内,他们就从美国境外提供服务。 + +## 奖励是怎么计算的? + +详情请查看 [奖励部分](rewards.md)。 + +## 我们怎么知道能否公开分享哪些信息? + +请查看 [保密协议](confidentiality.md)。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/submitting-bugs.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/submitting-bugs.md new file mode 100644 index 0000000000..04df217326 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/submitting-bugs.md @@ -0,0 +1,7 @@ +--- +title: 提交 Bug +--- + +请在[此Github代码库中的issue](https://github.com/solana-labs/solana/issues)提交所有的漏洞和反馈。 + +由于[Discord频道](useful-links.md)的信息流比较快,因此其中报告的问题很可能会在信息流中丢失。 在Github代码库中归档问题是确保记录并解决问题的唯一方法。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/useful-links.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/useful-links.md new file mode 100644 index 0000000000..6ef11c50f1 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/tour-de-sol/useful-links.md @@ -0,0 +1,15 @@ +--- +title: 有用的链接 & 讨论 +description: 阅读本指南以后 +--- + +- [网络浏览器](http://explorer.solana.com/) +- [TdS 性能指示板](https://metrics.solana.com:3000/d/monitor-edge/cluster-telemetry-edge?refresh=1m&from=now-15m&to=now&var-testnet=tds) +- 验证节点频道 + - [\#validator-support](https://discord.gg/rZsenD) 通用群组用于讨论 Tour de SOL 故障以外的验证节点相关疑问。 + - [\#tourdesol-validators](https://discord.gg/BdujK2) 群组供 Tour de SOL 参与者进行交流。 + - [\#tourdesol-annound](https://discord.gg/Q5TxEC),关于 Tour de SOL 关键信息的唯一官方发布频道。 +- [核心软件代码库](https://github.com/solana-labs/solana) +- [在此仓库中提交 bug 和反馈](https://github.com/solana-labs/solana/issues) + +> 找不到您想要的东西? 请发送电子邮件到 ryan@solana.com 或在 Discord 联系 @rshea\#2622。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/anatomy.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/anatomy.md new file mode 100644 index 0000000000..47adf14109 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/anatomy.md @@ -0,0 +1,13 @@ +--- +title: 验证节点的解析器 +--- + +![验证节点区块图](/img/validator.svg) + +## 流水线(Pipelining) + +验证节点广泛使用CPU设计中常见的优化方法, 称为_流水线处理_。 当有一个输入数据流需要通过一系列步骤进行处理,并且每个步骤都有不同的硬件负责时,流水线化是一个非常正确的思路。 典型的例子是用洗衣机和烘干机完成洗涤/烘干/折叠好几堆衣服。 洗涤必须在烘干前进行,烘干后才能折叠,但这三种操作都由单独的设备执行。 为了最大限度地提高效率,我们创建了 _三个阶段_ 的流水线处理。 我们将洗涤称为一个阶段,烘干称为第二个阶段,折叠过程称为第三个阶段。 为了让流水线跑起来,在第一批衣物被添加到烘干机之后,第二批衣物就可以添加到洗衣机当中去了。 同样的,在第二批衣物添加到烘干机之后,第三批衣物就可以添加到洗衣机中去了。 这时候第一批衣物应该到了折叠的阶段。 按照这样的方式,三堆衣物就会最大化的取得进展。源源不断的输入载荷,流水线化就会持续最优的完成工作。 + +## 验证节点中的流水线 + +验证节点有两类流水线,领导节点使用的流水线称为TPU,从节点使用的流水线成为TVU。 在这两种情况下,流水线化是一样的,网络输入、GPU卡、CPU内核、磁盘写入和网络输出。 不同之处在于每个阶段由不同的硬件完成。 TPU流水线的存在是为了创建和维护账本,而TVU流水线的存在是为了验证区块。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/blockstore.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/blockstore.md new file mode 100644 index 0000000000..21b43a1bbf --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/blockstore.md @@ -0,0 +1,91 @@ +--- +title: Blockstore(区块存储) +--- + +当一个区块到达最终状态时,从那个区块到创世区块之间所有区块形成了一条链,就是大家都熟悉区块链。 然而,在此之前,验证节点必须维护所有可能有效的链,称为_分叉(forks)_。 领导节点从验证节点中通过算法轮换选举,这个过程会自然的[产生分叉](../cluster/fork-generation.md)。 本节描述了验证节点的 _区块存储(blockstore)_ 数据结构是如何复制并处理这些分叉,直到确定最终的区块。 + +验证节点记录它在网络上观察到的每一个区块分片(无论任何顺序,只要区块分片是由给定插槽的领导者签名的)。 + +碎片被移动到一个可分叉的区间`领导者插槽` + `碎片索引` \(在一个 slot 区间\) 。 这允许Solana中的跳表数据结构完整的存储碎片,而无需事先选择跟随哪个分叉或者等待区块已经达到最终状态。 + +可以从内存中或者最近的文件中重组最新的区块碎片,较晚的区块碎片可以从磁盘的旧文件中重组,这取决于BlockStore的实现。 + +## Blockstore 功能 + +1. 持久性:Blockstore和节点的验证流水线打交道 + + 接收输入流和签名验证。 如果 + + 收到的区块碎片和领导节点的签名是一致的( + + 例如领导节点的分配插槽内接收的区块),它需要立即存储。 + +2. 重组:重组和上面提到的一样 + + 但是它能够为任何接收的区块碎片进行重组。 Blockstore存储带有签名的区块碎片, + + 保留区块链的历史记录。 + +3. 分叉:Blockstore支持区块碎片的随机访问, + + 因此可以支持验证节点回滚并且重放记录点后的交易。 + +4. 重启:通过适当的修剪/剔除, + + 区块储藏可以通过少数交易条目回放到 slot 0。 回放的逻辑就是 + + ()通过最新的Blockstore状态 + + 来处理的,例如处理分叉。 + +## Blockstore 设计 + +1. 每条记录都是通过键值对来存储的,键就是插槽索引加上区块碎片索引,值就是条目数据。 值得注意的是每个碎片索引都是重新从零开始的(按照每个插槽)。 +2. Blockstore 中每个插槽中的元组 `SlotMeta` 数据结构包含: + + - `slot_index` - 插槽索引 + - `num_blocks` - 插槽的区块数量 \(用于区块链中前一个插槽\) + - `consumed` - 碎片索引的连续最高值 `n`,对于所有的 `m < n`,,总会有一个碎片索引的值等于 `n` \(例如连续最高的碎片索引\)。 + - `received` - 碎片索引的最高值 + - `next slots` - 下一个插槽的列表 可以用于重建到 + + 一个记录点的回放 + + - `last _index` - 插槽的最后一个碎片标识 当领导节点在传输插槽的最后一个碎片索引时会带上这个标识。 + - `is_root` - 如果为True那么当前插槽所有区块碎片都是收集完整的。 我们可以按照以下的规则进行。 假设slot\(n\)是索引为`n`的插槽,并且slot\(n\).is_full\(\)为真,如果索引为`n`的插槽都收集到了所有的碎片。 假设 is_rooted\(n\) 表示“slot\(n\).is_root 为真”。 那么: + + is_rooted\(0\) is_rooted\(n+1\) iff\(is_rooted\(n\) and slot\(n\).is_full\(\) + +3. Chaining - 当`x`插槽的碎片到达时,我们检查新插槽中的\(`num_blocks`\)(这个信息在碎片中会有编码)。 我们就知道这个新插槽链是 `x - num_blocks` 插槽。 +4. Subscriptions - Blockstore记录一组已“订阅”到的插槽。 这意味着这些插槽的条目将被发送到Blockstore通道,供ReplayStage使用。 详情请查看 `Blockstore APIs`。 +5. Update notifications - 对于任意一个 `n`,Blockstore 更新 slot\(n\).is_rooted 这个值从false 变成true。 + +## Blockstore 接口 + +Blockstore提供了一个基于订阅的API,ReplayStage使用它来请求所需要的条目。 Blockstore有暴露相关的接口让请求方获取这些条目。 这些订阅API如下所示: 1. `fn get_slots_slots_slouts(slot_indexes: &[u64]) -> Vec`:返回`slot_indexes`中对应的区块碎片数据。 + +1. `fn get_slot_entries(slot_index: u64, entry_start_index: usize, max_entries: Option) -> Vec`:返回以 `entry_start_index` 开头的插槽入口向量,如果 `max_entries == Some(max)`,则将结果限制在 `max`,对返回向量的长度施加限制。 + +请注意:这意味着重播阶段现在必须知道一个slot何时结束,并订阅它感兴趣的下一个slot以获得下一组条目。 较旧的slot将会存储到Blockstore当中。 + +## 与Bank交互 + +Bank 暴露以下字段用于交易重放: + +1. `prev_hash`:PoH链上的最后一个区块哈希 + + 它处理过的条目 + +2. `tick_head`:PoH链中的滴答,由 Bank + + 进行验证 + +3. `votes`:包含以下内容的一堆记录: 1. `prev_hashes`: 上一次PoH的哈希值 2. `tick_high`:此投票的高度 3. `lockout period`:这个投票的最大截止时间 + + 能够在这次投票中被引用 + +在这个voteReplay阶段会建立分叉点,用Blockstore API找到它可以挂起的最长链。 如果当前链没有最新的投票,那么重放阶段将回滚到投票的分叉点,并从那里重新同步。 + +## Blockstore 剪枝 + +一旦Blockstore中记录太旧了,表示所有可能的分叉就变得不那么有用了,甚至可能在重启时重放出现问题。 一旦验证节点的投票达到最大截止时间限制,任何不在PoH链上的区块都可以被剪枝、删除。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/gossip.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/gossip.md new file mode 100644 index 0000000000..301df7a18d --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/gossip.md @@ -0,0 +1,92 @@ +--- +title: Gossip Service(八卦服务) +--- + +Gossip服务在控制平面中充当一个网关的角色。 验证节点使用该服务来确保集群中的所有其他节点都可以获取信息。 服务通过Gossip协议来广播相关的消息。 + +## 八卦传播概览 + +节点之间不断共享签名数据对象,以便管理集群。 例如,它们相互共享联系消息、区块高度和投票。 + +每十分之一秒,每个节点发送一个“推送”消息和/或“拉取”消息。 推送和拉取消息可能会引发响应,推送消息可能转发到集群中的其他节点。 + +Gossip在已知的UDP/IP端口或已知范围内的端口上运行。 一旦集群被触发,节点就会互相通告在哪里找到它们的对等端点\(一个 socket 地址\)。 + +## Gossip 记录 + +通过gossip共享的记录是任意的,但是需要根据需要进行签名和版本控制\(带有时间戳\) ,以便对接收它们的节点有意义。 如果一个节点从同一个源接收到两条记录,它将用带有最新时间戳的记录更新自己的副本。 + +## Gossip 服务接口 + +### 推送消息 + +节点发送一个push消息,告诉集群它有要共享的信息。 节点向 `PUSH_FANOUT` 发送消息到对等节点。 + +当节点接收到消息后,做如下检查: + +1. 复制:如果这个消息之前发送过,节点丢掉数据并返回 `PushMessagePrune` 如果这个数据是从低权重的节点发送的 +2. 新数据:如果这个数据是新来的 + + - 将带有新版本的新消息存储在群集当中, + + 清除以前的旧值 + + - 把消息存储在`pushed_once`当中\( + + 用来检测重复的消息,在`PUSH_MSG_TIMEOUT * 5`后擦除\) + + - 将消息重新传输到自己的对等节点 + +3. 过期:当超过`PUSH_MSG_TIMEOUT`这个时间间隔时,节点丢弃相关的消息 + +### 推送消息到对等节点,消息剪枝 + +节点从已知节点的活跃集合中随机选择其推送节点。 节点将此选择保留相对较长的时间。 当接收到修剪消息时,节点丢弃发送该消息的推送对等方。 Prune表示有另一个比直接推送更加复杂的路径到达该节点。 + +每隔`PUSH_MSG_TIMEOUT/2`毫秒,推送的节点集合都会进行更新,保证推送节点是比较新的。 + +### 拉取消息 + +节点发送一条"拉取"消息,询问集群是否有新信息。 拉取消息随机发送到单个对等点,包括节点已经拥有的内容的Bloom过滤器。 接收“拉取”消息的节点对其bloom过滤器进行迭代,并构造一个“拉取”响应,该响应包含未命中过滤器且适合消息的内容。 + +节点通过迭代当前值来构造pull Bloom过滤器。 + +节点处理pull响应中的记录的方式与处理push消息中的新数据的方式相同。 + +## 消息剪枝 + +节点保留较早的消息(通过推送和拉取更新的数据) 和过期的值(比`GOSSIP_PULL_CRDS_TIMEOUT_MS`更旧的值)`purged_values`(最新拥有的)。 节点修剪`purged_values`比`5*GOSSIP_PULL_CRDS_TIMEOUT_MS`这个时间间隔长。 + +## 日食攻击 + +日食攻击是试图接管大量节点的节点集合。 + +下面两个方面的因素是我们实现中需要考虑的。 + +- 拉取消息会从网络中随机的选择一个节点。 对_拉取消息_继续的日食攻击会影响节点的随机选择,从而只选择恶意节点进行数据同步。 +- 节点维护一组活跃的节点用于随机扩散消息。 日食攻击者会影响活跃的节点集合,这样_发送_的消息会传播到恶意节点。 + +### Time and Stake based weights(基于时间和质押的权重) + +权重是基于`上次当选的时间` 和 `质押权重` 的 `自然对数`而组成。 + +采用`ln`的权值可以使所有节点在合理的时间内获得更公平的网络覆盖机会。 它有助于规范化节点之间可能存在的`质押权重`差异较大的情况。 通过这样,与`质押权重`较大的节点相比,`质押权重`较低的节点只需等待几倍的ln\(`质押`\) 时间就可以被选中。 + +攻击节点无法影响这些参数。 + +### 拉取消息 + +上述计算权重的方法作为拉取信息来选择节点。 + +### 推送消息 + +剪枝只能从潜在连接中删除。 + +就像_拉取消息_一样,节点是根据权重来添加到活跃的节点集合中的。 + +## PlumTree的主要区别 + +本文描述的主动推送协议基于[Plum Tree](https://haslab.uminho.pt/sites/default/files/jop/files/lpr07a.pdf)。 主要区别是: + +- 推送的消息带有发送节点的时间戳。 当时间戳过期后数据就被删除了。 跃点限制很难在对抗性环境中实施。 +- 延迟推送之所以没有实施,是因为它不清楚如何阻止对手伪造消息指纹。 一个简单的方法允许对手根据它们的输入优先级进行拉取。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/runtime.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/runtime.md new file mode 100644 index 0000000000..6719acf686 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/runtime.md @@ -0,0 +1,69 @@ +--- +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) diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/tpu.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/tpu.md new file mode 100644 index 0000000000..9139c83fe6 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/tpu.md @@ -0,0 +1,5 @@ +--- +title: TPU +--- + +![TPU 区块图](/img/tpu.svg) diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/tvu.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/tvu.md new file mode 100644 index 0000000000..9142258838 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/validator/tvu.md @@ -0,0 +1,9 @@ +--- +title: TVU +--- + +![TVU 区块图](/img/tvu.svg) + +## 重新传输阶段 + +![重新传送区块](/img/retransmit_stage.svg) diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide.md new file mode 100644 index 0000000000..8915884301 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide.md @@ -0,0 +1,27 @@ +--- +title: Solana钱包指南 +--- + +本文将向Solana用户介绍一些不同的钱包使用方法,包括在索拉纳区块链上发送,接收,以及如何兑换SOL币。 + +## 什么是一个钱包? + +加密钱包是一种存储密钥集合的设备或应用程序,可用于发送,接收和跟踪加密货币的所有权。 钱包可以采用多种形式: 计算机文件系统中的目录或文件,一张纸,或称为_硬件钱包_的专用设备。 还有各种智能手机应用程序和计算机程序,它们提供了一种用户友好的方式来创建和管理钱包。 + +_keypair(密钥对)_是安全生成的_private key(私钥)_及其从密码派生出的_public key(公钥)_。 私钥及其对应的公钥一起合称为_密钥对_。 钱包包含一个或多个密钥对的集合,并提供了一些与它们进行交互的方式。 + +_public key_(通常缩写为_pubkey_) 被称为钱包的_接收地址_或简称为_地址_。 钱包地址**可以共享和公开**。 当一方要向钱包发送一定数量的加密货币时,他们需要知道钱包的接收地址。 根据区块链的实现方式,该地址还可以用于查看有关钱包的相关信息,例如查看余额,但不能更改有关钱包的任何内容或提取任何代币。 + +_私钥_是对任何交易进行数字签名,以将加密货币发送到另一个地址,或对钱包进行任何更改所必需的。 私钥**绝不能公开**。 如果某人获得了访问钱包私钥的权限,则他们可以提取其中包含的所有代币。 如果钱包的私钥丢失,则发送到该钱包地址的所有代币都将**永久丢失**。 + +不同的钱包解决方案提供了不同的方法来实现密钥对安全性,并与密钥对进行交互并签署交易以使用或者花费代币。 有些使用密钥容易一些。 另一些会更安全地存储和备份私钥。 Solana支持多种类型的钱包,因此您可以在安全性和便利性之间选择适当的平衡。 + +**如果您希望能够在Solana区块链上接收SOL代币,则首先需要创建一个钱包。** + +## 支持的钱包 + +Solana在命令行应用程序APP中支持多种类型的钱包以及第三方的钱包。 + +对于大多数用户,我们建议使用[app钱包](wallet-guide/apps.md)之一或基于浏览器的[网页钱包](wallet-guide/web-wallets.md),它们会提供更熟悉的用户体验,而无需学习指令工具。 + +对于高级用户或开发人员而言,[命令行钱包](wallet-guide/cli.md)可能更合适,因为在集成到第三方之前,始终会首先在命令行上支持Solana区块链上的新功能解决方案。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/apps.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/apps.md new file mode 100644 index 0000000000..366e95506f --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/apps.md @@ -0,0 +1,24 @@ +--- +title: 移动应用钱包 +--- + +Solana得到了多个第三方应用的支持,它们为大多数新手或加密钱包用户提供熟悉的体验。 + +## Trust Wallet +[Trust Wallet](https://trustwallet.com/) 是一款适用于iOS和Android的应用,可用于发送和接收SOL代币。 + +*请注意:Trust Wallet不支持质押帐户或抵押操作* + +### Trust Wallet 安全性 + +Trust Wallet中的代币安全性取决于安装该应用的设备。 任何能够解锁您的手机或平板电脑的人都可以使用Trust Wallet应用并转移您的代币。 为了提高安全性,您可以为Trust Wallet应用添加密码。 其操作为打开应用,然后转到 设置 -> 安全 -> 密码。 + +如果某人获得了您的Trust Wallet应用的访问权限,那么他们可以访问您的恢复助记词。 有权访问助记词的任何人都可以在其他设备上重新创建您的Trust Wallet密钥。 然后他们可以从那台设备而不是您自己的手机或平板电脑上签署交易。 创建新钱包后将显示助记词,您也可以在未来的任何时间通过以下步骤在应用中查看助记词: + +- 转到设置 -> 钱包 +- 在特定钱包的“选项”菜单下,点击“显示恢复助记词” + +## Coin98 +[Coin98](https://coin98.app/) 一款是 iOS 和 Android 应用,可用于发送和接收 SOL 代币。 + +*请注意:Coin98 不支持质押账户或质押操作* diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/cli.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/cli.md new file mode 100644 index 0000000000..a804147089 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/cli.md @@ -0,0 +1,39 @@ +--- +title: 命令行钱包 +--- + +Solana支持几种不同类型的钱包,它们可以直接与Solana命令行工具进行交互。 + +** 如果您不熟悉命令行程序的使用,并且只需要发送和接收SOL代币,我们建议您设置第三方 [App Wallet](apps.md)**。 + +您首先需要 [安装 Solana CLI 工具](../cli/install-solana-cli-tools.md) 才能使用命令行钱包。 + +## 文件系统钱包 + +_文件系统钱包_ (也称为FS钱包)是计算机文件系统中的目录。 目录中的每个文件都有一个密钥对。 + +### 文件系统钱包的安全性 + +文件系统钱包是最方便但安全性最差的一种钱包。 由于密钥对存储在一个简单的文件中,因此使用非常方便。 您可以生成任意数量的密钥,通过复制文件来轻松备份它们。 但这是很不安全的,因为密钥对文件**未经过加密**。 如果您是计算机的唯一用户,并且确信没有受到恶意软件攻击,则FS钱包是加密代币余额不多的理想解决方案。 但是,如果您的计算机包含恶意软件并且连接到互联网,那么某些恶意软件可能会上载您的密钥并使用它们来获取代币。 同样,由于密钥对以文件形式存储在您的计算机上,因此可以对计算机进行物理访问的黑客高手可能访问到它。 使用加密的硬盘驱动器(例如MacOS上的FileVault)可以最大程度地降低这种风险。 + +[文件系统钱包](file-system-wallet.md) + +## 纸钱包 + +_纸钱包_ 是把 _助记词_ 写在纸上进行备份的钱包合称。 种子短语是一些单词(通常为12或24),可用于重新生成密钥对。 + +### 纸钱包的安全性 + +在便利性与安全性方面,纸质钱包与FS钱包刚刚相反。 它们使用起来非常不方便,但是却提供了出色的安全性。 当纸钱包与 [离线签名](../offline-signing.md) 结合使用时,安全性将得到进一步增强。 托管服务(例如[Coinbase Custody](https://custody.coinbase.com/) )就是采用该方式。 纸钱包和托管服务是长期存储大额代币的最好方法。 + +[纸钱包](paper-wallet.md) + +## 硬件钱包 + +硬件钱包是一种用于存储密钥对的小型手持设备,它有一个用来签名交易的界面。 + +### 硬件钱包的安全性 + +像 [Ledger硬件钱包](https://www.ledger.com/) 这类硬件钱包为加密货币提供了完美的安全性和便利性。 它有效地自动化了链下签名过程,同时几乎保留了文件系统钱包所具备的便利。 + +[硬件钱包](hardware-wallets.md) diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/file-system-wallet.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/file-system-wallet.md new file mode 100644 index 0000000000..056e0e68f8 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/file-system-wallet.md @@ -0,0 +1,48 @@ +--- +title: 文件系统钱包 +--- + +本文档介绍了如何使用 Solana CLI 工具创建和使用文件系统钱包。 文件系统钱包的形式为计算机文件系统上的未加密密钥对文件。 + +> 文件系统钱包是存储 SOL 代币 **安全性最差**的方法。 我们 **不建议** 在文件系统钱包中存储大量代币。 + +## 准备工作 + +确保您 [已安装Solana命令行工具](../cli/install-solana-cli-tools.md) + +## 生成文件系统钱包密钥对 + +使用 Solana 的命令行工具 `solana-keygen` 来生成密钥对文件。 例如,从命令行 shell 运行下面的命令: + +```bash +mkdir ~/my-solana-wallet +solana-keygen new --outfile ~/my-solana-wallet/my-keypair.json +``` + +此文件包含您的 **未加密的** 密钥对。 实际上,即使您指定了密码,该密码也适用于恢复种子短语,而不适用于文件。 请不要分享这个文件给其他人。 有权访问此文件的任何人都可以转移该钱包地址的所有代币。 相反,您应该仅分享钱包的公共密钥。 要显示其公钥,请运行: + +```bash +solana-keygen pubkey ~/my-solana-wallet/my-keypair.json +``` + +它将输出一个字符串,例如: + +```text +ErRr1caKzK8L8nn4xmEWtimYRiTCAZXjBtVphuZ5vMKy +``` + +这是 `~/my-solana-wallet/my-keypair.json` 中对应的公钥。 密钥对文件的公钥即为您的 _钱包地址_。 + +## 使用密钥对文件验证您的地址 + +如需验证您某个给定地址的私钥,请使用 `solana-keygen verify` 命令: + +```bash +solana-keygen verify ~/my-solana-wallet/my-keypair.json +``` + +其中 `` 替换为你的钱包地址。 如果给定的地址与密钥对文件中的地址匹配,则命令将输出“成功”,否则输出“失败”。 + +## 创建多个文件系统钱包地址 + +您可以根据需要创建任意数量的钱包地址。 只需重新运行 [生成一个文件系统钱包](#generate-a-file-system-wallet-keypair) 命令,并确保传入 `--outfile` 参数来使用新文件名或路径。 如果需要在自己的帐户之间转移代币,多个钱包地址可能会很有用。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/hardware-wallets.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/hardware-wallets.md new file mode 100644 index 0000000000..c0e8e5eb16 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/hardware-wallets.md @@ -0,0 +1,35 @@ +--- +title: 在Solana CLI上使用硬件钱包 +--- + +签署任何一笔交易都需要私钥,但是在您的个人计算机或手机上存储私钥可能很容易被盗。 因此对密钥加入密码可以提高安全性,但是许多用户追求进一步的安全性,希望将私钥移动到称为 _硬件钱包_的独立物理设备上。 硬件钱包是一个小型的手持设备,它存储私钥并提供用于签署交易的界面。 + +Solana CLI对硬件钱包的支持非常充分。 在任何使用密钥对文件路径的地方(文档中用 `` 表示),都可以传入一个 _keypair URL_,该URL唯一地标识硬件钱包中的密钥对。 + +## 支持的硬件钱包 + +Solana CLI 支持以下硬件钱包: + +- [Ledger Nano S 和 Ledger Nano X](hardware-wallets/ledger.md) + +## 指定密钥对 URL + +Solana 定义了密钥对URL格式,让与计算机相连的硬件钱包唯一定位任何 Solana 密钥对。 + +密钥对的 URL 有以下形式,其中方括号表示可选字段: + +```text +usb://[/][?key=] +``` + +`WALLET_ID` 是一个用于清除多个设备的全局唯一密钥。 + +`DERVIATION_PATH` 用于导航到您硬件钱包中的 Solana 密钥。 路径有表单 `[/]`,其中每一个 `ACOUNT` 和 `CHANGE` 都是正整数。 + +例如,Ledger 设备完全合格的 URL 可能是: + +```text +usb://ledger/BsNsvfXqQTtJnagwFWdBS7FBXgnsK8VZ5CmuznN85swK?key=0/0 +``` + +所有衍生路径都隐含了前缀 `44'/501'`, 其中表示路径遵循 [BIP44 规则](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki),并且任何派生的密钥都是 Solana 密钥(代币类型为 501)。 单引号表示一个“固化”衍生。 因为 Solana 采用 Ed25519 密钥对,所以所有衍生地址都是固化的,因此添加单引号是可选的而不是必须的。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/hardware-wallets/ledger.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/hardware-wallets/ledger.md new file mode 100644 index 0000000000..8dba0de9e4 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/hardware-wallets/ledger.md @@ -0,0 +1,151 @@ +--- +title: Ledger Nano +--- + +本网页展示了如何通过 Ledger Nano S 或 Nano X 来使用命令行工具与 Solana 交互。 其他解决方案与 Solana 与 Nano 的交互, [请点击这里](../ledger-live.md#interact-with-the-solana-network) + +## 开始前的准备 + +- [使用 Solana 应用设置 Nano](../ledger-live.md) +- [安装 Solana 命令行工具](../../cli/install-solana-cli-tools.md) + +## 通过 Solana CLI 使用 Ledger Nano + +1. 确保 Ledger Live 应用程序已关闭 +2. 将您的 Nano 插入计算机 USB 端口 +3. 输入 pin 码并在 Nano 上启动 Solana 应用 +4. 确保屏幕显示“应用程序已准备好” + +### 查看您的钱包 ID + +在您的计算机运行: + +```bash +solana-keygen pubkey usb://ledger +``` + +该步骤确认您的 Ledger 设备已经连接正确,并且能够与 Solana CLI 正常交互。 该命令返回你 Ledger 设备唯一的_钱包 ID_. 当有多台 Nano 设备连接到同一台计算机时, 您可以通过钱包 ID 来指定想使用的 Ledger 硬件钱包。 如果您的电脑只使用一个 Nano 设备,那么就无需指明钱包 ID。 关于通过钱包 ID 使用特定 Ledger 的信息,请参阅[管理多个硬件钱包](#manage-multiple-hardware-wallets)。 + +### 查看您的钱包地址 + +您的 Nano 支持任意数量的有效钱包地址和签名者。 要查看任何地址,请使用前面所说的 `solana-keygen pubkey` 命令,然后接上一个有效的 [密钥对URL](../hardware-wallets.md#specify-a-keypair-url)。 + +如果需要在自己帐户之间的传输代币,您可以使用多个钱包地址。或在设备上对某一个抵押账号使用不同的键对作为签名授权。 + +以下所有的命令将显示不同的地址,关联到给定的密钥对路径。 来试一下吧! + +```bash +solana-keygen pubkey usb://ledger +solana-keygen pubkey usb://ledger?key=0 +solana-keygen pubkey usb://ledger?key=1 +solana-keygen pubkey usb://ledger?key=2 +``` + +* 注意:密钥对 URL 参数在 **zsh**  [更多解决方案](#troubleshooting)中将被忽视。 + +您也可以在 `key=` 后面输入其他的数值。 这些命令显示的任何地址都是有效的 Solana 钱包地址。 与每个地址相关联的隐私信息都安全地存储在 Nano 上,并对该地址的交易进行签名。 只需给你生成的任何地址的密钥对 URL 进行备注,就可以用来接收代币。 + +如果您只计划设备上使用一个地址/密钥对, 那么容易记住的一个路径可能是 `key=0` 的地址。 通过该命令查看它的地址: + +```bash +solana-keygen pubkey usb://ledger?key=0 +``` + +现在,你已经有一个(或多个) 钱包地址,你可以公开分享其中的任何一个地址作为代币接收地址,并且使用关联的密钥对 URL 作为该地址发起交易的签名人。 + +### 查看钱包余额 + +无论是哪个钱包,您都可以通过 `solana balance` 命令来查看帐户余额: + +```bash +solana balance SOME_WALLET_ADDRESS +``` + +例如,如果您的地址是 `7cvkjYAkUYs4W8XcXscca7cBrEGFeSUjeZmKoNBvEwyri`,那么可以输入以下命令查看余额: + +```bash +solana balance 7cvkjYAkUYs4W8XcXsca7cBrEGFeSUjeZmKoNBvEwyri +``` + +您也可以在[Explorer](https://explorer.solana.com/accounts)查看任何账户地址的余额,在网页浏览器中将地址粘贴到搜索框来查看余额。 + +注意:任何余额为 0 SOL的地址(例如您在 Ledger 新创建的地址),将在浏览器器中显示“未找到”。 Solana 对空账户和不存在账户的处理是一样的。 当您的帐户地址中有一些 SOL 代币的时候才会正确显示。 + +### 从 Nano 发送 SOL + +您需要使用该设备来签署交易,完成从 Nano 地址发送代币(通过生成钱包地址的相同密钥对 URL)。 请确保您的 Nano 已插入电脑,通过 PIN 解锁,并且 Ledger Live 处于未运行状态, 同时 Solana 应用在设备中打开,显示“应用已准备就绪”。 + +`solana transfer` 命令用于指定代币发送地址和数量,通过 `--keypair` 参数来指定发送代币的密钥对(签署交易),同时对应地址的余额将减少。 + +```bash +solana transfer RECIPIENT_ADDRESS AMOUNT --keypair KEYPAIR_URL_OF_SENDER +``` + +下面是一个完整的实例。 首先,通过某个密钥对 URL 中查看一个地址。 然后检查该地址的余额。 最后,输入一笔交易来发送 `1` SOL到接收地址 `7cvkjYAkUYs4W8XcXscca7cBrEGFeSUjeZmKoNBvEwyri`。 按下回车键传输命令时,您将看到在 Ledger 设备批准交易细节的提示。 在设备上通过左右键查看交易细节。 如果信息正确,请同时按下"允许"界面的两个按钮,否则请在"拒绝"界面按下这两个按钮。 + +```bash +~$ solana-keygen pubkey usb://ledger?key=42 +CjeqzArkZt6xwdnZ9NZSf8D1CNJN1rjeFiyd8q7iLWAV + +~$ solana balance CjeqzArkZt6xwdnZ9NZSf8D1CNJN1rjeFiyd8q7iLWAV +1.000005 SOL + +~$ solana transfer 7cvkjYAkUYs4W8XcXsca7cBrEGFeSUjeZmKoNBvEwyri 1 --keypair usb://ledger?key=42 + +等待您在 Ledger 硬件钱包确认 usb://ledger/2JT2Xvy6T8hSmT8g6WdeDbHUgoeGdj6bE2VueCZUJmyN +✅ 已允许 + +签名:kemu9jDEuPirKNRKiHan7ycybYsZp7pFefAdvWZRq5VRHCLgXTXaFVw3pfh87MQcWX4kQY4TjSBmESrwMApom1V +``` + +在设备批准交易后,应用界面会显示交易签名,您需要等待最大的确认数量(32) 才能返回。 这个过程只需要几秒钟,然后交易就能在 Solana 网络确认。 您可以到[Explorer](https://explorer.solana.com/transactions)交易栏中粘贴该交易签名,来查看这笔交易或任何其他交易的详细信息。 + +## 进阶操作 + +### 管理多个硬件钱包 + +有时候通过多个硬件钱包对交易进行签名非常有用。 使用多个钱包签名需要 _完全合格的密钥对 URL_。 当 URL 不完全合格时,Solana CLI 将提示所有已连接硬件钱包的完全合格的 URL,并要求您选择每个签名使用哪个钱包。 + +您可以使用界面交互提示而不是使用 Solana CLI `交易栏` 命令来生成完全合格的 URL。 例如,试着将 Nano 连接到 USB,输入 PIN 码解锁,并运行以下命令: + +```text +solana resolve-signer usb://ledger?key=0/0 +``` + +您将看到类似这样的输出: + +```text +usb://ledger/BsNsvfXqQTtJnagwFWdBS7FBXgnsK8VZ5CmuznN85swK?key=0/0 +``` + +但 `BsNsvfXqQTtJnagwFWdBS7FBXgnsK8VZ5CmuznN85swK` 是您的 `WALLET_ID`. + +当 URL 完全合格时,您可以连接多个硬件钱包到同一台计算机,并独立识别其中任何一个私钥对。 除了 ``,您可以在任何 `solana` 命令行的地方使用 `resolve-signer` 命令的输出去解决给定签名的解析路径问题。 + +## 疑难解答 + +### Zsh 忽略密钥对 URL 参数 + +Zsh 中问题标记字符是特殊字符。 如果您无需使用该功能,请在你的 `~/.zshrc` 中添加以下文本,将其作为的正常字符处理: + +```bash +unsetopt nomatch +``` + +然后重启您的 shell 窗口,或者运行 `~/.zshrc`: + +```bash +source ~/.zshrc +``` + +如果不想禁用 zsh 对问题标记字符的特殊处理,您可以在密钥对 URL 中使用反斜杠专门禁用它。 例如: + +```bash +solana-keygen pubkey usb://ledger\?key=0 +``` + +## 客服支持 + +查看 [钱包支持页面](../support.md) 获取帮助。 + +阅读更多关于 [发送和接收代币](../../cli/transfer-tokens.md) 和[委托质押](../../cli/delegate-stake.md)的信息。 您可以在任何接受 `` 选项或参的地方使用 Ledger 密钥对 URL。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/ledger-live.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/ledger-live.md new file mode 100644 index 0000000000..372caa466d --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/ledger-live.md @@ -0,0 +1,53 @@ +--- +title: Ledger Nano S 和 Nano X +--- + +本文档描述了如何设置 [Ledger Nano S](https://shop.ledger.com/products/ledger-nano-s)、[Ledger Nano X](https://shop.ledger.com/pages/ledger-nano-x) 与 [Ledger Live](https://www.ledger.com/ledger-live) 软件。 + +一旦下面显示的设置步骤完成,Solana 应用程序将安装在您的 Nano 设备上,用户有几个方法来 [使用 Nano 来与 Solana 网络交互](#interact-with-the-solana-network)。 + +## 准备工作 + +- 首先需要从 Ledger 订购一个 [Nano S](https://shop.ledger.com/products/ledger-nano-s) 或 [Nano X](https://shop.ledger.com/pages/ledger-nano-x)。 +- 按照快递中的使用说明或 [Ledger's Start page](https://www.ledger.com/start/) 来设置设备。 +- 安装 [Ledger Live 桌面软件](https://www.ledger.com/ledger-live/) + - 如果您已经安装了 Ledger Live,请更新到最新版本,该步骤将启用最新的固件和应用更新。 +- 将您的 Nano 连接到电脑并按照屏幕的指示。 +- 更新您的新 Nano设备 固件。 该步骤确保您安装了最新版本的 Solana 应用。 + - [更新 Nano S 固件](https://support.ledger.com/hc/en-us/articles/360002731113-Update-Ledger-Nano-S-firmware) + - [更新 Nano X 固件](https://support.ledger.com/hc/en-us/articles/360013349800) + +## 在 Nano 上安装 Solana 应用 + +- 打开 Ledger Live +- 点击应用程序左边窗口的“管理”,在应用目录中搜索"Solana",然后点击"安装"。 + - 请确保您的设备已通过 USB 接入并且通过 PIN 解锁。 +- 您可以在 Nano 上看到确认安装 Solana App 的提示 +- 在Ledger Live Manager 中,"Solana" 现在应该显示为“已安装” + +## 升级到最新版本的 Solana App + +为了确保您能够使用最新功能,如果您使用的是旧版本 Solana App,请按照以下步骤升级到 `v1.0.1`。 + +- 确保您的 Ledger Live 是 2.10.0 或更高版本。 + - 要检查您的 Ledger Live 版本,请单击右上角的“设置”按钮,然后单击“关于”。 如果有较新版本的 Ledger Live,那么当您首次打开 Ledger Live 时,应该会看到一个提示您进行升级的弹窗。 +- 在您的 Nano 更新固件 + - [更新 Nano S 固件](https://support.ledger.com/hc/en-us/articles/360002731113-Update-Ledger-Nano-S-firmware) + - [更新 Nano X 固件](https://support.ledger.com/hc/en-us/articles/360013349800) +- 成功更新固件后,Solana 应用会自动重新安装最新版本的应用程序。 + +## 与 Solana 网络交互 + +用户可以使用以下任何选项来通过 Nano 与 Solana 进行交互: + +- [SolFlare.com](https://solflare.com/) 一款是专门为 Solana 打造的非托管网络钱包,它支持使用 Ledger 设备进行的基本转账和质押操作。 请查阅 [结合 Nano 与 SolFlare 使用](solflare.md) 的指南。 + +- 开发者和高级用户可以 [结合使用 Nano与 Solana 命令行工具](hardware-wallets/ledger.md)。 在第三方钱包支持之前,本地命令行工具几乎总能够支持最新的钱包功能。 + +## 已知的问题 + +- 在 Windows 系统,Nano X 有时无法连接到网页钱包。 这可能会影响任何使用 WebUSB 的浏览器钱包。 Ledger 团队正在努力解决这个问题。 + +## 客服支持 + +请查看 [已支持钱包页面](support.md) 来获得帮助。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/paper-wallet.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/paper-wallet.md new file mode 100644 index 0000000000..afc226ad61 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/paper-wallet.md @@ -0,0 +1,129 @@ +--- +title: 纸钱包 +--- + +本文档描述了如何使用 Solana CLI 工具创建和使用纸钱包。 + +> 在此,我们不提供如何 _安全地_ 创建或管理纸钱包的建议。 请仔细研究安全相关的问题。 + +## 概述 + +Solana 提供了一个密钥生成工具,可以从符合 BIP39 规范的助记词中获取密钥。 用于运行验证节点和质押代币的 Solana CLI 命令均支持通过助记词输入密钥对。 + +要了解更多关于 BIP39 标准的信息,请访问 [这里](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) 查看比特币 BIPs Github 代码库。 + +## 纸钱包使用方法 + +无需将密钥对保存到计算机上的磁盘即可运行Solana命令。 如果将私钥写入磁盘可能会遇到安全问题,那么这个指南对你就非常有帮助了。 + +> 即使使用这个安全的输入方法,私钥仍有可能通过未加密的内存交换被写入到磁盘中。 避免这种情况的发生是用户的责任。 + +## 准备工作 + +- [安装 Solana 命令行工具](../cli/install-solana-cli-tools.md) + +### 检查您的安装 + +运行 `solana-keygen` 确保已正确安装: + +```bash +solana-keygen --version +``` + +## 创建一个纸钱包 + +使用 `solana-keygen` 工具可以生成新的助记词,并且从现有助记词和 (可选) 密码中生成一个密钥对。 助记词和密码可以作为纸钱包一起使用。 只要您将助记词和密码安全地存储起来,就可以使用它们来访问您的帐户。 + +> 如需了解更多关于助记词工作原理的信息,请参阅 [比特币百科网页](https://en.bitcoin.it/wiki/Seed_phrase)。 + +### 生成助记词 + +使用 `solana-keygen new` 命令生成新的密钥对。 该命令将生成一个随机的助记词,要求您输入一个可选的密码,然后将显示派生的公钥和纸钱包生成的助记词。 + +复制助记词以后,您可以使用 [公钥派生](#public-key-derivation) 说明来验证操作没有任何错误。 + +```bash +solana-keygen new --no-outfile +``` + +> 如果 `--no-outfile` 标志显示为 **omitted**,那么默认行为是将密钥写入到 `~/.config/solana/id.json`,最终产生一个 [文件系统钱包](file-system-wallet.md) + +此命令的输出将显示下面的这一行: + +```bash +pubkey: 9ZNTfG4NyQgxy2SWjSiQoUyBPEvXT2xo7fKc5hPYYJ7b +``` + +`pubkey: ` 后面显示的值即为您的 _钱包地址_。 + +**请注意:** 在使用纸钱包和文件系统钱包时,“pubkey”和“钱包地址”有时会互换使用。 + +> 为了增加安全性,请使用 `--word-count` 参数增加助记词的数量 + +完整的使用详细信息请运行: + +```bash +solana-keygen new --help +``` + +### 公钥派生 + +如果您选择使用公钥,则可以从助记词和密码派生公钥。 这对于使用离线生成的助记词来导出有效公钥非常有用。 `solana-keygen pubkey` 命令将引导您输入助记词和密码(如果您有设置的话)。 + +```bash +solana-keygen pubkey ASK +``` + +> 请注意,对于相同的助记词,您可能会使用不同的密码。 每个唯一的密码将产生不同的密钥对。 + +`solana-keygen` 工具与生成助记词的 BIP39 标准的英文单词列表是一样的。 如果您的助记词是通过另一个工具生成,您仍然可以使用 `solana-keygen` 命令,但需要通过 `--skip-seed-spoe-valide-` 参数并放弃验证。 + +```bash +solana-keygen pubkey ASK --skip-seed-phrase-validation +``` + +使用 `solana-keygen pubkey ASK` 输入您的助记词以后,控制台将显示一个 base-58 字符串。 这就是与助记词相关联的 _钱包地址_。 + +> 复制派生地址到 USB 以便网络计算机使用 + +> 通常下一步是 [检查与公钥关联的帐户余额](#checking-account-balance) + +完整是使用详细信息请运行: + +```bash +solana-keygen pubkey --help +``` + +## 验证密钥对 + +如需要验证您控制纸钱包地址的私钥,请使用 `solana-keygen verify` 命令: + +```bash +solana-keygen verify ASK +``` + +其中 `` 替换为钱包地址,他们的关键字 `ASK` 让命令行提示您使用密钥对的助记词。 请注意,出于安全原因,在您输入助记词的时候,它们不会显示出来。 输入您的助记词后, 如果给定的公钥匹配助记词生成的密钥,命令将输出“成功”,否则将输出“失败”。 + +## 检查账户余额 + +检查账户余额仅需要某个账户的公钥。 要安全地从纸钱包产生公钥, 请按照在一台 [气隙计算机](https://en.wikipedia.org/wiki/Air_gap_(networking)) 进行 [公钥衍生](#public-key-derivation) 的说明。 然后公钥可以通过手动输入或 USB 传输一台网络设备。 + +接下来,配置 `solana` CLI 工具到 [连接一个特定集群](../cli/choose-a-cluster.md): + +```bash +solana config set --url # (例如 https://api.mainnet-beta.solana.com) +``` + +最后,如需检查余额,请运行以下命令: + +```bash +solana balance +``` + +## 创建多个纸钱包地址 + +您可以根据需要创建任意数量的钱包地址。 只需重复运行 [生成助记词](#seed-phrase-generation) 或 [公钥衍生](#public-key-derivation),就可以创建一个新地址。 如果需要在自己的帐户之间转移代币,多个钱包地址可能会很有用。 + +## 支持 + +请查看 [已支持钱包页面](support.md) 来获得帮助。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/solflare.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/solflare.md new file mode 100644 index 0000000000..72a6fb7654 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/solflare.md @@ -0,0 +1,93 @@ +--- +title: SolFlare 网页钱包 +--- + +## 介绍 + +[SolFlare.com](https://solflare.com/) 是一个社区开发,专门为Solana打造的网页钱包。 SolFlare支持发送和接收原生SOL代币以及SPL代币(类似于Solana的ERC-20格式代币)。 另外,SolFlare还支持SOL代币的质押。 + +作为一个 _非托管_ 钱包,SolFlare网站本身不存储您的私钥,私钥存储在加密的 [Keystore 文件](#using-a-keystore-file) 或 [Ledger Nano S 或 X 硬件钱包](#using-a-ledger-nano-hardware-wallet) 中。 + +本指南介绍了使用SolFlare设置钱包、发送和接收SOL代币以及创建和管理质押账户等。 + +## 准备工作 + +在支持的浏览器中打开https://www.solflare.com。 大多数流行的网页浏览器都能与Keystore 文件进行交互,但与Ledger Nano交互时目前仅支持Chrome和Brave。 + +### 使用 Keystore 文件 + +#### 创建一个新的 Keystore 文件 +要使用密钥库文件创建钱包,请单击“创建钱包”,然后选择“使用 Keystore 文件”。 按照提示创建密码,该密码将用于加密 Keystore 文件,然后将新文件下载到您的计算机。 系统将提示您将 Keystore 文件上传到网站,来验证下载是否已正确保存。 + +**请注意:如果丢失了Keystore文件或配套登录的密码,该钱包中的所有资金将永久丢失。 Solana团队和SolFlare开发人员都无法帮助您恢复丢失的密钥。** + +您可能需要将Keystore文件的备份副本保存在主计算机以外的外部驱动器上,并将密码存储在独立的位置。 + +#### 使用Keystore文件访问您的钱包 +要将SolFlare与先前创建的Keystore文件一起使用,请单击“访问钱包”,然后选择“使用Keystore文件”。 如果您刚刚创建了新的Keystore文件,则将直接进入“访问”页面。 系统将提示您输入密码并上传您的Keystore文件,然后转到钱包界面的主页。 + +### 使用Ledger Nano硬件钱包 + +*注意:请查看目前在 Nano中出现的 [已知问题](ledger-live.md#known-issues)。* + +#### 初始设备设置 +要通过 SolFlare 配合使用 Ledger Nano,首先确认您已经在设备上 [设置了您的 Nano](ledger-live.md) 并安装了 [ 最新版本的 Solana 应用程序](ledger-live.md#upgrade-to-the-latest-version-of-the-solana-app)。 + +#### 选择一个访问账号地址 +插入你的 Nano 并打开 Solana 应用,这时候设备屏幕显示"应用准备就绪"。 + +从 SolFlare 主页,点击“访问一个钱包”,然后选择"使用 Ledger Nano S | Ledger Nano X"。 在“选择派生路径”下,选择唯一的选项: + +``Solana - 44`/501`/`` + +注意:您的浏览器可能会提示您询问 SolFlare 是否可以与您的 Ledger 设备通信。 请点击允许此操作。 + +从下拉框选择要交互的地址,然后点击“访问”。 + +Ledger设备可以生成大量私钥和相关的公共地址。 这允许您管理和交互来自同一设备的多个不同帐户。 + +如果您将资产存入 Ledger 设备派生的地址,请确保在使用 SolFlare 时访问相同的地址,以便能够访问这些资产。 如果连接到错误的地址,只需单击注销并使用正确的地址重新连接。 + +## 选择一个网络 + +Solana维护着[三个不同的网络](../clusters),每个网络都有不同的目的,支持着Solana生态。 默认情况下,在 SolFlare 上选择的是 Mainnet Beta,这是部署交易和其他生产应用的永久网络。 要选择其他网络,请在钱包仪表板顶部,单击当前选择的网络名称,即“Mainnet”,“Testnet ”或“ Devnet”,然后单击您要使用的网络的名称。 + +## 发送和接收 SOL 代币 + +### 接收 +要将代币接收到您的钱包中,您必须将一些代币转移到钱包地址。 该地址显示在屏幕的左上角,您可以单击复制图标来复制该地址,并将其提供给向您发送代币的任何人。 如果您将代币存放在其他钱包或交易所中,也可以提现到该地址。 转账完成后,SolFlare上显示的余额应在几秒钟内更新。 + +### 发送代币 +一旦您的钱包地址中有一些代币,您可以通过单击右上角的“ Transfer SOL”将其发送到任何其他钱包地址或兑换存款地址。 输入收件人地址和要转移的 SOL 数量,然后单击“提交”。 在 [使用密钥对交易进行签名](#signing-a-transaction) 之前,系统将提示您确认交易的详细信息,然后将其提交给网络。 + +## 质押 SOL 代币 +SolFlare 支持创建和管理质押账户和委托质押。 要了解 Solana 的通用工作原理,请参阅我们的[Staking 指南](../staking)。 + +### 创建一个质押账户 +您可以使用钱包中的一些SOL代币来创建新的质押账户。 在钱包主页单击顶部的“质押(Staking)”。 在右上角,单击“创建帐户(Create Account)”。 输入您想要用来为新的质押账户转入的SOL金额。 这笔转账将从您的钱包中提取并转入质押账户。 请勿将您的所有钱包余额转移到质押账户,因为该钱包还要支付与质押账户相关的任何交易费用。 请在您的钱包帐户中至少保留1个SOL。 + +提交并[签名交易](#signing-a-transaction)后,您将看到新的质押账户出现在“您的质押账户”框中。 + +在SolFlare上创建的质押账户将您的钱包地址设置为新账户的[抵押和提款权限](../staking/stake-accounts#understanding-account-authorities),这使您的钱包密钥有权签名与新质押账户有关的任何交易。 + +### 查看您的质押账户 +在钱包主页面或质押页面,您的质押账户将显示在“您的质押账户”框中。 质押账户地址和原来的钱包地址是不同的。 + +SolFlare将在[所选网络](#select-a-network)上找到任何显示所有质押账户的帐户,您的钱包地址已分配给该质押账户作为[质押授权](../staking/stake-accounts#understanding-account-authorities)。 只要在您登录时使用的钱包被指定为质押授权机构,在SolFlare外部创建的质押账户也将显示并可以管理。 + +### 在一个质押账户委托代币 +选择了 [一个验证节点](../staking#select-a-validator) 以后,您可以将某个账户中的代币分配给它们。 从 Staking 仪表板中点击质押账户右侧的“Delegate”。 从下拉列表中选择您想要委托的验证节点,然后点击委托。 + +要解除委托的代币(也称为停用质押) 的过程类似。 在 Staking 页面的委托质押账户右侧,点击“Undelegate”按钮并按提示操作。 + +### 拆分一个质押账户 +您可以将现有的质押账户拆分成两个账户。 点击钱包控制的密钥账户的地址,并在“Actions”栏下点击"Split"。 指定您想要拆分的 SOL 代币的数量。 这将会导致您新的密钥账户中代币金额和现有质押账户余额减少相同的数量。 拆分您的质押帐户能让您委托不同数量的代币给多个不同的验证节点。 您可以按需要多次拆分一个质押账户,来创建任何数量的质押账户。 + +## 签名交易 +每当您提交一笔交易(例如将代币发送到另一个钱包或委托质押)时,都需要使用私钥对交易进行签名,来让网络接受该交易。 + +### 使用 Keystore 文件 +如果您使用 Keystore 文件访问了钱包,则在每次需要密钥来签署交易时都会提示您输入密码。 + +### 使用 Ledger Nano 钱包 +如果用 Ledger Nano 访问您的钱包,每当您需要密钥签名时,您将看到确认设备上待处理的交易细节的提示。 在 Nano 上,使用左键和右键查看和确认所有交易细节。 如果一切看起来都正确,请单击右键直到屏幕显示“允许”。 同时按下两个按钮来批准交易。 如果出现错误,请再次按右键的“拒绝”,并同时按下两个按钮来拒绝交易。 在您批准或拒绝某笔交易后,您将在 SolFlare 网页看到这一点。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/support.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/support.md new file mode 100644 index 0000000000..7e2772f23d --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/support.md @@ -0,0 +1,9 @@ +--- +title: 支持 / 故障处理 +--- + +如果您有任何疑问或者在设置或使用钱包的时候遇到困难,请确保您已查阅 [钱包指南(Wallet Guide)](paper-wallet.md) 中的所有相关内容。 Solana团队正在努力支持流行钱包的新功能,并且尽最大努力让文档与最新的可用功能保持更新。 + +如果您在阅读文档后有任何疑问,请随时通过 [Telegram](https://t.me/solanaio) 与我们联系。 + +需要获得 **技术支持**,请到 [Discord](https://discordapp.com/invite/pquxPsq) 社区分组的 #wallet-support 频道 与我们联系。 diff --git a/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/web-wallets.md b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/web-wallets.md new file mode 100644 index 0000000000..16379bac25 --- /dev/null +++ b/docs/i18n/zh/docusaurus-plugin-content-docs/current/wallet-guide/web-wallets.md @@ -0,0 +1,17 @@ +--- +title: 网页钱包 +--- + +## SolFlare +[SolFlare.com](https://solflare.com/) 是一个社区开发,专门为Solana打造的非托管网页钱包。 SolFlare 支持质押账户的创建和管理,并支持用户发送和接收任何类型的SPL代币。 + +查看 [SolFlare 钱包使用指南](solflare.md)。 + +## Sollet +[sollet.io](https://www.sollet.io/) 是一个由 [Project Serum](https://projectserum.com/) 团队开发的非托管网页钱包。 sollet.io 可用于发送和接收SOL和任何SPL代币。 + +## MathWallet + +[MathWallet](https://mathwallet.org/) 支持通过浏览器插件和网页钱包界面发送和接收SOL和SPL代币。 + +*请注意:MathWallet iOS和Android应用尚未支持SOL和SPL代币* diff --git a/docs/i18n/zh/docusaurus-theme-classic/footer.json b/docs/i18n/zh/docusaurus-theme-classic/footer.json new file mode 100644 index 0000000000..fd2962f254 --- /dev/null +++ b/docs/i18n/zh/docusaurus-theme-classic/footer.json @@ -0,0 +1,42 @@ +{ + "link.title.Docs": { + "message": "文档", + "description": "The title of the footer links column with title=Docs in the footer" + }, + "link.title.Community": { + "message": "社区", + "description": "The title of the footer links column with title=Community in the footer" + }, + "link.title.More": { + "message": "更多信息", + "description": "The title of the footer links column with title=More in the footer" + }, + "link.item.label.Introduction": { + "message": "介绍", + "description": "The label of footer link with label=Introduction linking to introduction" + }, + "link.item.label.Tour de SOL": { + "message": "Tour de SOL", + "description": "The label of footer link with label=Tour de SOL linking to tour-de-sol" + }, + "link.item.label.Discord": { + "message": "Discord", + "description": "The label of footer link with label=Discord linking to https://discordapp.com/invite/pquxPsq" + }, + "link.item.label.Twitter": { + "message": "推特", + "description": "The label of footer link with label=Twitter linking to https://twitter.com/solana" + }, + "link.item.label.Forums": { + "message": "论坛", + "description": "The label of footer link with label=Forums linking to https://forums.solana.com" + }, + "link.item.label.GitHub": { + "message": "GitHub", + "description": "The label of footer link with label=GitHub linking to https://github.com/solana-labs/solana" + }, + "copyright": { + "message": "Copyright © 2021 Solana Foundation", + "description": "The footer copyright" + } +} \ No newline at end of file diff --git a/docs/i18n/zh/docusaurus-theme-classic/navbar.json b/docs/i18n/zh/docusaurus-theme-classic/navbar.json new file mode 100644 index 0000000000..02f79098c9 --- /dev/null +++ b/docs/i18n/zh/docusaurus-theme-classic/navbar.json @@ -0,0 +1,30 @@ +{ + "item.label.Program Library »": { + "message": "程序库", + "description": "Navbar item with label Program Library »" + }, + "item.label.Develop": { + "message": "开发", + "description": "Navbar item with label Develop" + }, + "item.label.Validate": { + "message": "验证", + "description": "Navbar item with label Validate" + }, + "item.label.Integrate": { + "message": "集成", + "description": "Navbar item with label Integrate" + }, + "item.label.Learn": { + "message": "学习资源", + "description": "Navbar item with label Learn" + }, + "item.label.Chat": { + "message": "聊天室", + "description": "Navbar item with label Chat" + }, + "item.label.GitHub": { + "message": "GitHub", + "description": "Navbar item with label GitHub" + } +} \ No newline at end of file diff --git a/docs/src/developing/on-chain-programs/debugging.md b/docs/src/developing/on-chain-programs/debugging.md index 433e2936c1..a9ded2bd31 100644 --- a/docs/src/developing/on-chain-programs/debugging.md +++ b/docs/src/developing/on-chain-programs/debugging.md @@ -84,8 +84,7 @@ operations they wish to profile. - [Log the remaining compute units from a C program](developing-c.md#compute-budget) -See [compute -budget](developing/programming-model/../../../programming-model/runtime.md/#compute-budget) +See [compute budget](developing/programming-model/runtime.md#compute-budget) for more information. ## ELF Dump diff --git a/docs/src/developing/on-chain-programs/developing-c.md b/docs/src/developing/on-chain-programs/developing-c.md index 67fb7c72ac..b48509cc34 100644 --- a/docs/src/developing/on-chain-programs/developing-c.md +++ b/docs/src/developing/on-chain-programs/developing-c.md @@ -177,8 +177,7 @@ Use the system call to log a message containing the remaining number of compute units the program may consume before execution is halted -See [compute -budget](developing/programming-model/../../../programming-model/runtime.md/#compute-budget) +See [compute budget](developing/programming-model/runtime.md#compute-budget) for more information. ## ELF Dump diff --git a/docs/src/developing/on-chain-programs/developing-rust.md b/docs/src/developing/on-chain-programs/developing-rust.md index 8d6b72ee6c..52cdfdbf32 100644 --- a/docs/src/developing/on-chain-programs/developing-rust.md +++ b/docs/src/developing/on-chain-programs/developing-rust.md @@ -30,8 +30,7 @@ features = [] ``` Solana Rust programs may depend directly on each other in order to gain access -to instruction helpers when making [cross-program -invocations](developing/../../programming-model/calling-between-programs.md#cross-program-invocations). +to instruction helpers when making [cross-program invocations](developing/programming-model/calling-between-programs.md#cross-program-invocations). When doing so it's important to not pull in the dependent program's entrypoint symbols because they may conflict with the program's own. To avoid this, programs should define an `exclude_entrypoint` feature in `Cargo.toml` and use @@ -250,8 +249,8 @@ single-threaded environment, and must be deterministic: - No support for `println!`, `print!`, the Solana [logging helpers](#logging) should be used instead. - The runtime enforces a limit on the number of instructions a program can - execute during the processing of one instruction. See [computation - budget](developing/programming-model/runtime.md#compute-budget) for more + execute during the processing of one instruction. See + [computation budget](developing/programming-model/runtime.md#compute-budget) for more information. ## Depending on Rand @@ -375,8 +374,7 @@ Use the system call to log a message containing the remaining number of compute units the program may consume before execution is halted -See [compute -budget](developing/programming-model/../../../programming-model/runtime.md#compute-budget) +See [compute budget](developing/programming-model/runtime.md#compute-budget) for more information. ## ELF Dump diff --git a/docs/src/developing/programming-model/transactions.md b/docs/src/developing/programming-model/transactions.md index f642fb6189..72c85a5c27 100644 --- a/docs/src/developing/programming-model/transactions.md +++ b/docs/src/developing/programming-model/transactions.md @@ -139,7 +139,7 @@ accounts are permanently marked as executable by the loader once they are successfully deployed. The runtime will reject transactions that specify programs that are not executable. -Unlike on-chain programs, [Native Programs](/developing/runtime-facilities/programs) +Unlike on-chain programs, [Native Programs](developing/runtime-facilities/programs) are handled differently in that they are built directly into the Solana runtime. ### Accounts