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 =
|
||||
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)
|
||||
|
|
|
@ -33,7 +33,7 @@ type
|
|||
|
||||
nimbus_message* = object
|
||||
kind* : evmc_call_kind
|
||||
flags* : uint32
|
||||
flags* : evmc_flags
|
||||
depth* : int32
|
||||
gas* : int64
|
||||
recipient* : EthAddress
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) =
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -11,4 +11,4 @@
|
|||
import ./types
|
||||
|
||||
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],
|
||||
../common/evmforks,
|
||||
../core/eip4844,
|
||||
./modexp
|
||||
./modexp,
|
||||
./computation
|
||||
|
||||
|
||||
type
|
||||
|
@ -48,7 +49,7 @@ type
|
|||
# paBlsMapG1
|
||||
# paBlsMapG2
|
||||
# Cancun
|
||||
|
||||
|
||||
|
||||
proc getMaxPrecompileAddr(fork: EVMFork): PrecompileAddresses =
|
||||
if fork < FkByzantium: paIdentity
|
||||
|
@ -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 = 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)
|
||||
#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)
|
||||
except OutOfGas as e:
|
||||
# cannot use setError here, cyclic dependency
|
||||
computation.error = Error(info: e.msg, burnsGas: true)
|
||||
except CatchableError as e:
|
||||
if fork >= FkByzantium and precompile > paIdentity:
|
||||
computation.error = Error(info: e.msg, burnsGas: true)
|
||||
else:
|
||||
# swallow any other precompiles errors
|
||||
debug "execPrecompiles validation error", msg=e.msg
|
||||
let lb = c.msg.codeAddress[19]
|
||||
if not validPrecompileAddr(lb, fork):
|
||||
return
|
||||
|
||||
let precompile = PrecompileAddresses(lb)
|
||||
try:
|
||||
case precompile
|
||||
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(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:
|
||||
c.setError(EVMC_OUT_OF_GAS, e.msg, true)
|
||||
except CatchableError as e:
|
||||
if fork >= FkByzantium and precompile > paIdentity:
|
||||
c.setError(EVMC_PRECOMPILE_FAILURE, e.msg, true)
|
||||
else:
|
||||
# swallow any other precompiles errors
|
||||
debug "execPrecompiles validation error", msg=e.msg
|
||||
true
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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,27 +43,26 @@ type
|
|||
ClearCache
|
||||
|
||||
BaseVMState* = ref object of RootObj
|
||||
prevHeaders* : seq[BlockHeader]
|
||||
com* : CommonRef
|
||||
gasPool* : GasInt
|
||||
parent* : BlockHeader
|
||||
timestamp* : EthTime
|
||||
gasLimit* : GasInt
|
||||
fee* : Option[UInt256]
|
||||
prevRandao* : Hash256
|
||||
blockDifficulty*: UInt256
|
||||
flags* : set[VMFlag]
|
||||
tracer* : TracerRef
|
||||
receipts* : seq[Receipt]
|
||||
stateDB* : AccountsCache
|
||||
com* : CommonRef
|
||||
gasPool* : GasInt
|
||||
parent* : BlockHeader
|
||||
timestamp* : EthTime
|
||||
gasLimit* : GasInt
|
||||
fee* : Option[UInt256]
|
||||
prevRandao* : Hash256
|
||||
blockDifficulty* : UInt256
|
||||
flags* : set[VMFlag]
|
||||
tracer* : TracerRef
|
||||
receipts* : seq[Receipt]
|
||||
stateDB* : AccountsCache
|
||||
cumulativeGasUsed*: GasInt
|
||||
txOrigin* : EthAddress
|
||||
txGasPrice* : GasInt
|
||||
txOrigin* : EthAddress
|
||||
txGasPrice* : GasInt
|
||||
txVersionedHashes*: VersionedHashes
|
||||
gasCosts* : GasCosts
|
||||
fork* : EVMFork
|
||||
minerAddress* : EthAddress
|
||||
asyncFactory* : AsyncOperationFactory
|
||||
gasCosts* : GasCosts
|
||||
fork* : EVMFork
|
||||
minerAddress* : EthAddress
|
||||
asyncFactory* : AsyncOperationFactory
|
||||
|
||||
Computation* = ref object
|
||||
# The execution computation
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue