可重现的构建
原文:https://docs.elrond.com/developers/reproducible-contract-builds
通过利用 Docker 和 DockerHub 上的一组 冻结 Docker 镜像,该页面将引导您完成支持可复制合约构建的过程。
您还将学习如何重现一个合约构建,给出它的源代码和一个冻结的 Docker 映像的名称(标签),该映像用于它的前一个构建(我们想要重现)。
可复制构建,也称为确定性编译,是一个编译软件的过程,确保生成的二进制代码可以被复制。使用确定性编译编译的源代码将总是输出相同的二进制【维基百科】。
重要
截至 2022 年 9 月,Rust 工具链不支持开箱即用的可再现构建,因此我们建议智能合约开发者遵循本教程,以实现确定性编译。
智能合约codehash
在深入合约构建可再现性之前,让我们先理解一下codehash
的概念。
当部署智能合约时,网络存储字节码,并计算其blake2b
校验和(使用 256 位的摘要长度)。这被称为codehash
。
假设我们对下面的合约感兴趣,部署在devnet:er D1 qqqqqqqqqpgqahertgz 4020 wegswus 8m 7 F2 AK 8 a 6d 0 gv 396 qw3t 2 zy。它的源代码公布在 GitHub 上。
我们可以从 API 中获取合约的 codehash :
curl -s https://devnet-api.elrond.com/accounts/erd1qqqqqqqqqqqqqpgqahertgz4020wegswus8m7f2ak8a6d0gv396qw3t2zy \
| jq -r -j .codeHash \
| base64 -d \
| xxd -p \
| tr -d '\n'
输出是:
58c6e78f40bd6ccc30d8a01f952b34a13ebfdad796a2526678be17c5d7820174
如果WASM
文件是直接可用的,我们也可以使用实用程序b2sum
来本地计算代码哈希:
b2sum -l 256 adder.wasm
输出将是相同的:
58c6e78f40bd6ccc30d8a01f952b34a13ebfdad796a2526678be17c5d7820174
总而言之,为了验证合约的两个给定构建的字节码相等性,我们可以简单地比较 codehash 属性。
支持可重现构建
截至 2022 年 10 月,为您的智能合约支持可复制构建的推荐方法是使用一个构建脚本,该脚本依赖于一个特别设计的、公开可用的、带标签的 Docker 映像,其中包括带标签的、显式版本的构建工具( Rust 、 wasm-opt 等)。).
建议采用这种方法,以抵消与cargo
(防锈工具链的基本组件)对环境的敏感性相关的最终非确定性。
重要
如果您的智能合约的代码源托管在 GitHub 上,那么定义一个类似于这个的 GitHub 工作流是一个很好的实践,它在发布过程中执行部署(生产就绪)构建。
选择一个图像标签
支持可再现构建的第一步是决定使用特定的 Docker 镜像标签。检查elrond network/build-contract-rust上列出的冻结标签,检查它们的标签——特别是标签rust
和wasm-opt-binaryen
:
LABEL rust=nightly-2022-08-23
LABEL wasm-opt-binaryen=version_105
对于尚未发布(部署在网络上)的新智能合约,建议选择具有最大索引号的标签,它通常包括rust
的最新版本和其他必要的依赖项。
然而,对于较小的版本或补丁,坚持使用之前选择的 image 标记是明智的,出于同样的(细微的)原因,您不会在修复关键 bug 的过程中拥抱开发工具的更新(在任何开发环境中)。
所选择的、冻结的图像标签应伴随版本化的源代码(例如,通过发布说明),以便告知其他人如何再现特定的构建(特定源代码版本)。在这个上下文中,冻结图像标签指的是 Docker 镜像标签,它在首次发布后将不会得到任何更新。
提示
在你的合约的每个(主要)版本上切换到一个更新的图像标签是完全正常的。请确保您传播了这些信息——即使用发行说明。
警告
永远不要为生产就绪的构建选择名为latest
的标签。
通过 Docker 构建(可重复构建)
在这一节中,您将学习如何运行一个可重现的构建,或者换句话说,如何在本地机器上使用 Docker 来重现一个先前的构建(由您或其他人在过去创建的),而不需要安装其他工具,例如 erdpy (及其依赖项)。
获取源代码
让我们在本地克隆示例源代码,并切换到我们想要构建的某个版本:
mkdir -p ~/contracts && cd ~/contracts
git clone https://github.com/ElrondNetwork/reproducible-contract-build-example.git --branch=v0.1.4 --depth=1
通过查看发行说明,我们看到 v0.1.4
是使用image:tag = elrondnetwork/build-contract-rust:v2.0.0
构建的。
下载构建包装
构建过程(通过 Docker)被包装在一个易于使用、友好的 Python 脚本中。让我们下载它:
wget https://raw.githubusercontent.com/ElrondNetwork/elrond-sdk-images-build-contract-rust/main/build_with_docker.py
准备环境变量
导出以下变量:
export PROJECT=~/contracts/reproducible-contract-build-example
export BUILD_OUTPUT=~/contracts/output-from-docker
export IMAGE=elrondnetwork/build-contract-rust:v2.0.0
后面的导出语句明确地选择了要使用的、冻结的Docker 镜像标签。
*### 执行构建
现在,让我们通过调用之前下载的构建包装器来构建合约:
python3 ./build_contract_rust_with_docker.py --image=${IMAGE} \
--project=${PROJECT} \
--output=${BUILD_OUTPUT}
在output
文件夹中,您应该看到以下文件(示例):
adder.wasm
:智能合约的实际字节码,将被部署在网络上;adder.abi.json
:智能合约的 ABI(端点和类型定义的列表),在开发 dApps 或简单地与合约交互时使用(例如,使用erdjs);adder.codehash.txt
:包含合约计算的codehash
的文件。adder.wat
:字节码的文本表示,如有必要,将在文本编辑器中显示;adder.imports.json
:合约导入使用的 VM API 函数列表。adder-v1.2.3.zip
:包含用作构建输入的源代码的版本化档案。
TL;灾难恢复构建片段
话虽如此,让我们将上述步骤总结成一个 bash 片段:
wget https://raw.githubusercontent.com/ElrondNetwork/elrond-sdk-images-build-contract-rust/main/build_with_docker.py
export PROJECT=~/contracts/reproducible-contract-build-example
export BUILD_OUTPUT=~/contracts/output-from-docker
export IMAGE=elrondnetwork/build-contract-rust:v2.0.0
python3 ./build_contract_rust_with_docker.py --image=${IMAGE} \
--project=${PROJECT} \
--output=${BUILD_OUTPUT}
比较代码哈希
一旦构建就绪,您就可以通过检查文件*.codehash.txt
来检查生成的*.wasm
的 codehash
对于我们的示例,应该是:
adder.codehash.txt: 58c6e78f40bd6ccc30d8a01f952b34a13ebfdad796a2526678be17c5d7820174
我们可以看到它与之前获取(或计算)的 codehash 相匹配。也就是说,部署在erd1 qqqqqqqqqqpgqahertgz 4020 wegswus 8m 7 F2 AK 8 a 6d 0 gv 396 qw3t 2 zy的合约保证是从与我们签出的源代码版本相同的源代码版本构建的。
恭喜你!您已经完成了可重复的合约构建🎉*