Polygon zkEVM zkROM代码解析

Posted mutourend

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Polygon zkEVM zkROM代码解析相关的知识,希望对你有一定的参考价值。

1. 引言

前序博客为:

2. D:循环处理交易

zkROM第四步为循环处理交易:

;;;;;;;;;;;;;;;;;;
;; D - Loop processing transactions
;;      - Load transaction data and interpret it
;;;;;;;;;;;;;;;;;;

txLoop:
        $ => A          :MLOAD(pendingTxs)
        ; 一次处理一笔交易,更新pendingTxs减1
        ; pendingTxs表示 Number of transactions decoded in RLP block
        A-1 => A        :MSTORE(pendingTxs)
        ; 若A为负数,则跳转到processTxsEnd
        A               :JMPN(processTxsEnd)
		; ctxTxToUse表示 First context to be used when processing transactions
        $ => A          :MLOAD(ctxTxToUse) ; Load first context used by transaction
        ; 更新ctxTxToUse加1
        A+1 => CTX      :MSTORE(ctxTxToUse)
		; 跳转到processTx
                        :JMP(processTx)

processTxEnd:
		; 打印该笔交易处理完毕日志,继续处理下一笔交易
        $eventLog(onFinishTx)
                        :JMP(txLoop)

processTxsEnd:

其中processTx表示单笔交易处理流程。

2.1 processTx单笔交易处理

processTx表示单笔交易处理流程为:

  • 1)A:验证ECDSA签名
  • 2)B:验证chainID
  • 3)C:验证nonce并递增nonce
  • 4)D:检查预付cost
  • 5)E:检查交易类型:
    • 5.1)E.1:合约调用交易
    • 5.2)E.2:部署合约交易
  • 6)F:处理Gas
processTx:
;;;;;;;;;;;;;;;;;;
;; A - Verify ecdsa signature
;;;;;;;;;;;;;;;;;;
		; 打印日志
        $eventLog(onProcessTx)
        ; 预留足够的STEP以确保能处理单笔交易
        ; Minimum of 100000 steps left to process a tx
        %MAX_CNT_STEPS - STEP - 100000 :JMPN(outOfCounters)
        ; Get sigDataSize
        ; sigDataSize表示 hash position for the ethereum transaction hash
        $ => HASHPOS                     :MLOAD(sigDataSize)

        ; Check keccak counters
        ; HASHKDIGEST操作符为对136取模,确保CNT_KECCAK_F计数器符合上限要求
        HASHPOS                          :MSTORE(arithA)
        136                              :MSTORE(arithB)
                                         :CALL(divARITH)
        $ => B                           :MLOAD(arithRes1)
        %MAX_CNT_KECCAK_F - CNT_KECCAK_F - %MIN_CNT_KECCAK_BATCH => A
        $                                :LT, JMPC(outOfCounters)

        ; Get hash address previously stored in RLP parsing
        ; lastTxHashId表示First hash address to be used when processing transactions
        ; 更新lastTxHashId加1
        $ => E                          :MLOAD(lastTxHashId)
        E+1 => E                        :MSTORE(lastTxHashId)

        ; Check the signature
		; lastHashKIdUsed表示Last hash address used
        $ => A                          :MLOAD(lastHashKIdUsed)
        A + 1                           :MSTORE(lastHashKIdUsed)
        A + 1                           :MSTORE(ecrecover_lastHashIdUsed)
        $ => A                          :HASHKDIGEST(E)
        $ => B                          :MLOAD(txR)
        $ => C                          :MLOAD(txS)
        $ => D                          :MLOAD(txV)
        ; 调用ecrecover获得签名地址 存在 A寄存器中
                                        :CALL(ecrecover)
        ; Check result is non-zero
