Solidity 智能合约编程语言:仓库全景解读、编译安装与实战示例指南
Solidity 智能合约编程语言:仓库全景解读、编译安装与实战示例指南
Solidity 是一门面向合约的静态类型高级编程语言,专为在以太坊虚拟机(EVM)上实现智能合约而设计。本文以本仓库(Solidity 编译器官方源码,当前版本 0.8.37)为核心,完整梳理语言定位、编译器的多种安装途径、Hello World 级入门示例、四个经典实战合约(投票、盲拍、安全远程购买、微支付通道),并结合 CMake 构建脚本与测试源码,给出可直接落地的操作路径与底层原理依据。读完本文,你将掌握从零获取 Solidity 编译器、搭建开发环境、理解合约范式到读懂版本语义的完整技能链。
仓库与语言背景
本仓库即 Solidity 编程语言及其编译器的官方源码仓库,核心产物是 solc 编译器,它由 C++ 编写,包含 libsolidity(前端解析、语法分析与类型检查)、libevmasm(EVM 汇编)、libyul(中间表示与优化器)、libsolutil(通用工具)等模块,目录结构可参考 CMakeLists.txt。
Solidity 是一种静态类型、花括号语法的合约导向语言,运行于 EVM 之上。智能合约是运行在点对点网络中的程序,网络中没有任何人拥有对执行的特殊权限,因此任何人都可以用它实现价值代币、所有权、投票以及其他逻辑。从语言血统看,Solidity 受到 C++、Python 和 JavaScript 的影响,支持继承、库、复杂的用户自定义类型等特性,可用于投票、众筹、盲拍、多签钱包等多种场景(见 docs/index.rst)。
重要版本提示:部署合约时应始终使用最新发布版。Solidity 目前采用 0.x 版本号以体现其快速的迭代节奏——破坏性变更、新特性与 bug 修复会定期引入。当前仓库在 CMakeLists.txt 中声明项目版本为
0.8.37。
安装与构建 Solidity 编译器
完整安装指南收录在 docs/installing-solidity.rst。总体而言,官方推荐的路径是:小合约与快速学习用 Remix;大型合约或需要更多编译选项时,在本地安装命令行编译器。
版本语义(SemVer)
Solidity 遵循语义化版本规范(SemVer)。特别地,主版本号为 0 的补丁级发布(即 0.x.y)不包含破坏性变更,即能由 0.x.y 编译的代码通常也能由 0.x.z(z > y)编译。除了正式发布,官方还提供 prereleases 与 nightly 开发构建,方便开发者提前尝试新特性并反馈,但这些构建包含开发分支中的前沿代码,质量不受保证,可能包含未文档化甚至损坏的变更,不应用于生产环境。
版本字符串由四部分组成:版本号、预发布标签(通常为 develop.YYYY.MM.DD、pre.N 或 nightly.YYYY.MM.DD)、形如 commit.GITHASH 的提交哈希、以及平台细节;若存在本地修改,提交部分会追加 .mod 后缀。示例如下:
- 正式版:
0.4.8+commit.60cc1668.Emscripten.clang - 预发布:
0.4.9-pre.3+commit.fb60450bc.Emscripten.clang - 每日构建:
0.4.9-nightly.2017.1.17+commit.6ecb4aa3.Emscripten.clang
方式一:Remix(无需安装)
Remix 是官方推荐的浏览器 IDE,适合小合约与快速学习,访问 Remix 即可在线使用;如需离线环境,可下载 Remix Desktop。Remix 也便于测试 nightly 构建,而无需安装多个 Solidity 版本。
方式二:npm / Node.js(solcjs)
solcjs 是 Solidity 编译器的 JavaScript 移植版,通过 Emscripten 将 C++ 版 solc 编译而来,二者共用同一份编译器源码。安装命令:
npm install --global solc
注意:命令行可执行文件名为 solcjs,它的命令行选项与完整版 solc 不兼容,期望 solc 行为的工具(如 geth)无法与 solcjs 配合工作。完整功能请使用 solc。
方式三:Docker
使用 solc 官方镜像,stable 标签对应最新发布版,nightly 对应 develop 分支上可能不稳定的变更。查看帮助:
docker run ghcr.io/argotorg/solc:stable --help
编译宿主机上的合约文件时,需挂载本地目录作为输入输出,例如:
docker run \
--volume "/tmp/some/local/path/:/sources/" \
ghcr.io/argotorg/solc:stable \
/sources/Contract.sol \
--abi \
--bin \
--output-dir /sources/output/
与工具链集成时推荐使用标准 JSON 接口,只要 JSON 输入自包含(不引用需由导入回调加载的外部文件),就无需挂载任何目录:
docker run ghcr.io/argotorg/solc:stable --standard-json < input.json > output.json
方式四:Linux 发行版包
官方提供无需额外安装步骤即可运行的独立静态二进制(见下文)。Ubuntu 0.8.30 及以前版本曾通过 ethereum/ethereum PPA 分发,但该分发方式已停止,未来版本不会继续添加。各发行版维护者提供的包通常保持更新;此外还有社区维护的脚本(Arch Linux AUR 的 solidity 与 solidity-bin、Nix 的 solc.nix 等),请注意这些脚本未经发行版维护者审核,使用需谨慎。
snap 包也可用(sudo snap install solc 安装最新稳定版,sudo snap install solc --edge 安装最新开发版),但当前已停止维护。snap 采用严格限制(strict confinement),只能访问 /home 与 /media 目录中的文件。
方式五:macOS / Homebrew
通过 Homebrew 以源码构建方式分发(暂不支持预编译 bottle):
brew update
brew upgrade
brew tap ethereum/ethereum
brew install solidity
旧版本可通过 brew install solidity@4、brew install solidity@5 安装;如需特定版本,可从 homebrew-ethereum 仓库检出对应版本的 formula 后用 brew install solidity.rb 安装。
方式六:静态二进制与 solc-bin
官方维护了包含所有受支持平台历史与当前版本静态构建的 solc-bin 仓库,其内容镜像到 HTTPS 端点,无需认证、不限速、无需 git,且以正确的 Content-Type 与宽松的 CORS 配置提供,浏览器工具可直接加载。二进制无需安装或解包,具备高度向后兼容性:文件一经添加不会删除或移动,也不会原地修改,始终与原始校验和一致。
每个平台目录下都有一个 list.json 列出可用二进制,例如 emscripten-wasm32/list.json 中关于 0.7.4 的条目:
{
"path": "solc-emscripten-wasm32-v0.7.4+commit.3f05b770.js",
"version": "0.7.4",
"build": "commit.3f05b770",
"longVersion": "0.7.4+commit.3f05b770",
"keccak256": "0x300330ecd127756b824aa13e843cb1f43c473cb22eaf3750d5fb9c99279af8c3",
"sha256": "0x2b55ed5fec4d9625b6c7b3ab1abd2b7fb7dd2a9c68543bf0323db2c7e2d55af2",
"urls": [
"dweb:/ipfs/QmTLs5MuLEWXQkths41HiACoXDiH8zxyqBHGFDRSzVE5CS"
]
}
该条目表明:二进制与 list.json 同目录存放(可能是符号链接);可通过 keccak256(用 keccak256sum 或 keccak256() 计算)与 sha256 校验完整性。编写新工具时,建议使用 emscripten-wasm32/(性能更佳的 WebAssembly 构建,自 0.6.2 起默认)并解析 list.json,避免使用 bin/、list.js 等遗留元素。
方式七:从源码构建
构建前置依赖(所有操作系统通用):CMake(Windows 上 3.21.3+,其他平台 3.13+)、Boost(Windows 上 1.77+,其他平台 1.83+)、Git,以及可选用于 SMT 检查器的 z3(4.8.16+)。C++ 编译器最低版本要求:GCC 13.3+、Clang 18.1.3+、MSVC 2019+。
克隆仓库(注意 --recursive 拉取子模块):
git clone --recursive https://github.com/argotorg/solidity.git
cd solidity
命令行构建:
mkdir build
cd build
cmake .. && make
Linux/macOS 上更简单的做法是直接运行仓库自带的 scripts/build.sh(默认以 Release 类型构建,并安装 solc 与 soltest 到 /usr/local/bin):
./scripts/build.sh
Windows 下用 cmake -G "Visual Studio 16 2019" .. 生成 solidity.sln,或在命令行执行 cmake --build . --config Release。Windows 可用辅助脚本 scripts/install_deps.ps1 将 boost 与 cmake 安装到 deps 子目录,此时需额外传入 -DBoost_ROOT="deps/boost" -DBoost_INCLUDE_DIR="deps/boost/include" 与 -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded。
关键 CMake 选项
可用 cmake .. -LH 查看全部选项,以下选项在 CMakeLists.txt 中有明确声明:
-DPEDANTIC=OFF:关闭默认开启的 pedantic 模式(该模式开启额外警告并将警告视为错误)。仅为发布构建而不打算修改源码时可关闭,但不推荐。-DSTRICT_Z3_VERSION=OFF:允许使用任意满足最低版本要求的 z3 构建(默认要求测试套件所对应的精确版本),此时运行scripts/tests.sh需加--no-smt跳过 SMT 测试。-DSOLC_LINK_STATIC=ON:在受支持平台上静态链接solc可执行文件。-DIGNORE_VENDORED_DEPENDENCIES=ON:忽略仓库以子模块形式提供的依赖库(fmtlib、nlohmann-json、range-v3,见 cmake/EthDependencies.cmake),改用系统中安装的版本。- 安装 ccache 可加速重复构建,CMake 会自动识别。
SMT 求解器与构建
Solidity 可选用 SMT 求解器 z3、cvc5 与 Eldarica,但它们的检测发生在运行时,不是构建成功的必要条件。Emscripten 构建则例外,它静态链接 z3。SMT 相关实现位于 libsmtutil/ 与 libsolidity/formal/(如 BMC.cpp、CHC.cpp)。
第一个合约:Hello World
README 中给出的 "Hello World" 示例(本仓库 README.md):
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.9.0;
contract HelloWorld {
function helloWorld() external pure returns (string memory) {
return "Hello, World!";
}
}
要点拆解:
pragma solidity >=0.6.0 <0.9.0;是版本指令,声明源码可被 0.6.0 至 0.9.0 之前的编译器编译。这与上文版本语义一节紧密呼应:0.x 补丁版本不引入破坏性变更,故区间下限可安全放宽。external表示仅允许外部调用;pure承诺不读写状态;returns (string memory)指定返回动态字符串及存储位置。
入门后,可用浏览器 IDE Remix 直接编译部署。更系统的示例见 docs/solidity-by-example.rst 及其展开章节。
经典实战示例
README 推荐了四个出自官方文档的经典示例合约,以下逐一分析其核心机制与安全要点。
1. 委托投票合约(Voting / Ballot)
完整代码见 docs/examples/voting.rst。该合约实现委托式投票,使计票自动且完全透明。核心设计:
- 每个提案(ballot)部署一个合约,为每个选项提供短名称;合约创建者作为
chairperson逐一授予投票权。 struct Voter记录weight(通过委托累积的权重)、voted、delegate与所投提案索引;mapping(address => Voter) public voters为每个地址保存选民信息。giveRightToVote()由主席调用,通过require校验调用者身份、防止重复投票。delegate()支持将票委托给信任的人,并沿委托链向前转发(while (voters[to].delegate != address(0))),同时检测委托环(require(to != msg.sender, "Found loop in delegation."))。文档特别警告:此类循环若过长可能耗尽区块可用 gas,导致委托无法执行,极端情况下甚至让合约"卡死"。vote()将委托积累的权重累加到提案的voteCount;数组越界会自动回滚所有变更。winningProposal()与winnerName()在投票期结束后返回得票最多的提案。文档在"可能的改进"中提示:为所有参与者分配投票权需要大量交易;平票时winningProposal()无法判定平局。
2. 盲拍合约(Blind Auction)
完整代码见 docs/examples/blind-auction.rst,文档从简单的公开拍卖逐步扩展到盲拍。
SimpleAuction(公开拍卖) 要点:竞拍期内人人可出价并附带押金(Ether)以约束出价;被超越的最高出价者通过 pendingReturns 映射以提款模式收回押金,而非由合约主动转账——这是防重入的经典做法;auctionEnd() 遵循"检查条件 → 修改状态 → 外部交互"三阶段顺序,避免重入导致重复支付。合约无法自我激活,因此拍卖结束后须由外部手动调用结算函数。
BlindAuction(盲拍) 解决"透明链上如何保密出价"的矛盾:竞拍期只提交出价的哈希(blindedBid = keccak256(abi.encodePacked(value, fake, secret))),出价人以哈希作出承诺;竞拍结束后进入揭示期,出价人提交明文值,合约校验哈希一致即兑现出价。由于以太坊无法隐藏转账金额,合约通过接受"大于当前最高价"的任意押金并允许 fake 假标书,让竞拍者可以投放高值无效标书迷惑对手。出价、揭示、结算三个阶段的时限由 onlyBefore / onlyAfter 修饰器控制。
3. 安全远程购买合约(Safe Remote Purchase)
完整代码见 docs/examples/safe-remote.rst。远程购物无法确认货物是否送达,该合约要求买卖双方各存入商品价值两倍的 Ether 作为托管:资金锁定后,买方确认收货时退回其押金的一半(即商品价值),卖方获得三倍价值(其押金加商品价值)。若双方互不配合,资金将永久锁定,从而为双方提供解决纠纷的激励。
该合约是状态机范式的教科书示例:enum State { Created, Locked, Release, Inactive } 配合 onlyBuyer、onlySeller、inState、condition 等修饰器约束每个函数的合法调用时机;abort()、confirmPurchase()、confirmReceived()、refundSeller() 依次推进状态。所有资金转出函数都先修改状态再执行 call,从根本上阻断重入。
4. 微支付通道(Micropayment Channel)
完整代码见 docs/examples/micropayment.rst。支付通道利用密码学签名,让同一对参与方之间的 Ether 转移做到安全、即时、无交易费。
签名部分(ReceiverPays 合约):Alice(付款方)离线签署包含收款地址、金额、nonce 与合约地址的消息(nonce 防重放,合约地址防跨合约重放),Bob 持签名消息向合约 claimPayment() 领取资金。合约端用内联汇编的 splitSignature() 从 65 字节签名中切出 r、s、v,用内建函数 ecrecover 恢复签名者地址,并通过 prefixed() 构造 "\x19Ethereum Signed Message:\n32" 前缀哈希以模拟 eth_sign 的行为。
通道部分(SimplePaymentChannel 合约):三步流程——(1) Alice 部署合约并托管 Ether 以"开启"通道;(2) Alice 离线签署每条消息,指定迄今为止累计应付总额(而非单笔金额),只有一条消息会被兑现,收款方自然会选择总额最高的最新消息;(3) Bob 调用 close() 关闭通道,领取应得份额并把余额退回给 Alice。通道设有 expiration 超时,超时后 Alice 可调用 claimTimeout() 收回托管资金,防止 Bob 拒不关闭通道。完整流程中只有第 1、3 步需要链上交易,任意多次转账都只需两笔交易。文档同时建议收款方在链下用 ethereumjs-util 自行校验每条消息(合约地址匹配、总额合理、不超托管余额、签名有效),并提醒 splitSignature 并非生产级实现,应改用如 OpenZeppelin ECDSA 等经过严格测试的库。
文档、开发与治理
- 文档:Solidity 官方文档位于
docs/目录(reStructuredText 源文件),涵盖语言描述(docs/types.rst、docs/contracts.rst)、编译器使用(docs/using-the-compiler.rst)、内部机制(docs/internals/layout_in_storage.rst、docs/internals/optimizer.rst)与安全注意事项(docs/security-considerations.rst)等。 - 开发:Solidity 仍在持续开发中,欢迎贡献,贡献指引见 docs/contributing.rst 与 CONTRIBUTING.md。仓库内的测试体系规模庞大:
test/libsolidity/下存放 7000+ 个 Solidity 测试用例,test/libyul/下有 1200+ 个 Yul 测试用例,可运行 scripts/tests.sh 执行完整测试。 - 维护与治理:Solidity 语言与编译器是开源社区项目,由核心团队治理,核心团队由以太坊基金会赞助。
- 许可证:Solidity 以 GNU General Public License v3.0 授权,部分第三方代码有其独立的许可条款(见 cmake/templates/license.h.in)。
- 安全:安全策略见 SECURITY.md。
结语
从 README 出发,本文覆盖了 Solidity 的定位、编译器全渠道安装、Hello World 入门与四个高价值实战范式。实际开发中建议遵循官方节奏:部署用最新发布版,学习用 Remix,工程化用命令行 solc,集成用标准 JSON 接口;编写生产代码前务必通读 docs/security-considerations.rst,并善用仓库内海量测试用例验证行为。