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:
jangko 2023-08-28 19:10:31 +07:00
parent 00262a1d48
commit 26620eb672
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
20 changed files with 182 additions and 203 deletions

View File

@ -51,7 +51,7 @@ const
# ------------------------------------------------------------------------------
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)
result = generateAddress(c.msg.sender, creationNonce)
else:
@ -273,7 +273,26 @@ proc rollback*(c: Computation) =
c.vmState.stateDB.rollback(c.savePoint)
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)
{.gcsafe, raises: [CatchableError].} =
@ -292,16 +311,14 @@ proc writeContract*(c: Computation)
# EIP-3541 constraint (https://eips.ethereum.org/EIPS/eip-3541).
if fork >= FkLondon and c.output[0] == 0xEF.byte:
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
# EIP-170 constraint (https://eips.ethereum.org/EIPS/eip-3541).
if fork >= FkSpurious and len > EIP170_MAX_CODE_SIZE:
withExtra trace, "New contract code exceeds EIP-170 limit",
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
# 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:
# 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:
# 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:
@ -416,7 +432,7 @@ proc traceError*(c: Computation) {.gcsafe, raises: [].} =
c.gasMeter.gasRefunded,
c.returnData,
c.msg.depth + 1,
some(c.error.info))
c.errorOpt)
proc prepareTracer*(c: Computation) =
c.vmState.capturePrepare(c, c.msg.depth)

View File

@ -33,7 +33,7 @@ type
nimbus_message* = object
kind* : evmc_call_kind
flags* : uint32
flags* : evmc_flags
depth* : int32
gas* : int64
recipient* : EthAddress

View File