checkAndSaveFrom:
		; 要求ecrecover获得的签名地址不为0,否则为无效交易。
		; 同时将签名地址存入txSrcAddr和txSrcOriginAddr全局变量中。
		; txSrcOriginAddr表示origin address of a tx
		; txSrcAddr表示 address that sends a transaction 'message.sender'
        0 => B
        A                               :MSTORE(txSrcAddr)
        A                               :MSTORE(txSrcOriginAddr)
        $                               :EQ,JMPC(invalidIntrinsicTx)

;;;;;;;;;
;; Store init state
;;;;;;;;;

        ; Store initial state at the beginning of the transaction
        ; originSR表示State root before processing each transaction
        ; initSR表示state-tree once the initial upfront cost is substracted and nonce is increased
        SR                              :MSTORE(originSR)
        SR                              :MSTORE(initSR)

;;;;;;;;;;;;;;;;;;
;; B - Verify chainID,验证chainID
;;;;;;;;;;;;;;;;;;
		; txChainId表示 transaction parameter: 'chainId'
        $ => A                          :MLOAD(txChainId)                                       ; A: chainId tx
        ; CONST %ZKEVM_CHAINID = 1000
        %ZKEVM_CHAINID => B                                                               ; B: defaultChainId, A: chainId tx
        $                               :EQ,JMPC(endCheckChainId)                               ; If A == B --> endCheckChainId
                                        :JMP(invalidIntrinsicTx)                                         ; If A != B --> invalidIntrinsicTx
endCheckChainId:

;; Reset warm/cold information,更新信息
        $ => A                          :MLOAD(txSrcOriginAddr)
        ; 将ctx.input.touchedAddress置空
        $resetTouchedAddress() ; clean touchedAddresses since there is a new transaction
        ; 将ctx.input.touchedStorageSlots置空
        $resetStorageSlots() ; clean storageSlots since there is a new transaction
        ; 更新ctx.input.touchedAddress为签名者地址
        $touchedAddress(A) ; add tx.origin to touched addresses

;; Set gasPrice global var
		; txGasPriceRLP表示 transaction parameter: 'gasPrice' decoded from the RLP
        $ => A                          :MLOAD(txGasPriceRLP)
        ; txGasPrice表示 transaction parameter: 'gasPrice' global var
        A                               :MSTORE(txGasPrice)
;;;;;;;;;;;;;;;;;;
;; C - Verify and increase nonce
;;;;;;;;;;;;;;;;;;
		; 将交易签名者地址存入A和E中
        $ => A, E                       :MLOAD(txSrcOriginAddr) ; Address of the origin to A and E
        ; CONST %SMT_KEY_NONCE = 1,为SMT CONSTANT KEY
        %SMT_KEY_NONCE => B
        0 => C
        ; 从Storage中读取以签名者地址(A)和SMT_KEY_NONCE(B)
        ; 以及C为key 的Value值,存入A寄存器中
        $ => A                          :SLOAD
        ; txNonce表示 transaction parameter: nonce
        $ => B                          :MLOAD(txNonce)
        ; 若从Storage中读的nonce值 与 交易中的nonce值 相等,则C=1;否则C=0,为无效交易。
        $ => C                          :EQ
        C - 1                           :JMPN(invalidIntrinsicTx) ; Compare nonce state tree with nonce transaction
        ; 断言 B==A
        B                               :ASSERT ; sanity check
        ; 将nonce值加1,再更新到Storage中相应key中。
        A + 1 => D
        E => A
        %SMT_KEY_NONCE => B
        0 => C
        $ => SR                         :SSTORE ; Store the nonce plus one

