Skip to content

Commit

Permalink
Merge pull request #481 from matter-labs/yul-charge-decommit-fixed
Browse files Browse the repository at this point in the history
[EVM-Equivalence] Charge for zkEVM Contract Decommits
  • Loading branch information
jrchatruc authored Jul 29, 2024
2 parents dc2e056 + 1a88e64 commit 398aeb4
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 36 deletions.
29 changes: 17 additions & 12 deletions system-contracts/contracts/EvmInterpreterFunctions.template.yul
Original file line number Diff line number Diff line change
Expand Up @@ -822,11 +822,9 @@ function GAS_DIVISOR() -> gas_div { gas_div := 5 }
function EVM_GAS_STIPEND() -> gas_stipend { gas_stipend := shl(30, 1) } // 1 << 30
function OVERHEAD() -> overhead { overhead := 2000 }

function GAS_CONSTANTS() -> divisor, stipend, overhead {
divisor := GAS_DIVISOR()
stipend := EVM_GAS_STIPEND()
overhead := OVERHEAD()
}
// From precompiles/CodeOracle
function DECOMMIT_COST_PER_WORD() -> cost { cost := 4 }
function UINT32_MAX() -> ret { ret := 4294967295 } // 2^32 - 1

function _calcEVMGas(_zkevmGas) -> calczkevmGas {
calczkevmGas := div(_zkevmGas, GAS_DIVISOR())
Expand All @@ -845,11 +843,18 @@ function getEVMGas() -> evmGas {
}
}

