---
# System prepended metadata

title: Zksync合约解析

---

# Zksync合约解析


用户可以layer2或者layer1（priority operation）上创建交易.
处理完用户交易请求后，operator会打包区块，并创建一个rollup操作。operator会提交block commitment到合约。zksync合约验证proof是否为true，为true则可以确定新状态。
![](https://i.imgur.com/KjedqTF.png)


## 1 发起交易  
 以depositETH为例子，
 会将用户请求encode成pubdata,
 ```
  abi.encodePacked(
            uint8(OpType.Deposit),
            bytes4(0), // accountId (ignored) (update when ACCOUNT_ID_BYTES is changed)
            op.tokenId, // tokenId
            op.amount, // amount
            op.owner // owner
 ```
 
 然后放入priorityRequests队列中(用来存储链上交易的队列),可以看一下 PriorityOperation 的数据结构（表示layer1链上的交易，优先级较高)。
 ```

    /// @notice Priority Operation container
    /// @member hashedPubData Hashed priority operation public data
    /// @member expirationBlock Expiration block number (ETH block) for this request (must be satisfied before)
    /// @member opType Priority operation type
    struct PriorityOperation {
        bytes20 hashedPubData;     //交易数据的hash
        uint64 expirationBlock;     //超时时间
        Operations.OpType opType;    //操作类型
    }
 ``` 
 这个队列存储用户这笔交易pubdata的hash，超时时间，和操作类型；
 ```
        priorityRequests[nextPriorityRequestId] = PriorityOperation({
            hashedPubData: hashedPubData,
            expirationBlock: expirationBlock,
            opType: _opType
        });

 ```
 
 并发出事件，后续Server服务监听处理。
 ```
        emit NewPriorityRequest(msg.sender, nextPriorityRequestId, _opType, _pubData, uint256(expirationBlock));
 ```
 
 ## 2 提交区块 commitblock
 operator提交区块函数如下：
 ```
  function commitBlocks(StoredBlockInfo memory _lastCommittedBlockData, CommitBlockInfo[] memory _newBlocksData)
        external
        nonReentrant
```
- _lastCommittedBlockData: 上一次已经committed的block，committed的区块在链上为StoredBlockInfo形式存储.
- _newBlocksData: 新commit的block.
 先看数据结构
 ```
 /// @notice Data needed to process onchain operation from block public data.
   struct OnchainOperationData {
        bytes ethWitness;          //  只在ChangePubKey类型交易的时候用到
        uint32 publicDataOffset;   // 每笔交易在总publicdata里的偏移
    }
 ```
 
 以及提交区块的数据结构
 ```
 /// @notice Data needed to commit new block
    struct CommitBlockInfo {
        bytes32 newStateHash;    //新的状态hash,只在createBlockCommitment时候用一下，后端传入。
        bytes publicData;            //打包的交易数据
        uint256 timestamp;      
        OnchainOperationData[] onchainOperations;    //待处理交易，里面包含每笔交易的偏移，以及ethwitness
        uint32 blockNumber;       //区块高度
        uint32 feeAccount;
    }
```
commitBlock函数最终返回StoredBlockInfo, 保存在链上。它的作用主要是对交易数据生成hash。

```
struct StoredBlockInfo {
  uint32 blockNumber;   // rollup block number
  uint64 priorityOperations;   // 本区块priority operations 的数量
  bytes32 pendingOnchainOperationsHash;  // 所有交易的hash
  uint256 timestamp;
  bytes32 stateHash;      //root hash of the rollup account tree state
  bytes32 commitment;    //rollup 区块承诺
}
```

 然后依次执行每个commitBlockInfo，主要调用commitOneBlock函数
   - 1 检查时间戳
   - 2  执行collectOnchainOps(_newBlock)函数。
 计算出 所有操作数据pubdata的hash， 优先交易的数量，以及onchainOperation的偏移。

```
 /// @dev processableOperationsHash - hash of the all operations that needs to be executed  (Deposit, Exits, ChangPubKey)
    /// @dev priorityOperationsProcessed - number of priority operations processed in this block (Deposits, FullExits)
    /// @dev offsetsbment - array where 1 is stored in chunk where onchainOperation begins and other are 0 (used in commitments)

 (
            bytes32 pendingOnchainOpsHash,
            uint64 priorityReqCommitted,
            bytes memory onchainOpsOffsetCommitment
        ) = collectOnchainOps(_newBlock);
 
```

- 3  对区块创建区块的commitment。

     区块的commit：包含块高，feeAccount, 上一个块stateHash,当前块状态hash，时间戳，以及当前块的数据交易数据的整体hash.

```
 function createBlockCommitment(
  StoredBlockInfo memory _previousBlock,CommitBlockInfo memory _newBlockData, bytes memory_offsetCommitment
    ) internal view returns (bytes32 commitment) {
        bytes32 hash = sha256(abi.encodePacked(uint256(_newBlockData.blockNumber), uint256(_newBlockData.feeAccount))); 
        hash = sha256(abi.encodePacked(hash, _previousBlock.stateHash));
        hash = sha256(abi.encodePacked(hash, _newBlockData.newStateHash));
        hash = sha256(abi.encodePacked(hash, uint256(_newBlockData.timestamp)));
        bytes memory pubdata = abi.encodePacked(_newBlockData.publicData, _offsetCommitment);
       commitment = sha256(abi.encodePacked(hash, publicData))  // blockcommit
```

