前序博客见:
本文重点关注如何使用 Polygon zkEVM现有代码 编译生成zkEVM proofs。
运行proverjs来完成setup phase。在setup phase所生成的电路可根据需要多次使用。
实际生产环境,运行的是C++版本实现的prover程序。该prover程序通过GRPC API来获取特定组合proofs的信息。
为验证合约,运行机器配置要求至少为16核256GB。
本文以具有16核、32线程、512GB SSD的r6a.8xlarge AWS实例为例,运行Ubuntu 22.04 LTS操作系统,每小时成本为1.82美金。
为支持运行验证流程,需安装tmux、git和curl:
sudo apt update
sudo apt install -y tmux git cur
需修改内核配置参数来支持大内存容量:
echo " vm.max_map_count=655300" | sudo tee -a /etc/sysctl.conf
sudo sysctl -w vm.max_map_count=655300
export NODE_OPTIONS = "--max-old-space-size=230000"
需安装Node.js 18.x版本:
curl -sL " https://deb.nodesource.com/setup_18.x" -o nodesource_setup.sh
sudo bash nodesource_setup.sh
sudo apt install -y nodejs
node -v
为支持编译所需电路,需安装circom:
cd ~
git clone https://github.com/iden3/circom.git
cd circom
git checkout v2.1.4
git log --pretty=format:'%H' -n 1
相应commit hash应为:ca3345681549c859af1f3f42128e53e3e43fe5e2
使用Rust包管理和build工具——cargo,来编译和安装circom:
sudo apt install -y cargo
cargo build --release
cargo install --path circom
export PATH=$PATH:~/.cargo/bin
echo 'PATH=$PATH:~/.cargo/bin' >> ~/.profile
circom --version
proverjs中生成constants tree的代码运行效率低,为此在c++版的prover程序中集成了一个效率更高的名为bctree的工具——仅需要约8分钟即可生成constants tree:
cd ~
git clone https://github.com/0xPolygonHermez/zkevm-prover.git
cd zkevm-prover
git checkout b9179f3b870c2922b11d09462b447d0fc35dd2f9
git submodule init
git submodule update
sudo apt install -y build-essential libomp-dev libgmp-dev nlohmann-json3-dev
libpqxx-dev nasm libgrpc++-dev libprotobuf-dev grpc-proto libsodium-dev
uuid-dev libsecp256k1-dev
make -j bctree
执行proverjs 中的buildsetup流程,用于生成所有constants和电路。注意其中的bctree工具替换为之前编译的C++版本:
cd ~
git clone https://github.com/0xPolygonHermez/zkevm-proverjs.git
cd zkevm-proverjs
git checkout 59694e4a8a9358772c23e8110f53aee049e2d5bd
npm install
tmux -c "npm run buildsetup --bctree=../zkevm-prover/build/bctree"
整个buildsetup流程用时较长,需要约4.5小时,其中2小时用于下载powersOfTau28_hez_final.ptau
文件——该文件约288GB,仅需要下载一次。
通过前面预处理中的buildsetup流程,会生成验证proof的智能合约文件final.fflonk.verifier.sol
。支持使用源代码 或 字节码 来验证该智能合约。
final.fflonk.verifier.sol
合约为验证final.fflonk.verifier.sol
合约的字节码,需采用完全相同的版本、编译器和参数来编译,以确保字节码中所包含的metadata hash完全相同。如下指令使用hardhat工具来生成一个项目:
cd ~
mkdir contract
cd contract
npm init -y
npm install hardhat
mkdir -p contracts/verifiers
echo -e "module.exports={solidity:{compilers:[{version: \"0.8.17\" , settings:{optimizer:{enabled:true,runs:999999}}}]}}" > hardhat.config.js
一旦创建了项目结构,必须将之前buildsetup流程所生成的智能合约文件final.fflonk.verifier.sol
(在~/zkevm-proverjs/build/proof
目录下),拷贝到contracts/verifiers
目录下,且合约文件名必须修改为FflonkVerifier.sol
。若文件名或路径改变,则metadata hash也将修改,为此,需保证有完全相同的名字和路径。相应的操作命令为:
cp ~/zkevm-proverjs/build/proof/final.fflonk.verifier.sol contracts/verifiers/FflonkVerifier.sol
sha256sum contracts/verifiers/FflonkVerifier.sol
这样可检查FflonkVerifier.sol
的输出哈希摘要准确为:60a850bd73a316d6f85bfdf05bc69ee01f84d889004e98b07847719f59e49761。
一旦检查通过,则可使用如下命令来编译合约:
npx hardhat compile
FflonkVerifier.sol
合约的字节码在artifacts/contracts/verifiers/FflonkVerifier.sol/FflonkVerifier.json
文件的bytecode字段内:
608060405234801561001057600080fd5b50612a
07806100206000396000f3fe6080604052348015
61001057600080fd5b506004361061002b576000
:
:
017fffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffe0908116603f01
1681019083821181831017156129875761298761
28aa565b81604052828152886020848701011115
6129a057600080fd5b8260208601602083013760
006020848301015280965050505050506129c884
602085016128d9565b9050925092905056fea264
6970667358221220 f7f0438c1c741f762e101c4e
ae732373046d40de3d0f2e0808e1fac1d863c78f
64736f6c63430008110033
可通过如下指令将上面的字节码拷贝到FflonkVerifier.sol.compiled.bytecode
文件中:
grep bytecode artifacts/contracts/verifiers/FflonkVerifier.sol/FflonkVerifier.json |sed 's/.*"\(0x.*\)".*/\1/' > FflonkVerifier.sol.compiled.bytecode
也可以手工拷贝artifacts/contracts/verifiers/FflonkVerifier.sol/FflonkVerifier.json
文件的bytecode字段到FflonkVerifier.sol.compiled.bytecode
文件内。注意拷贝是不需要双引号。
然后使用哈希摘要来验证所编译字节码的完整性:
sha256sum FflonkVerifier.sol.compiled.bytecode
其结果应为:44f70b6a1548f49214027169db477f03e92492f19ac5594c648edb478316cbec。
final.fflonk.verifier.sol
合约下载所部署智能合约的字节码,需知道该合约的地址。本文对应的合约地址为0x4ceB990D2E2ee6d0e163fa80d12bac72C0F28D52
。通过该地址,可直接到Etherscan、Blockscout或Beaconcha中获取交易字节码。
在终端上运行某些应用可能会在输入缓存溢出之前,限制其能接受的输入量。为避免该情况,可通过nano
或vi
来创建FflonkVerifier.sol.explorer.bytecode
文件:
cd ~/contract
nano FflonkVerifier.sol.explorer.bytecode
然后将获取的交易字节码拷贝到该文件中,并与上面“选项1”中的文件比较是否完全一样,可使用diff
指令:
cd ~/contract
diff FflonkVerifier.sol.compiled.bytecode FflonkVerifier.sol.explorer.bytecode
或采用哈希文件完整性验证方法:
cd ~/contract
sha256sum FflonkVerifier.sol.*.bytecode
对应的输出应为:
44f70b6a1548f49214027169db477f03e92492f19ac5594c648edb478316cbec
FflonkVerifier.sol.compiled.bytecode
44f70b6a1548f49214027169db477f03e92492f19ac5594c648edb478316cbec
FflonkVerifier.sol.explorer.bytecode
src
文件夹下的main_executor
脚本,基于输入文件input.json
和已编译文件rom.json
,生成committed多项式commit.bin
的execution trace,其中:
rom.json
文件:为zkASM编译器编译rom.zkasm
文件的结果。input.json
文件:为特定输入集合文件。node src/main_executor <input.json> -r <rom.json> -o <commit.bin>
额外的参数还有:
-t
:Test。-l
:输出日志。-s
:跳过.pil
文件编译。-d
:debug模式。-p
:选择某具体的PIL程序。如pilprogram.pil
。-P
:加载pilConfig.json
文件。-u
:未签名交易模式。-e
:跳过对newStateRoot
和newLocalExitRoot
的断言。-v
:Verbose详细模式。buildall
命令用作之前章节提到的所有build setup step的主要entrypoint:
npm run buildall
配套的参数有:
--pil=
:该选项用于指定编译的特定PIL文件名。如--pil=src/main.pil
。--pilconfig=
:该选项用于指定所使用的PIL配置文件名。PIL配置文件中包含了影响编译过程的各种设置和选项。如--pilconfig=config/pilconfig.json
。--starkstruct=debug
:该选项会适配PIL bits number来自动生成STARK struct。通常用于调试目的。--from=
:指定开始build/rebuild流程的step。如--from=c12setup
。--continue
:继续上一次build所剩余的build流程。--step=
:指定执行单个特定的build step。如--step=c12setup
。--build=
:指定所使用的build路径名。编译输出文件会存储在该build路径下。如--build=build/basic_proof
。--input=
:指定用于build流程的输入文件。如--input=test/myinputfile.json
。编译和运行zkEVM Prover的代码和指令见:
zkEVM Prover可提供3个RPC服务:
1)Executor服务:调用zkEVM Prover的Executor模块来为L2交易集生成execution trace。该execution trace可用于执行完所包含的所有交易之后所生成的新状态。但是,Executor服务并不生成proof,仅生成execution trace。该服务可用于快速检查某proposed batch,或batches of transactions,是否构建正确,以及是否适于放入单个execution trace内。换句话说,是检查某batch内的交易,或多个batch,是否适于单个proof。
2)StateDB服务:提供了访问L2状态数据库的结构。该状态以Merkle tree root来简洁表示,且StateDB服务会提供相应的数据及其Merkle proofs。StateDB服务:
3)Aggregator服务:提供了zkEVM Prover所能提供的最高层服务:
调用Aggregator服务来生成proof,该服务:
当调用Aggregator服务传入了相邻batches的proofs pair时,会生成aggregated proof。
Aggregator服务的接口定义在:aggregator.proto文件内。
[1] Polygon zkEVM技术文档 Recursion, aggregation and composition of proofs v.1.1