本指南旨在为希望在 Solana 上为其程序实现验证构建的开发者提供参考。我们将介绍什么是验证构建、如何使用它们、需要注意的特殊事项以及确保程序链上真实性的最佳实践。
什么是验证构建?
验证构建确保您部署到 Solana 网络的可执行程序与您代码库中的源代码相匹配。通过这样做,开发者和用户可以确信链上运行的程序与公共代码库完全一致,从而促进透明性和安全性。
验证过程包括将链上程序的哈希值与从源代码本地构建的程序的哈希值进行比较。这确保了两者之间没有差异。
虽然验证构建不应被认为比未验证构建更安全,但它使开发者能够自行验证源代码与链上部署的内容相匹配。使用源代码,开发者可以验证代码在发送交易时执行的内容。
验证构建流程由 Ellipsis Labs 和 OtterSec 设计并维护。有关更多详细信息,请参阅 原始验证构建 库中的指南,以及在 Anza 工具套件中直接支持的验证构建流程(支持后)。
它是如何工作的?
验证过程是通过比较链上程序的哈希值与从源代码本地构建的程序的哈希值来完成的。您可以使用 Solana Verify CLI 和 Docker 在受控环境中构建您的程序。这确保了构建过程在不同系统之间是确定性和一致的。一旦您获得了可执行文件,您就可以将其部署到 Solana 网络。在构建过程中,会创建一个 PDA(程序派生地址)用于 verify program。这个 PDA 包含验证程序所需的所有数据。PDA 包括程序地址、Git URL、提交哈希值以及用于构建程序的参数。
通过 PDA 中的数据,任何人都可以在本地运行 verify program 命令,检查程序是否是从提供的源代码构建的。然后,任何人都可以完全无需信任地自行验证,或者运行由 OtterSec 维护的 verify API,为用户提供一个便捷的验证访问点。您已经可以在 Solana Explorer 和 SolanaFM 等平台上看到这些 API 调用 的使用。
为什么我应该使用已验证的构建?
使用已验证的构建可以带来以下好处:
-
安全性:保证链上运行的程序与源代码一致,防止恶意篡改。
-
透明性:允许其他用户和开发者通过与公共代码库进行比较来验证链上程序的可信度。
-
信任:提高用户信心,因为已验证的构建表明您的程序链上行为与您的公共代码一致。在构建可验证程序时,您可以最大限度地减少运行未经授权或恶意代码的风险。这也确保您遵循最佳实践,并为安全研究人员提供一种简单的联系方式。此外,只要程序经过验证,钱包和其他工具也可以更轻松地允许来自您的程序的交易。
-
可发现性:当您提供经过验证的程序构建版本时,所有人都可以找到您的源代码、文档、程序 SDK 或 IDL,并且如果出现问题,他们还可以通过 GitHub 轻松联系您。
如何创建经过验证的构建?
要创建经过验证的构建,您需要按照以下步骤操作:
摘要:
- 将您的代码提交到公共代码库
- 在 Docker 中构建一个经过验证的构建
- 部署经过验证的构建
- 根据公共 API 验证已部署的程序
如果您验证的程序不是在 Docker 容器中构建的,很可能会失败,因为 Solana 程序构建在不同系统之间并非确定性一致。
安装 Docker 和 Cargo
安装必要的工具,确保您已安装 Docker 和 Cargo。Docker 提供了一个受控的构建环境以确保一致性,而 Cargo 用于管理 Rust 包。
- Docker:按照 Docker 网站 上的步骤为您的平台安装 Docker。安装完成后,确保 Docker 服务正在运行,并继续按照本指南操作。
- Cargo:如果您尚未安装 Cargo,可以通过运行以下命令进行安装:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
安装 Solana Verify CLI
Solana Verify CLI 是用于验证构建的主要工具。Solana Verify CLI 目前由 Ellipsis Labs 维护,可以通过 Cargo 安装。
您可以通过运行以下命令安装:
cargo install solana-verify
如果您需要特定版本的 CLI,可以通过以下方式固定版本:
cargo install solana-verify --version $VERSION
如果需要,您还可以直接从特定提交中安装一个版本:
cargo install solana-verify --git https://github.com/Ellipsis-Labs/solana-verifiable-build --rev 13a1db2
准备项目
要针对仓库进行验证,仓库根目录下需要有一个 Cargo.lock
文件。如果你的仓库中只有一个程序,并且根目录下有 cargo.lock
文件,你可以直接进入下一步并构建你的程序。
如果你的程序在子文件夹中,并且你有一个 Rust
workspace,则需要在仓库根目录下创建一个 workspace Cargo.toml 文件。
你可以将此 Cargo.toml 示例作为预设:
[workspace]members = ["program/programs/*"]resolver = "2"[profile.release]overflow-checks = truelto = "fat"codegen-units = 1[profile.release.build-override]opt-level = 3incremental = falsecodegen-units = 1
请确保你的程序在 workspace/members 数组中,并且你的程序的 Cargo.toml
已正确配置 lib 名称。
重要的是
lib name,而不是 package 名称!
类似于以下内容:
[package]name = "waffle"version = "0.1.0"edition = "2021"[lib]name = "waffle"crate-type = ["cdylib", "lib"][dependencies]solana-program = "2.1.0"
在这个 repository
中,你可以看到一个包含子文件夹程序的 workspace 示例。还要注意,当程序在子文件夹中时,后续需要将该文件夹作为
--mount-path 添加到 verify-from-repo 命令中。
在这个 存储库 中,您可以找到一个 Anchor 示例。在这个 存储库 中,您可以找到一个原生 Rust 示例。
有了这个 Cargo.toml 文件后,你可以运行
cargo generate-lockfile,以创建 lock 文件并继续构建你的程序。
构建可验证程序
要可验证地构建你的 Solana 程序,请进入包含 workspace Cargo.toml
文件的目录并运行:
solana-verify build
这将把您的环境复制到一个 Docker 容器中,并以确定性的方式构建它。
请确保你实际部署的是已验证的构建版本,不要意外地用
anchor build或cargo build-sbf覆盖它,因为这些很可能不会生成相同的哈希值,从而导致验证失败。
对于包含多个程序的项目,可以使用库名称(而不是包名称)来构建特定的程序:
solana-verify build --library-name $PROGRAM_LIB_NAME
此过程可确保构建的确定性,但可能需要一些时间,尤其是在某些系统(例如 M1 MacBook)上,因为它是在 docker 容器中运行的。为了加快构建速度,建议使用运行 x86 架构的 Linux 机器。
构建完成后,可以使用以下命令检索可执行文件的哈希值:
solana-verify get-executable-hash target/deploy/$PROGRAM_LIB_NAME.so
部署可验证程序
在构建程序并检索其哈希值后,可以将其部署到 Solana 网络。建议使用多签名或治理解决方案(例如 Squads Protocol)进行安全部署,但也可以直接部署:
solana program deploy -u $NETWORK_URL target/deploy/$PROGRAM_LIB_NAME.so --program-id $PROGRAM_ID --with-compute-unit-price 50000 --max-sign-attempts 100 --use-rpc
您可以从 rpc 提供商(例如 Quicknode)请求当前适合的低优先级费用。
要验证已部署的程序与构建的可执行文件是否匹配,请运行:
solana-verify get-program-hash -u $NETWORK_URL $PROGRAM_ID
您可能在不同的 Solana 集群(例如 devnet、testnet、mainnet)上部署了不同的版本。确保使用正确的网络 URL 来验证目标 Solana 集群上的程序。远程验证仅适用于 mainnet。
与存储库进行验证
要将程序与其公共存储库进行验证,请使用:
solana-verify verify-from-repo -u $NETWORK_URL --program-id $PROGRAM_ID https://github.com/$REPO_PATH --commit-hash $COMMIT_HASH --library-name $PROGRAM_LIB_NAME --mount-path $MOUNT_PATH
当你在程序目录下运行已验证的构建时,执行
verify-from-repo时需要添加--mount-path标志。这个参数应为包含Cargo.toml的文件夹路径,该文件夹中包含你程序的库名称。
此命令将链上程序的哈希值与从指定提交哈希的源代码构建的可执行文件哈希值进行比较。
最后,命令会询问您是否希望将验证数据上传到链上。如果您选择上传,Solana Explorer 将立即显示您程序的验证数据。在通过远程构建验证之前,它将显示为未验证。了解如何在下一步中通过公共 API 验证您的程序。
如果你想将验证锁定到某个特定版本,可以在命令后追加 --commit-hash 标志。
通过公共 API 验证
在您使用 verify-from-repo 将验证 PDA 上传到链上后,向
OtterSec API
提交一个远程验证任务:
solana-verify remote submit-job --program-id <program-id> --uploader <address>
--uploader
是上传验证 PDA 的地址,通常是您程序的升级权限账户。如果您的程序由多签账户控制,请继续阅读本指南下方的
多签验证
部分。
verify-from-repo上的旧版--remote标志已被弃用。请先上传您的 PDA,然后再运行remote submit-job。
这将向 OtterSec API 提交一个任务。您可以通过以下方式查看任务状态:
solana-verify remote get-job --job-id <job-id>
验证成功完成后(可能需要一段时间),您将能够在 OtterSec API(单个程序) 以及 Solana Explorer、 SolanaFM、 SolScan 中查看您的程序已通过验证,最终也会显示在由 0xDeep 维护的社区网站 SolanaVerify.org、 OtterSec 已验证程序 API 以及 已验证程序 Dune 数据看板 上,从而为更健康的 Solana 生态系统做出贡献。
如何在程序由 Squads 等多签账户控制时进行验证
要使远程验证正常工作,您需要将验证数据写入由程序权限账户签名的 PDA 中。如果您的程序由多签账户控制,您可以导出此写入 PDA 的交易,并通过 Squads Protocol 或您选择的其他多签解决方案来提交。
2. 部署程序
solana config set --url "PayedMainnetRPCAddress" // the public endpoint will be rate limited too muchsolana program deploy target/deploy/verify_squads.so
在本多签指南的后续内容中,我们将使用示例程序 ID
6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD。
3. 提交并与代码库进行验证
完成后,我们将项目提交到 GitHub。以下是一个示例: https://github.com/solana-developers/verify-squads
可选:先尝试在本地进行验证(此命令使用示例程序 ID
6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD):
solana-verify verify-from-repo https://github.com/solana-developers/verify-squads --program-id 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD
请确保您的参数设置正确。
4. 将程序权限转移至多签
如果您尚未将程序权限转移至多签,请复制多签授权地址,下一步将会用到。
5. 导出 PDA 交易
当您在本地拥有程序权限时,使用命令 solana-verify verify-from-repo
时系统会提示您将构建数据上传至链上。
由于使用多签时无法直接执行此操作,您需要手动导出 PDA 交易,然后通过 Squads 触发该交易。
solana-verify export-pda-tx https://github.com/solana-developers/verify-squads --program-id 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD --uploader <your program authority> --encoding base58 --compute-unit-price 0
这将返回一个 base58 编码的交易。如果您需要用于交易检查器的 base64 编码交易,可以使用
--encoding base64。
P6vBfcPaaXb8fZoT3NBAYEcdtEj7tubA1k2gBxmFKZ3UWF5YyrmDMFTvLKALCJoUuRsPAjMckudYruCu3eeWQtuDrFbEMLxLFutnKXac974fnkMivcwUdY66VLjbxQT6ATmcy7F4hBtz1G4P1h6iBJLhb8WtrtgY3i4qq45MUEb7RjuMEfUFXKrNgPdGxkz5xvMHq3dxKRcpmEK5k2DkeW6SUQYBVe19Ga3B9GyhTX8k3CMt9JCEah13WyRnQd8GjoK6sTEvGJym6xDNvmd8yiJYSNcaYwEJsjHEUf4Yh6kAC7ki2KRvVAr3NVe1gjqK9McrwSQjtUatvydTG8Zovcr7PPUEMf3yPMgKXjZLB2QpkH63yTTYdNAnWFuv9E6b6nYRqye5XcNi436yKw5U14fXh65yK34bgYLi9328UT1huJELsJU9BRGnGUmb6GWp6c2WL5BhnzgNTSnt9TXFfEgUMzhvKzpVBxLP44hwqqBdyUhHFysCF37531PnmiESq8x1xou23xJ6FcQbc199754MkqQd7tX9CUznGzAEqHGkzn3VBoJnojsKtgYmiTYbdRsT1CU18MbYEE7WvGAvXyxxbpNzbAcc94HrnM6cqRGmwhEBroPfFghTdmzg9D
6. 通过 Squads 提交交易
前往 Squads 交易构建器并导入 base58 编码的交易。请务必在模拟中确认该交易仅调用了 osec 验证程序和计算预算程序,不包含任何其他内容!
7. 提交远程验证任务
一旦向 Squads 提交的交易成功,您即可提交远程验证任务:
solana-verify remote submit-job --program-id 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD--uploader <your program authority>
就是这样!您已经对照公共仓库验证了您的程序,并向 OtterSec API 提交了一个远程任务。现在您应该可以在 Solana 浏览器和其他地方看到相应的反馈了。
8. 更新程序(可选)
当您更新程序时,需要导出一个新的 PDA 交易,并再次通过 Squads 提交。
对程序进行更新:
solana-verify buildsolana program write-buffer target/deploy/verify_squads.so --with-compute-unit-price 50000 --max-sign-attempts 50
然后将该缓冲区权限转移给多签账户,或直接以多签账户的权限创建缓冲区。
solana program set-buffer-authority Fu3k79g53ZozAj47uq1tXrFy4QbQYh7y745DDsxjtyLR --new-buffer-authority 3JG6ULvZVCrkKtSSskKNJGe8RNZGFe8Ruev9KUhxzK5K
9. 导出并提交新的 PDA 交易
不要忘记将您的更改提交到 GitHub。再次导出 PDA 升级交易:
solana-verify export-pda-tx https://github.com/solana-developers/verify-squads --program-id 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD --uploader 3JG6ULvZVCrkKtSSskKNJGe8RNZGFe8Ruev9KUhxzK5K
再次通过 Squads 提交该交易。
您可以在此处查看一个示例交易。
然后提交另一次远程构建:
solana-verify remote submit-job --program-id 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD --uploader 3JG6ULvZVCrkKtSSskKNJGe8RNZGFe8Ruev9KUhxzK5K
结果应类似如下:
Verification request sent with request id: b63339d2-163e-49ac-b55d-3454c1c2b5b3Verification in progress... ⏳ [00:18:02] ✅ Process completed. (Done in 18minutes) Program 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD has been verified.✅ The provided GitHub build matches the onchain hash. On Chain Hash:96f8c3d9400258f7759408d1f6f8435b4a24d9b52f5a0340d97907e567cb8773 ExecutableHash: 96f8c3d9400258f7759408d1f6f8435b4a24d9b52f5a0340d97907e567cb8773 Repo URL:https://github.com/Woody4618/verify-squads/tree/0fb0a2e30c15c51732c0ad5e837975a6f7bbc7edCheck the verification status at:https://verify.osec.io/status/6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD Joburl: https://verify.osec.io/job/b63339d2-163e-49ac-b55d-3454c1c2b5b3
恭喜您,已成功在多签升级后完成程序验证!
通过 Docker 镜像进行验证
您也可以通过运行以下命令,对照 Docker 镜像验证您的程序:
solana-verify verify-from-image -eexamples/hello_world/target/deploy/hello_world.so -iellipsislabs/hello_world_verifiable_build:latest -p2ZrriTQSVekoj414Ynysd48jyn4AX6ZF4TTJRqHfbJfn
该命令加载存储在 ellipsislabs/hello_world_verifiable_build:latest
的镜像,并验证容器中可执行文件路径的哈希值是否与命令中提供的链上程序的哈希值一致。由于构建文件已上传至镜像,无需重新完整构建可执行文件,从而节省了大量时间。
创建镜像 ellipsislabs/hello_world_verifiable_build:latest
的 Dockerfile 可在 Ellipsis Labs 仓库的
/examples/hello_world
中找到。
以下是预期输出:
Verifying image: "ellipsislabs/hello_world_verifiable_build:latest", on network"https://api.mainnet.solana.com" against program ID2ZrriTQSVekoj414Ynysd48jyn4AX6ZF4TTJRqHfbJfn Executable path in container:"examples/hello_world/target/deploy/hello_world.so"Executable hash:08d91368d349c2b56c712422f6d274a1e8f1946ff2ecd1dc3efc3ebace52a760 Program hash:08d91368d349c2b56c712422f6d274a1e8f1946ff2ecd1dc3efc3ebace52a760 Executablematches onchain program data ✅
已验证构建示例
以下是使用此
代码库中的源代码验证 ID 为
FWEYpBAf9WsemQiNbAewhyESfR38GBBHLrCaU3MpEKWv 的示例程序的演示:
solana-verify verify-from-repo https://github.com/solana-developers/verified-program --url YOUR-RPC-URL --program-id FWEYpBAf9WsemQiNbAewhyESfR38GBBHLrCaU3MpEKWv --mount-path waffle --library-name waffle --commit-hash 5b82b86f02afbde330dff3e1847bed2d42069f4e
默认情况下,verify-from-repo
命令会使用主分支上的最新提交。如果您希望继续在该代码库上进行开发,也可以通过
commit-hash 参数指定特定的提交:
--commit-hash 5b82b86f02afbde330dff3e1847bed2d42069f4e
出现提示时,选择是以将您的验证 PDA 上传至链上。然后向 OtterSec API 提交远程验证任务:
solana-verify remote submit-job --program-id FWEYpBAf9WsemQiNbAewhyESfR38GBBHLrCaU3MpEKWv --uploader <your-upgrade-authority>
已通过验证的热门程序
Phoenix
solana-verify verify-from-repo -um --program-id PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY https://github.com/Ellipsis-Labs/phoenix-v1
最终输出:
Executable Program Hash from repo: 6877a5b732b3494b828a324ec846d526d962223959534dbaf4209e0da3b2d6a9Onchain Program Hash: 6877a5b732b3494b828a324ec846d526d962223959534dbaf4209e0da3b2d6a9Program hash matches ✅
Squads V3
solana-verify verify-from-repo https://github.com/Squads-Protocol/squads-mpl --commit-hash c95b7673d616c377a349ca424261872dfcf8b19d --program-id SMPLecH534NA9acpos4G6x7uf3LWbCAwZQE9e8ZekMu -um --library-name squads_mpl --bpf
请注意,我们需要指定
library-name,因为 Squads 代码库包含多个程序。我们使用--bpf标志,是因为squads_mpl此前已通过 Anchor 进行了验证。
最终输出:
Executable Program Hash from repo: 72da599d9ee14b2a03a23ccfa6f06d53eea4a00825ad2191929cbd78fb69205cOnchain Program Hash: 72da599d9ee14b2a03a23ccfa6f06d53eea4a00825ad2191929cbd78fb69205cProgram hash matches ✅
Drift V2
solana-verify verify-from-repo -um --program-id dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH https://github.com/drift-labs/protocol-v2 --commit-hash 110d3ff4f8ba07c178d69f9bfc7b30194fac56d6 --library-name drift
最终输出:
Executable Program Hash from repo: e31d58edeabc3c30bf6f2aa60bfaa5e492b41ec203e9006404b463e5adee5828Onchain Program Hash: e31d58edeabc3c30bf6f2aa60bfaa5e492b41ec203e9006404b463e5adee5828Program hash matches ✅
Marginfi V2
solana-verify verify-from-repo -um --program-id MFv2hWf31Z9kbCa1snEPYctwafyhdvnV7FZnsebVacA https://github.com/mrgnlabs/marginfi-v2 --commit-hash d33e649e415c354cc2a1e3c49131725552d69ba0 --library-name marginfi -- --features mainnet-beta
最终输出:
Executable Program Hash from repo: 890d68f48f96991016222b1fcbc2cc81b8ef2dcbf280c44fe378c523c108fad5Onchain Program Hash: 890d68f48f96991016222b1fcbc2cc81b8ef2dcbf280c44fe378c523c108fad5Program hash matches ✅
常见问题
我的验证失败了。该怎么办?
请检查以下常见问题:
- 签名者错误:通过运行
solana program show YourProgramId确认您的签名者是该程序的升级权限账户 - 链上无 PDA:运行
solana-verify verify-from-repo -um并在提示时选择"是"。若未上传 PDA,API 将无法检索您的验证元数据。 - PDA 数据不匹配:若您已重新部署程序,请更新您的 PDA。您的 PDA 数据必须与已部署的程序一致。
- 提交哈希不正确:请使用您部署时所用的确切提交哈希来创建 PDA
- 构建环境差异:创建 PDA 时请使用带有 solana-verify 的 Docker
我的本地构建哈希与链上哈希不匹配。为什么?
这通常意味着:
- 您使用了不同版本的 Rust/Solana 工具链
- 您的依赖项在两次构建之间有所更新
- 您没有在 Docker 容器中进行构建
- 您检出了错误的提交
解决方法:在 Docker 中使用
solana-verify build,并基于您所部署的确切提交进行构建。
我的验证需要多长时间?
根据您的程序大小,预计所需时间如下:
- 简单程序:1-5 分钟
- 复杂程序:5-15 分钟
- 超大型程序:最多 30 分钟
请使用作业状态端点跟踪您的进度。
我的程序是不可变的(无升级权限)。如何验证?
如果您的程序没有升级权限,或在创建 PDA 之前已被设为不可变,我们为此类情况提供了一个白名单地址。请通过 contact@osec.io 联系我们,我们将协助您完成程序验证。
什么是 PDA,为什么它很重要?
您的 PDA(程序派生账户)支持无需信任的验证:
- 链上存储:将您的验证元数据(代码库 URL、提交哈希、构建参数)存储在由 Otter
Verify 程序(
verifycLy8mB96wd9wqq3WDXQwM4oU6r42Th37Db9fC)拥有的 PDA 中 - 加密关联:您的 PDA 由您的程序地址派生,与验证数据形成不可篡改的链接
- 去中心化信任:任何人均可读取您的 PDA 并独立验证您的程序
为什么必须在使用 API 之前创建 PDA?
API 仅适用于链上 PDA,原因如下:
- 无需信任:API 拒绝任意数据——它仅使用您的升级权限在链上存储的内容
- 更简便:只需提供签名者和 program_id,API 将从您的 PDA 中获取其余所有信息
- 防篡改:您的 PDA 创建了一条任何人都可独立验证的不可变记录
- 所有权证明:您的签名者必须是升级权限方,以加密方式证明您对程序的控制权
我应该多久验证一次程序?
在以下情况下验证您的程序:
- 每次部署或升级后
- 更新源代码库时
- 其他情况无需重复验证——API 每 24 小时自动重新验证所有程序
升级程序后会发生什么?
升级后请按照以下步骤操作:
- API 检测到您的升级后,将取消您程序的验证状态。
- 使用新的验证元数据更新您的 PDA:
solana-verify verify-from-repo -um \--program-id YourProgramId... \https://github.com/your-org/your-program
- 使用您的升级权限提交新的验证请求
- API 将根据更新后的 PDA 验证您的新版本
重要提示:请始终使用升级权限并附上已升级程序的新提交哈希来更新您的 PDA。
我可以信任验证结果吗?
可以——该系统设计为无需信任且可独立验证:
可信赖的原因:
- 链上 PDA:您的验证元数据存储在链上,不受任何中心化机构控制
- 升级权限证明:只有您程序的升级权限方才能创建/更新 PDA
- 独立验证:任何人均可通过读取您的 PDA 并在本地运行
solana-verify来进行验证 - 持续重新验证:API 每 24 小时自动对所有程序重新验证一次
了解以下局限性:
- 验证仅确认源代码与部署内容一致——并不代表您的代码是安全的
- 在与程序交互之前,请务必审查代码
- 已验证 ≠ 已审计或安全
- 请查看 PDA 中的代码仓库和提交记录,以确认其来自可信来源
如何独立验证一个程序?
您可以通过读取其链上 PDA 并在本地运行验证,自行验证任意程序:
第一步:读取链上 PDA
# Install solana-verify if you haven'tcargo install solana-verify# Get the PDA datasolana-verify list-program-pdas --program-id YourProgramId...
第二步:在本地验证
# Verify using the repository and commit & other arguments from the PDAsolana-verify verify-from-repo \--program-id YourProgramId... \https://github.com/your-org/your-program--commit-hash <commit-hash>... (other arguments from the PDA)# Confirm the hash output matches the onchain program hash
这可以证明:
- PDA 元数据是真实的(存储在链上)
- PDA 代码仓库中的源代码与已部署的程序一致
- 您无需信任 API——可在链上自行验证一切
其他人可以在未经许可的情况下验证我的程序吗?
可以,这正是我们要求签名者必须是升级权限方的原因。只有当签名者是升级权限方时,我们才认为验证有效。
创建可验证构建需要哪些条件?
请安装以下工具:
- Docker(用于确定性构建)
- Cargo(Rust 包管理器)
- Solana Verify CLI:
cargo install solana-verify - 包含源代码的公开 Git 仓库
我可以验证私有仓库吗?
不可以——验证需要公开的源代码:
- 您的 PDA 存储了一个任何人都可以访问的公共仓库 URL
- 无需信任的验证依赖于对公共代码的访问
- 用户需要阅读您的源代码以了解您的程序功能
- 整个系统的目的是让用户独立验证源代码与部署内容相匹配
私有仓库会破坏验证系统核心的信任模型。
如何验证由 Squads Multisig 控制的程序?
请按照以下步骤操作多签控制的程序:
# 1. Build and deploy normallysolana-verify buildsolana program deploy <your-program.so> --program-id YourProgramId...# 2. Verify locally first - confirm the hash matchessolana-verify verify-from-repo -um \--program-id YourProgramId... \https://github.com/your-org/your-program# 3. Export the PDA creation transactionsolana-verify export-pda-tx \--program-id YourProgramId... \https://github.com/your-org/your-program# 4. Execute the PDA transaction through your Squads Multisig interface# 5. After multisig execution, trigger remote verificationsolana-verify remote submit-job \--program-id YourProgramId... \--uploader YourMultisigAddress...
重要提示:请务必在本地执行验证(步骤 2),确认构建哈希匹配后,再导出 PDA 交易。
总结
使用 Solana 上的已验证构建 可确保您的程序在网络上的完整性和可信度,并允许开发者通过 Solana Explorer 直接找到您的 SDK。借助 Solana Verify CLI 和 Docker 等工具,您可以维护与源代码一致的可验证安全构建。请始终采取必要的预防措施以使用一致的环境,并考虑采用治理方案来安全地进行升级和部署。
安全说明与免责声明
尽管已验证构建是确保 Solana 程序完整性的强大工具,但在默认配置下并非完全无需信任。Docker 镜像由 Solana 基金会构建和托管。
请注意,您是在下载的 Docker 镜像中构建项目的,您的整个构建环境(包括潜在的敏感信息)都会被复制到该 Docker 镜像中。
如果您希望实现完全无需信任的配置,可以自行构建 Docker 镜像并将其托管在自己的基础设施上。这样您可以确保 Docker 镜像未被篡改。您可以在 已验证构建仓库 中找到创建自定义 Docker 镜像的脚本,也可以 Fork 该仓库并自行运行 GitHub Actions,或验证其正确性。
此外,对于远程验证,您在一定程度上信任 OtterSec API 和 Solana Explorer。
如果 API 或 Solana Explorer 遭到入侵,可能会显示不正确的信息。
如果您希望建立完全无需信任的环境,可以自行运行
Verify API,或使用
verify-from-repo 命令在本地执行程序验证,该命令使用保存在
PDA
中的链上验证数据,该 PDA 由程序的部署权限和
verify program
派生。
verify program 由 OtterSec 团队 部署,目前尚未冻结,因此可随时升级。
Solana 基金会、OtterSec 及 Ellipsis Labs 团队对使用已验证构建流水线所造成的任何损失或损害概不负责。
Solana 程序的 Security.txt
除了已验证构建之外,您还可以在程序中添加 security.txt
文件。未来一旦实现,security.txt
将存储验证者 pubkey,以便轻松访问存储在验证 PDA 中的验证数据。包含构建和验证程序所需全部信息的 PDA 由程序地址和验证者 pubkey 派生。默认情况下,这与构建和部署程序的 pubkey 相同,但也可以是在
security.txt 中指定的另一个 pubkey。
security.txt
功能允许开发者将联系信息和安全信息直接嵌入其 Solana 智能合约中。该方法受
securitytxt.org
启发,为安全研究人员提供了一种标准化的方式,即使他们只知道合约地址,也能联系到项目维护者。
为什么使用 security.txt?
对于许多项目,尤其是规模较小或私有的项目,仅凭合约地址来识别开发者可能既困难又耗时。在程序中嵌入
security.txt
文件,可确保安全研究人员能够轻松联系到正确的负责人,从而有效预防漏洞利用,并确保漏洞报告得到及时处理。
如何实现 security.txt
要将 security.txt 添加到您的 Solana 程序中,请按以下步骤操作:
将 solana-security-txt 依赖项添加到您的 Cargo.toml 中:
[dependencies]solana-security-txt = "1.1.1"
在您的合约中使用 security_txt!
宏来定义安全信息。您可以包含联系方式、项目 URL,甚至安全策略。以下是一个示例:
#[cfg(not(feature = "no-entrypoint"))]use {default_env::default_env, solana_security_txt::security_txt};#[cfg(not(feature = "no-entrypoint"))]security_txt! {name: "MyProject",project_url: "https://myproject.com",contacts: "email:security@myproject.com,discord:security#1234",policy: "https://myproject.com/security-policy",// Optional Fieldspreferred_languages: "en,de",source_code: "https://github.com/solana-developers/solana-game-preset",source_revision: "5vJwnLeyjV8uNJSp1zn7VLW8GwiQbcsQbGaVSwRmkE4r",source_release: "",encryption: "",auditors: "Verifier pubkey: 5vJwnLeyjV8uNJSp1zn7VLW8GwiQbcsQbGaVSwRmkE4r",acknowledgements: "Thank you to our bug bounty hunters!"}
一旦 security.txt 信息嵌入到您的程序中,即可通过 Solana
Explorer 等工具轻松查询,确保您的联系方式和安全详情对所有希望报告潜在问题的人员可见。
最佳实践
-
使用链接:对于可能发生变更的信息(例如联系方式),建议链接到网页,而非将其硬编码到合约中。这样可以避免频繁升级程序的需要。
-
验证:在部署之前,请使用
query-security-txt工具验证格式和内容,该工具可对链上程序和本地二进制文件进行验证:
query-security-txt target/bpfel-unknown-unknown/release/my_contract.so
通过将安全联系信息直接嵌入您的合约,可以让研究人员更方便地与您取得联系,从而促进 Solana 生态系统中更完善的安全保障与沟通协作。
这是 security.txt 在 Solana Explorer 中的示例效果
security.txt 项目由 Neodyme Labs 维护
您可以在 verify.osec.io 查看验证状态并浏览已验证的程序。
Is this page helpful?