最后返回 

```
StoredBlockInfo(
                _newBlock.blockNumber,
                priorityReqCommitted,  
                pendingOnchainOpsHash,
                _newBlock.timestamp,
                _newBlock.newStateHash,  
                commitment
            );
```
可见stateHash是由传入的newBlock里面的newStateHash直接赋值的。 （需要进一步看后端的newStateHash的生成逻辑）



## 3 proveBlock 验证零知识证明
```
function proveBlocks(StoredBlockInfo[] memory _committedBlocks, ProofInput memory _proof) external nonReentrant
```

主要逻辑是验证proof,并更改totalBlocksProven（当前已经证明的block）状态，传入已经commitBlock数组。

```
   bool success = verifier.verifyAggregatedBlockProof(
            _proof.recursiveInput,    
            _proof.proof,           
            _proof.vkIndexes,   //此参数用于获取对应VK
            _proof.commitments,   
            _proof.subproofsLimbs
        );
```

## 4 executeOneBlock， 执行block交易，处理资金充提；
执行区块，完成高优先级交易，以及处理资金提取
函数如下：
```
executeBlocks(ExecuteBlockInfo[] memory _blocksData, bool _completeWithdrawals) 
```
可以查看
```
  struct ExecuteBlockInfo {
        StoredBlockInfo storedBlock;
        bytes[] pendingOnchainOpsPubdata;
    }
```
根据pendingOnchainOpsPubdata执行交易。
然后更改各存储状态,主要是更改最新请求的ID和已执行区块数量。

```
        firstPriorityRequestId += priorityRequestsExecuted;
        totalCommittedPriorityRequests -= priorityRequestsExecuted;
        totalOpenPriorityRequests -= priorityRequestsExecuted;
        totalBlocksExecuted += nBlocks;
```




## 证明部分

### verify合约
```
 function verifyAggregatedBlockProof(
        uint256[] memory _recursiveInput,  
        uint256[] calldata _proof,
        uint8[] memory _vkIndexes,
        uint256[] memory _individualVksInputs, 
        uint256[16] memory _subproofsLimbs
    ) external view returns (bool)
```
- _recursiveInput - input of the recursive aggregated circuit
- _vkIndexes - index of the verification keys in the aggregated verification keys tree
- _individualVksInputs - block commitments to be verified
- _subproofsLimbs - data needed for recursive proof verification

### 获取VK

#### 四种VK获取
1 KeysWithPlonkVerifier合约， 获取VK有
  1  function getVkAggregated(uint32 _proofs) internal pure returns (VerificationKey memory vk) {
        if (_proofs == uint32(1)) { return getVkAggregated1(); }
        else if (_proofs == uint32(4)) { return getVkAggregated4(); }
        else if (_proofs == uint32(8)) { return getVkAggregated8(); }
    }

 2 getVkExit()



### 区块，账户电路

#### 1 block commitment

区块电路:一批交易作用后，从上一个区块状态到新的区块状态的状态转移函数.

Public inputs（电路的公开输入）:

- pub_data_commitment: 
 区块的新状态的承诺，是一个hash，包含以下内容:
 old_root, new_root, block_number, validator_address, pub_data_rolling_hash , timestamp, onhain_ops_offset_commitment

Witness（电路的见证）:

1. old_root,
2. new_root,
3. block_number,
4. validator_address,
5. pub_data,
6. pub_data_rolling_hash,
7. list of transactions,
8. state Merkle trees.

-  oncahin_ops_offset_commitment
 是字节数组，其中一个字节对应于每个公共数据块(chunk)，如果数据块是onchain操作的第一个数据块，则被设置为1，否则为0。
 
 
 #### 2 账户树
 主要有accout tree 和 balance tree;
 account tree height(24)
- nonce  
- pubkey_hash   //RollupPubkeyHash	
- address	   //EthAddress
- state_tree_root	
balance tree height(8)
即各种token的余额
 
 ![](https://i.imgur.com/gkeFu9U.png)

整个状态是由账户和Token信息组成的两层Merkle树。账户是以追加方式一个个添加。账户信息比较少的情况下，存在大量的空节点。
有一个主要的account tree，并且叶子账户都有一个余额树。
整个只维护状态树的root即可。

在执行完当前Operation后，当前的branch的相关信息（nonce，balance等等）都会更新。需要更新一下对应的状态根，因为下一个Operation需要在新的状态根上更新。注意，下一个Operation提供的branch witness信息是在上一个Operation更新的基础上产生的。电路只需要证明新的Root正确即可。这个也是原因，整个证明电路并没有维护整个状态树的原因。


## 疑问

![](https://i.imgur.com/RQQ6U5J.png)
order没有tree。 更改状态都是在account tree上




## 参考链接：
- https://github.com/matter-labs/zksync/blob/master/docs/protocol.md#rollup-operation-8 
- https://docs.zksync.io/dev/swaps/#atomic-swaps
- https://mp.weixin.qq.com/s/lTuKbI2S1tOHeYYNm9A2dQ
- https://docs.starkware.co/starkex/oracle-price-tick.html


 
 
 