@ -142,7 +142,7 @@ proc staticCallParams(c: Computation): LocalParams =
result.value = 0.u256
result.sender = c.msg.contractAddress
result.flags = emvcStatic
result.flags.incl EVMC_STATIC
result.contractAddress = result.codeAddress
result.updateStackAndParams(c)
@ -196,7 +196,7 @@ const
## 0xf1, Message-Call into an account
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(
StaticContextError,
"Cannot modify state while inside of a STATICCALL context")
@ -248,7 +248,7 @@ const
msg = new(nimbus_message)
c = cpt
msg[] = nimbus_message(
kind : evmcCall.ord.evmc_call_kind,
kind : EVMC_CALL,
depth : (cpt.msg.depth + 1).int32,
gas : childGasLimit,
sender : p.sender,
@ -257,7 +257,7 @@ const
input_data : cpt.memory.readPtr(p.memInPos),
input_size : p.memInLen.uint,
value : toEvmc(p.value),
flags : p.flags.uint32
flags : p.flags
)
c.execSubCall(msg, p)
else:
@ -265,7 +265,7 @@ const
memPos = p.memOutPos,
memLen = p.memOutLen,
childMsg = Message(
kind: evmcCall,
kind: EVMC_CALL,
depth: cpt.msg.depth + 1,
gas: childGasLimit,
sender: p.sender,
@ -327,7 +327,7 @@ const
msg = new(nimbus_message)
c = cpt
msg[] = nimbus_message(
kind : evmcCallCode.ord.evmc_call_kind,
kind : EVMC_CALLCODE,
depth : (cpt.msg.depth + 1).int32,
gas : childGasLimit,
sender : p.sender,
@ -336,7 +336,7 @@ const
input_data : cpt.memory.readPtr(p.memInPos),
input_size : p.memInLen.uint,
value : toEvmc(p.value),
flags : p.flags.uint32
flags : p.flags
)
c.execSubCall(msg, p)
else:
@ -344,7 +344,7 @@ const
memPos = p.memOutPos,
memLen = p.memOutLen,
childMsg = Message(
kind: evmcCallCode,
kind: EVMC_CALLCODE,
depth: cpt.msg.depth + 1,
gas: childGasLimit,
sender: p.sender,
@ -401,7 +401,7 @@ const
msg = new(nimbus_message)
c = cpt
msg[] = nimbus_message(
kind : evmcDelegateCall.ord.evmc_call_kind,
kind : EVMC_DELEGATECALL,
depth : (cpt.msg.depth + 1).int32,
gas : childGasLimit,
sender : p.sender,
@ -410,7 +410,7 @@ const
input_data : cpt.memory.readPtr(p.memInPos),
input_size : p.memInLen.uint,
value : toEvmc(p.value),
flags : p.flags.uint32
flags : p.flags
)
c.execSubCall(msg, p)
else:
@ -418,7 +418,7 @@ const
memPos = p.memOutPos,
memLen = p.memOutLen,
childMsg = Message(
kind: evmcDelegateCall,
kind: EVMC_DELEGATECALL,
depth: cpt.msg.depth + 1,
gas: childGasLimit,
sender: p.sender,
@ -476,7 +476,7 @@ const
msg = new(nimbus_message)
c = cpt
msg[] = nimbus_message(
kind : evmcCall.ord.evmc_call_kind,
kind : EVMC_CALL,
depth : (cpt.msg.depth + 1).int32,
gas : childGasLimit,
sender : p.sender,
@ -485,7 +485,7 @@ const
input_data : cpt.memory.readPtr(p.memInPos),
input_size : p.memInLen.uint,
value : toEvmc(p.value),
flags : p.flags.uint32
flags : p.flags
)
c.execSubCall(msg, p)
else:
@ -493,7 +493,7 @@ const
memPos = p.memOutPos,
memLen = p.memOutLen,
childMsg = Message(
kind: evmcCall,
kind: EVMC_CALL,
depth: cpt.msg.depth + 1,
gas: childGasLimit,
sender: p.sender,

View File

@ -140,7 +140,7 @@ const
msg = new(nimbus_message)
c = cpt
msg[] = nimbus_message(
kind: evmcCreate.ord.evmc_call_kind,
kind: EVMC_CREATE,
depth: (cpt.msg.depth + 1).int32,
gas: createMsgGas,
sender: cpt.msg.contractAddress,
@ -153,7 +153,7 @@ const
else:
cpt.execSubCreate(
childMsg = Message(
kind: evmcCreate,
kind: EVMC_CREATE,
depth: cpt.msg.depth + 1,
gas: createMsgGas,
sender: cpt.msg.contractAddress,
@ -222,7 +222,7 @@ const
msg = new(nimbus_message)
c = cpt
msg[] = nimbus_message(
kind: evmcCreate2.ord.evmc_call_kind,
kind: EVMC_CREATE2,
depth: (cpt.msg.depth + 1).int32,
gas: createMsgGas,
sender: cpt.msg.contractAddress,
@ -236,7 +236,7 @@ const
cpt.execSubCreate(
salt = salt,
childMsg = Message(
kind: evmcCreate2,
kind: EVMC_CREATE2,
depth: cpt.msg.depth + 1,
gas: createMsgGas,
sender: cpt.msg.contractAddress,

View File

@ -20,7 +20,6 @@ import
../gas_costs,
eth/common,
eth/common/eth_types,
macros,
stint
when defined(evmc_enabled):
@ -64,7 +63,7 @@ proc gasEip2929AccountCheck*(c: Computation; address: EthAddress, slot: UInt256)
template checkInStaticContext*(c: Computation) =
## 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
# when fork >= FkByzantium
raise newException(

View File

@ -21,7 +21,6 @@ import
../../stack,
../../types,
../gas_costs,
../gas_meter,
../op_codes,
../utils/utils_numeric,
./oph_defs,
@ -33,6 +32,7 @@ import
when not defined(evmc_enabled):
import
../gas_meter,
../../state,
../../../db/accounts_cache

View File

@ -64,7 +64,7 @@ const
k.cpt.memory.extend(pos, len)
k.cpt.output = k.cpt.memory.read(pos, len)
# 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) =

View File

@ -102,7 +102,7 @@ proc selectVM(c: Computation, fork: EVMFork, shouldPrepareTracer: bool)
proc beforeExecCall(c: Computation) =
c.snapshot()
if c.msg.kind == evmcCall:
if c.msg.kind == EVMC_CALL:
c.vmState.mutateStateDB:
db.subBalance(c.msg.sender, c.msg.value)
db.addBalance(c.msg.contractAddress, c.msg.value)
@ -182,7 +182,7 @@ const
]
func msgToOp(msg: Message): Op =
if emvcStatic == msg.flags:
if EVMC_STATIC in msg.flags:
return STATICCALL
MsgKindToOp[msg.kind]
@ -212,18 +212,14 @@ proc afterExec(c: Computation)
if c.msg.depth > 0:
let gasUsed = c.msg.gas - c.gasMeter.gasRemaining
let error = if c.isError:
some(c.error.info)
else:
none(string)
c.vmState.captureExit(c, c.output, gasUsed, error)
c.vmState.captureExit(c, c.output, gasUsed, c.errorOpt)
# ------------------------------------------------------------------------------
# Public functions
# ------------------------------------------------------------------------------
proc executeOpcodes*(c: Computation, shouldPrepareTracer: bool = true)
{.gcsafe, raises: [CatchableError].} =
{.gcsafe, raises: [].} =
let fork = c.fork
block:
@ -263,7 +259,6 @@ proc executeOpcodes*(c: Computation, shouldPrepareTracer: bool = true)
if c.isError() and c.continuation.isNil:
if c.tracingEnabled: c.traceError()
#trace "executeOpcodes error", msg=c.error.info
when vm_use_recursion:
# Recursion with tiny stack frame per level.

View File

@ -11,4 +11,4 @@
import ./types
proc isCreate*(message: Message): bool =
message.kind in {evmcCreate, evmcCreate2}
message.kind in {EVMC_CREATE, EVMC_CREATE2}

View File

@ -17,7 +17,8 @@ import
nimcrypto/[ripemd, sha2, utils], bncurve/[fields, groups],
../common/evmforks,
../core/eip4844,
./modexp
./modexp,
./computation
type
@ -74,9 +75,9 @@ iterator activePrecompiles*(fork: EVMFork): EthAddress =
res[^1] = c.byte
yield res
proc getSignature(computation: Computation): (array[32, byte], Signature) =
proc getSignature(c: Computation): (array[32, byte], Signature) =
# 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
let maxPos = min(data.high, 127)
@ -100,7 +101,7 @@ proc getSignature(computation: Computation): (array[32, byte], Signature) =
let sig = Signature.fromRaw(bytes)
if sig.isErr:
raise newException(ValidationError, "Could not recover signature computation")
raise newException(ValidationError, "Could not recover signature c")
result[1] = sig[]
# 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):
raise newException(ValidationError, "Could not get FR value")
proc ecRecover*(computation: Computation) =
computation.gasMeter.consumeGas(
proc ecRecover*(c: Computation) =
c.gasMeter.consumeGas(
GasECRecover,
reason="ECRecover Precompile")
var
(msgHash, sig) = computation.getSignature()
(msgHash, sig) = c.getSignature()
var pubkey = recover(sig, SkMessage(msgHash))
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)
computation.output[12..31] = pubkey[].toCanonicalAddress()
c.output.setLen(32)
c.output[12..31] = pubkey[].toCanonicalAddress()
#trace "ECRecover precompile", derivedKey = pubkey[].toCanonicalAddress()
proc sha256*(computation: Computation) =
proc sha256*(c: Computation) =
let
wordCount = wordCount(computation.msg.data.len)
wordCount = wordCount(c.msg.data.len)
gasFee = GasSHA256 + wordCount * GasSHA256Word
computation.gasMeter.consumeGas(gasFee, reason="SHA256 Precompile")
computation.output = @(sha2.sha256.digest(computation.msg.data).data)
#trace "SHA256 precompile", output = computation.output.toHex
c.gasMeter.consumeGas(gasFee, reason="SHA256 Precompile")
c.output = @(sha2.sha256.digest(c.msg.data).data)
#trace "SHA256 precompile", output = c.output.toHex
proc ripemd160*(computation: Computation) =
proc ripemd160*(c: Computation) =
let
wordCount = wordCount(computation.msg.data.len)
wordCount = wordCount(c.msg.data.len)
gasFee = GasRIPEMD160 + wordCount * GasRIPEMD160Word
computation.gasMeter.consumeGas(gasFee, reason="RIPEMD160 Precompile")
computation.output.setLen(32)
computation.output[12..31] = @(ripemd.ripemd160.digest(computation.msg.data).data)
#trace "RIPEMD160 precompile", output = computation.output.toHex
c.gasMeter.consumeGas(gasFee, reason="RIPEMD160 Precompile")
c.output.setLen(32)
c.output[12..31] = @(ripemd.ripemd160.digest(c.msg.data).data)
#trace "RIPEMD160 precompile", output = c.output.toHex
proc identity*(computation: Computation) =
proc identity*(c: Computation) =
let
wordCount = wordCount(computation.msg.data.len)
wordCount = wordCount(c.msg.data.len)
gasFee = GasIdentity + wordCount * GasIdentityWord
computation.gasMeter.consumeGas(gasFee, reason="Identity Precompile")
computation.output = computation.msg.data
#trace "Identity precompile", output = computation.output.toHex
c.gasMeter.consumeGas(gasFee, reason="Identity Precompile")
c.output = c.msg.data
#trace "Identity precompile", output = c.output.toHex
proc modExpFee(c: Computation, baseLen, expLen, modLen: UInt256, fork: EVMFork): GasInt =
template data: untyped {.dirty.} =
@ -287,16 +288,16 @@ proc modExp*(c: Computation, fork: EVMFork = FkByzantium) =
c.output = newSeq[byte](modLen)
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
computation.gasMeter.consumeGas(gasFee, reason = "ecAdd Precompile")
c.gasMeter.consumeGas(gasFee, reason = "ecAdd Precompile")
var
input: array[128, byte]
output: array[64, byte]
# Padding data
let len = min(computation.msg.data.len, 128) - 1
input[0..len] = computation.msg.data[0..len]
let len = min(c.msg.data.len, 128) - 1
input[0..len] = c.msg.data[0..len]
var p1 = G1.getPoint(input.toOpenArray(0, 63))
var p2 = G1.getPoint(input.toOpenArray(64, 127))
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
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
computation.gasMeter.consumeGas(gasFee, reason="ecMul Precompile")
c.gasMeter.consumeGas(gasFee, reason="ecMul Precompile")
var
input: array[96, byte]
output: array[64, byte]
# Padding data
let len = min(computation.msg.data.len, 96) - 1
input[0..len] = computation.msg.data[0..len]
let len = min(c.msg.data.len, 96) - 1
input[0..len] = c.msg.data[0..len]
var p1 = G1.getPoint(input.toOpenArray(0, 63))
var fr = getFR(input.toOpenArray(64, 95))
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
discard apo.get().toBytes(output)
computation.output = @output
c.output = @output
proc bn256ecPairing*(computation: Computation, fork: EVMFork = FkByzantium) =
let msglen = len(computation.msg.data)
proc bn256ecPairing*(c: Computation, fork: EVMFork = FkByzantium) =
let msglen = len(c.msg.data)
if msglen mod 192 != 0:
raise newException(ValidationError, "Invalid input length")
@ -336,7 +337,7 @@ proc bn256ecPairing*(computation: Computation, fork: EVMFork = FkByzantium) =
GasECPairingBase + numPoints * GasECPairingPerPoint
else:
GasECPairingBaseIstanbul + numPoints * GasECPairingPerPointIstanbul
computation.gasMeter.consumeGas(gasFee, reason="ecPairing Precompile")
c.gasMeter.consumeGas(gasFee, reason="ecPairing Precompile")
var output: array[32, byte]
if msglen == 0:
@ -351,9 +352,9 @@ proc bn256ecPairing*(computation: Computation, fork: EVMFork = FkByzantium) =
for i in 0..<count:
let s = i * 192
# 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]
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
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
discard BNU256.one().toBytes(output)
computation.output = @output
c.output = @output
proc blake2bf*(c: Computation) =
template input: untyped =
@ -685,45 +686,45 @@ proc pointEvaluation*(c: Computation) =
# return a constant
c.output = @PointEvaluationResult
proc execPrecompiles*(computation: Computation, fork: EVMFork): bool {.inline.} =
proc execPrecompiles*(c: Computation, fork: EVMFork): bool {.inline.} =
for i in 0..18:
if computation.msg.codeAddress[i] != 0: return
if c.msg.codeAddress[i] != 0: return
let lb = c.msg.codeAddress[19]
if not validPrecompileAddr(lb, fork):
return
let lb = computation.msg.codeAddress[19]
if validPrecompileAddr(lb, fork):
result = true
let precompile = PrecompileAddresses(lb)
#trace "Call precompile", precompile = precompile, codeAddr = computation.msg.codeAddress
try:
case precompile
of paEcRecover: ecRecover(computation)
of paSha256: sha256(computation)
of paRipeMd160: ripemd160(computation)
of paIdentity: identity(computation)
of paModExp: modExp(computation, fork)
of paEcAdd: bn256ecAdd(computation, fork)
of paEcMul: bn256ecMul(computation, fork)
of paPairing: bn256ecPairing(computation, fork)
of paBlake2bf: blake2bf(computation)
of paPointEvaluation: pointEvaluation(computation)
of paEcRecover: ecRecover(c)
of paSha256: sha256(c)
of paRipeMd160: ripemd160(c)
of paIdentity: identity(c)
of paModExp: modExp(c, fork)
of paEcAdd: bn256ecAdd(c, fork)
of paEcMul: bn256ecMul(c, fork)
of paPairing: bn256ecPairing(c, fork)
of paBlake2bf: blake2bf(c)
of paPointEvaluation: pointEvaluation(c)
#else: discard
# EIP 2537: disabled
# reason: not included in berlin
# of paBlsG1Add: blsG1Add(computation)
# of paBlsG1Mul: blsG1Mul(computation)
# of paBlsG1MultiExp: blsG1MultiExp(computation)
# of paBlsG2Add: blsG2Add(computation)
# of paBlsG2Mul: blsG2Mul(computation)
# of paBlsG2MultiExp: blsG2MultiExp(computation)
# of paBlsPairing: blsPairing(computation)
# of paBlsMapG1: blsMapG1(computation)
# of paBlsMapG2: blsMapG2(computation)
# of paBlsG1Add: blsG1Add(c)
# of paBlsG1Mul: blsG1Mul(c)
# of paBlsG1MultiExp: blsG1MultiExp(c)
# of paBlsG2Add: blsG2Add(c)
# of paBlsG2Mul: blsG2Mul(c)
# of paBlsG2MultiExp: blsG2MultiExp(c)
# of paBlsPairing: blsPairing(c)
# of paBlsMapG1: blsMapG1(c)
# of paBlsMapG2: blsMapG2(c)
except OutOfGas as e:
# cannot use setError here, cyclic dependency
computation.error = Error(info: e.msg, burnsGas: true)
c.setError(EVMC_OUT_OF_GAS, e.msg, true)
except CatchableError as e:
if fork >= FkByzantium and precompile > paIdentity:
computation.error = Error(info: e.msg, burnsGas: true)
c.setError(EVMC_PRECOMPILE_FAILURE, e.msg, true)
else:
# swallow any other precompiles errors
debug "execPrecompiles validation error", msg=e.msg
true

View File

@ -35,7 +35,6 @@ proc init(
asyncFactory: AsyncOperationFactory = AsyncOperationFactory(maybeDataSource: none[AsyncDataSource]()))
{.gcsafe.} =
## Initialisation helper
self.prevHeaders = @[]
self.parent = parent
self.timestamp = timestamp
self.gasLimit = gasLimit
@ -297,17 +296,6 @@ method getAncestorHash*(
else:
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.} =
ReadOnlyStateDB(vmState.stateDB)

View File

@ -37,16 +37,6 @@ iterator storage(ctx: LegacyTracer, compDepth: int): UInt256 =
for key in ctx.storageKeys[compDepth]:
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 =
let trace = newJObject()

View File

@ -17,6 +17,14 @@ import
../db/accounts_cache,
../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: [].}
when defined(evmc_enabled):
@ -35,7 +43,6 @@ type
ClearCache
BaseVMState* = ref object of RootObj
prevHeaders* : seq[BlockHeader]
com* : CommonRef
gasPool* : GasInt
parent* : BlockHeader
@ -43,7 +50,7 @@ type
gasLimit* : GasInt
fee* : Option[UInt256]
prevRandao* : Hash256
blockDifficulty*: UInt256
blockDifficulty* : UInt256
flags* : set[VMFlag]
tracer* : TracerRef
receipts* : seq[Receipt]
@ -82,23 +89,17 @@ type
continuation*: proc() {.gcsafe, raises: [CatchableError].}
Error* = ref object
info*: string
burnsGas*: bool
statusCode*: evmc_status_code
info* : string
burnsGas* : bool
GasMeter* = object
gasRefunded*: GasInt
gasRemaining*: GasInt
CallKind* = enum
evmcCall = 0, # CALL
evmcDelegateCall = 1, # DELEGATECALL
evmcCallCode = 2, # CALLCODE
evmcCreate = 3, # CREATE
evmcCreate2 = 4 # CREATE2
CallKind* = evmc_call_kind
MsgFlags* = enum
emvcNoFlags = 0
emvcStatic = 1
MsgFlags* = evmc_flags
Message* = ref object
kind*: CallKind

View File

@ -66,7 +66,7 @@ proc hostToComputationMessage*(msg: EvmcMessage): Message =
# When input size is zero, input data pointer may be null.
data: if msg.input_size <= 0: @[]
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.} =
@ -206,9 +206,9 @@ when defined(evmc_enabled):
if callResult.status_code == EVMC_SUCCESS:
c.error = nil
elif callResult.status_code == EVMC_REVERT:
c.setError("EVMC_REVERT", false)
c.setError(EVMC_REVERT, false)
else:
c.setError($callResult.status_code, true)
c.setError(callResult.status_code, true)
c.gasMeter.gasRemaining = callResult.gas_left
c.msg.contractAddress = callResult.create_address.fromEvmc
@ -278,12 +278,7 @@ proc finishRunningComputation(host: TransactionHost, call: CallParams): CallResu
let gasRemaining = calculateAndPossiblyRefundGas(host, call)
# evm gas used without intrinsic gas
let gasUsed = host.msg.gas - gasRemaining
let error = if c.isError:
some(c.error.info)
else:
none(string)
host.vmState.captureEnd(c, c.output, gasUsed, error)
host.vmState.captureEnd(c, c.output, gasUsed, c.errorOpt)
result.isError = c.isError
result.gasUsed = call.gasLimit - gasRemaining

View File

@ -83,11 +83,11 @@ proc accessStorage(p: evmc_host_context, address: var evmc_address,
proc getTransientStorage(p: evmc_host_context, address: var evmc_address,
key: var evmc_bytes32): evmc_bytes32
{.cdecl, raises: [RlpError].} =
{.cdecl, raises: [].} =
toHost(p).getTransientStorage(address.fromEvmc, key.flip256.fromEvmc).toEvmc.flip256
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)
let hostInterface = evmc_host_interface(

View File

@ -9,7 +9,7 @@
{.push raises: [].}
import
./host_types, evmc/evmc, stew/ranges/ptr_arith,
./host_types, evmc/evmc,
".."/[vm_types, vm_computation, vm_state_transactions]
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(
# Standard EVMC result, if a bit generic.
status_code: if c.isSuccess: EVMC_SUCCESS
elif not c.error.burnsGas: EVMC_REVERT
else: EVMC_FAILURE,
status_code: c.statusCode,
# 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
else: c.gasMeter.gasRemaining.int64,

View File

@ -43,7 +43,7 @@ proc afterExecCreateEvmcNested(host: TransactionHost, child: Computation,
res.status_code = EVMC_SUCCESS
res.create_address = child.msg.contractAddress.toEvmc
else:
res.status_code = if child.shouldBurnGas: EVMC_FAILURE else: EVMC_REVERT
res.status_code = child.statusCode
if child.output.len > 0:
# TODO: can we move the ownership of seq to raw pointer?
res.output_size = child.output.len.uint
@ -65,7 +65,7 @@ proc beforeExecCallEvmcNested(host: TransactionHost,
host.computation.msg.contractAddress,
value: m.value.fromEvmc,
data: @(makeOpenArray(m.inputData, m.inputSize.int)),
flags: if m.isStatic: emvcStatic else: emvcNoFlags,
flags: m.flags,
)
return newComputation(host.vmState, childMsg)
@ -78,7 +78,7 @@ proc afterExecCallEvmcNested(host: TransactionHost, child: Computation,
host.computation.merge(child)
res.status_code = EVMC_SUCCESS
else:
res.status_code = if child.shouldBurnGas: EVMC_FAILURE else: EVMC_REVERT
res.status_code = child.statusCode
if child.output.len > 0:
# TODO: can we move the ownership of seq to raw pointer?

View File

@ -9,7 +9,7 @@
#{.push raises: [].}
import
sets, times, stint, chronicles,
times, stint, chronicles,
eth/common/eth_types, ../db/accounts_cache,
../common/[evmforks, common],
".."/[vm_state, vm_computation, vm_internals, vm_gas_costs],

View File

@ -88,9 +88,6 @@ template flip256*(word256: evmc_uint256be): evmc_uint256be =
template isCreate*(kind: EvmcCallKind): bool =
kind in {EVMC_CREATE, EVMC_CREATE2}
template isStatic*(msg: EvmcMessage): bool =
EVMC_STATIC in msg.flags
template isZero*(n: evmc_bytes32): bool =
n == default(evmc_bytes32)

View File

@ -8,9 +8,6 @@
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
# The VM computation module suffers from a circular include/import dependency.
# After fixing this wrapper should be re-factored.
import
./evm/computation as vmc,
./evm/interpreter_dispatch as vmi
@ -57,6 +54,8 @@ export
vmc.traceOpCodeEnded,
vmc.traceOpCodeStarted,
vmc.tracingEnabled,
vmc.writeContract
vmc.writeContract,
vmc.statusCode,
vmc.errorOpt
# End