;;;;;;;;;;;;;;;;;;
;; D - Verify upfront cost,检查预付cost
;;;;;;;;;;;;;;;;;;

        ; Verify batch gas limit
        ; txGasLimit表示transaction parameter: 'gas limit'
        $ => B                          :MLOAD(txGasLimit)
        ; Check batch gas limit is not exceeded by transaction
        ; CONST %BATCH_GAS_LIMIT = 30000000
        %BATCH_GAS_LIMIT => A
        ; txGasLimit应大于等于BATCH_GAS_LIMIT ,否则为无效交易
        $                               :LT,JMPC(invalidIntrinsicTx)

        ; Intrinsic gas --> gas Limit >= 21000 + calldata cost + deployment cost
        ; CONST %BASE_TX_GAS = 21000
        %BASE_TX_GAS => E ; Store init intrinsic gas at E
        ; 当交易中to参数为空时,设置了isCreateContract为1;否则为0
        $ => A                          :MLOAD(isCreateContract)
        ; 若交易中to参数为空,则调用addDeploymentGasCost;否则调用getCalldataGasCost
        -A                              :JMPN(addDeploymentGasCost)
                                        :JMP(getCalldataGasCost)

addDeploymentGasCost:
		; CONST %BASE_TX_DEPLOY_GAS = 32000
        E + %BASE_TX_DEPLOY_GAS => E ; Add 32000 if transaction is a create

getCalldataGasCost:
		; txCalldataLen表示 calldata length
        $ => A                          :MLOAD(txCalldataLen)
        0 => B
        ; 若txCalldataLen为0值,则调用endCalldataIntrinsicGas
        $                               :EQ,JMPC(endCalldataIntrinsicGas)

addGas:
		; dataStarts表示 hash position where de transaction 'data' starts in the batchHashData
        $ => HASHPOS                    :MLOAD(dataStarts)
        ; 调用loopBytes之前,初始化C为0
        0 => C
                                        :JMP(loopBytes)
loopBytes:
		; 预留足够的step
        %MAX_CNT_STEPS - STEP - 20 :JMPN(outOfCounters)
        ; 逐个处理txCalldataLen
        A - C - 1                       :JMPN(endCalldataIntrinsicGas)
        ; E寄存器中存储的为累加gas费
        E => B
        HASHPOS => D
        1 => D
        $ => E                          :MLOAD(batchHashDataId)
        $ => D                          :HASHK(E)
        B => E
        C + 1 => C
        D - 1                           :JMPN(add4Gas)
                                        :JMP(add16Gas)

add4Gas:
        E + 4 => E
                                        :JMP(loopBytes)

add16Gas:
        E + 16 => E
                                        :JMP(loopBytes)

endCalldataIntrinsicGas:
        ; Compare gas limit >= intrinsic gas
        $ => A                          :MLOAD(txGasLimit)
        E => B
        $                               :LT, JMPC(invalidIntrinsicTx)
        ; Store calculated gas for later usage
        E                               :MSTORE(gasCalldata)

        ; Check upfront cost: balance >= gas price * gas limit + value
        ; gas price * gas limit
        $ => B                          :MLOAD(txGasPrice)
        A                               :MSTORE(arithA)
        B                               :MSTORE(arithB)
                                        :CALL(mulARITH)
        $ => D                          :MLOAD(arithRes1)
        ; Get caller balance
        $ => A                          :MLOAD(txSrcOriginAddr)
        0 => B, C
        $ => C                          :SLOAD
        ; (gas price * gas limit) + value
        $ => B                          :MLOAD(txValue)
        D                               :MSTORE(arithA)
        B                               :MSTORE(arithB)
                                        :CALL(addARITH)
        $ => B                          :MLOAD(arithRes1)
        ; Comparison
        C => A
        $                               :LT, JMPC(invalidIntrinsicTx)

        ; Substract (gas price * gas limit) from caller balance
        C                               :MSTORE(arithA)
        D                               :MSTORE(arithB)
                                        :CALL(subARITH)
        ; Substracted balance result in D
        $ => D                          :MLOAD(arithRes1)
        $ => A                          :MLOAD(txSrcOriginAddr)
        0 => B,C
        $ => SR                         :SSTORE

        ; Store state root with upfront cost substracted and nonce increased
        SR                              :MSTORE(initSR)

        ; Substract intrinsic gas
        $ => GAS                        :MLOAD(txGasLimit)
        $ => A                          :MLOAD(gasCalldata)
        GAS - A => GAS

