zkSync 2.0目前主网上线仍是Baby Alpha 版本,代码尚未开源。将在 Fair Onboarding Alpha版本开源代码,预计在2023年第2季度。
基本概念
交易
zkSync 2.0 网络上的交易结构如下:
/// @notice Structure used to represent zkSync transaction.
struct Transaction {
// The type of the transaction.
uint256 txType;
// The caller.
uint256 from;
// The callee.
uint256 to;
// The ergsLimit to pass with the transaction.
// It has the same meaning as Ethereum's gasLimit.
uint256 ergsLimit;
// The maximum amount of ergs the user is willing to pay for a byte of pubdata.
uint256 ergsPerPubdataByteLimit;
// The maximum fee per erg that the user is willing to pay.
// It is akin to EIP1559's maxFeePerGas.
uint256 maxFeePerErg;
// The maximum priority fee per erg that the user is willing to pay.
// It is akin to EIP1559's maxPriorityFeePerGas.
uint256 maxPriorityFeePerErg;
// The transaction's paymaster. If there is no paymaster, it is equal to 0.
uint256 paymaster;
// In the future, we might want to add some
// new fields to the struct. The `txData` struct
// is to be passed to account and any changes to its structure
// would mean a breaking change to these accounts. In order to prevent this,
// we should keep some fields as "reserved".
// It is also recommneded that their length is fixed, since
// it would allow easier proof integration (in case we will need
// some special circuit for preprocessing transactions).
uint256[6] reserved;
// The transaction's calldata.
bytes data;
// The signature of the transaction.
bytes signature;
// The properly formatted hashes of bytecodes that must be published on L1
// with the inclusion of this transaction. Note, that a bytecode has been published
// before, the user won't pay fees for its republishing.
bytes32[] factoryDeps;
// The input to the paymaster.
bytes paymasterInput;
// Reserved dynamic type for the future use-case. Using it should be avoided,
// But it is still here, just in case we want to enable some additional functionality.
bytes reservedDynamic;
}
- 支持三种交易类型:传统交易类型,EIP1559, EIP712.
- ergsLimit: 类似于以太坊交易中的gasLimit;
- ergsPerPubdataByteLimit: 用户对每个Pubdata 字节愿意支持的最大 ergs.
- maxFeePerErg: 类似于EIP1559中的maxFeePerGas.
- maxPriorityFeePerErg: 类似于EIP1559中的maxPriorityFeePerGas.
- payMaster: 用于支持采用ERC20支持交易手续费, 或者也可以支持由合约为用户支付手续费;
- factoryDeps: 用于部署合约的字节码的hash.
- paymasterInput: payMaster的输入
Operators: 负责产块,打包交易,向以太坊上提交验证的数据。
区块
L2的区块在提交到L1时,是将多个连续的块合并成一个Batch一块提交,以包含尽可能多的交易以降低交易手续费, l1BatchNumber 用于表示这个Batch 编号 。
L2区块的Hash 计算方式为:keccak256(l2_block_number)
, 因为L2区块Hash对L1来说无意义。
系统合约
为了保证零知识证明电路尽可能简单,zkSync 实现一些系统合约,用以实现一些专用的目的,如部署合约等。目前只提供了接口,具体实现尚未开源。
ContractDeployer
主要利用create/create2部署新的合约,并生成新的合约地址,执行完还会发出 ContractDeployed
事件。
L1Messenger
用于从zkSync 向 Ethereum 发送信息,并发出L1MessageSent
事件。
NonceHolder
主要用来存放账nonces, 包含tx nonce
和 deployment nonce
.
Bootloader
Bootloader
主要用来实现扩展,降低负载,方便实现account abstract
功能。
L1 合约
Diamond
主要用来管理Diamond
的存储:
struct DiamondStorage {
mapping(bytes4 => SelectorToFacet) selectorToFacet;
mapping(address => FacetToSelectors) facetToSelectors;
address[] facets;
bool isFrozen;
}
DiamondProxy
L1合约实现主要采用 EIP-2535 Diamond
代理方式,通过fallback
代理具体实现合约的调用。
DiamondInit
用于初始化Diamond
代理合约。
DiamondCutFacet
主要用来升级Diamond facets
, 主要以下阶段:
-
proposeDiamondCut
: 由gover
发起一个升级; -
approveEmergencyDiamondCutAsSecurityCouncilMember
: 安全委员会成员同意升级; -
executeDiamondCutProposal
: 完成升级过程。
GettersFacet
主要提升view
和pure
方法;
GovernanceFacet
主要用来管理governor, validators
和一些系统参数;
MailboxFacet
主要用来处理L2<--->L1之间的通信过程,主要关注信息的传递,不涉及资产(ETH, ERC20, NFT)的转移。
对于 L1->L2 通信,主要是从L1发起在L2上的交易,用户从L1发起交易,添加到队列中,由validator
执行,并在L1上进行标记,相关的函数有:
requestL2Transaction
l2TransactionBaseCost
serializeL2Transaction
对于每个L1->L2执行的交易, 系统会发起 L2->L1的log.
对于L2->L1通信,主要通过调用Messenger 系统合约传递信息,而不是在L1上执行交易 。
function sendToL1(bytes memory _message) external returns (bytes32 messageHash);
在L2上, 有个zkEVM 字节码为l2ToL1Log
, 当将L2区块提交到L1上时,validator
会提交l2ToL1Logs
.
ExecutorFacet
用于接收L2 区块, 保证数据可用性,并检查零知识证明, 主要分为以下三个阶段:
-
commitBlocks
: 检查L2区块时间戳,处理L2日志,保存区块的数据; -
proveBlocks
: 用以验证零知识证明; -
executeBlocks
: 用于固化状态,标记L1->L2通信过程, 处理L2 日志。
Account abstraction
以太坊只有EOA账户能发起交易,对于智能合约钱包或Tornado cash 等隐私协议,只能通过relayers 发起交易,会导致诸多不便。
zkSync 2.0的账户能够以合约方式实现任意的逻辑,也能像EOA一起发起交易,这种功能即为·Account abstract
.
抽象账户需要实现IAccount
接口, 如下:
-
validateTransaction
: 主要实现验证有效性验证的逻辑; -
executeTransaction
: 主要执行交易; -
payForTransacton
: 可选的方法,在交易没有paymaster
的情况下,用以支付交易的手续费; -
prePaymaster
: 可选的方法,在交易有paymaster
的情况下,通过paymaster
支付交易手续续; -
executeTransactionFromOutside
: 主要用于L2抗审查,即operator
无响应,可通过优先级模式发起交易。
Paymaster 接口
抽象账户支持paymasters, 主要用来支持其它账户交易的执行。paymaster
主要实现IPaymaster
接口:
-
validateAndPayForPaymasterTransaction
: 主要用来验证paymaster是否同意为对应的交易支付手续费; -
postOp
: 在交易执行后调用,主要用于交易手续的refund
.
Transaction 保留的字段
-
reserved[0]
: nonce; -
reserved[1]
: msg.value
Transaction flow
在交易的验证过程,账户会决定是否接收交易,并支付手续费;若交易验证失败,账户不会支付手续费,交易也不会打包进块中。
- Step 1: 系统检查交易的nonce尚未被使用;
- Step 2: 系统调用账户的
validateTransaction
方法; - Step 3: 系统检查交易的nonce已经被标记使用;
- Step 4: 若没有paymaster, 系统调用账户的
payForTransaction
方法支付手续费; - Step 4: 若指定paymaster, 系统调用发送者
prePaymaster
方法,然后调用paymaster 的validateAndPayForPaymasterTransaction
方法; - Step 5: 系统验证 bootloader 接收了
tx.ergsPrice * tx.ergsLimit
的ETH.
在执行过程中,主要是执行交易,并对未使用的ergs进行退款。若没有发生revert
,则交易将会打包进块中。
- Step 6: 系统调用账户的
executeTransaction
方法; - Step 7: 对于存在paymaster的情况下,调用paymaster 的
postOp
方法,用于给发送者退回未使用的ergs。
采用 SystemContractCaller 库
为了提升安全,NonceHolder
和ContractDeployer
合约只能通过 isSystem
的标签调用,需要采用SystemContractsCaller
库的方法:
systemCall
systemCallWithPropagatedRevert
systemCallWithReturndata
跨链桥
桥由两个合约实现,一个部署在L1上,一个部署在L2上。
Deposits (to L2)
用户调用L1 桥合约的deposit
方法,向L2 发起存款操作:
- 用户的L1 代币发送到L1 桥合约上,并被锁定;
- L1桥合约发起一个向L2桥合约的交易;
- 在L2的交易中,将会mint相应的代币并发送到指定的地址上。
- 若相应的代币在zkSync尚未存在,将自动部署新的合约,合约地址是确定的(根据原始的L1合约地址,名称和符号)。
- 对于每个执行的L1-> L2交易,会有一个L2->L1日志用以确认执行。
- 最后调用
finalizeDeposit
方法,完成存款操作。
对交易执行过程中失败,会有日志记录失败,用户可通过日志从L1桥发起退款:claimFailedDeposit
。
Withdraws (to L1)
用户需要调用L2 桥合约的withdraw
方法,执行以下过程:
- burn L2 代币;
- 发起关于取款的L2->L1 消息;
- 用户在L1 桥合约调用
finalizedWithdraw
方法完成取款。
智能合约开发
支持Solidity 版本 >-0.4.10
, 但建议采用^0.8.0
版本。
对于Solidity 库合约,若是内联的,即只包含private
和internal
方法,则可以直接使用;
若库包含public
或external
方法,不是内联的,则需要将合约地址传给编译器。
支持Vyper^0.3.3
版本;
目前有两种编译器:
- zksolc: Solidity 编译器;
- zkvyper: Vyper编译器。
EVM 兼容性
虽然兼容大部分合约,但有一些例外:
-
SELFDESTRUCT
: 将在EIP6049中废弃; -
CALLCODE
: 将在EIP2488中被废弃,由DELEGACALL 取代。 -
EXTCODECOPY
: 在zkEVM 中并不需要; -
CODECOPY
: 由CALLDATACOPY
取代; -
PC
: 在Yul 和 Solidity>=0.7.0
版本不支持。
Web3 API
zkSync 2.0 完全兼容Ethereum JSON-RPC API, 也添加L2相关的接口。
zks_getMainContract
zks_L1ChainId
zks_getConfirmedTokens
zks_getL2ToL1LogProof
zks_getL2ToL1MsgProof
zks_getBridgeContracts
zks_getBlockDetails
SDK
zkSync 2.0 提供了Javascript, Python, Go, Java, Swift 多种SDK 工具方便开发者部署合约,并进行交互 。
zkSync 2.0还提供了Hardhat, Block explorer, zkSync CLI 工具。
参考
https://github.com/matter-labs/v2-testnet-contracts
https://blog.matter-labs.io/baby-alpha-has-arrived-5b10798bc623
https://blog.matter-labs.io/a-year-of-growth-for-zksync-bb117d1b4f0c
https://blog.matter-labs.io/open-source-is-freedom-8b1b914daa98
网友评论