clean up code for call handlers

This commit is contained in:
Jordan Hrycaj 2021-04-16 18:46:51 +01:00 committed by zah
parent 4ac32d360b
commit 4e2af7937b
1 changed files with 159 additions and 223 deletions

View File

@ -118,83 +118,107 @@ else:
# Private # Private
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
proc callParams(c: Computation): (UInt256, UInt256, EthAddress, type
EthAddress, int, int, int, LocalParams = tuple
int, MsgFlags) = gas: UInt256
let gas = c.stack.popInt() value: UInt256
let destination = c.stack.popAddress() destination: EthAddress
let value = c.stack.popInt() sender: EthAddress
memInPos: int
memInLen: int
memOutPos: int
memOutLen: int
flags: MsgFlags
memOffset: int
memLength: int
contractAddress: EthAddress
result = (gas,
value,
destination,
c.msg.contractAddress, # sender
c.stack.popInt().cleanMemRef,
c.stack.popInt().cleanMemRef,
c.stack.popInt().cleanMemRef,
c.stack.popInt().cleanMemRef,
c.msg.flags)
proc updateStackAndParams(q: var LocalParams; c: Computation) =
c.stack.push(0) c.stack.push(0)
let
outLen = calcMemSize(q.memOutPos, q.memOutLen)
inLen = calcMemSize(q.memInPos, q.memInLen)
proc callCodeParams(c: Computation): (UInt256, UInt256, EthAddress, # get the bigger one
EthAddress, int, int, int, if outLen < inLen:
int, MsgFlags) = q.memOffset = q.memInPos
let gas = c.stack.popInt() q.memLength = q.memInLen
let destination = c.stack.popAddress() else:
let value = c.stack.popInt() q.memOffset = q.memOutPos
q.memLength = q.memOutLen
result = (gas, # EIP2929: This came before old gas calculator
value, # because it will affect `c.gasMeter.gasRemaining`
destination, # and further `childGasLimit`
c.msg.contractAddress, # sender if FkBerlin <= c.fork:
c.stack.popInt().cleanMemRef, c.vmState.mutateStateDB:
c.stack.popInt().cleanMemRef, if not db.inAccessList(q.destination):
c.stack.popInt().cleanMemRef, db.accessList(q.destination)
c.stack.popInt().cleanMemRef,
c.msg.flags)
c.stack.push(0) # The WarmStorageReadCostEIP2929 (100) is already deducted in
# the form of a constant `gasCall`
c.gasMeter.consumeGas(
ColdAccountAccessCost - WarmStorageReadCost,
reason = "EIP2929 gasCall")
proc callParams(c: Computation): LocalParams =
## Helper for callOp()
result.gas = c.stack.popInt()
result.destination = c.stack.popAddress()
result.value = c.stack.popInt()
result.memInPos = c.stack.popInt().cleanMemRef
result.memInLen = c.stack.popInt().cleanMemRef
result.memOutPos = c.stack.popInt().cleanMemRef
result.memOutLen = c.stack.popInt().cleanMemRef
proc delegateCallParams(c: Computation): (UInt256, UInt256, EthAddress, result.sender = c.msg.contractAddress
EthAddress, int, int, int, result.flags = c.msg.flags
int, MsgFlags) = result.contractAddress = result.destination
let gas = c.stack.popInt()
let destination = c.stack.popAddress()
result = (gas, result.updateStackAndParams(c)
c.msg.value, # value
destination,
c.msg.sender, # sender
c.stack.popInt().cleanMemRef,
c.stack.popInt().cleanMemRef,
c.stack.popInt().cleanMemRef,
c.stack.popInt().cleanMemRef,
c.msg.flags)
c.stack.push(0)
proc staticCallParams(c: Computation): (UInt256, UInt256, EthAddress, proc callCodeParams(c: Computation): LocalParams =
EthAddress, int, int, int, ## Helper for callCodeOp()
int, MsgFlags) = result = c.callParams
let gas = c.stack.popInt() result.contractAddress = c.msg.contractAddress
let destination = c.stack.popAddress()
result = (gas,
0.u256, # value
destination,
c.msg.contractAddress, # sender
c.stack.popInt().cleanMemRef,
c.stack.popInt().cleanMemRef,
c.stack.popInt().cleanMemRef,
c.stack.popInt().cleanMemRef,
emvcStatic) # is_static
c.stack.push(0) proc delegateCallParams(c: Computation): LocalParams =
## Helper for delegateCall()
result.gas = c.stack.popInt()
result.destination = c.stack.popAddress()
result.memInPos = c.stack.popInt().cleanMemRef
result.memInLen = c.stack.popInt().cleanMemRef
result.memOutPos = c.stack.popInt().cleanMemRef
result.memOutLen = c.stack.popInt().cleanMemRef
result.value = c.msg.value
result.sender = c.msg.sender
result.flags = c.msg.flags
result.contractAddress = c.msg.contractAddress
result.updateStackAndParams(c)
proc staticCallParams(c: Computation): LocalParams =
## Helper for staticCall()
result.gas = c.stack.popInt()
result.destination = c.stack.popAddress()
result.memInPos = c.stack.popInt().cleanMemRef
result.memInLen = c.stack.popInt().cleanMemRef
result.memOutPos = c.stack.popInt().cleanMemRef
result.memOutLen = c.stack.popInt().cleanMemRef
result.value = 0.u256
result.sender = c.msg.contractAddress
result.flags = emvcStatic
result.contractAddress = result.destination
result.updateStackAndParams(c)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Private, op handlers implementation # Private, op handlers implementation
@ -203,46 +227,24 @@ proc staticCallParams(c: Computation): (UInt256, UInt256, EthAddress,
const const
callOp: Vm2OpFn = proc(k: Vm2Ctx) = callOp: Vm2OpFn = proc(k: Vm2Ctx) =
## 0xf1, Message-Call into an account ## 0xf1, Message-Call into an account
if emvcStatic == k.cpt.msg.flags and k.cpt.stack[^3, UInt256] > 0.u256: if emvcStatic == k.cpt.msg.flags and k.cpt.stack[^3, UInt256] > 0.u256:
raise newException( raise newException(
StaticContextError, StaticContextError,
"Cannot modify state while inside of a STATICCALL context") "Cannot modify state while inside of a STATICCALL context")
let
let (gas, value, destination, sender, memInPos, memInLen, memOutPos, p = k.cpt.callParams
memOutLen, flags) = callParams(k.cpt)
let (memOffset, memLength) =
if calcMemSize(memInPos, memInLen) > calcMemSize(memOutPos, memOutLen):
(memInPos, memInLen)
else:
(memOutPos, memOutLen)
# EIP2929
# This came before old gas calculator
# because it will affect `k.cpt.gasMeter.gasRemaining`
# and further `childGasLimit`
if k.cpt.fork >= FkBerlin:
k.cpt.vmState.mutateStateDB:
if not db.inAccessList(destination):
db.accessList(destination)
# The WarmStorageReadCostEIP2929 (100) is already deducted in
# the form of a constant `gasCall`
k.cpt.gasMeter.consumeGas(
ColdAccountAccessCost - WarmStorageReadCost,
reason = "EIP2929 gasCall")
let contractAddress = destination
var (gasCost, childGasLimit) = k.cpt.gasCosts[Call].c_handler( var (gasCost, childGasLimit) = k.cpt.gasCosts[Call].c_handler(
value, p.value,
GasParams( GasParams(
kind: Call, kind: Call,
c_isNewAccount: not k.cpt.accountExists(contractAddress), c_isNewAccount: not k.cpt.accountExists(p.contractAddress),
c_gasBalance: k.cpt.gasMeter.gasRemaining, c_gasBalance: k.cpt.gasMeter.gasRemaining,
c_contractGas: gas, c_contractGas: p.gas,
c_currentMemSize: k.cpt.memory.len, c_currentMemSize: k.cpt.memory.len,
c_memOffset: memOffset, c_memOffset: p.memOffset,
c_memLength: memLength)) c_memLength: p.memLength))
# EIP 2046: temporary disabled # EIP 2046: temporary disabled
# reduce gas fee for precompiles # reduce gas fee for precompiles
@ -264,11 +266,11 @@ const
raise newException( raise newException(
OutOfGas, "Gas not enough to perform calculation (call)") OutOfGas, "Gas not enough to perform calculation (call)")
k.cpt.memory.extend(memInPos, memInLen) k.cpt.memory.extend(p.memInPos, p.memInLen)
k.cpt.memory.extend(memOutPos, memOutLen) k.cpt.memory.extend(p.memOutPos, p.memOutLen)
let senderBalance = k.cpt.getBalance(sender) let senderBalance = k.cpt.getBalance(p.sender)
if senderBalance < value: if senderBalance < p.value:
debug "Insufficient funds", debug "Insufficient funds",
available = senderBalance, available = senderBalance,
needed = k.cpt.msg.value needed = k.cpt.msg.value
@ -279,12 +281,12 @@ const
kind: evmcCall, kind: evmcCall,
depth: k.cpt.msg.depth + 1, depth: k.cpt.msg.depth + 1,
gas: childGasLimit, gas: childGasLimit,
sender: sender, sender: p.sender,
contractAddress: contractAddress, contractAddress: p.contractAddress,
codeAddress: destination, codeAddress: p.destination,
value: value, value: p.value,
data: k.cpt.memory.read(memInPos, memInLen), data: k.cpt.memory.read(p.memInPos, p.memInLen),
flags: flags) flags: p.flags)
var child = newComputation(k.cpt.vmState, msg) var child = newComputation(k.cpt.vmState, msg)
k.cpt.chainTo(child): k.cpt.chainTo(child):
@ -296,50 +298,28 @@ const
k.cpt.stack.top(1) k.cpt.stack.top(1)
k.cpt.returnData = child.output k.cpt.returnData = child.output
let actualOutputSize = min(memOutLen, child.output.len) let actualOutputSize = min(p.memOutLen, child.output.len)
if actualOutputSize > 0: if actualOutputSize > 0:
k.cpt.memory.write(memOutPos, k.cpt.memory.write(p.memOutPos,
child.output.toOpenArray(0, actualOutputSize - 1)) child.output.toOpenArray(0, actualOutputSize - 1))
# --------------------- # ---------------------
callCodeOp: Vm2OpFn = proc(k: Vm2Ctx) = callCodeOp: Vm2OpFn = proc(k: Vm2Ctx) =
## 0xf2, Message-call into this account with an alternative account's code. ## 0xf2, Message-call into this account with an alternative account's code.
let (gas, value, destination, sender, memInPos, memInLen, memOutPos, let
memOutLen, flags) = callCodeParams(k.cpt) p = k.cpt.callCodeParams
let (memOffset, memLength) =
if calcMemSize(memInPos, memInLen) > calcMemSize(memOutPos, memOutLen):
(memInPos, memInLen)
else:
(memOutPos, memOutLen)
# EIP2929
# This came before old gas calculator
# because it will affect `k.cpt.gasMeter.gasRemaining`
# and further `childGasLimit`
if k.cpt.fork >= FkBerlin:
k.cpt.vmState.mutateStateDB:
if not db.inAccessList(destination):
db.accessList(destination)
# The WarmStorageReadCostEIP2929 (100) is already deducted in
# the form of a constant `gasCall`
k.cpt.gasMeter.consumeGas(
ColdAccountAccessCost - WarmStorageReadCost,
reason = "EIP2929 gasCall")
let contractAddress = k.cpt.msg.contractAddress
var (gasCost, childGasLimit) = k.cpt.gasCosts[CallCode].c_handler( var (gasCost, childGasLimit) = k.cpt.gasCosts[CallCode].c_handler(
value, p.value,
GasParams( GasParams(
kind: CallCode, kind: CallCode,
c_isNewAccount: not k.cpt.accountExists(contractAddress), c_isNewAccount: not k.cpt.accountExists(p.contractAddress),
c_gasBalance: k.cpt.gasMeter.gasRemaining, c_gasBalance: k.cpt.gasMeter.gasRemaining,
c_contractGas: gas, c_contractGas: p.gas,
c_currentMemSize: k.cpt.memory.len, c_currentMemSize: k.cpt.memory.len,
c_memOffset: memOffset, c_memOffset: p.memOffset,
c_memLength: memLength)) c_memLength: p.memLength))
# EIP 2046: temporary disabled # EIP 2046: temporary disabled
# reduce gas fee for precompiles # reduce gas fee for precompiles
@ -364,11 +344,11 @@ const
raise newException( raise newException(
OutOfGas, "Gas not enough to perform calculation (callCode)") OutOfGas, "Gas not enough to perform calculation (callCode)")
k.cpt.memory.extend(memInPos, memInLen) k.cpt.memory.extend(p.memInPos, p.memInLen)
k.cpt.memory.extend(memOutPos, memOutLen) k.cpt.memory.extend(p.memOutPos, p.memOutLen)
let senderBalance = k.cpt.getBalance(sender) let senderBalance = k.cpt.getBalance(p.sender)
if senderBalance < value: if senderBalance < p.value:
debug "Insufficient funds", debug "Insufficient funds",
available = senderBalance, available = senderBalance,
needed = k.cpt.msg.value needed = k.cpt.msg.value
@ -379,12 +359,12 @@ const
kind: evmcCallCode, kind: evmcCallCode,
depth: k.cpt.msg.depth + 1, depth: k.cpt.msg.depth + 1,
gas: childGasLimit, gas: childGasLimit,
sender: sender, sender: p.sender,
contractAddress: contractAddress, contractAddress: p.contractAddress,
codeAddress: destination, codeAddress: p.destination,
value: value, value: p.value,
data: k.cpt.memory.read(memInPos, memInLen), data: k.cpt.memory.read(p.memInPos, p.memInLen),
flags: flags) flags: p.flags)
var child = newComputation(k.cpt.vmState, msg) var child = newComputation(k.cpt.vmState, msg)
k.cpt.chainTo(child): k.cpt.chainTo(child):
@ -396,9 +376,9 @@ const
k.cpt.stack.top(1) k.cpt.stack.top(1)
k.cpt.returnData = child.output k.cpt.returnData = child.output
let actualOutputSize = min(memOutLen, child.output.len) let actualOutputSize = min(p.memOutLen, child.output.len)
if actualOutputSize > 0: if actualOutputSize > 0:
k.cpt.memory.write(memOutPos, k.cpt.memory.write(p.memOutPos,
child.output.toOpenArray(0, actualOutputSize - 1)) child.output.toOpenArray(0, actualOutputSize - 1))
# --------------------- # ---------------------
@ -406,41 +386,19 @@ const
delegateCallOp: Vm2OpFn = proc(k: Vm2Ctx) = delegateCallOp: Vm2OpFn = proc(k: Vm2Ctx) =
## 0xf4, Message-call into this account with an alternative account's ## 0xf4, Message-call into this account with an alternative account's
## code, but persisting the current values for sender and value. ## code, but persisting the current values for sender and value.
let (gas, value, destination, sender, memInPos, memInLen, memOutPos, let
memOutLen, flags) = delegateCallParams(k.cpt) p = k.cpt.delegateCallParams
let (memOffset, memLength) =
if calcMemSize(memInPos, memInLen) > calcMemSize(memOutPos, memOutLen):
(memInPos, memInLen)
else:
(memOutPos, memOutLen)
# EIP2929
# This came before old gas calculator
# because it will affect `k.cpt.gasMeter.gasRemaining`
# and further `childGasLimit`
if k.cpt.fork >= FkBerlin:
k.cpt.vmState.mutateStateDB:
if not db.inAccessList(destination):
db.accessList(destination)
# The WarmStorageReadCostEIP2929 (100) is already deducted in
# the form of a constant `gasCall`
k.cpt.gasMeter.consumeGas(
ColdAccountAccessCost - WarmStorageReadCost,
reason = "EIP2929 gasCall")
let contractAddress = k.cpt.msg.contractAddress
var (gasCost, childGasLimit) = k.cpt.gasCosts[DelegateCall].c_handler( var (gasCost, childGasLimit) = k.cpt.gasCosts[DelegateCall].c_handler(
value, p.value,
GasParams( GasParams(
kind: DelegateCall, kind: DelegateCall,
c_isNewAccount: not k.cpt.accountExists(contractAddress), c_isNewAccount: not k.cpt.accountExists(p.contractAddress),
c_gasBalance: k.cpt.gasMeter.gasRemaining, c_gasBalance: k.cpt.gasMeter.gasRemaining,
c_contractGas: gas, c_contractGas: p.gas,
c_currentMemSize: k.cpt.memory.len, c_currentMemSize: k.cpt.memory.len,
c_memOffset: memOffset, c_memOffset: p.memOffset,
c_memLength: memLength)) c_memLength: p.memLength))
# EIP 2046: temporary disabled # EIP 2046: temporary disabled
# reduce gas fee for precompiles # reduce gas fee for precompiles
@ -461,19 +419,19 @@ const
raise newException( raise newException(
OutOfGas, "Gas not enough to perform calculation (delegateCall)") OutOfGas, "Gas not enough to perform calculation (delegateCall)")
k.cpt.memory.extend(memInPos, memInLen) k.cpt.memory.extend(p.memInPos, p.memInLen)
k.cpt.memory.extend(memOutPos, memOutLen) k.cpt.memory.extend(p.memOutPos, p.memOutLen)
let msg = Message( let msg = Message(
kind: evmcDelegateCall, kind: evmcDelegateCall,
depth: k.cpt.msg.depth + 1, depth: k.cpt.msg.depth + 1,
gas: childGasLimit, gas: childGasLimit,
sender: sender, sender: p.sender,
contractAddress: contractAddress, contractAddress: p.contractAddress,
codeAddress: destination, codeAddress: p.destination,
value: value, value: p.value,
data: k.cpt.memory.read(memInPos, memInLen), data: k.cpt.memory.read(p.memInPos, p.memInLen),
flags: flags) flags: p.flags)
var child = newComputation(k.cpt.vmState, msg) var child = newComputation(k.cpt.vmState, msg)
k.cpt.chainTo(child): k.cpt.chainTo(child):
@ -485,51 +443,29 @@ const
k.cpt.stack.top(1) k.cpt.stack.top(1)
k.cpt.returnData = child.output k.cpt.returnData = child.output
let actualOutputSize = min(memOutLen, child.output.len) let actualOutputSize = min(p.memOutLen, child.output.len)
if actualOutputSize > 0: if actualOutputSize > 0:
k.cpt.memory.write(memOutPos, k.cpt.memory.write(p.memOutPos,
child.output.toOpenArray(0, actualOutputSize - 1)) child.output.toOpenArray(0, actualOutputSize - 1))
# --------------------- # ---------------------
staticCallOp: Vm2OpFn = proc(k: Vm2Ctx) = staticCallOp: Vm2OpFn = proc(k: Vm2Ctx) =
## 0xfa, Static message-call into an account. ## 0xfa, Static message-call into an account.
let (gas, value, destination, sender, memInPos, memInLen, memOutPos,
memOutLen, flags) = staticCallParams(k.cpt)
let (memOffset, memLength) = let
if calcMemSize(memInPos, memInLen) > calcMemSize(memOutPos, memOutLen): p = k.cpt.staticCallParams
(memInPos, memInLen)
else:
(memOutPos, memOutLen)
# EIP2929
# This came before old gas calculator
# because it will affect `k.cpt.gasMeter.gasRemaining`
# and further `childGasLimit`
if k.cpt.fork >= FkBerlin:
if k.cpt.fork >= FkBerlin:
k.cpt.vmState.mutateStateDB:
if not db.inAccessList(destination):
db.accessList(destination)
# The WarmStorageReadCostEIP2929 (100) is already deducted in
# the form of a constant `gasCall`
k.cpt.gasMeter.consumeGas(
ColdAccountAccessCost - WarmStorageReadCost,
reason = "EIP2929 gasCall")
let contractAddress = destination
var (gasCost, childGasLimit) = k.cpt.gasCosts[StaticCall].c_handler( var (gasCost, childGasLimit) = k.cpt.gasCosts[StaticCall].c_handler(
value, p.value,
GasParams( GasParams(
kind: StaticCall, kind: StaticCall,
c_isNewAccount: not k.cpt.accountExists(contractAddress), c_isNewAccount: not k.cpt.accountExists(p.contractAddress),
c_gasBalance: k.cpt.gasMeter.gasRemaining, c_gasBalance: k.cpt.gasMeter.gasRemaining,
c_contractGas: gas, c_contractGas: p.gas,
c_currentMemSize: k.cpt.memory.len, c_currentMemSize: k.cpt.memory.len,
c_memOffset: memOffset, c_memOffset: p.memOffset,
c_memLength: memLength)) c_memLength: p.memLength))
# EIP 2046: temporary disabled # EIP 2046: temporary disabled
# reduce gas fee for precompiles # reduce gas fee for precompiles
@ -555,19 +491,19 @@ const
raise newException( raise newException(
OutOfGas, "Gas not enough to perform calculation (staticCall)") OutOfGas, "Gas not enough to perform calculation (staticCall)")
k.cpt.memory.extend(memInPos, memInLen) k.cpt.memory.extend(p.memInPos, p.memInLen)
k.cpt.memory.extend(memOutPos, memOutLen) k.cpt.memory.extend(p.memOutPos, p.memOutLen)
let msg = Message( let msg = Message(
kind: evmcCall, kind: evmcCall,
depth: k.cpt.msg.depth + 1, depth: k.cpt.msg.depth + 1,
gas: childGasLimit, gas: childGasLimit,
sender: sender, sender: p.sender,
contractAddress: contractAddress, contractAddress: p.contractAddress,
codeAddress: destination, codeAddress: p.destination,
value: value, value: p.value,
data: k.cpt.memory.read(memInPos, memInLen), data: k.cpt.memory.read(p.memInPos, p.memInLen),
flags: flags) flags: p.flags)
var child = newComputation(k.cpt.vmState, msg) var child = newComputation(k.cpt.vmState, msg)
k.cpt.chainTo(child): k.cpt.chainTo(child):
@ -579,9 +515,9 @@ const
k.cpt.stack.top(1) k.cpt.stack.top(1)
k.cpt.returnData = child.output k.cpt.returnData = child.output
let actualOutputSize = min(memOutLen, child.output.len) let actualOutputSize = min(p.memOutLen, child.output.len)
if actualOutputSize > 0: if actualOutputSize > 0:
k.cpt.memory.write(memOutPos, k.cpt.memory.write(p.memOutPos,
child.output.toOpenArray(0, actualOutputSize - 1)) child.output.toOpenArray(0, actualOutputSize - 1))
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------