EVM embrace more EVMC types
Also embed evmc_status_code to computation.error, and make the tracer produce cleaner output. No more "Revert opcode executed" error message. We can distinguish error code between REVERT and FAILURE in a more cleaner way.
This commit is contained in:
parent
00262a1d48
commit
26620eb672
|
@ -51,7 +51,7 @@ const
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
proc generateContractAddress(c: Computation, salt: ContractSalt): EthAddress =
|
proc generateContractAddress(c: Computation, salt: ContractSalt): EthAddress =
|
||||||
if c.msg.kind == evmcCreate:
|
if c.msg.kind == EVMC_CREATE:
|
||||||
let creationNonce = c.vmState.readOnlyStateDB().getNonce(c.msg.sender)
|
let creationNonce = c.vmState.readOnlyStateDB().getNonce(c.msg.sender)
|
||||||
result = generateAddress(c.msg.sender, creationNonce)
|
result = generateAddress(c.msg.sender, creationNonce)
|
||||||
else:
|
else:
|
||||||
|
@ -273,7 +273,26 @@ proc rollback*(c: Computation) =
|
||||||
c.vmState.stateDB.rollback(c.savePoint)
|
c.vmState.stateDB.rollback(c.savePoint)
|
||||||
|
|
||||||
proc setError*(c: Computation, msg: string, burnsGas = false) =
|
proc setError*(c: Computation, msg: string, burnsGas = false) =
|
||||||
c.error = Error(info: msg, burnsGas: burnsGas)
|
c.error = Error(statusCode: EVMC_FAILURE, info: msg, burnsGas: burnsGas)
|
||||||
|
|
||||||
|
proc setError*(c: Computation, code: evmc_status_code, burnsGas = false) =
|
||||||
|
c.error = Error(statusCode: code, info: $code, burnsGas: burnsGas)
|
||||||
|
|
||||||
|
proc setError*(c: Computation, code: evmc_status_code, msg: string, burnsGas = false) =
|
||||||
|
c.error = Error(statusCode: code, info: msg, burnsGas: burnsGas)
|
||||||
|
|
||||||
|
func statusCode*(c: Computation): evmc_status_code =
|
||||||
|
if c.isSuccess:
|
||||||
|
EVMC_SUCCESS
|
||||||
|
else:
|
||||||
|
c.error.statusCode
|
||||||
|
|
||||||
|
func errorOpt*(c: Computation): Option[string] =
|
||||||
|
if c.isSuccess:
|
||||||
|
return none(string)
|
||||||
|
if c.error.statusCode == EVMC_REVERT:
|
||||||
|
return none(string)
|
||||||
|
some(c.error.info)
|
||||||
|
|
||||||
proc writeContract*(c: Computation)
|
proc writeContract*(c: Computation)
|
||||||
{.gcsafe, raises: [CatchableError].} =
|
{.gcsafe, raises: [CatchableError].} =
|
||||||
|
@ -292,16 +311,14 @@ proc writeContract*(c: Computation)
|
||||||
# EIP-3541 constraint (https://eips.ethereum.org/EIPS/eip-3541).
|
# EIP-3541 constraint (https://eips.ethereum.org/EIPS/eip-3541).
|
||||||
if fork >= FkLondon and c.output[0] == 0xEF.byte:
|
if fork >= FkLondon and c.output[0] == 0xEF.byte:
|
||||||
withExtra trace, "New contract code starts with 0xEF byte, not allowed by EIP-3541"
|
withExtra trace, "New contract code starts with 0xEF byte, not allowed by EIP-3541"
|
||||||
# TODO: Return `EVMC_CONTRACT_VALIDATION_FAILURE` (like Silkworm).
|
c.setError(EVMC_CONTRACT_VALIDATION_FAILURE, true)
|
||||||
c.setError("EVMC_CONTRACT_VALIDATION_FAILURE", true)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# EIP-170 constraint (https://eips.ethereum.org/EIPS/eip-3541).
|
# EIP-170 constraint (https://eips.ethereum.org/EIPS/eip-3541).
|
||||||
if fork >= FkSpurious and len > EIP170_MAX_CODE_SIZE:
|
if fork >= FkSpurious and len > EIP170_MAX_CODE_SIZE:
|
||||||
withExtra trace, "New contract code exceeds EIP-170 limit",
|
withExtra trace, "New contract code exceeds EIP-170 limit",
|
||||||
codeSize=len, maxSize=EIP170_MAX_CODE_SIZE
|
codeSize=len, maxSize=EIP170_MAX_CODE_SIZE
|
||||||
# TODO: Return `EVMC_OUT_OF_GAS` (like Silkworm).
|
c.setError(EVMC_OUT_OF_GAS, true)
|
||||||
c.setError("EVMC_OUT_OF_GAS", true)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Charge gas and write the code even if the code address is self-destructed.
|
# Charge gas and write the code even if the code address is self-destructed.
|
||||||
|
@ -322,8 +339,7 @@ proc writeContract*(c: Computation)
|
||||||
|
|
||||||
if fork >= FkHomestead:
|
if fork >= FkHomestead:
|
||||||
# EIP-2 (https://eips.ethereum.org/EIPS/eip-2).
|
# EIP-2 (https://eips.ethereum.org/EIPS/eip-2).
|
||||||
# TODO: Return `EVMC_OUT_OF_GAS` (like Silkworm).
|
c.setError(EVMC_OUT_OF_GAS, true)
|
||||||
c.setError("EVMC_OUT_OF_GAS", true)
|
|
||||||
else:
|
else:
|
||||||
# Before EIP-2, when out of gas for code storage, the account ends up with
|
# Before EIP-2, when out of gas for code storage, the account ends up with
|
||||||
# zero-length code and no error. No gas is charged. Code cited in EIP-2:
|
# zero-length code and no error. No gas is charged. Code cited in EIP-2:
|
||||||
|
@ -416,7 +432,7 @@ proc traceError*(c: Computation) {.gcsafe, raises: [].} =
|
||||||
c.gasMeter.gasRefunded,
|
c.gasMeter.gasRefunded,
|
||||||
c.returnData,
|
c.returnData,
|
||||||
c.msg.depth + 1,
|
c.msg.depth + 1,
|
||||||
some(c.error.info))
|
c.errorOpt)
|
||||||
|
|
||||||
proc prepareTracer*(c: Computation) =
|
proc prepareTracer*(c: Computation) =
|
||||||
c.vmState.capturePrepare(c, c.msg.depth)
|
c.vmState.capturePrepare(c, c.msg.depth)
|
||||||
|
|
|
@ -33,7 +33,7 @@ type
|
||||||
|
|
||||||
nimbus_message* = object
|
nimbus_message* = object
|
||||||
kind* : evmc_call_kind
|
kind* : evmc_call_kind
|
||||||
flags* : uint32
|
flags* : evmc_flags
|
||||||
depth* : int32
|
depth* : int32
|
||||||
gas* : int64
|
gas* : int64
|
||||||
recipient* : EthAddress
|
recipient* : EthAddress
|
||||||
|
|
|
@ -142,7 +142,7 @@ proc staticCallParams(c: Computation): LocalParams =
|
||||||
|
|
||||||
result.value = 0.u256
|
result.value = 0.u256
|
||||||
result.sender = c.msg.contractAddress
|
result.sender = c.msg.contractAddress
|
||||||
result.flags = emvcStatic
|
result.flags.incl EVMC_STATIC
|
||||||
result.contractAddress = result.codeAddress
|
result.contractAddress = result.codeAddress
|
||||||
|
|
||||||
result.updateStackAndParams(c)
|
result.updateStackAndParams(c)
|
||||||
|
@ -196,7 +196,7 @@ const
|
||||||
## 0xf1, Message-Call into an account
|
## 0xf1, Message-Call into an account
|
||||||
let cpt = k.cpt
|
let cpt = k.cpt
|
||||||
|
|
||||||
if emvcStatic == cpt.msg.flags and cpt.stack[^3, UInt256] > 0.u256:
|
if EVMC_STATIC in cpt.msg.flags and 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")
|
||||||
|
@ -248,7 +248,7 @@ const
|
||||||
msg = new(nimbus_message)
|
msg = new(nimbus_message)
|
||||||
c = cpt
|
c = cpt
|
||||||
msg[] = nimbus_message(
|
msg[] = nimbus_message(
|
||||||
kind : evmcCall.ord.evmc_call_kind,
|
kind : EVMC_CALL,
|
||||||
depth : (cpt.msg.depth + 1).int32,
|
depth : (cpt.msg.depth + 1).int32,
|
||||||
gas : childGasLimit,
|
gas : childGasLimit,
|
||||||
sender : p.sender,
|
sender : p.sender,
|
||||||
|
@ -257,7 +257,7 @@ const
|
||||||
input_data : cpt.memory.readPtr(p.memInPos),
|
input_data : cpt.memory.readPtr(p.memInPos),
|
||||||
input_size : p.memInLen.uint,
|
input_size : p.memInLen.uint,
|
||||||
value : toEvmc(p.value),
|
value : toEvmc(p.value),
|
||||||
flags : p.flags.uint32
|
flags : p.flags
|
||||||
)
|
)
|
||||||
c.execSubCall(msg, p)
|
c.execSubCall(msg, p)
|
||||||
else:
|
else:
|
||||||
|
@ -265,7 +265,7 @@ const
|
||||||
memPos = p.memOutPos,
|
memPos = p.memOutPos,
|
||||||
memLen = p.memOutLen,
|
memLen = p.memOutLen,
|
||||||
childMsg = Message(
|
childMsg = Message(
|
||||||
kind: evmcCall,
|
kind: EVMC_CALL,
|
||||||
depth: cpt.msg.depth + 1,
|
depth: cpt.msg.depth + 1,
|
||||||
gas: childGasLimit,
|
gas: childGasLimit,
|
||||||
sender: p.sender,
|
sender: p.sender,
|
||||||
|
@ -327,7 +327,7 @@ const
|
||||||
msg = new(nimbus_message)
|
msg = new(nimbus_message)
|
||||||
c = cpt
|
c = cpt
|
||||||
msg[] = nimbus_message(
|
msg[] = nimbus_message(
|
||||||
kind : evmcCallCode.ord.evmc_call_kind,
|
kind : EVMC_CALLCODE,
|
||||||
depth : (cpt.msg.depth + 1).int32,
|
depth : (cpt.msg.depth + 1).int32,
|
||||||
gas : childGasLimit,
|
gas : childGasLimit,
|
||||||
sender : p.sender,
|
sender : p.sender,
|
||||||
|
@ -336,7 +336,7 @@ const
|
||||||
input_data : cpt.memory.readPtr(p.memInPos),
|
input_data : cpt.memory.readPtr(p.memInPos),
|
||||||
input_size : p.memInLen.uint,
|
input_size : p.memInLen.uint,
|
||||||
value : toEvmc(p.value),
|
value : toEvmc(p.value),
|
||||||
flags : p.flags.uint32
|
flags : p.flags
|
||||||
)
|
)
|
||||||
c.execSubCall(msg, p)
|
c.execSubCall(msg, p)
|
||||||
else:
|
else:
|
||||||
|
@ -344,7 +344,7 @@ const
|
||||||
memPos = p.memOutPos,
|
memPos = p.memOutPos,
|
||||||
memLen = p.memOutLen,
|
memLen = p.memOutLen,
|
||||||
childMsg = Message(
|
childMsg = Message(
|
||||||
kind: evmcCallCode,
|
kind: EVMC_CALLCODE,
|
||||||
depth: cpt.msg.depth + 1,
|
depth: cpt.msg.depth + 1,
|
||||||
gas: childGasLimit,
|
gas: childGasLimit,
|
||||||
sender: p.sender,
|
sender: p.sender,
|
||||||
|
@ -401,7 +401,7 @@ const
|
||||||
msg = new(nimbus_message)
|
msg = new(nimbus_message)
|
||||||
c = cpt
|
c = cpt
|
||||||
msg[] = nimbus_message(
|
msg[] = nimbus_message(
|
||||||
kind : evmcDelegateCall.ord.evmc_call_kind,
|
kind : EVMC_DELEGATECALL,
|
||||||
depth : (cpt.msg.depth + 1).int32,
|
depth : (cpt.msg.depth + 1).int32,
|
||||||
gas : childGasLimit,
|
gas : childGasLimit,
|
||||||
sender : p.sender,
|
sender : p.sender,
|
||||||
|
@ -410,7 +410,7 @@ const
|
||||||
input_data : cpt.memory.readPtr(p.memInPos),
|
input_data : cpt.memory.readPtr(p.memInPos),
|
||||||
input_size : p.memInLen.uint,
|
input_size : p.memInLen.uint,
|
||||||
value : toEvmc(p.value),
|
value : toEvmc(p.value),
|
||||||
flags : p.flags.uint32
|
flags : p.flags
|
||||||
)
|
)
|
||||||
c.execSubCall(msg, p)
|
c.execSubCall(msg, p)
|
||||||
else:
|
else:
|
||||||
|
@ -418,7 +418,7 @@ const
|
||||||
memPos = p.memOutPos,
|
memPos = p.memOutPos,
|
||||||
memLen = p.memOutLen,
|
memLen = p.memOutLen,
|
||||||
childMsg = Message(
|
childMsg = Message(
|
||||||
kind: evmcDelegateCall,
|
kind: EVMC_DELEGATECALL,
|
||||||
depth: cpt.msg.depth + 1,
|
depth: cpt.msg.depth + 1,
|
||||||
gas: childGasLimit,
|
gas: childGasLimit,
|
||||||
sender: p.sender,
|
sender: p.sender,
|
||||||
|
@ -476,7 +476,7 @@ const
|
||||||
msg = new(nimbus_message)
|
msg = new(nimbus_message)
|
||||||
c = cpt
|
c = cpt
|
||||||
msg[] = nimbus_message(
|
msg[] = nimbus_message(
|
||||||
kind : evmcCall.ord.evmc_call_kind,
|
kind : EVMC_CALL,
|
||||||
depth : (cpt.msg.depth + 1).int32,
|
depth : (cpt.msg.depth + 1).int32,
|
||||||
gas : childGasLimit,
|
gas : childGasLimit,
|
||||||
sender : p.sender,
|
sender : p.sender,
|
||||||
|
@ -485,7 +485,7 @@ const
|
||||||
input_data : cpt.memory.readPtr(p.memInPos),
|
input_data : cpt.memory.readPtr(p.memInPos),
|
||||||
input_size : p.memInLen.uint,
|
input_size : p.memInLen.uint,
|
||||||
value : toEvmc(p.value),
|
value : toEvmc(p.value),
|
||||||
flags : p.flags.uint32
|
flags : p.flags
|
||||||
)
|
)
|
||||||
c.execSubCall(msg, p)
|
c.execSubCall(msg, p)
|
||||||
else:
|
else:
|
||||||
|
@ -493,7 +493,7 @@ const
|
||||||
memPos = p.memOutPos,
|
memPos = p.memOutPos,
|
||||||
memLen = p.memOutLen,
|
memLen = p.memOutLen,
|
||||||
childMsg = Message(
|
childMsg = Message(
|
||||||
kind: evmcCall,
|
kind: EVMC_CALL,
|
||||||
depth: cpt.msg.depth + 1,
|
depth: cpt.msg.depth + 1,
|
||||||
gas: childGasLimit,
|
gas: childGasLimit,
|
||||||
sender: p.sender,
|
sender: p.sender,
|
||||||
|
|
|
@ -140,7 +140,7 @@ const
|
||||||
msg = new(nimbus_message)
|
msg = new(nimbus_message)
|
||||||
c = cpt
|
c = cpt
|
||||||
msg[] = nimbus_message(
|
msg[] = nimbus_message(
|
||||||
kind: evmcCreate.ord.evmc_call_kind,
|
kind: EVMC_CREATE,
|
||||||
depth: (cpt.msg.depth + 1).int32,
|
depth: (cpt.msg.depth + 1).int32,
|
||||||
gas: createMsgGas,
|
gas: createMsgGas,
|
||||||
sender: cpt.msg.contractAddress,
|
sender: cpt.msg.contractAddress,
|
||||||
|
@ -153,7 +153,7 @@ const
|
||||||
else:
|
else:
|
||||||
cpt.execSubCreate(
|
cpt.execSubCreate(
|
||||||
childMsg = Message(
|
childMsg = Message(
|
||||||
kind: evmcCreate,
|
kind: EVMC_CREATE,
|
||||||
depth: cpt.msg.depth + 1,
|
depth: cpt.msg.depth + 1,
|
||||||
gas: createMsgGas,
|
gas: createMsgGas,
|
||||||
sender: cpt.msg.contractAddress,
|
sender: cpt.msg.contractAddress,
|
||||||
|
@ -222,7 +222,7 @@ const
|
||||||
msg = new(nimbus_message)
|
msg = new(nimbus_message)
|
||||||
c = cpt
|
c = cpt
|
||||||
msg[] = nimbus_message(
|
msg[] = nimbus_message(
|
||||||
kind: evmcCreate2.ord.evmc_call_kind,
|
kind: EVMC_CREATE2,
|
||||||
depth: (cpt.msg.depth + 1).int32,
|
depth: (cpt.msg.depth + 1).int32,
|
||||||
gas: createMsgGas,
|
gas: createMsgGas,
|
||||||
sender: cpt.msg.contractAddress,
|
sender: cpt.msg.contractAddress,
|
||||||
|
@ -236,7 +236,7 @@ const
|
||||||
cpt.execSubCreate(
|
cpt.execSubCreate(
|
||||||
salt = salt,
|
salt = salt,
|
||||||
childMsg = Message(
|
childMsg = Message(
|
||||||
kind: evmcCreate2,
|
kind: EVMC_CREATE2,
|
||||||
depth: cpt.msg.depth + 1,
|
depth: cpt.msg.depth + 1,
|
||||||
gas: createMsgGas,
|
gas: createMsgGas,
|
||||||
sender: cpt.msg.contractAddress,
|
sender: cpt.msg.contractAddress,
|
||||||
|
|
|
@ -20,7 +20,6 @@ import
|
||||||
../gas_costs,
|
../gas_costs,
|
||||||
eth/common,
|
eth/common,
|
||||||
eth/common/eth_types,
|
eth/common/eth_types,
|
||||||
macros,
|
|
||||||
stint
|
stint
|
||||||
|
|
||||||
when defined(evmc_enabled):
|
when defined(evmc_enabled):
|
||||||
|
@ -64,7 +63,7 @@ proc gasEip2929AccountCheck*(c: Computation; address: EthAddress, slot: UInt256)
|
||||||
|
|
||||||
template checkInStaticContext*(c: Computation) =
|
template checkInStaticContext*(c: Computation) =
|
||||||
## Verify static context in handler function, raise an error otherwise
|
## Verify static context in handler function, raise an error otherwise
|
||||||
if emvcStatic == c.msg.flags:
|
if EVMC_STATIC in c.msg.flags:
|
||||||
# TODO: if possible, this check only appear
|
# TODO: if possible, this check only appear
|
||||||
# when fork >= FkByzantium
|
# when fork >= FkByzantium
|
||||||
raise newException(
|
raise newException(
|
||||||
|
|
|
@ -21,7 +21,6 @@ import
|
||||||
../../stack,
|
../../stack,
|
||||||
../../types,
|
../../types,
|
||||||
../gas_costs,
|
../gas_costs,
|
||||||
../gas_meter,
|
|
||||||
../op_codes,
|
../op_codes,
|
||||||
../utils/utils_numeric,
|
../utils/utils_numeric,
|
||||||
./oph_defs,
|
./oph_defs,
|
||||||
|
@ -33,6 +32,7 @@ import
|
||||||
|
|
||||||
when not defined(evmc_enabled):
|
when not defined(evmc_enabled):
|
||||||
import
|
import
|
||||||
|
../gas_meter,
|
||||||
../../state,
|
../../state,
|
||||||
../../../db/accounts_cache
|
../../../db/accounts_cache
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ const
|
||||||
k.cpt.memory.extend(pos, len)
|
k.cpt.memory.extend(pos, len)
|
||||||
k.cpt.output = k.cpt.memory.read(pos, len)
|
k.cpt.output = k.cpt.memory.read(pos, len)
|
||||||
# setError(msg, false) will signal cheap revert
|
# setError(msg, false) will signal cheap revert
|
||||||
k.cpt.setError("REVERT opcode executed", false)
|
k.cpt.setError(EVMC_REVERT, "REVERT opcode executed", false)
|
||||||
|
|
||||||
|
|
||||||
invalidOp: Vm2OpFn = proc(k: var Vm2Ctx) =
|
invalidOp: Vm2OpFn = proc(k: var Vm2Ctx) =
|
||||||
|
|
|
@ -102,7 +102,7 @@ proc selectVM(c: Computation, fork: EVMFork, shouldPrepareTracer: bool)
|
||||||
|
|
||||||
proc beforeExecCall(c: Computation) =
|
proc beforeExecCall(c: Computation) =
|
||||||
c.snapshot()
|
c.snapshot()
|
||||||
if c.msg.kind == evmcCall:
|
if c.msg.kind == EVMC_CALL:
|
||||||
c.vmState.mutateStateDB:
|
c.vmState.mutateStateDB:
|
||||||
db.subBalance(c.msg.sender, c.msg.value)
|
db.subBalance(c.msg.sender, c.msg.value)
|
||||||
db.addBalance(c.msg.contractAddress, c.msg.value)
|
db.addBalance(c.msg.contractAddress, c.msg.value)
|
||||||
|
@ -182,7 +182,7 @@ const
|
||||||
]
|
]
|
||||||
|
|
||||||
func msgToOp(msg: Message): Op =
|
func msgToOp(msg: Message): Op =
|
||||||
if emvcStatic == msg.flags:
|
if EVMC_STATIC in msg.flags:
|
||||||
return STATICCALL
|
return STATICCALL
|
||||||
MsgKindToOp[msg.kind]
|
MsgKindToOp[msg.kind]
|
||||||
|
|
||||||
|
@ -212,18 +212,14 @@ proc afterExec(c: Computation)
|
||||||
|
|
||||||
if c.msg.depth > 0:
|
if c.msg.depth > 0:
|
||||||
let gasUsed = c.msg.gas - c.gasMeter.gasRemaining
|
let gasUsed = c.msg.gas - c.gasMeter.gasRemaining
|
||||||
let error = if c.isError:
|
c.vmState.captureExit(c, c.output, gasUsed, c.errorOpt)
|
||||||
some(c.error.info)
|
|
||||||
else:
|
|
||||||
none(string)
|
|
||||||
c.vmState.captureExit(c, c.output, gasUsed, error)
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Public functions
|
# Public functions
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
proc executeOpcodes*(c: Computation, shouldPrepareTracer: bool = true)
|
proc executeOpcodes*(c: Computation, shouldPrepareTracer: bool = true)
|
||||||
{.gcsafe, raises: [CatchableError].} =
|
{.gcsafe, raises: [].} =
|
||||||
let fork = c.fork
|
let fork = c.fork
|
||||||
|
|
||||||
block:
|
block:
|
||||||
|
@ -263,7 +259,6 @@ proc executeOpcodes*(c: Computation, shouldPrepareTracer: bool = true)
|
||||||
|
|
||||||
if c.isError() and c.continuation.isNil:
|
if c.isError() and c.continuation.isNil:
|
||||||
if c.tracingEnabled: c.traceError()
|
if c.tracingEnabled: c.traceError()
|
||||||
#trace "executeOpcodes error", msg=c.error.info
|
|
||||||
|
|
||||||
when vm_use_recursion:
|
when vm_use_recursion:
|
||||||
# Recursion with tiny stack frame per level.
|
# Recursion with tiny stack frame per level.
|
||||||
|
|
|
@ -11,4 +11,4 @@
|
||||||
import ./types
|
import ./types
|
||||||
|
|
||||||
proc isCreate*(message: Message): bool =
|
proc isCreate*(message: Message): bool =
|
||||||
message.kind in {evmcCreate, evmcCreate2}
|
message.kind in {EVMC_CREATE, EVMC_CREATE2}
|
||||||
|
|
|
@ -17,7 +17,8 @@ import
|
||||||
nimcrypto/[ripemd, sha2, utils], bncurve/[fields, groups],
|
nimcrypto/[ripemd, sha2, utils], bncurve/[fields, groups],
|
||||||
../common/evmforks,
|
../common/evmforks,
|
||||||
../core/eip4844,
|
../core/eip4844,
|
||||||
./modexp
|
./modexp,
|
||||||
|
./computation
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
|
@ -48,7 +49,7 @@ type
|
||||||
# paBlsMapG1
|
# paBlsMapG1
|
||||||
# paBlsMapG2
|
# paBlsMapG2
|
||||||
# Cancun
|
# Cancun
|
||||||
|
|
||||||
|
|
||||||
proc getMaxPrecompileAddr(fork: EVMFork): PrecompileAddresses =
|
proc getMaxPrecompileAddr(fork: EVMFork): PrecompileAddresses =
|
||||||
if fork < FkByzantium: paIdentity
|
if fork < FkByzantium: paIdentity
|
||||||
|
@ -74,9 +75,9 @@ iterator activePrecompiles*(fork: EVMFork): EthAddress =
|
||||||
res[^1] = c.byte
|
res[^1] = c.byte
|
||||||
yield res
|
yield res
|
||||||
|
|
||||||
proc getSignature(computation: Computation): (array[32, byte], Signature) =
|
proc getSignature(c: Computation): (array[32, byte], Signature) =
|
||||||
# input is Hash, V, R, S
|
# input is Hash, V, R, S
|
||||||
template data: untyped = computation.msg.data
|
template data: untyped = c.msg.data
|
||||||
var bytes: array[65, byte] # will hold R[32], S[32], V[1], in that order
|
var bytes: array[65, byte] # will hold R[32], S[32], V[1], in that order
|
||||||
let maxPos = min(data.high, 127)
|
let maxPos = min(data.high, 127)
|
||||||
|
|
||||||
|
@ -100,7 +101,7 @@ proc getSignature(computation: Computation): (array[32, byte], Signature) =
|
||||||
|
|
||||||
let sig = Signature.fromRaw(bytes)
|
let sig = Signature.fromRaw(bytes)
|
||||||
if sig.isErr:
|
if sig.isErr:
|
||||||
raise newException(ValidationError, "Could not recover signature computation")
|
raise newException(ValidationError, "Could not recover signature c")
|
||||||
result[1] = sig[]
|
result[1] = sig[]
|
||||||
|
|
||||||
# extract message hash, only need to copy when there is a valid signature
|
# extract message hash, only need to copy when there is a valid signature
|
||||||
|
@ -143,49 +144,49 @@ proc getFR(data: openArray[byte]): FR =
|
||||||
if not result.fromBytes2(data):
|
if not result.fromBytes2(data):
|
||||||
raise newException(ValidationError, "Could not get FR value")
|
raise newException(ValidationError, "Could not get FR value")
|
||||||
|
|
||||||
proc ecRecover*(computation: Computation) =
|
proc ecRecover*(c: Computation) =
|
||||||
computation.gasMeter.consumeGas(
|
c.gasMeter.consumeGas(
|
||||||
GasECRecover,
|
GasECRecover,
|
||||||
reason="ECRecover Precompile")
|
reason="ECRecover Precompile")
|
||||||
|
|
||||||
var
|
var
|
||||||
(msgHash, sig) = computation.getSignature()
|
(msgHash, sig) = c.getSignature()
|
||||||
|
|
||||||
var pubkey = recover(sig, SkMessage(msgHash))
|
var pubkey = recover(sig, SkMessage(msgHash))
|
||||||
if pubkey.isErr:
|
if pubkey.isErr:
|
||||||
raise newException(ValidationError, "Could not derive public key from computation")
|
raise newException(ValidationError, "Could not derive public key from c")
|
||||||
|
|
||||||
computation.output.setLen(32)
|
c.output.setLen(32)
|
||||||
computation.output[12..31] = pubkey[].toCanonicalAddress()
|
c.output[12..31] = pubkey[].toCanonicalAddress()
|
||||||
#trace "ECRecover precompile", derivedKey = pubkey[].toCanonicalAddress()
|
#trace "ECRecover precompile", derivedKey = pubkey[].toCanonicalAddress()
|
||||||
|
|
||||||
proc sha256*(computation: Computation) =
|
proc sha256*(c: Computation) =
|
||||||
let
|
let
|
||||||
wordCount = wordCount(computation.msg.data.len)
|
wordCount = wordCount(c.msg.data.len)
|
||||||
gasFee = GasSHA256 + wordCount * GasSHA256Word
|
gasFee = GasSHA256 + wordCount * GasSHA256Word
|
||||||
|
|
||||||
computation.gasMeter.consumeGas(gasFee, reason="SHA256 Precompile")
|
c.gasMeter.consumeGas(gasFee, reason="SHA256 Precompile")
|
||||||
computation.output = @(sha2.sha256.digest(computation.msg.data).data)
|
c.output = @(sha2.sha256.digest(c.msg.data).data)
|
||||||
#trace "SHA256 precompile", output = computation.output.toHex
|
#trace "SHA256 precompile", output = c.output.toHex
|
||||||
|
|
||||||
proc ripemd160*(computation: Computation) =
|
proc ripemd160*(c: Computation) =
|
||||||
let
|
let
|
||||||
wordCount = wordCount(computation.msg.data.len)
|
wordCount = wordCount(c.msg.data.len)
|
||||||
gasFee = GasRIPEMD160 + wordCount * GasRIPEMD160Word
|
gasFee = GasRIPEMD160 + wordCount * GasRIPEMD160Word
|
||||||
|
|
||||||
computation.gasMeter.consumeGas(gasFee, reason="RIPEMD160 Precompile")
|
c.gasMeter.consumeGas(gasFee, reason="RIPEMD160 Precompile")
|
||||||
computation.output.setLen(32)
|
c.output.setLen(32)
|
||||||
computation.output[12..31] = @(ripemd.ripemd160.digest(computation.msg.data).data)
|
c.output[12..31] = @(ripemd.ripemd160.digest(c.msg.data).data)
|
||||||
#trace "RIPEMD160 precompile", output = computation.output.toHex
|
#trace "RIPEMD160 precompile", output = c.output.toHex
|
||||||
|
|
||||||
proc identity*(computation: Computation) =
|
proc identity*(c: Computation) =
|
||||||
let
|
let
|
||||||
wordCount = wordCount(computation.msg.data.len)
|
wordCount = wordCount(c.msg.data.len)
|
||||||
gasFee = GasIdentity + wordCount * GasIdentityWord
|
gasFee = GasIdentity + wordCount * GasIdentityWord
|
||||||
|
|
||||||
computation.gasMeter.consumeGas(gasFee, reason="Identity Precompile")
|
c.gasMeter.consumeGas(gasFee, reason="Identity Precompile")
|
||||||
computation.output = computation.msg.data
|
c.output = c.msg.data
|
||||||
#trace "Identity precompile", output = computation.output.toHex
|
#trace "Identity precompile", output = c.output.toHex
|
||||||
|
|
||||||
proc modExpFee(c: Computation, baseLen, expLen, modLen: UInt256, fork: EVMFork): GasInt =
|
proc modExpFee(c: Computation, baseLen, expLen, modLen: UInt256, fork: EVMFork): GasInt =
|
||||||
template data: untyped {.dirty.} =
|
template data: untyped {.dirty.} =
|
||||||
|
@ -287,16 +288,16 @@ proc modExp*(c: Computation, fork: EVMFork = FkByzantium) =
|
||||||
c.output = newSeq[byte](modLen)
|
c.output = newSeq[byte](modLen)
|
||||||
c.output[^output.len..^1] = output[0..^1]
|
c.output[^output.len..^1] = output[0..^1]
|
||||||
|
|
||||||
proc bn256ecAdd*(computation: Computation, fork: EVMFork = FkByzantium) =
|
proc bn256ecAdd*(c: Computation, fork: EVMFork = FkByzantium) =
|
||||||
let gasFee = if fork < FkIstanbul: GasECAdd else: GasECAddIstanbul
|
let gasFee = if fork < FkIstanbul: GasECAdd else: GasECAddIstanbul
|
||||||
computation.gasMeter.consumeGas(gasFee, reason = "ecAdd Precompile")
|
c.gasMeter.consumeGas(gasFee, reason = "ecAdd Precompile")
|
||||||
|
|
||||||
var
|
var
|
||||||
input: array[128, byte]
|
input: array[128, byte]
|
||||||
output: array[64, byte]
|
output: array[64, byte]
|
||||||
# Padding data
|
# Padding data
|
||||||
let len = min(computation.msg.data.len, 128) - 1
|
let len = min(c.msg.data.len, 128) - 1
|
||||||
input[0..len] = computation.msg.data[0..len]
|
input[0..len] = c.msg.data[0..len]
|
||||||
var p1 = G1.getPoint(input.toOpenArray(0, 63))
|
var p1 = G1.getPoint(input.toOpenArray(0, 63))
|
||||||
var p2 = G1.getPoint(input.toOpenArray(64, 127))
|
var p2 = G1.getPoint(input.toOpenArray(64, 127))
|
||||||
var apo = (p1 + p2).toAffine()
|
var apo = (p1 + p2).toAffine()
|
||||||
|
@ -304,19 +305,19 @@ proc bn256ecAdd*(computation: Computation, fork: EVMFork = FkByzantium) =
|
||||||
# we can discard here because we supply proper buffer
|
# we can discard here because we supply proper buffer
|
||||||
discard apo.get().toBytes(output)
|
discard apo.get().toBytes(output)
|
||||||
|
|
||||||
computation.output = @output
|
c.output = @output
|
||||||
|
|
||||||
proc bn256ecMul*(computation: Computation, fork: EVMFork = FkByzantium) =
|
proc bn256ecMul*(c: Computation, fork: EVMFork = FkByzantium) =
|
||||||
let gasFee = if fork < FkIstanbul: GasECMul else: GasECMulIstanbul
|
let gasFee = if fork < FkIstanbul: GasECMul else: GasECMulIstanbul
|
||||||
computation.gasMeter.consumeGas(gasFee, reason="ecMul Precompile")
|
c.gasMeter.consumeGas(gasFee, reason="ecMul Precompile")
|
||||||
|
|
||||||
var
|
var
|
||||||
input: array[96, byte]
|
input: array[96, byte]
|
||||||
output: array[64, byte]
|
output: array[64, byte]
|
||||||
|
|
||||||
# Padding data
|
# Padding data
|
||||||
let len = min(computation.msg.data.len, 96) - 1
|
let len = min(c.msg.data.len, 96) - 1
|
||||||
input[0..len] = computation.msg.data[0..len]
|
input[0..len] = c.msg.data[0..len]
|
||||||
var p1 = G1.getPoint(input.toOpenArray(0, 63))
|
var p1 = G1.getPoint(input.toOpenArray(0, 63))
|
||||||
var fr = getFR(input.toOpenArray(64, 95))
|
var fr = getFR(input.toOpenArray(64, 95))
|
||||||
var apo = (p1 * fr).toAffine()
|
var apo = (p1 * fr).toAffine()
|
||||||
|
@ -324,10 +325,10 @@ proc bn256ecMul*(computation: Computation, fork: EVMFork = FkByzantium) =
|
||||||
# we can discard here because we supply buffer of proper size
|
# we can discard here because we supply buffer of proper size
|
||||||
discard apo.get().toBytes(output)
|
discard apo.get().toBytes(output)
|
||||||
|
|
||||||
computation.output = @output
|
c.output = @output
|
||||||
|
|
||||||
proc bn256ecPairing*(computation: Computation, fork: EVMFork = FkByzantium) =
|
proc bn256ecPairing*(c: Computation, fork: EVMFork = FkByzantium) =
|
||||||
let msglen = len(computation.msg.data)
|
let msglen = len(c.msg.data)
|
||||||
if msglen mod 192 != 0:
|
if msglen mod 192 != 0:
|
||||||
raise newException(ValidationError, "Invalid input length")
|
raise newException(ValidationError, "Invalid input length")
|
||||||
|
|
||||||
|
@ -336,7 +337,7 @@ proc bn256ecPairing*(computation: Computation, fork: EVMFork = FkByzantium) =
|
||||||
GasECPairingBase + numPoints * GasECPairingPerPoint
|
GasECPairingBase + numPoints * GasECPairingPerPoint
|
||||||
else:
|
else:
|
||||||
GasECPairingBaseIstanbul + numPoints * GasECPairingPerPointIstanbul
|
GasECPairingBaseIstanbul + numPoints * GasECPairingPerPointIstanbul
|
||||||
computation.gasMeter.consumeGas(gasFee, reason="ecPairing Precompile")
|
c.gasMeter.consumeGas(gasFee, reason="ecPairing Precompile")
|
||||||
|
|
||||||
var output: array[32, byte]
|
var output: array[32, byte]
|
||||||
if msglen == 0:
|
if msglen == 0:
|
||||||
|
@ -351,9 +352,9 @@ proc bn256ecPairing*(computation: Computation, fork: EVMFork = FkByzantium) =
|
||||||
for i in 0..<count:
|
for i in 0..<count:
|
||||||
let s = i * 192
|
let s = i * 192
|
||||||
# Loading AffinePoint[G1], bytes from [0..63]
|
# Loading AffinePoint[G1], bytes from [0..63]
|
||||||
var p1 = G1.getPoint(computation.msg.data.toOpenArray(s, s + 63))
|
var p1 = G1.getPoint(c.msg.data.toOpenArray(s, s + 63))
|
||||||
# Loading AffinePoint[G2], bytes from [64..191]
|
# Loading AffinePoint[G2], bytes from [64..191]
|
||||||
var p2 = G2.getPoint(computation.msg.data.toOpenArray(s + 64, s + 191))
|
var p2 = G2.getPoint(c.msg.data.toOpenArray(s + 64, s + 191))
|
||||||
# Accumulate pairing result
|
# Accumulate pairing result
|
||||||
acc = acc * pairing(p1, p2)
|
acc = acc * pairing(p1, p2)
|
||||||
|
|
||||||
|
@ -361,7 +362,7 @@ proc bn256ecPairing*(computation: Computation, fork: EVMFork = FkByzantium) =
|
||||||
# we can discard here because we supply buffer of proper size
|
# we can discard here because we supply buffer of proper size
|
||||||
discard BNU256.one().toBytes(output)
|
discard BNU256.one().toBytes(output)
|
||||||
|
|
||||||
computation.output = @output
|
c.output = @output
|
||||||
|
|
||||||
proc blake2bf*(c: Computation) =
|
proc blake2bf*(c: Computation) =
|
||||||
template input: untyped =
|
template input: untyped =
|
||||||
|
@ -685,45 +686,45 @@ proc pointEvaluation*(c: Computation) =
|
||||||
# return a constant
|
# return a constant
|
||||||
c.output = @PointEvaluationResult
|
c.output = @PointEvaluationResult
|
||||||
|
|
||||||
proc execPrecompiles*(computation: Computation, fork: EVMFork): bool {.inline.} =
|
proc execPrecompiles*(c: Computation, fork: EVMFork): bool {.inline.} =
|
||||||
for i in 0..18:
|
for i in 0..18:
|
||||||
if computation.msg.codeAddress[i] != 0: return
|
if c.msg.codeAddress[i] != 0: return
|
||||||
|
|
||||||
let lb = computation.msg.codeAddress[19]
|
let lb = c.msg.codeAddress[19]
|
||||||
if validPrecompileAddr(lb, fork):
|
if not validPrecompileAddr(lb, fork):
|
||||||
result = true
|
return
|
||||||
let precompile = PrecompileAddresses(lb)
|
|
||||||
#trace "Call precompile", precompile = precompile, codeAddr = computation.msg.codeAddress
|
let precompile = PrecompileAddresses(lb)
|
||||||
try:
|
try:
|
||||||
case precompile
|
case precompile
|
||||||
of paEcRecover: ecRecover(computation)
|
of paEcRecover: ecRecover(c)
|
||||||
of paSha256: sha256(computation)
|
of paSha256: sha256(c)
|
||||||
of paRipeMd160: ripemd160(computation)
|
of paRipeMd160: ripemd160(c)
|
||||||
of paIdentity: identity(computation)
|
of paIdentity: identity(c)
|
||||||
of paModExp: modExp(computation, fork)
|
of paModExp: modExp(c, fork)
|
||||||
of paEcAdd: bn256ecAdd(computation, fork)
|
of paEcAdd: bn256ecAdd(c, fork)
|
||||||
of paEcMul: bn256ecMul(computation, fork)
|
of paEcMul: bn256ecMul(c, fork)
|
||||||
of paPairing: bn256ecPairing(computation, fork)
|
of paPairing: bn256ecPairing(c, fork)
|
||||||
of paBlake2bf: blake2bf(computation)
|
of paBlake2bf: blake2bf(c)
|
||||||
of paPointEvaluation: pointEvaluation(computation)
|
of paPointEvaluation: pointEvaluation(c)
|
||||||
#else: discard
|
#else: discard
|
||||||
# EIP 2537: disabled
|
# EIP 2537: disabled
|
||||||
# reason: not included in berlin
|
# reason: not included in berlin
|
||||||
# of paBlsG1Add: blsG1Add(computation)
|
# of paBlsG1Add: blsG1Add(c)
|
||||||
# of paBlsG1Mul: blsG1Mul(computation)
|
# of paBlsG1Mul: blsG1Mul(c)
|
||||||
# of paBlsG1MultiExp: blsG1MultiExp(computation)
|
# of paBlsG1MultiExp: blsG1MultiExp(c)
|
||||||
# of paBlsG2Add: blsG2Add(computation)
|
# of paBlsG2Add: blsG2Add(c)
|
||||||
# of paBlsG2Mul: blsG2Mul(computation)
|
# of paBlsG2Mul: blsG2Mul(c)
|
||||||
# of paBlsG2MultiExp: blsG2MultiExp(computation)
|
# of paBlsG2MultiExp: blsG2MultiExp(c)
|
||||||
# of paBlsPairing: blsPairing(computation)
|
# of paBlsPairing: blsPairing(c)
|
||||||
# of paBlsMapG1: blsMapG1(computation)
|
# of paBlsMapG1: blsMapG1(c)
|
||||||
# of paBlsMapG2: blsMapG2(computation)
|
# of paBlsMapG2: blsMapG2(c)
|
||||||
except OutOfGas as e:
|
except OutOfGas as e:
|
||||||
# cannot use setError here, cyclic dependency
|
c.setError(EVMC_OUT_OF_GAS, e.msg, true)
|
||||||
computation.error = Error(info: e.msg, burnsGas: true)
|
except CatchableError as e:
|
||||||
except CatchableError as e:
|
if fork >= FkByzantium and precompile > paIdentity:
|
||||||
if fork >= FkByzantium and precompile > paIdentity:
|
c.setError(EVMC_PRECOMPILE_FAILURE, e.msg, true)
|
||||||
computation.error = Error(info: e.msg, burnsGas: true)
|
else:
|
||||||
else:
|
# swallow any other precompiles errors
|
||||||
# swallow any other precompiles errors
|
debug "execPrecompiles validation error", msg=e.msg
|
||||||
debug "execPrecompiles validation error", msg=e.msg
|
true
|
||||||
|
|
|
@ -35,7 +35,6 @@ proc init(
|
||||||
asyncFactory: AsyncOperationFactory = AsyncOperationFactory(maybeDataSource: none[AsyncDataSource]()))
|
asyncFactory: AsyncOperationFactory = AsyncOperationFactory(maybeDataSource: none[AsyncDataSource]()))
|
||||||
{.gcsafe.} =
|
{.gcsafe.} =
|
||||||
## Initialisation helper
|
## Initialisation helper
|
||||||
self.prevHeaders = @[]
|
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.timestamp = timestamp
|
self.timestamp = timestamp
|
||||||
self.gasLimit = gasLimit
|
self.gasLimit = gasLimit
|
||||||
|
@ -297,17 +296,6 @@ method getAncestorHash*(
|
||||||
else:
|
else:
|
||||||
result = db.getBlockHash(blockNumber)
|
result = db.getBlockHash(blockNumber)
|
||||||
|
|
||||||
#TODO: should we use deque here?
|
|
||||||
# someday we may revive this code when
|
|
||||||
# we already have working miner
|
|
||||||
when false:
|
|
||||||
let idx = ancestorDepth.toInt
|
|
||||||
if idx >= vmState.prevHeaders.len:
|
|
||||||
return
|
|
||||||
|
|
||||||
var header = vmState.prevHeaders[idx]
|
|
||||||
result = header.hash
|
|
||||||
|
|
||||||
proc readOnlyStateDB*(vmState: BaseVMState): ReadOnlyStateDB {.inline.} =
|
proc readOnlyStateDB*(vmState: BaseVMState): ReadOnlyStateDB {.inline.} =
|
||||||
ReadOnlyStateDB(vmState.stateDB)
|
ReadOnlyStateDB(vmState.stateDB)
|
||||||
|
|
||||||
|
|
|
@ -37,16 +37,6 @@ iterator storage(ctx: LegacyTracer, compDepth: int): UInt256 =
|
||||||
for key in ctx.storageKeys[compDepth]:
|
for key in ctx.storageKeys[compDepth]:
|
||||||
yield key
|
yield key
|
||||||
|
|
||||||
template stripLeadingZeros(value: string): string =
|
|
||||||
var cidx = 0
|
|
||||||
# ignore the last character so we retain '0' on zero value
|
|
||||||
while cidx < value.len - 1 and value[cidx] == '0':
|
|
||||||
cidx.inc
|
|
||||||
value[cidx .. ^1]
|
|
||||||
|
|
||||||
proc encodeHexInt(x: SomeInteger): JsonNode =
|
|
||||||
%("0x" & x.toHex.stripLeadingZeros.toLowerAscii)
|
|
||||||
|
|
||||||
proc newLegacyTracer*(flags: set[TracerFlags]): LegacyTracer =
|
proc newLegacyTracer*(flags: set[TracerFlags]): LegacyTracer =
|
||||||
let trace = newJObject()
|
let trace = newJObject()
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,14 @@ import
|
||||||
../db/accounts_cache,
|
../db/accounts_cache,
|
||||||
../common/[common, evmforks]
|
../common/[common, evmforks]
|
||||||
|
|
||||||
|
# this import not guarded by `when defined(evmc_enabled)`
|
||||||
|
# because we want to use evmc types such as evmc_call_kind
|
||||||
|
# and evmc_flags
|
||||||
|
import
|
||||||
|
evmc/evmc
|
||||||
|
|
||||||
|
export evmc
|
||||||
|
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
when defined(evmc_enabled):
|
when defined(evmc_enabled):
|
||||||
|
@ -35,27 +43,26 @@ type
|
||||||
ClearCache
|
ClearCache
|
||||||
|
|
||||||
BaseVMState* = ref object of RootObj
|
BaseVMState* = ref object of RootObj
|
||||||
prevHeaders* : seq[BlockHeader]
|
com* : CommonRef
|
||||||
com* : CommonRef
|
gasPool* : GasInt
|
||||||
gasPool* : GasInt
|
parent* : BlockHeader
|
||||||
parent* : BlockHeader
|
timestamp* : EthTime
|
||||||
timestamp* : EthTime
|
gasLimit* : GasInt
|
||||||
gasLimit* : GasInt
|
fee* : Option[UInt256]
|
||||||
fee* : Option[UInt256]
|
prevRandao* : Hash256
|
||||||
prevRandao* : Hash256
|
blockDifficulty* : UInt256
|
||||||
blockDifficulty*: UInt256
|
flags* : set[VMFlag]
|
||||||
flags* : set[VMFlag]
|
tracer* : TracerRef
|
||||||
tracer* : TracerRef
|
receipts* : seq[Receipt]
|
||||||
receipts* : seq[Receipt]
|
stateDB* : AccountsCache
|
||||||
stateDB* : AccountsCache
|
|
||||||
cumulativeGasUsed*: GasInt
|
cumulativeGasUsed*: GasInt
|
||||||
txOrigin* : EthAddress
|
txOrigin* : EthAddress
|
||||||
txGasPrice* : GasInt
|
txGasPrice* : GasInt
|
||||||
txVersionedHashes*: VersionedHashes
|
txVersionedHashes*: VersionedHashes
|
||||||
gasCosts* : GasCosts
|
gasCosts* : GasCosts
|
||||||
fork* : EVMFork
|
fork* : EVMFork
|
||||||
minerAddress* : EthAddress
|
minerAddress* : EthAddress
|
||||||
asyncFactory* : AsyncOperationFactory
|
asyncFactory* : AsyncOperationFactory
|
||||||
|
|
||||||
Computation* = ref object
|
Computation* = ref object
|
||||||
# The execution computation
|
# The execution computation
|
||||||
|
@ -82,23 +89,17 @@ type
|
||||||
continuation*: proc() {.gcsafe, raises: [CatchableError].}
|
continuation*: proc() {.gcsafe, raises: [CatchableError].}
|
||||||
|
|
||||||
Error* = ref object
|
Error* = ref object
|
||||||
info*: string
|
statusCode*: evmc_status_code
|
||||||
burnsGas*: bool
|
info* : string
|
||||||
|
burnsGas* : bool
|
||||||
|
|
||||||
GasMeter* = object
|
GasMeter* = object
|
||||||
gasRefunded*: GasInt
|
gasRefunded*: GasInt
|
||||||
gasRemaining*: GasInt
|
gasRemaining*: GasInt
|
||||||
|
|
||||||
CallKind* = enum
|
CallKind* = evmc_call_kind
|
||||||
evmcCall = 0, # CALL
|
|
||||||
evmcDelegateCall = 1, # DELEGATECALL
|
|
||||||
evmcCallCode = 2, # CALLCODE
|
|
||||||
evmcCreate = 3, # CREATE
|
|
||||||
evmcCreate2 = 4 # CREATE2
|
|
||||||
|
|
||||||
MsgFlags* = enum
|
MsgFlags* = evmc_flags
|
||||||
emvcNoFlags = 0
|
|
||||||
emvcStatic = 1
|
|
||||||
|
|
||||||
Message* = ref object
|
Message* = ref object
|
||||||
kind*: CallKind
|
kind*: CallKind
|
||||||
|
|
|
@ -66,7 +66,7 @@ proc hostToComputationMessage*(msg: EvmcMessage): Message =
|
||||||
# When input size is zero, input data pointer may be null.
|
# When input size is zero, input data pointer may be null.
|
||||||
data: if msg.input_size <= 0: @[]
|
data: if msg.input_size <= 0: @[]
|
||||||
else: @(makeOpenArray(msg.input_data, msg.input_size.int)),
|
else: @(makeOpenArray(msg.input_data, msg.input_size.int)),
|
||||||
flags: if msg.isStatic: emvcStatic else: emvcNoFlags
|
flags: msg.flags
|
||||||
)
|
)
|
||||||
|
|
||||||
func intrinsicGas*(call: CallParams, vmState: BaseVMState): GasInt {.inline.} =
|
func intrinsicGas*(call: CallParams, vmState: BaseVMState): GasInt {.inline.} =
|
||||||
|
@ -206,9 +206,9 @@ when defined(evmc_enabled):
|
||||||
if callResult.status_code == EVMC_SUCCESS:
|
if callResult.status_code == EVMC_SUCCESS:
|
||||||
c.error = nil
|
c.error = nil
|
||||||
elif callResult.status_code == EVMC_REVERT:
|
elif callResult.status_code == EVMC_REVERT:
|
||||||
c.setError("EVMC_REVERT", false)
|
c.setError(EVMC_REVERT, false)
|
||||||
else:
|
else:
|
||||||
c.setError($callResult.status_code, true)
|
c.setError(callResult.status_code, true)
|
||||||
|
|
||||||
c.gasMeter.gasRemaining = callResult.gas_left
|
c.gasMeter.gasRemaining = callResult.gas_left
|
||||||
c.msg.contractAddress = callResult.create_address.fromEvmc
|
c.msg.contractAddress = callResult.create_address.fromEvmc
|
||||||
|
@ -278,12 +278,7 @@ proc finishRunningComputation(host: TransactionHost, call: CallParams): CallResu
|
||||||
let gasRemaining = calculateAndPossiblyRefundGas(host, call)
|
let gasRemaining = calculateAndPossiblyRefundGas(host, call)
|
||||||
# evm gas used without intrinsic gas
|
# evm gas used without intrinsic gas
|
||||||
let gasUsed = host.msg.gas - gasRemaining
|
let gasUsed = host.msg.gas - gasRemaining
|
||||||
let error = if c.isError:
|
host.vmState.captureEnd(c, c.output, gasUsed, c.errorOpt)
|
||||||
some(c.error.info)
|
|
||||||
else:
|
|
||||||
none(string)
|
|
||||||
|
|
||||||
host.vmState.captureEnd(c, c.output, gasUsed, error)
|
|
||||||
|
|
||||||
result.isError = c.isError
|
result.isError = c.isError
|
||||||
result.gasUsed = call.gasLimit - gasRemaining
|
result.gasUsed = call.gasLimit - gasRemaining
|
||||||
|
|
|
@ -83,11 +83,11 @@ proc accessStorage(p: evmc_host_context, address: var evmc_address,
|
||||||
|
|
||||||
proc getTransientStorage(p: evmc_host_context, address: var evmc_address,
|
proc getTransientStorage(p: evmc_host_context, address: var evmc_address,
|
||||||
key: var evmc_bytes32): evmc_bytes32
|
key: var evmc_bytes32): evmc_bytes32
|
||||||
{.cdecl, raises: [RlpError].} =
|
{.cdecl, raises: [].} =
|
||||||
toHost(p).getTransientStorage(address.fromEvmc, key.flip256.fromEvmc).toEvmc.flip256
|
toHost(p).getTransientStorage(address.fromEvmc, key.flip256.fromEvmc).toEvmc.flip256
|
||||||
|
|
||||||
proc setTransientStorage(p: evmc_host_context, address: var evmc_address,
|
proc setTransientStorage(p: evmc_host_context, address: var evmc_address,
|
||||||
key, value: var evmc_bytes32) {.cdecl, raises: [RlpError].} =
|
key, value: var evmc_bytes32) {.cdecl, raises: [].} =
|
||||||
toHost(p).setTransientStorage(address.fromEvmc, key.flip256.fromEvmc, value.flip256.fromEvmc)
|
toHost(p).setTransientStorage(address.fromEvmc, key.flip256.fromEvmc, value.flip256.fromEvmc)
|
||||||
|
|
||||||
let hostInterface = evmc_host_interface(
|
let hostInterface = evmc_host_interface(
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import
|
import
|
||||||
./host_types, evmc/evmc, stew/ranges/ptr_arith,
|
./host_types, evmc/evmc,
|
||||||
".."/[vm_types, vm_computation, vm_state_transactions]
|
".."/[vm_types, vm_computation, vm_state_transactions]
|
||||||
|
|
||||||
proc evmcReleaseResult(result: var evmc_result) {.cdecl.} =
|
proc evmcReleaseResult(result: var evmc_result) {.cdecl.} =
|
||||||
|
@ -56,9 +56,7 @@ proc evmcExecute(vm: ptr evmc_vm, hostInterface: ptr evmc_host_interface,
|
||||||
|
|
||||||
return evmc_result(
|
return evmc_result(
|
||||||
# Standard EVMC result, if a bit generic.
|
# Standard EVMC result, if a bit generic.
|
||||||
status_code: if c.isSuccess: EVMC_SUCCESS
|
status_code: c.statusCode,
|
||||||
elif not c.error.burnsGas: EVMC_REVERT
|
|
||||||
else: EVMC_FAILURE,
|
|
||||||
# Gas left is required to be zero when not `EVMC_SUCCESS` or `EVMC_REVERT`.
|
# Gas left is required to be zero when not `EVMC_SUCCESS` or `EVMC_REVERT`.
|
||||||
gas_left: if result.status_code notin {EVMC_SUCCESS, EVMC_REVERT}: 0'i64
|
gas_left: if result.status_code notin {EVMC_SUCCESS, EVMC_REVERT}: 0'i64
|
||||||
else: c.gasMeter.gasRemaining.int64,
|
else: c.gasMeter.gasRemaining.int64,
|
||||||
|
|
|
@ -43,7 +43,7 @@ proc afterExecCreateEvmcNested(host: TransactionHost, child: Computation,
|
||||||
res.status_code = EVMC_SUCCESS
|
res.status_code = EVMC_SUCCESS
|
||||||
res.create_address = child.msg.contractAddress.toEvmc
|
res.create_address = child.msg.contractAddress.toEvmc
|
||||||
else:
|
else:
|
||||||
res.status_code = if child.shouldBurnGas: EVMC_FAILURE else: EVMC_REVERT
|
res.status_code = child.statusCode
|
||||||
if child.output.len > 0:
|
if child.output.len > 0:
|
||||||
# TODO: can we move the ownership of seq to raw pointer?
|
# TODO: can we move the ownership of seq to raw pointer?
|
||||||
res.output_size = child.output.len.uint
|
res.output_size = child.output.len.uint
|
||||||
|
@ -65,7 +65,7 @@ proc beforeExecCallEvmcNested(host: TransactionHost,
|
||||||
host.computation.msg.contractAddress,
|
host.computation.msg.contractAddress,
|
||||||
value: m.value.fromEvmc,
|
value: m.value.fromEvmc,
|
||||||
data: @(makeOpenArray(m.inputData, m.inputSize.int)),
|
data: @(makeOpenArray(m.inputData, m.inputSize.int)),
|
||||||
flags: if m.isStatic: emvcStatic else: emvcNoFlags,
|
flags: m.flags,
|
||||||
)
|
)
|
||||||
return newComputation(host.vmState, childMsg)
|
return newComputation(host.vmState, childMsg)
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ proc afterExecCallEvmcNested(host: TransactionHost, child: Computation,
|
||||||
host.computation.merge(child)
|
host.computation.merge(child)
|
||||||
res.status_code = EVMC_SUCCESS
|
res.status_code = EVMC_SUCCESS
|
||||||
else:
|
else:
|
||||||
res.status_code = if child.shouldBurnGas: EVMC_FAILURE else: EVMC_REVERT
|
res.status_code = child.statusCode
|
||||||
|
|
||||||
if child.output.len > 0:
|
if child.output.len > 0:
|
||||||
# TODO: can we move the ownership of seq to raw pointer?
|
# TODO: can we move the ownership of seq to raw pointer?
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#{.push raises: [].}
|
#{.push raises: [].}
|
||||||
|
|
||||||
import
|
import
|
||||||
sets, times, stint, chronicles,
|
times, stint, chronicles,
|
||||||
eth/common/eth_types, ../db/accounts_cache,
|
eth/common/eth_types, ../db/accounts_cache,
|
||||||
../common/[evmforks, common],
|
../common/[evmforks, common],
|
||||||
".."/[vm_state, vm_computation, vm_internals, vm_gas_costs],
|
".."/[vm_state, vm_computation, vm_internals, vm_gas_costs],
|
||||||
|
|
|
@ -88,9 +88,6 @@ template flip256*(word256: evmc_uint256be): evmc_uint256be =
|
||||||
template isCreate*(kind: EvmcCallKind): bool =
|
template isCreate*(kind: EvmcCallKind): bool =
|
||||||
kind in {EVMC_CREATE, EVMC_CREATE2}
|
kind in {EVMC_CREATE, EVMC_CREATE2}
|
||||||
|
|
||||||
template isStatic*(msg: EvmcMessage): bool =
|
|
||||||
EVMC_STATIC in msg.flags
|
|
||||||
|
|
||||||
template isZero*(n: evmc_bytes32): bool =
|
template isZero*(n: evmc_bytes32): bool =
|
||||||
n == default(evmc_bytes32)
|
n == default(evmc_bytes32)
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,6 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except
|
# at your option. This file may not be copied, modified, or distributed except
|
||||||
# according to those terms.
|
# according to those terms.
|
||||||
|
|
||||||
|
|
||||||
# The VM computation module suffers from a circular include/import dependency.
|
|
||||||
# After fixing this wrapper should be re-factored.
|
|
||||||
import
|
import
|
||||||
./evm/computation as vmc,
|
./evm/computation as vmc,
|
||||||
./evm/interpreter_dispatch as vmi
|
./evm/interpreter_dispatch as vmi
|
||||||
|
@ -57,6 +54,8 @@ export
|
||||||
vmc.traceOpCodeEnded,
|
vmc.traceOpCodeEnded,
|
||||||
vmc.traceOpCodeStarted,
|
vmc.traceOpCodeStarted,
|
||||||
vmc.tracingEnabled,
|
vmc.tracingEnabled,
|
||||||
vmc.writeContract
|
vmc.writeContract,
|
||||||
|
vmc.statusCode,
|
||||||
|
vmc.errorOpt
|
||||||
|
|
||||||
# End
|
# End
|
||||||
|
|
Loading…
Reference in New Issue