Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nonce address fix #24

Closed
wants to merge 11 commits into from
Closed
2 changes: 1 addition & 1 deletion system-contracts/contracts/ContractDeployer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ contract ContractDeployer is IContractDeployer, ISystemContract {
// Subtract 1 for EOA since the nonce has already been incremented for this transaction
uint256 senderNonce = msg.sender == tx.origin
? NONCE_HOLDER_SYSTEM_CONTRACT.getMinNonce(msg.sender) - 1
: NONCE_HOLDER_SYSTEM_CONTRACT.incrementDeploymentNonce(msg.sender);
: NONCE_HOLDER_SYSTEM_CONTRACT.incrementDeploymentNonce(msg.sender) + 1;
address newAddress = Utils.getNewAddressCreateEVM(msg.sender, senderNonce);
_evmDeployOnAddress(newAddress, _initCode);
return newAddress;
Expand Down
38 changes: 23 additions & 15 deletions system-contracts/contracts/EvmInterpreter.template.yul
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,27 @@ object "EVMInterpreter" {
code {
<!-- @include EvmInterpreterFunctions.template.yul -->

function $llvm_NoInline_llvm$_simulate(
isCallerEVM,
evmGasLeft,
isStatic,
) -> returnOffset, returnLen {

returnOffset := MEM_OFFSET_INNER()
returnLen := 0

<!-- @include EvmInterpreterLoop.template.yul -->

if eq(isCallerEVM, 1) {
// Includes gas
returnOffset := sub(returnOffset, 32)
checkOverflow(returnLen, 32, evmGasLeft)
returnLen := add(returnLen, 32)

mstore(returnOffset, evmGasLeft)
}
}

////////////////////////////////////////////////////////////////
// FALLBACK
////////////////////////////////////////////////////////////////
Expand All @@ -131,22 +152,9 @@ object "EVMInterpreter" {
// segment of memory.
getDeployedBytecode()

let returnOffset := MEM_OFFSET_INNER()
let returnLen := 0

pop(warmAddress(address()))

<!-- @include EvmInterpreterLoop.template.yul -->

if eq(isCallerEVM, 1) {
// Includes gas
returnOffset := sub(returnOffset, 32)
checkOverflow(returnLen, 32, evmGasLeft)
returnLen := add(returnLen, 32)

mstore(returnOffset, evmGasLeft)
}
pop($llvm_AlwaysInline_llvm$_warmAddress(address()))

let returnOffset, returnLen := $llvm_NoInline_llvm$_simulate(isCallerEVM, evmGasLeft, isStatic)
return(returnOffset, returnLen)
}
}
Expand Down
148 changes: 102 additions & 46 deletions system-contracts/contracts/EvmInterpreterFunctions.template.yul
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,31 @@ function pushStackItem(sp, item, evmGasLeft) -> newSp {
mstore(newSp, item)
}

function popStackItemWithoutCheck(sp) -> a, newSp {
a := mload(sp)
newSp := sub(sp, 0x20)
}

function pushStackItemWithoutCheck(sp, item) -> newSp {
newSp := add(sp, 0x20)
mstore(newSp, item)
}

function popStackCheck(sp, evmGasLeft, numInputs) {
if lt(sub(sp, mul(0x20, sub(numInputs, 1))), STACK_OFFSET()) {
revertWithGas(evmGasLeft)
}
}

function popPushStackCheck(sp, evmGasLeft, numInputs) {
let popCheck := lt(sub(sp, mul(0x20, sub(numInputs, 1))), STACK_OFFSET())
let pushOffset := sub(sp, mul(0x20, numInputs))
let pushCheck := or(gt(pushOffset, BYTECODE_OFFSET()), eq(pushOffset, BYTECODE_OFFSET()))
if or(popCheck, pushCheck) {
revertWithGas(evmGasLeft)
}
}

function getCodeAddress() -> addr {
addr := verbatim_0i_1o("code_source")
}
Expand Down Expand Up @@ -571,6 +596,19 @@ function warmSlot(key,currentValue) -> isWarm, originalValue {
originalValue := mload(32)
}

function MAX_SYSTEM_CONTRACT_ADDR() -> ret {
ret := 0x000000000000000000000000000000000000ffff
}

/// @dev Checks whether an address is an EOA (i.e. has not code deployed on it)
/// @param addr The address to check
function isEOA(addr) -> ret {
ret := 0
if gt(addr, MAX_SYSTEM_CONTRACT_ADDR()) {
ret := iszero(_getRawCodeHash(addr))
}
}

function getNewAddress(addr) -> newAddr {
let digest, nonce, addressEncoded, nonceEncoded, nonceEncodedLength, listLength, listLengthEconded

Expand Down Expand Up @@ -670,7 +708,7 @@ function addGasIfEvmRevert(isCallerEVM,offset,size,evmGasLeft) -> newOffset,newS
}
}

function warmAddress(addr) -> isWarm {
function $llvm_AlwaysInline_llvm$_warmAddress(addr) -> isWarm {
// TODO: Unhardcode this selector 0x8db2ba78
mstore8(0, 0x8d)
mstore8(1, 0xb2)
Expand Down Expand Up @@ -798,12 +836,13 @@ function getEVMGas() -> evmGas {
let _gas := gas()
let requiredGas := add(EVM_GAS_STIPEND(), OVERHEAD())

if lt(sub(_gas,shl(30,1)), requiredGas) {
// This cheks if enough zkevm gas was provided, we are substracting 2^30 since that's the stipend,
// and we need to make sure that the gas provided over that is enough for security reasons
revert(0, 0)
switch lt(_gas, requiredGas)
case 1 {
evmGas := 0
}
default {
evmGas := div(sub(_gas, requiredGas), GAS_DIVISOR())
}
evmGas := div(sub(_gas, requiredGas), GAS_DIVISOR())
}

function _getZkEVMGas(_evmGas) -> zkevmGas {
Expand Down Expand Up @@ -861,12 +900,13 @@ function _saveReturndataAfterZkEVMCall() {
function performStaticCall(oldSp,evmGasLeft) -> extraCost, sp {
let gasToPass,addr, argsOffset, argsSize, retOffset, retSize

gasToPass, sp := popStackItem(oldSp, evmGasLeft)
addr, sp := popStackItem(sp, evmGasLeft)
argsOffset, sp := popStackItem(sp, evmGasLeft)
argsSize, sp := popStackItem(sp, evmGasLeft)
retOffset, sp := popStackItem(sp, evmGasLeft)
retSize, sp := popStackItem(sp, evmGasLeft)
popStackCheck(oldSp, evmGasLeft, 6)
gasToPass, sp := popStackItemWithoutCheck(oldSp)
addr, sp := popStackItemWithoutCheck(sp)
argsOffset, sp := popStackItemWithoutCheck(sp)
argsSize, sp := popStackItemWithoutCheck(sp)
retOffset, sp := popStackItemWithoutCheck(sp)
retSize, sp := popStackItemWithoutCheck(sp)

addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff)

Expand All @@ -877,7 +917,7 @@ function performStaticCall(oldSp,evmGasLeft) -> extraCost, sp {
checkMemOverflow(add(add(retOffset, retSize), MEM_OFFSET_INNER()), evmGasLeft)

extraCost := 0
if iszero(warmAddress(addr)) {
if iszero($llvm_AlwaysInline_llvm$_warmAddress(addr)) {
extraCost := 2500
}

Expand Down Expand Up @@ -983,13 +1023,14 @@ function _performCall(addr,gasToPass,value,argsOffset,argsSize,retOffset,retSize
function performCall(oldSp, evmGasLeft, isStatic) -> extraCost, sp {
let gasToPass,addr,value,argsOffset,argsSize,retOffset,retSize

gasToPass, sp := popStackItem(oldSp, evmGasLeft)
addr, sp := popStackItem(sp, evmGasLeft)
value, sp := popStackItem(sp, evmGasLeft)
argsOffset, sp := popStackItem(sp, evmGasLeft)
argsSize, sp := popStackItem(sp, evmGasLeft)
retOffset, sp := popStackItem(sp, evmGasLeft)
retSize, sp := popStackItem(sp, evmGasLeft)
popStackCheck(oldSp, evmGasLeft, 7)
gasToPass, sp := popStackItemWithoutCheck(oldSp)
addr, sp := popStackItemWithoutCheck(sp)
value, sp := popStackItemWithoutCheck(sp)
argsOffset, sp := popStackItemWithoutCheck(sp)
argsSize, sp := popStackItemWithoutCheck(sp)
retOffset, sp := popStackItemWithoutCheck(sp)
retSize, sp := popStackItemWithoutCheck(sp)

addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff)

Expand All @@ -1001,7 +1042,7 @@ function performCall(oldSp, evmGasLeft, isStatic) -> extraCost, sp {
// If value is not 0 and the address given points to an empty account, then value_to_empty_account_cost is 25000. An account is empty if its balance is 0, its nonce is 0 and it has no code.

extraCost := 0
if iszero(warmAddress(addr)) {
if iszero($llvm_AlwaysInline_llvm$_warmAddress(addr)) {
extraCost := 2500
}

Expand Down Expand Up @@ -1051,12 +1092,13 @@ function delegateCall(oldSp, oldIsStatic, evmGasLeft) -> sp, isStatic, extraCost
sp := oldSp
isStatic := oldIsStatic

gasToPass, sp := popStackItem(sp, evmGasLeft)
addr, sp := popStackItem(sp, evmGasLeft)
argsOffset, sp := popStackItem(sp, evmGasLeft)
argsSize, sp := popStackItem(sp, evmGasLeft)
retOffset, sp := popStackItem(sp, evmGasLeft)
retSize, sp := popStackItem(sp, evmGasLeft)
popStackCheck(sp, evmGasLeft, 6)
gasToPass, sp := popStackItemWithoutCheck(sp)
addr, sp := popStackItemWithoutCheck(sp)
argsOffset, sp := popStackItemWithoutCheck(sp)
argsSize, sp := popStackItemWithoutCheck(sp)
retOffset, sp := popStackItemWithoutCheck(sp)
retSize, sp := popStackItemWithoutCheck(sp)

// addr := and(addr, 0xffffffffffffffffffffffffffffffffffffffff)

Expand All @@ -1071,7 +1113,7 @@ function delegateCall(oldSp, oldIsStatic, evmGasLeft) -> sp, isStatic, extraCost
}

extraCost := 0
if iszero(warmAddress(addr)) {
if iszero($llvm_AlwaysInline_llvm$_warmAddress(addr)) {
extraCost := 2500
}

Expand Down Expand Up @@ -1206,7 +1248,7 @@ function _fetchConstructorReturnGas() -> gasLeft {
}

function genericCreate(addr, offset, size, sp, value, evmGasLeftOld) -> result, evmGasLeft {
pop(warmAddress(addr))
pop($llvm_AlwaysInline_llvm$_warmAddress(addr))

_eraseReturndataPointer()

Expand Down Expand Up @@ -1251,28 +1293,40 @@ function genericCreate(addr, offset, size, sp, value, evmGasLeftOld) -> result,

_popEVMFrame()

incrementNonce(address())
switch result
case 1 {
incrementNonce(address())
}
default {
switch isEOA(address())
case 1 {
incrementNonce(address())
}
default {}
}

let back

back, sp := popStackItem(sp, evmGasLeft)
popStackCheck(sp, evmGasLeft, 4)
back, sp := popStackItemWithoutCheck(sp)
mstore(sub(offset, 0x20), back)
back, sp := popStackItem(sp, evmGasLeft)
back, sp := popStackItemWithoutCheck(sp)
mstore(sub(offset, 0x40), back)
back, sp := popStackItem(sp, evmGasLeft)
back, sp := popStackItemWithoutCheck(sp)
mstore(sub(offset, 0x60), back)
back, sp := popStackItem(sp, evmGasLeft)
back, sp := popStackItemWithoutCheck(sp)
mstore(sub(offset, 0x80), back)
}

function performExtCodeCopy(evmGas,oldSp) -> evmGasLeft, sp {
evmGasLeft := chargeGas(evmGas, 100)

let addr, dest, offset, len
addr, sp := popStackItem(oldSp, evmGasLeft)
dest, sp := popStackItem(sp, evmGasLeft)
offset, sp := popStackItem(sp, evmGasLeft)
len, sp := popStackItem(sp, evmGasLeft)
popStackCheck(oldSp, evmGasLeft, 4)
addr, sp := popStackItemWithoutCheck(oldSp)
dest, sp := popStackItemWithoutCheck(sp)
offset, sp := popStackItemWithoutCheck(sp)
len, sp := popStackItemWithoutCheck(sp)

// dynamicGas = 3 * minimum_word_size + memory_expansion_cost + address_access_cost
// minimum_word_size = (size + 31) / 32
Expand All @@ -1281,7 +1335,7 @@ function performExtCodeCopy(evmGas,oldSp) -> evmGasLeft, sp {
mul(3, shr(5, add(len, 31))),
expandMemory(add(dest, len))
)
if iszero(warmAddress(addr)) {
if iszero($llvm_AlwaysInline_llvm$_warmAddress(addr)) {
dynamicGas := add(dynamicGas, 2500)
}
evmGasLeft := chargeGas(evmGasLeft, dynamicGas)
Expand Down Expand Up @@ -1312,9 +1366,10 @@ function performCreate(evmGas,oldSp,isStatic) -> evmGasLeft, sp {

let value, offset, size

value, sp := popStackItem(oldSp, evmGasLeft)
offset, sp := popStackItem(sp, evmGasLeft)
size, sp := popStackItem(sp, evmGasLeft)
popStackCheck(oldSp, evmGasLeft, 3)
value, sp := popStackItemWithoutCheck(oldSp)
offset, sp := popStackItemWithoutCheck(sp)
size, sp := popStackItemWithoutCheck(sp)

checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft)

Expand Down Expand Up @@ -1357,10 +1412,11 @@ function performCreate2(evmGas, oldSp, isStatic) -> evmGasLeft, sp, result, addr

let value, offset, size, salt

value, sp := popStackItem(oldSp, evmGasLeft)
offset, sp := popStackItem(sp, evmGasLeft)
size, sp := popStackItem(sp, evmGasLeft)
salt, sp := popStackItem(sp, evmGasLeft)
popStackCheck(oldSp, evmGasLeft, 4)
value, sp := popStackItemWithoutCheck(oldSp)
offset, sp := popStackItemWithoutCheck(sp)
size, sp := popStackItemWithoutCheck(sp)
salt, sp := popStackItemWithoutCheck(sp)

checkMultipleOverflow(offset, size, MEM_OFFSET_INNER(), evmGasLeft)

Expand Down
Loading
Loading