本文介绍了如何为加密项目设置持续集成和持续部署(CI/CD)环境,包括设置代码仓库、初始化项目、编写智能合约代码、编写测试和部署脚本,以及编写pipeline。通过使用GitHub Actions,可以自动化测试、漏洞扫描和部署流程,提高项目的效率和安全性。
所以你想编写和部署一个智能合约,是吗?
开始行动,像专业人士一样去做,使用最佳软件中常见的最佳实践。 没有必要重新发明轮子,改变那些有效的流程。 有时我们只需要调整工具——这就是本文的重点。
让我们从头开始为一个示例项目设置这个环境。
从两个代码仓库开始被认为是好的实践。 一个是用于主要活动的公共仓库,第二个是私有仓库,也存放代码库,因为项目中的某些活动不应该公开讨论,例如,可能影响用户的实时漏洞/安全补丁。 这种方法可以帮助我们避免黑客在已发布的代码修复之前,利用拉取请求中披露的漏洞。
为了避免使本教程复杂化,我们将只使用一个公共仓库(在 GitHub 上)。
让我们逐步浏览代码仓库设置,并考虑更改关键参数,例如团队的分支保护规则或访问控制。
克隆你的空代码仓库并进入。 在代码仓库文件夹中,使用以下命令初始化项目的模板:
brownie init
该命令将准备所有需要的文件夹,包括 .gitignore 文件。
现在,我们准备好编写代码了。 让我们从 OpenZeppelin Solidity Wizard 生成的以下代码开始,并进行一些更改(错误)。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
contract MyToken is ERC20, Ownable, Pausable {
constructor() ERC20("MyToken", "MTK") {
_mint(msg.sender, 1000000 * 10**18);
}
function pause() public onlyOwner {
_pause();
}
function unpause() public onlyOwner {
_unpause();
}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
function _beforeTokenTransfer(address from, address to, uint256 amount)
internal
whenNotPaused
override
{
super._beforeTokenTransfer(from, to, amount);
}
function burn(uint256 amount) public {
_burn(tx.origin, amount);
}
}
此代码包含一些包,因此我们必须使用 npm 添加它们(不要忘记将 node_modules 添加到 .gitignore)。
npm install @openzeppelin/contracts dotenv
当我们安装了这些包后,我们可以测试编译。
brownie compile
在当前状态下,我们有一个工作项目,其结构如下。
首先,我们需要针对源代码初始化 pytypes:
brownie compile
然后我们将编写一些基本测试:
import pytest
from brownie import MyToken, accounts
def test_initial_supply():
# Arrange
account = accounts[0]
# Act
token = MyToken.deploy({"from": account})
# Assert
assert token.totalSupply() == 1000000 * 10**18
assert token.balanceOf(account) == 1000000 * 10**18
我们可以使用以下命令运行测试:
brownie test
我们将把合约部署到 Holesky 测试网。 编写部署脚本与编写测试非常相似。
from brownie import MyToken, accounts, network
from dotenv import load_dotenv
import os
load_dotenv()
def main():
account = accounts.add(os.getenv("PRIVATE_KEY"))
print(f"Deploying from account: {account.address}")
# We don't want to deploy to live net with that script
if network.show_active() == "mainnet":
return
publish_source = False
if os.getenv("ETHERSCAN_TOKEN"):
publish_source = True
my_token = MyToken.deploy({"from": account}, publish_source=publish_source)
print(f"MyToken Deployed at: {my_token.address}")
在部署之前,我们需要在 .env 文件中设置私钥,并使用 dotenv 库检索它,然后我们可以测试部署。
export ETHERSCAN_TOKEN=XXX
brownie run scripts/deploy.py --network holesky
一切都按预期工作:测试、部署和编译,因此我们可以继续编写流水线以使这些步骤自动化。
我们将从创建一个文件夹来存放我们的流水线开始:
mkdir .github
mkdir .github/workflows
然后,在此文件夹中,我们将创建以下文件:pipeline.yml。
name: Pipeline
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Wake Setup
uses: acknowledgeware/wake-setup@v1
- name: Test
run: brownie test
- name: Detect
uses: acknowledgeware/wake-detect@v1
deploy:
needs: tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Wake Setup
uses: acknowledgeware/wake-setup@v1
- name: Deploy
run: |
export ETHERSCAN_TOKEN=$
brownie run scripts/deploy.py --network holesky
env:
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
ETHERSCAN_TOKEN: ${{ secrets.ETHERSCAN_TOKEN }}
我们有两个 job。 一个用于测试拉取请求到 master 的请求,并分析将要合并的新代码。 第二个 job 用于部署,并且仅在合并/推送到 master 时触发。 我们使用 Wake Setup action 来设置测试和部署的环境。 然后,我们使用专门的 Wake Detect action 来扫描代码中的漏洞。 在部署部分,我们必须通过 GitHub secrets 使用 dotenv 传递私钥。 该 secret 必须在代码仓库设置中设置。
一旦我们设置了 secret,我们就可以开始了。
一切都已设置完毕。 我们可以检出到另一个分支并推送我们的代码库。 推送后,不会触发任何操作,因为我们没有为此行为定义流水线。 这是预期的。
创建拉取请求后,我们可以看到流水线已触发(跳过部署)。
显然,由于我们之前没有运行静态分析,我们可以看到流水线检测到错误并将它们附加到我们的拉取请求中。
因此,根据我们的代码仓库策略,在我们完全解决问题之前,我们可能无法合并到 master。
我们回到代码来修复它。 删除未使用的引入,并将 tx.origin 替换为 msg.sender。
现在我们可以看到我们已准备好进行部署。
让我们合并它!
我们通过 GitHub actions 成功部署了合约。
本教程介绍了如何使用 GitHub actions 来增强你的 CI/CD 流程。
这些 actions 将帮助你使你的项目更持久和高效。 提供的示例纯粹是信息性的,现在由你来为你的项目找到最佳匹配。
- 原文链接: ackee.xyz/blog/on-the-wa...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!