;;;;;;;;;;;;;;;;;;
;; E - Check transaction type
;;;;;;;;;;;;;;;;;;
txType:

        ; Compute deployment address if create contract operation
        $ => A                          :MLOAD(isCreateContract)
        0 - A                           :JMPN(getContractAddress)
        $ => A                          :MLOAD(txDestAddr)
        ; Add 'to' to touched addresses
        $touchedAddress(A)
        ; Check 'to' is zero or precompiled contract
        ; Check zero address since zero address is not a precompiled contract
        0 => B
        $                               :EQ, JMPC(callContract)
        10 => B
        $                               :LT,JMPC(selectorPrecompiled)
                                        :JMP(callContract)

;;;;;;;;;;;;;;;;;;
;; E.2 - Deploy contract
;;     - Compute new contract address
;;     - Process bytecode
;;     - End deploy: add state-tree hash bytecode and bytecode length
;;;;;;;;;;;;;;;;;;

;; compute new create address
getContractAddress:
        ; A new hash with position 0 is started
        0 => HASHPOS
        ; We get a new hashId
        $ => E                          :MLOAD(lastHashKIdUsed)
        E+1 => E                        :MSTORE(lastHashKIdUsed)
        ; Check if create is with CREATE2 opcode
        $ => A                          :MLOAD(isCreate2)
        0 - A                           :JMPN(create2)
        $ => A                          :MLOAD(txNonce)
        0x80 => B
        $                               :LT,JMPC(nonce1byte)
        $ => C                          :MLOAD(lengthNonce)
        1 => D
        ; 1 byte length address + 20 bytes address + 1 byte length nonce + C bytes nonce
        0xc0 + 22 + C                   :HASHK(E)
        0x94                            :HASHK(E)
        20 => D
        $ => B                          :MLOAD(txSrcAddr)
        B                               :HASHK(E)
        1 => D
        0x80 + C                        :HASHK(E)
        C => D
        A                               :HASHK(E)
                                        :JMP(endContractAddress)

nonce1byte:
        $ => A                          :MLOAD(txSrcAddr)
        $ => B                          :MLOAD(txNonce)
        1 => D
        0xc0 + 22                       :HASHK(E)
        0x94                            :HASHK(E)
        20 => D
        A                               :HASHK(E)
        1 => D
        B - 1                           :JMPN(nonceIs0)
        B                               :HASHK(E)
                                        :JMP(endContractAddress)

nonceIs0:
        0x80                            :HASHK(E)

endContractAddress:
        ; end contract address hash and get the 20 first bytes
        HASHPOS                         :HASHKLEN(E)
        %MAX_CNT_KECCAK_F - CNT_KECCAK_F - %MIN_CNT_KECCAK_BATCH - 1 :JMPN(outOfCounters)
        $ => A                          :HASHKDIGEST(E)
                                        :CALL(maskAddress) ; Mask address to 20 bytes
        A                               :MSTORE(createContractAddress)
        A                               :MSTORE(txDestAddr)
        A                               :MSTORE(storageAddr)
        ; TODO: Add check CREATE or deployment with constructor reverted
                                        :JMP(deploy)