function _getZkEVMGas(_evmGas) -> zkevmGas {
/*
TODO: refine the formula, especially with regard to decommitment costs
*/
function _getZkEVMGas(_evmGas, addr) -> zkevmGas {
zkevmGas := mul(_evmGas, GAS_DIVISOR())
let byteSize := extcodesize(addr)
let should_ceil := mod(byteSize, 32)
if gt(should_ceil, 0) {
byteSize := add(byteSize, sub(32, should_ceil))
}
let decommitGasCost := mul(div(byteSize,32), DECOMMIT_COST_PER_WORD())
zkevmGas := sub(zkevmGas, decommitGasCost)
if gt(zkevmGas, UINT32_MAX()) {
zkevmGas := UINT32_MAX()
}
}

function _saveReturndataAfterEVMCall(_outputOffset, _outputLen) -> _gasLeft{
Expand Down Expand Up @@ -944,7 +949,7 @@ function performStaticCall(oldSp,evmGasLeft) -> extraCost, sp {

// zkEVM native
if iszero(_isEVM(addr)) {
gasToPass := _getZkEVMGas(gasToPass)
gasToPass := _getZkEVMGas(gasToPass, addr)
let zkevmGasBefore := gas()
success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, add(MEM_OFFSET_INNER(), retOffset), retSize)
_saveReturndataAfterZkEVMCall()
Expand Down Expand Up @@ -1007,7 +1012,7 @@ function _performCall(addr,gasToPass,value,argsOffset,argsSize,retOffset,retSize

// zkEVM native
if and(iszero(is_evm), iszero(isStatic)) {
gasToPassNew := _getZkEVMGas(gasToPassNew)
gasToPassNew := _getZkEVMGas(gasToPassNew, addr)
let zkevmGasBefore := gas()
success := call(gasToPassNew, addr, value, argsOffset, argsSize, retOffset, retSize)
_saveReturndataAfterZkEVMCall()
Expand Down Expand Up @@ -1203,7 +1208,7 @@ function _performStaticCall(

// zkEVM native
if iszero(_calleeIsEVM) {
_calleeGas := _getZkEVMGas(_calleeGas)
_calleeGas := _getZkEVMGas(_calleeGas, _callee)
let zkevmGasBefore := gas()
success := staticcall(_calleeGas, _callee, _inputOffset, _inputLen, _outputOffset, _outputLen)

Expand Down
58 changes: 34 additions & 24 deletions system-contracts/contracts/EvmInterpreterPreprocessed.yul
Original file line number Diff line number Diff line change
Expand Up @@ -896,11 +896,9 @@ object "EVMInterpreter" {
function EVM_GAS_STIPEND() -> gas_stipend { gas_stipend := shl(30, 1) } // 1 << 30
function OVERHEAD() -> overhead { overhead := 2000 }

function GAS_CONSTANTS() -> divisor, stipend, overhead {
divisor := GAS_DIVISOR()
stipend := EVM_GAS_STIPEND()
overhead := OVERHEAD()
}
// From precompiles/CodeOracle
function DECOMMIT_COST_PER_WORD() -> cost { cost := 4 }
function UINT32_MAX() -> ret { ret := 4294967295 } // 2^32 - 1

function _calcEVMGas(_zkevmGas) -> calczkevmGas {
calczkevmGas := div(_zkevmGas, GAS_DIVISOR())
Expand All @@ -919,11 +917,18 @@ object "EVMInterpreter" {
}
}

function _getZkEVMGas(_evmGas) -> zkevmGas {
/*
TODO: refine the formula, especially with regard to decommitment costs
*/
function _getZkEVMGas(_evmGas, addr) -> zkevmGas {
zkevmGas := mul(_evmGas, GAS_DIVISOR())
let byteSize := extcodesize(addr)
let should_ceil := mod(byteSize, 32)
if gt(should_ceil, 0) {
byteSize := add(byteSize, sub(32, should_ceil))
}
let decommitGasCost := mul(div(byteSize,32), DECOMMIT_COST_PER_WORD())
zkevmGas := sub(zkevmGas, decommitGasCost)
if gt(zkevmGas, UINT32_MAX()) {
zkevmGas := UINT32_MAX()
}
}

function _saveReturndataAfterEVMCall(_outputOffset, _outputLen) -> _gasLeft{
Expand Down Expand Up @@ -1018,7 +1023,7 @@ object "EVMInterpreter" {

// zkEVM native
if iszero(_isEVM(addr)) {
gasToPass := _getZkEVMGas(gasToPass)
gasToPass := _getZkEVMGas(gasToPass, addr)
let zkevmGasBefore := gas()
success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, add(MEM_OFFSET_INNER(), retOffset), retSize)
_saveReturndataAfterZkEVMCall()
Expand Down Expand Up @@ -1081,7 +1086,7 @@ object "EVMInterpreter" {

// zkEVM native
if and(iszero(is_evm), iszero(isStatic)) {
gasToPassNew := _getZkEVMGas(gasToPassNew)
gasToPassNew := _getZkEVMGas(gasToPassNew, addr)
let zkevmGasBefore := gas()
success := call(gasToPassNew, addr, value, argsOffset, argsSize, retOffset, retSize)
_saveReturndataAfterZkEVMCall()
Expand Down Expand Up @@ -1277,7 +1282,7 @@ object "EVMInterpreter" {

// zkEVM native
if iszero(_calleeIsEVM) {
_calleeGas := _getZkEVMGas(_calleeGas)
_calleeGas := _getZkEVMGas(_calleeGas, _callee)
let zkevmGasBefore := gas()
success := staticcall(_calleeGas, _callee, _inputOffset, _inputLen, _outputOffset, _outputLen)

Expand Down Expand Up @@ -3751,11 +3756,9 @@ object "EVMInterpreter" {
function EVM_GAS_STIPEND() -> gas_stipend { gas_stipend := shl(30, 1) } // 1 << 30
function OVERHEAD() -> overhead { overhead := 2000 }

function GAS_CONSTANTS() -> divisor, stipend, overhead {
divisor := GAS_DIVISOR()
stipend := EVM_GAS_STIPEND()
overhead := OVERHEAD()
}
// From precompiles/CodeOracle
function DECOMMIT_COST_PER_WORD() -> cost { cost := 4 }
function UINT32_MAX() -> ret { ret := 4294967295 } // 2^32 - 1

function _calcEVMGas(_zkevmGas) -> calczkevmGas {
calczkevmGas := div(_zkevmGas, GAS_DIVISOR())
Expand All @@ -3774,11 +3777,18 @@ object "EVMInterpreter" {
}
}

function _getZkEVMGas(_evmGas) -> zkevmGas {
/*
TODO: refine the formula, especially with regard to decommitment costs
*/
function _getZkEVMGas(_evmGas, addr) -> zkevmGas {
zkevmGas := mul(_evmGas, GAS_DIVISOR())
let byteSize := extcodesize(addr)
let should_ceil := mod(byteSize, 32)
if gt(should_ceil, 0) {
byteSize := add(byteSize, sub(32, should_ceil))
}
let decommitGasCost := mul(div(byteSize,32), DECOMMIT_COST_PER_WORD())
zkevmGas := sub(zkevmGas, decommitGasCost)
if gt(zkevmGas, UINT32_MAX()) {
zkevmGas := UINT32_MAX()
}
}

function _saveReturndataAfterEVMCall(_outputOffset, _outputLen) -> _gasLeft{
Expand Down Expand Up @@ -3873,7 +3883,7 @@ object "EVMInterpreter" {

// zkEVM native
if iszero(_isEVM(addr)) {
gasToPass := _getZkEVMGas(gasToPass)
gasToPass := _getZkEVMGas(gasToPass, addr)
let zkevmGasBefore := gas()
success := staticcall(gasToPass, addr, add(MEM_OFFSET_INNER(), argsOffset), argsSize, add(MEM_OFFSET_INNER(), retOffset), retSize)
_saveReturndataAfterZkEVMCall()
Expand Down Expand Up @@ -3936,7 +3946,7 @@ object "EVMInterpreter" {

// zkEVM native
if and(iszero(is_evm), iszero(isStatic)) {
gasToPassNew := _getZkEVMGas(gasToPassNew)
gasToPassNew := _getZkEVMGas(gasToPassNew, addr)
let zkevmGasBefore := gas()
success := call(gasToPassNew, addr, value, argsOffset, argsSize, retOffset, retSize)
_saveReturndataAfterZkEVMCall()
Expand Down Expand Up @@ -4132,7 +4142,7 @@ object "EVMInterpreter" {

// zkEVM native
if iszero(_calleeIsEVM) {
_calleeGas := _getZkEVMGas(_calleeGas)
_calleeGas := _getZkEVMGas(_calleeGas, _callee)
let zkevmGasBefore := gas()
success := staticcall(_calleeGas, _callee, _inputOffset, _inputLen, _outputOffset, _outputLen)

Expand Down

0 comments on commit 398aeb4

Please sign in to comment.