;; compute new contract address as CREATE2 spec: keccak256(0xff ++ address ++ salt ++ keccak256(init_code))[12:] (https://eips.ethereum.org/EIPS/eip-1014)
create2:
        $ => C                          :MLOAD(txCalldataLen)
        $ => CTX                        :MLOAD(originCTX)
        $ => B                          :MLOAD(argsOffsetCall)

loopCreate2:
        %MAX_CNT_STEPS - STEP - 100 :JMPN(outOfCounters)
        %MAX_CNT_BINARY - CNT_BINARY - 4 :JMPN(outOfCounters)

        C - 1                           :JMPN(create2end)
        C - 32                          :JMPN(endloopCreate2)
        B => E
                                        :CALL(MLOAD32)
        E => B
        32 => D
        $ => E                          :MLOAD(lastHashKIdUsed)
        A                               :HASHK(E)
        C - 32 => C
                                        :JMP(loopCreate2)

endloopCreate2:
        B => E
                                        :CALL(MLOADX)
        32 - C => D
                                        :CALL(SHRarith)
        C => D
        $ => E                          :MLOAD(lastHashKIdUsed)
        A                               :HASHK(E)

create2end:
        $ => CTX                        :MLOAD(currentCTX)
        HASHPOS                         :HASHKLEN(E)
        ; Check keccak counters
        HASHPOS                         :MSTORE(arithA)
        136                             :MSTORE(arithB)
                                        :CALL(divARITH)
        $ => B                          :MLOAD(arithRes1)
        %MAX_CNT_KECCAK_F - CNT_KECCAK_F - %MIN_CNT_KECCAK_BATCH => A
        $                               :LT, JMPC(outOfCounters)
        $ => C                          :HASHKDIGEST(E)
        ; new hash with position 0 is started
        0 => HASHPOS
        $ => E                          :MLOAD(lastHashKIdUsed)
        E+1 => E                        :MSTORE(lastHashKIdUsed)
        1 => D
        0xff                            :HASHK(E)
        20 => D
        $ => A                          :MLOAD(txSrcAddr)
        A                               :HASHK(E)
        32 => D
        $ => B                          :MLOAD(salt)
        B                               :HASHK(E)
        32 => D
        C                               :HASHK(E)
        HASHPOS                         :HASHKLEN(E)

        ; Check keccak counters
        HASHPOS                         :MSTORE(arithA)
        136                             :MSTORE(arithB)
                                        :CALL(divARITH)
        $ => B                          :MLOAD(arithRes1)
        %MAX_CNT_KECCAK_F - CNT_KECCAK_F - %MIN_CNT_KECCAK_BATCH => A
        $                               :LT, JMPC(outOfCounters)

        $ => A                          :HASHKDIGEST(E)
                                        :CALL(maskAddress) ; Mask address to 20 bytes
        A                               :MSTORE(createContractAddress)
        A                               :MSTORE(txDestAddr)
        A                               :MSTORE(storageAddr)

;; deploy contract in state-tree
deploy:
        ; add address to touched addresses
        $touchedAddress(A)

        ; check if address is deployable ( nonce == bytecode == 0)
        A => E

        ; read nonce
        0 => C
        %SMT_KEY_NONCE => B
        $ => B                      :SLOAD
        0 => A
        $                           :LT,JMPC(deployAddressCollision)

        ; read bytecode
        E => A
        %SMT_KEY_SC_CODE => B
        $ => B                      :SLOAD
        0 => A
        $                           :LT,JMPC(deployAddressCollision)

        ; set contract nonce to 1
        E => A
        1 => D
        %SMT_KEY_NONCE => B
        $ => SR                         :SSTORE
        ; Move balances if value > 0 just before deploy
        $ => B                          :MLOAD(txValue)
        0 => A
        zkPC+2 => RR
        $                               :LT, JMPC(moveBalances)
        0 => PC
        0 => SP
                                        :JMP(readCode)

;; read calldata bytes of a deploy transaction and process them
readDeployBytecode:
        ; check transaction is a deploy transaction
        $ => B                          :MLOAD(isCreate)
        0 - B                           :JMPN(readDeployBytecodeCreate)
        ; check enough bytes to read in calldata
        $ => B                          :MLOAD(txCalldataLen)
        B - PC - 1                      :JMPN(defaultOpCode)
        $ => HASHPOS                    :MLOAD(dataStarts)
        HASHPOS + PC => HASHPOS
        $ => E                          :MLOAD(batchHashDataId)
        1 => D
        $ => RR                         :HASHK(E)
        $eventLog(onOpcode(RR))
        PC + 1 => PC
                                        :JMP(@mapping_opcodes + RR)

;; read calldata bytes of a CREATE/CREATE2 call and process them
readDeployBytecodeCreate:
        $ => E                          :MLOAD(txCalldataLen)
        $ => CTX                        :MLOAD(originCTX)
        ; check enough bytes to read in memory
        E - PC - 1                      :JMPN(readDeployBytecodeCreateDefault)

        $ => E                          :MLOAD(argsOffsetCall)
        E + PC => E
        1 => C
                                        :CALL(MLOADX)
        $ => CTX                        :MLOAD(currentCTX)
        31 => D
                                        :CALL(SHRarith)
        A => RR
        $eventLog(onOpcode(RR))
        PC + 1 => PC
                                        :JMP(@mapping_opcodes + RR)

;; handle error no more bytecode to read when call CREATE/CREATE2
readDeployBytecodeCreateDefault:
        $ => CTX                        :MLOAD(currentCTX)
                                        :JMP(defaultOpCode)

;;;;;;;;;;;;;;;;;;
;; E.1 - Call contract
;;     - Check bytecode to process against state-tree hash bytecode
;;     - Process bytecode
;;     - End deploy: add state-tree hash bytecode and bytecode length
;;;;;;;;;;;;;;;;;;
callContract:
        ; Move balances if value > 0 just before executing the contract CALL
        $ => B                          :MLOAD(txValue)
        0 => A
        zkPC+2 => RR
        $                               :LT, JMPC(moveBalances)
        0 => PC
        0 => SP

        $ => A                          :MLOAD(txDestAddr)
        ; get contract length
        %SMT_KEY_SC_LENGTH => B
        0 => C
        $ => B                          :SLOAD
        B                               :MSTORE(bytecodeLength)
        0 => A
        $                               :EQ, JMPC(defaultOpCode) ;no bytecode

        $ => A                          :MLOAD(txDestAddr)
        ; get hash contract
        %SMT_KEY_SC_CODE => B
        $ => A                          :SLOAD
        A                               :MSTORE(hashContractTxDestAddr)
        0 => HASHPOS
        1 => D
        $ => B                          :MLOAD(bytecodeLength)

        ; get a new hashPId
        $ => E                          :MLOAD(nextHashPId)
        E                               :MSTORE(contractHashId)
        E+1                             :MSTORE(nextHashPId)

checkHashBytecodeLoop:
        %MAX_CNT_STEPS - STEP - 10 :JMPN(outOfCounters)
        B - 1 - HASHPOS                         :JMPN(checkHashBytecodeEnd) ; finish reading bytecode
        $getBytecode(A, HASHPOS, 1)           :HASHP(E) ; hash contract bytecode
                                                :JMP(checkHashBytecodeLoop)

checkHashBytecodeEnd:
        HASHPOS                         :HASHPLEN(E)
        $ => E                          :HASHPDIGEST(E)
        ; check hash computed matches hash in the smt leaf
        $ => A                          :MLOAD(hashContractTxDestAddr)
        E                               :ASSERT
                                        :JMP(readCode)

readByteCode:
        $ => E                          :MLOAD(contractHashId) ; hash index
        $ => A                          :MLOAD(txDestAddr)
        ; check next byte exist on the bytecode
        $ => B                          :MLOAD(bytecodeLength)
        B - PC - 1                      :JMPN(defaultOpCode) ; no bytecode treated as 0x00
        PC => HASHPOS
        1 => D
        $ => RR                         :HASHP(E)
        $eventLog(onOpcode(RR))
        PC + 1 => PC
                                        :JMP(@mapping_opcodes + RR)

readCode:
        $ => A                          :MLOAD(isCreateContract)
        0 - A                           :JMPN(readDeployBytecode)
                                        :JMP(readByteCode)

;; Compute and save hash bytecode and bytecode length in the state-tree
endDeploy:
        ; called from `opRETURNDeploy` which has: C --> length, E --> offset
        ; only when first context ends on deploy
        ; If length is 0 do not modify state-tree
        C - 1                           :JMPN(handleGas)
        ; save offset memory and length to compute hash bytecode
        E                               :MSTORE(memOffsetLinearPoseidon)
        C                               :MSTORE(memSizeLinearPoseidon)
        ; set bytecode length
        $ => A                          :MLOAD(createContractAddress)
        %SMT_KEY_SC_LENGTH => B
        C => D
        0 => C
        $ => SR                         :SSTORE
        A                               :MSTORE(txDestAddr)
                                        :CALL(hashPoseidonLinearFromMemory)
        $ => A                          :MLOAD(createContractAddress)
        0 => C
        %SMT_KEY_SC_CODE => B
        $ => SR                         :SSTORE

;;;;;;;;;;;;;;;;;;
;; F - Handle GAS
;;   - Check refund gas
;;   - Return gas not used to caller
;;   - Pay gas to sequencer
;;;;;;;;;;;;;;;;;;

;; compute maximum gas to refund
handleGas:
        0 => A
        $ => B                          :MLOAD(gasRefund)
        B - 1                           :JMPN(refundGas)
        $ => A                          :MLOAD(txGasLimit)
        A - GAS => A
        ; Div operation with Arith
        A                               :MSTORE(arithA)
        2                               :MSTORE(arithB)
                                        :CALL(divARITH)
        $ => A                          :MLOAD(arithRes1)
        A - B                           :JMPN(refundGas)
        B => A

;; add remaining gas to transaction origin
refundGas:
        GAS + A => GAS
        GAS => A
        $ => B                          :MLOAD(txGasPrice)
        ;Mul operation with Arith
        A                               :MSTORE(arithA)
        B                               :MSTORE(arithB)
                                        :CALL(mulARITH)
        $ => D                          :MLOAD(arithRes1)

        $ => A                          :MLOAD(txSrcOriginAddr)
        0 => B,C ; balance key smt
        $ => A                          :SLOAD ; Original Balance in A

        ; Add operation with Arith
        A                               :MSTORE(arithA)
        D                               :MSTORE(arithB)
                                        :CALL(addARITH)
        $ => D                          :MLOAD(arithRes1)

        $ => A                          :MLOAD(txSrcOriginAddr)
        0 => B,C                        ; balance key smt
        $ => SR                         :SSTORE


;; Send gas spent to sequencer
sendGasSeq:
        $ => A          :MLOAD(txGasLimit)
        A - GAS => A

        $ => B          :MLOAD(txGasPrice)
        ; Mul operation with Arith
        A               :MSTORE(arithA)
        B               :MSTORE(arithB)
                        :CALL(mulARITH)
        $ => D          :MLOAD(arithRes1) ; value to pay the sequencer in D

        $ => A          :MLOAD(sequencerAddr)
        0 => B,C ; Balance key smt
        $ => A          :SLOAD ; Original Balance in A
        ; Add operation with Arith
        A               :MSTORE(arithA)
        D               :MSTORE(arithB)
                        :CALL(addARITH)
        $ => D          :MLOAD(arithRes1)
        $ => A          :MLOAD(sequencerAddr)
        0 => B,C ; balance key smt
        $ => SR         :SSTORE
                        :JMP(processTxEnd)


;; handle invalid transaction due to intrinsic checks
invalidIntrinsicTx:
        $eventLog(onError, intrinsic_invalid)
        $ => SR                         :MLOAD(originSR)
                                        :JMP(processTxEnd)

;; handle error no more bytecode to read
defaultOpCode:
        $eventLog(onOpcode(0))
                                        :JMP(opSTOP)

附录:Polygon Hermez 2.0 zkEVM系列博客

以上是关于Polygon zkEVM zkROM代码解析的主要内容,如果未能解决你的问题,请参考以下文章

Polygon zkEVM zkROM代码解析

Polygon zkEVM zkROM代码解析

Polygon zkEVM zkROM代码解析

Polygon zkEVM zkROM代码解析

Polygon zkEVM节点代码解析

Polygon zkEVM PIL编译器——pilcom 代码解析