mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-11 21:04:11 +00:00
Merge branch 'master' into fluffy-evm-integration
This commit is contained in:
commit
83d603a849
@ -91,7 +91,11 @@ proc canAddPendingTransfer(
|
||||
|
||||
try:
|
||||
let contentIds = transfers[nodeId]
|
||||
(contentIds.len() < limit) and not contentIds.contains(contentId)
|
||||
if (contentIds.len() < limit) and not contentIds.contains(contentId):
|
||||
return true
|
||||
else:
|
||||
debug "Pending transfer limit reached for peer", nodeId, contentId
|
||||
return false
|
||||
except KeyError as e:
|
||||
raiseAssert(e.msg)
|
||||
|
||||
|
@ -37,13 +37,7 @@ type
|
||||
tx: TransactionRef
|
||||
updatedCache: TrieDatabaseRef
|
||||
|
||||
PreimagesBackendRef = ref object of RootObj
|
||||
cfHandle: ColFamilyHandleRef
|
||||
tx: TransactionRef
|
||||
updatedCache: TrieDatabaseRef
|
||||
|
||||
DatabaseBackendRef =
|
||||
AccountsBackendRef | StorageBackendRef | BytecodeBackendRef | PreimagesBackendRef
|
||||
DatabaseBackendRef = AccountsBackendRef | StorageBackendRef | BytecodeBackendRef
|
||||
|
||||
DatabaseRef* = ref object
|
||||
rocksDb: OptimisticTxDbRef
|
||||
@ -51,7 +45,6 @@ type
|
||||
accountsBackend: AccountsBackendRef
|
||||
storageBackend: StorageBackendRef
|
||||
bytecodeBackend: BytecodeBackendRef
|
||||
preimagesBackend: PreimagesBackendRef
|
||||
|
||||
proc init*(T: type DatabaseRef, baseDir: string): Result[T, string] =
|
||||
let dbPath = baseDir / "db"
|
||||
@ -79,9 +72,6 @@ proc init*(T: type DatabaseRef, baseDir: string): Result[T, string] =
|
||||
bytecodeBackend = BytecodeBackendRef(
|
||||
cfHandle: db.getColFamilyHandle(COL_FAMILY_NAME_BYTECODE).get()
|
||||
)
|
||||
preimagesBackend = PreimagesBackendRef(
|
||||
cfHandle: db.getColFamilyHandle(COL_FAMILY_NAME_PREIMAGES).get()
|
||||
)
|
||||
|
||||
ok(
|
||||
T(
|
||||
@ -90,7 +80,6 @@ proc init*(T: type DatabaseRef, baseDir: string): Result[T, string] =
|
||||
accountsBackend: accountsBackend,
|
||||
storageBackend: storageBackend,
|
||||
bytecodeBackend: bytecodeBackend,
|
||||
preimagesBackend: preimagesBackend,
|
||||
)
|
||||
)
|
||||
|
||||
@ -138,9 +127,6 @@ proc getStorageBackend*(db: DatabaseRef): TrieDatabaseRef {.inline.} =
|
||||
proc getBytecodeBackend*(db: DatabaseRef): TrieDatabaseRef {.inline.} =
|
||||
trieDB(db.bytecodeBackend)
|
||||
|
||||
proc getPreimagesBackend*(db: DatabaseRef): TrieDatabaseRef {.inline.} =
|
||||
trieDB(db.preimagesBackend)
|
||||
|
||||
proc getAccountsUpdatedCache*(db: DatabaseRef): TrieDatabaseRef {.inline.} =
|
||||
db.accountsBackend.updatedCache
|
||||
|
||||
@ -179,12 +165,10 @@ proc beginTransaction*(db: DatabaseRef): Result[void, string] =
|
||||
db.accountsBackend.tx = tx
|
||||
db.storageBackend.tx = tx
|
||||
db.bytecodeBackend.tx = tx
|
||||
db.preimagesBackend.tx = tx
|
||||
|
||||
db.accountsBackend.updatedCache = newMemoryDB()
|
||||
db.storageBackend.updatedCache = newMemoryDB()
|
||||
db.bytecodeBackend.updatedCache = newMemoryDB()
|
||||
db.preimagesBackend.updatedCache = nil # not used
|
||||
|
||||
ok()
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Nimbus
|
||||
# Copyright (c) 2024 Status Research & Development GmbH
|
||||
# Copyright (c) 2021-2024 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
|
@ -16,7 +16,6 @@ import
|
||||
eth/common/[hashes, accounts, headers, addresses],
|
||||
../db/[ledger, core_db],
|
||||
../constants,
|
||||
../utils/utils,
|
||||
./chain_config
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
@ -79,10 +78,6 @@ proc toGenesisHeader*(
|
||||
result.excessBlobGas = Opt.some g.excessBlobGas.get(0'u64)
|
||||
result.parentBeaconBlockRoot = Opt.some g.parentBeaconBlockRoot.get(default(Hash32))
|
||||
|
||||
if fork >= Prague:
|
||||
const EmptyRequestsHash = calcRequestsHash()
|
||||
result.requestsHash = Opt.some(EmptyRequestsHash)
|
||||
|
||||
proc toGenesisHeader*(
|
||||
genesis: Genesis;
|
||||
fork: HardFork;
|
||||
|
@ -453,7 +453,6 @@ proc getNonce*(ac: LedgerRef, address: Address): AccountNonce =
|
||||
proc getCode*(ac: LedgerRef,
|
||||
address: Address,
|
||||
returnHash: static[bool] = false): auto =
|
||||
# Always returns non-nil!
|
||||
let acc = ac.getAccount(address, false)
|
||||
if acc.isNil:
|
||||
when returnHash:
|
||||
@ -526,7 +525,7 @@ proc getDelegateAddress*(ac: LedgerRef, address: Address): Address =
|
||||
let delegateTo = parseDelegationAddress(code).valueOr:
|
||||
return
|
||||
delegateTo
|
||||
|
||||
|
||||
proc getCommittedStorage*(ac: LedgerRef, address: Address, slot: UInt256): UInt256 =
|
||||
let acc = ac.getAccount(address, false)
|
||||
if acc.isNil:
|
||||
|
@ -11,6 +11,7 @@
|
||||
{.push raises: [].}
|
||||
|
||||
import
|
||||
std/sequtils,
|
||||
".."/[db/ledger, constants],
|
||||
"."/[code_stream, memory, message, stack, state],
|
||||
"."/[types],
|
||||
@ -21,8 +22,7 @@ import
|
||||
../utils/utils,
|
||||
../common/common,
|
||||
eth/common/eth_types_rlp,
|
||||
chronicles, chronos,
|
||||
sets
|
||||
chronicles, chronos
|
||||
|
||||
export
|
||||
common
|
||||
@ -260,39 +260,44 @@ template resolveCode*(c: Computation, address: Address): CodeBytesRef =
|
||||
c.vmState.readOnlyStateDB.resolveCode(address)
|
||||
|
||||
proc newComputation*(vmState: BaseVMState, sysCall: bool, message: Message,
|
||||
salt: ContractSalt = ZERO_CONTRACTSALT): Computation =
|
||||
isPrecompile, keepStack: bool, salt: ContractSalt = ZERO_CONTRACTSALT): Computation =
|
||||
new result
|
||||
result.vmState = vmState
|
||||
result.msg = message
|
||||
result.memory = EvmMemory.init()
|
||||
result.stack = EvmStack.init()
|
||||
result.returnStack = @[]
|
||||
result.gasMeter.init(message.gas)
|
||||
result.sysCall = sysCall
|
||||
result.keepStack = keepStack
|
||||
|
||||
if result.msg.isCreate():
|
||||
result.msg.contractAddress = result.generateContractAddress(salt)
|
||||
result.code = CodeStream.init(message.data)
|
||||
message.data = @[]
|
||||
else:
|
||||
if vmState.fork >= FkPrague:
|
||||
result.code = CodeStream.init(
|
||||
vmState.readOnlyStateDB.resolveCode(message.codeAddress))
|
||||
if not isPrecompile:
|
||||
result.memory = EvmMemory.init()
|
||||
result.stack = EvmStack.init()
|
||||
|
||||
if result.msg.isCreate():
|
||||
result.msg.contractAddress = result.generateContractAddress(salt)
|
||||
result.code = CodeStream.init(message.data)
|
||||
message.data = @[]
|
||||
else:
|
||||
result.code = CodeStream.init(
|
||||
vmState.readOnlyStateDB.getCode(message.codeAddress))
|
||||
if vmState.fork >= FkPrague:
|
||||
result.code = CodeStream.init(
|
||||
vmState.readOnlyStateDB.resolveCode(message.codeAddress))
|
||||
else:
|
||||
result.code = CodeStream.init(
|
||||
vmState.readOnlyStateDB.getCode(message.codeAddress))
|
||||
|
||||
|
||||
func newComputation*(vmState: BaseVMState, sysCall: bool,
|
||||
message: Message, code: CodeBytesRef): Computation =
|
||||
message: Message, code: CodeBytesRef, isPrecompile, keepStack: bool, ): Computation =
|
||||
new result
|
||||
result.vmState = vmState
|
||||
result.msg = message
|
||||
result.memory = EvmMemory.init()
|
||||
result.stack = EvmStack.init()
|
||||
result.returnStack = @[]
|
||||
result.gasMeter.init(message.gas)
|
||||
result.code = CodeStream.init(code)
|
||||
result.sysCall = sysCall
|
||||
result.keepStack = keepStack
|
||||
|
||||
if not isPrecompile:
|
||||
result.code = CodeStream.init(code)
|
||||
result.memory = EvmMemory.init()
|
||||
result.stack = EvmStack.init()
|
||||
|
||||
template gasCosts*(c: Computation): untyped =
|
||||
c.vmState.gasCosts
|
||||
@ -317,6 +322,12 @@ proc commit*(c: Computation) =
|
||||
|
||||
proc dispose*(c: Computation) =
|
||||
c.vmState.stateDB.safeDispose(c.savePoint)
|
||||
if c.stack != nil:
|
||||
if c.keepStack:
|
||||
c.finalStack = toSeq(c.stack.items())
|
||||
|
||||
c.stack.dispose()
|
||||
c.stack = nil
|
||||
c.savePoint = nil
|
||||
|
||||
proc rollback*(c: Computation) =
|
||||
|
@ -34,7 +34,7 @@ proc blockhashOp(cpt: VmCpt): EvmResultVoid =
|
||||
## 0x40, Get the hash of one of the 256 most recent complete blocks.
|
||||
template block256(top, number, conv) =
|
||||
if number > high(BlockNumber).u256:
|
||||
top = zero(UInt256)
|
||||
conv(zero(UInt256), top)
|
||||
else:
|
||||
conv(cpt.getBlockHash(number.truncate(BlockNumber)), top)
|
||||
|
||||
@ -82,7 +82,7 @@ proc blobHashOp(cpt: VmCpt): EvmResultVoid =
|
||||
if index < len:
|
||||
conv(cpt.getVersionedHash(index).data, top)
|
||||
else:
|
||||
top = zero(UInt256)
|
||||
conv(zero(UInt256), top)
|
||||
|
||||
cpt.stack.unaryWithTop(blob256)
|
||||
|
||||
|
@ -21,6 +21,7 @@ import
|
||||
../../../core/eip7702,
|
||||
../../computation,
|
||||
../../memory,
|
||||
../../precompiles,
|
||||
../../stack,
|
||||
../../types,
|
||||
../gas_costs,
|
||||
@ -215,7 +216,9 @@ else:
|
||||
# need to provide explicit <c> and <child> for capturing in chainTo proc()
|
||||
# <memPos> and <memLen> are provided by value and need not be captured
|
||||
var
|
||||
child = newComputation(c.vmState, false, childMsg)
|
||||
precompile = getPrecompile(c.fork, childMsg.codeAddress)
|
||||
child = newComputation(
|
||||
c.vmState, false, childMsg, isPrecompile = precompile.isSome(), keepStack = false)
|
||||
|
||||
c.chainTo(child):
|
||||
if not child.shouldBurnGas:
|
||||
|
@ -67,7 +67,7 @@ else:
|
||||
|
||||
# need to provide explicit <c> and <child> for capturing in chainTo proc()
|
||||
var
|
||||
child = newComputation(c.vmState, false, childMsg, salt)
|
||||
child = newComputation(c.vmState, false, childMsg, false, false, salt)
|
||||
|
||||
c.chainTo(child):
|
||||
if not child.shouldBurnGas:
|
||||
|
@ -68,7 +68,7 @@ proc logImpl(c: Computation, opcode: Op, topicCount: static int): EvmResultVoid
|
||||
when evmc_enabled:
|
||||
var topics: array[4, evmc_bytes32]
|
||||
for i in 0 ..< topicCount:
|
||||
topics[i].bytes = c.stack.lsPeekTopic(^(i+3))
|
||||
topics[i].bytes = c.stack.lsPeekTopic(^(i+3)).data
|
||||
|
||||
c.host.emitLog(c.msg.contractAddress,
|
||||
c.memory.read(memPos, len),
|
||||
@ -77,7 +77,7 @@ proc logImpl(c: Computation, opcode: Op, topicCount: static int): EvmResultVoid
|
||||
var log: Log
|
||||
log.topics = newSeqOfCap[Topic](topicCount)
|
||||
for i in 0 ..< topicCount:
|
||||
log.topics.add Bytes32 c.stack.lsPeekTopic(^(i+3))
|
||||
log.topics.add c.stack.lsPeekTopic(^(i+3))
|
||||
|
||||
assign(log.data, c.memory.read(memPos, len))
|
||||
log.address = c.msg.contractAddress
|
||||
|
@ -178,7 +178,7 @@ proc mstore8Op(cpt: VmCpt): EvmResultVoid =
|
||||
proc sloadOp(cpt: VmCpt): EvmResultVoid =
|
||||
## 0x54, Load word from storage.
|
||||
template sload256(top, slot, conv) =
|
||||
top = cpt.getStorage(slot)
|
||||
conv(cpt.getStorage(slot), top)
|
||||
cpt.stack.unaryWithTop(sload256)
|
||||
|
||||
proc sloadEIP2929Op(cpt: VmCpt): EvmResultVoid =
|
||||
@ -186,7 +186,7 @@ proc sloadEIP2929Op(cpt: VmCpt): EvmResultVoid =
|
||||
template sloadEIP2929(top, slot, conv) =
|
||||
let gasCost = cpt.gasEip2929AccountCheck(cpt.msg.contractAddress, slot)
|
||||
? cpt.opcodeGasCost(Sload, gasCost, reason = "sloadEIP2929")
|
||||
top = cpt.getStorage(slot)
|
||||
conv(cpt.getStorage(slot), top)
|
||||
cpt.stack.unaryWithTop(sloadEIP2929)
|
||||
|
||||
# -------
|
||||
|
@ -197,8 +197,11 @@ proc executeOpcodes*(c: Computation, shouldPrepareTracer: bool = true) =
|
||||
let fork = c.fork
|
||||
|
||||
block blockOne:
|
||||
if c.continuation.isNil and c.execPrecompiles(fork):
|
||||
break blockOne
|
||||
if c.continuation.isNil:
|
||||
let precompile = c.fork.getPrecompile(c.msg.codeAddress)
|
||||
if precompile.isSome:
|
||||
c.execPrecompile(precompile[])
|
||||
break blockOne
|
||||
|
||||
let cont = c.continuation
|
||||
if not cont.isNil:
|
||||
|
@ -70,10 +70,6 @@ func getMaxPrecompileAddr(fork: EVMFork): PrecompileAddresses =
|
||||
func validPrecompileAddr(addrByte, maxPrecompileAddr: byte): bool =
|
||||
(addrByte in PrecompileAddresses.low.byte .. maxPrecompileAddr)
|
||||
|
||||
func validPrecompileAddr(addrByte: byte, fork: EVMFork): bool =
|
||||
let maxPrecompileAddr = getMaxPrecompileAddr(fork)
|
||||
validPrecompileAddr(addrByte, maxPrecompileAddr.byte)
|
||||
|
||||
func getSignature(c: Computation): EvmResult[SigRes] =
|
||||
# input is Hash, V, R, S
|
||||
template data: untyped = c.msg.data
|
||||
@ -719,16 +715,21 @@ func activePrecompilesList*(fork: EVMFork): seq[Address] =
|
||||
for address in activePrecompiles(fork):
|
||||
result.add address
|
||||
|
||||
proc execPrecompiles*(c: Computation, fork: EVMFork): bool =
|
||||
proc getPrecompile*(fork: EVMFork, b: byte): Opt[PrecompileAddresses] =
|
||||
let maxPrecompileAddr = getMaxPrecompileAddr(fork)
|
||||
if validPrecompileAddr(b, maxPrecompileAddr.byte):
|
||||
Opt.some(PrecompileAddresses(b))
|
||||
else:
|
||||
Opt.none(PrecompileAddresses)
|
||||
|
||||
proc getPrecompile*(fork: EVMFork, codeAddress: Address): Opt[PrecompileAddresses] =
|
||||
for i in 0..18:
|
||||
if c.msg.codeAddress.data[i] != 0:
|
||||
return false
|
||||
if codeAddress.data[i] != 0:
|
||||
return Opt.none(PrecompileAddresses)
|
||||
getPrecompile(fork, codeAddress.data[19])
|
||||
|
||||
let lb = c.msg.codeAddress.data[19]
|
||||
if not validPrecompileAddr(lb, fork):
|
||||
return false
|
||||
|
||||
let precompile = PrecompileAddresses(lb)
|
||||
proc execPrecompile*(c: Computation, precompile: PrecompileAddresses) =
|
||||
let fork = c.fork
|
||||
let res = case precompile
|
||||
of paEcRecover: ecRecover(c)
|
||||
of paSha256: sha256(c)
|
||||
@ -759,5 +760,3 @@ proc execPrecompiles*(c: Computation, fork: EVMFork): bool =
|
||||
else:
|
||||
# swallow any other precompiles errors
|
||||
debug "execPrecompiles validation error", errCode = $res.error.code
|
||||
|
||||
true
|
||||
|
@ -8,182 +8,200 @@
|
||||
# at your option. This file may not be copied, modified, or distributed except
|
||||
# according to those terms.
|
||||
|
||||
# Type managing the EVM stack that comprises of 1024 256-bit words.
|
||||
#
|
||||
# The stack is a hot spot in EVM execution since it's used for practically every
|
||||
# opcode. We use custom-allocated memory for several reasons, chiefly
|
||||
# performance (at the time of writing, using a seq carried about 5% overhead on
|
||||
# total EVM execution time):
|
||||
#
|
||||
# * no zeromem - the way the EVM uses the stack, it always writes full words
|
||||
# meaning that whatever zeroing was done gets overwritten anyway - compilers
|
||||
# are typically not smart enough to get rid of all of this
|
||||
# * no reallocation - since we can allocate memory without zeroing, we can
|
||||
# allocate the full stack length on creation and never grow / reallocate
|
||||
# * less redundant range checking - we have to perform range checks manually and
|
||||
# the compiler is not able to remove them consistently even though we range
|
||||
# check manually
|
||||
# * 32-byte alignment helps vector instruction optimization
|
||||
#
|
||||
# After calling `init`, the stack must be freed manually using `dispose`!
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
import
|
||||
system/ansi_c,
|
||||
stew/[assign2, ptrops],
|
||||
stint,
|
||||
eth/common/[base, addresses, hashes],
|
||||
std/[macros],
|
||||
std/typetraits,
|
||||
./evm_errors,
|
||||
./interpreter/utils/utils_numeric
|
||||
|
||||
const evmStackSize = 1024
|
||||
## https://ethereum.org/en/developers/docs/evm/#evm-instructions
|
||||
|
||||
type
|
||||
EvmStack* = ref object
|
||||
values: seq[EvmStackElement]
|
||||
values: ptr EvmStackElement
|
||||
memory: pointer
|
||||
len*: int
|
||||
|
||||
EvmStackElement = object
|
||||
data {.align: 32.}: UInt256
|
||||
|
||||
EvmStackElement = UInt256
|
||||
EvmStackInts = uint64 | uint | int | GasInt
|
||||
EvmStackBytes32 = array[32, byte]
|
||||
|
||||
func len*(stack: EvmStack): int {.inline.} =
|
||||
len(stack.values)
|
||||
static:
|
||||
# A few sanity checks because we skip the GC / parts of the nim type system:
|
||||
doAssert sizeof(UInt256) == 32, "no padding etc"
|
||||
doAssert supportsCopyMem(EvmStackElement), "byte-based ops must work sanely"
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private functions
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
template toStackElem(v: UInt256, elem: EvmStackElement) =
|
||||
template `[]`*(s: EvmStack, i: int): EvmStackElement =
|
||||
s.values.offset(i)[]
|
||||
|
||||
template `[]`*(s: EvmStack, i: BackwardsIndex): EvmStackElement =
|
||||
s.values.offset(s.len - int(i))[]
|
||||
|
||||
template `[]=`*(s: EvmStack, i: int, v: EvmStackElement) =
|
||||
assign(s[i], v)
|
||||
|
||||
template `[]=`*(s: EvmStack, i: BackwardsIndex, v: EvmStackElement) =
|
||||
assign(s[i], v)
|
||||
|
||||
template toStackElem(v: EvmStackElement, elem: EvmStackElement) =
|
||||
elem = v
|
||||
|
||||
template toStackElem(v: UInt256, elem: EvmStackElement) =
|
||||
elem.data = v
|
||||
|
||||
template toStackElem(v: EvmStackInts, elem: EvmStackElement) =
|
||||
elem = v.u256
|
||||
elem.data = v.u256
|
||||
|
||||
template toStackElem(v: Address, elem: EvmStackElement) =
|
||||
elem.initFromBytesBE(v.data)
|
||||
elem.data.initFromBytesBE(v.data)
|
||||
|
||||
template toStackElem(v: Hash32, elem: EvmStackElement) =
|
||||
elem.initFromBytesBE(v.data)
|
||||
elem.data.initFromBytesBE(v.data)
|
||||
|
||||
template toStackElem(v: openArray[byte], elem: EvmStackElement) =
|
||||
doAssert(v.len <= 32)
|
||||
elem.initFromBytesBE(v)
|
||||
elem.data.initFromBytesBE(v)
|
||||
|
||||
template fromStackElem(elem: EvmStackElement, _: type UInt256): UInt256 =
|
||||
elem
|
||||
elem.data
|
||||
|
||||
func fromStackElem(elem: EvmStackElement, _: type Address): Address =
|
||||
elem.to(Bytes32).to(Address)
|
||||
elem.data.to(Bytes32).to(Address)
|
||||
|
||||
template fromStackElem(elem: EvmStackElement, _: type Hash32): Hash32 =
|
||||
Hash32(elem.toBytesBE())
|
||||
Hash32(elem.data.toBytesBE())
|
||||
|
||||
template fromStackElem(elem: EvmStackElement, _: type EvmStackBytes32): EvmStackBytes32 =
|
||||
elem.toBytesBE()
|
||||
|
||||
func pushAux[T](stack: var EvmStack, value: T): EvmResultVoid =
|
||||
if len(stack.values) > 1023:
|
||||
return err(stackErr(StackFull))
|
||||
stack.values.setLen(stack.values.len + 1)
|
||||
toStackElem(value, stack.values[^1])
|
||||
ok()
|
||||
template fromStackElem(elem: EvmStackElement, _: type Bytes32): Bytes32 =
|
||||
elem.data.toBytesBE().to(Bytes32)
|
||||
|
||||
func ensurePop(stack: EvmStack, expected: int): EvmResultVoid =
|
||||
if stack.values.len < expected:
|
||||
if stack.len < expected:
|
||||
return err(stackErr(StackInsufficient))
|
||||
ok()
|
||||
|
||||
func popAux(stack: var EvmStack, T: type): EvmResult[T] =
|
||||
func popAux(stack: EvmStack, T: type): EvmResult[T] =
|
||||
? ensurePop(stack, 1)
|
||||
result = ok(fromStackElem(stack.values[^1], T))
|
||||
stack.values.setLen(stack.values.len - 1)
|
||||
|
||||
func internalPopTuple(stack: var EvmStack, T: type, tupleLen: static[int]): EvmResult[T] =
|
||||
? ensurePop(stack, tupleLen)
|
||||
var
|
||||
i = 0
|
||||
v: T
|
||||
let sz = stack.values.high
|
||||
for f in fields(v):
|
||||
f = fromStackElem(stack.values[sz - i], UInt256)
|
||||
inc i
|
||||
stack.values.setLen(sz - tupleLen + 1)
|
||||
ok(v)
|
||||
|
||||
macro genTupleType(len: static[int], elemType: untyped): untyped =
|
||||
result = nnkTupleConstr.newNimNode()
|
||||
for i in 0 ..< len: result.add(elemType)
|
||||
stack.len -= 1
|
||||
ok(fromStackElem(stack[stack.len], T))
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
func push*(stack: var EvmStack,
|
||||
value: EvmStackInts | UInt256 | Address | Hash32): EvmResultVoid =
|
||||
pushAux(stack, value)
|
||||
func push*(stack: EvmStack,
|
||||
value: EvmStackElement | EvmStackInts | UInt256 | Address | Hash32): EvmResultVoid =
|
||||
let len = stack.len
|
||||
if len > 1023:
|
||||
return err(stackErr(StackFull))
|
||||
toStackElem(value, stack[len])
|
||||
stack.len = len + 1
|
||||
ok()
|
||||
|
||||
func push*(stack: var EvmStack, value: openArray[byte]): EvmResultVoid =
|
||||
pushAux(stack, value)
|
||||
|
||||
func popInt*(stack: var EvmStack): EvmResult[UInt256] =
|
||||
func popInt*(stack: EvmStack): EvmResult[UInt256] =
|
||||
popAux(stack, UInt256)
|
||||
|
||||
func popSafeInt*(stack: var EvmStack): EvmResult[int] =
|
||||
? ensurePop(stack, 1)
|
||||
result = ok(fromStackElem(stack.values[^1], UInt256).safeInt)
|
||||
stack.values.setLen(stack.values.len - 1)
|
||||
|
||||
func popMemRef*(stack: var EvmStack): EvmResult[int] =
|
||||
? ensurePop(stack, 1)
|
||||
result = ok(fromStackElem(stack.values[^1], UInt256).cleanMemRef)
|
||||
stack.values.setLen(stack.values.len - 1)
|
||||
|
||||
func popInt*(stack: var EvmStack, numItems: static[int]): auto =
|
||||
type T = genTupleType(numItems, UInt256)
|
||||
stack.internalPopTuple(T, numItems)
|
||||
|
||||
func popAddress*(stack: var EvmStack): EvmResult[Address] =
|
||||
func popAddress*(stack: EvmStack): EvmResult[Address] =
|
||||
popAux(stack, Address)
|
||||
|
||||
func popTopic*(stack: var EvmStack): EvmResult[EvmStackBytes32] =
|
||||
popAux(stack, EvmStackBytes32)
|
||||
proc init*(_: type EvmStack): EvmStack =
|
||||
let memory = c_malloc(evmStackSize * sizeof(EvmStackElement) + 31)
|
||||
|
||||
func init*(_: type EvmStack): EvmStack =
|
||||
EvmStack(
|
||||
values: newSeqOfCap[EvmStackElement](128)
|
||||
values: cast[ptr EvmStackElement](((cast[uint](memory) + 31) div 32) * 32) ,
|
||||
memory: memory, # Need to free the same pointer that we got from malloc
|
||||
len: 0,
|
||||
)
|
||||
|
||||
func swap*(stack: var EvmStack, position: int): EvmResultVoid =
|
||||
## Perform a SWAP operation on the stack
|
||||
let idx = position + 1
|
||||
if idx < stack.values.len + 1:
|
||||
(stack.values[^1], stack.values[^idx]) = (stack.values[^idx], stack.values[^1])
|
||||
proc dispose*(stack: EvmStack) =
|
||||
if stack[].memory != nil:
|
||||
c_free(stack[].memory)
|
||||
stack[].reset()
|
||||
|
||||
func swap*(stack: EvmStack, position: static int): EvmResultVoid =
|
||||
## Swap the `top` and `top - position` items
|
||||
let
|
||||
idx = position + 1 # locals help compiler reason about overflows
|
||||
len = stack.len
|
||||
if stack.len >= idx:
|
||||
let
|
||||
l1 = len - 1
|
||||
li = len - idx
|
||||
let tmp {.noinit.} = stack[l1]
|
||||
stack[l1] = stack[li]
|
||||
stack[li] = tmp
|
||||
ok()
|
||||
else:
|
||||
err(stackErr(StackInsufficient))
|
||||
|
||||
func dup*(stack: var EvmStack, position: int): EvmResultVoid =
|
||||
## Perform a DUP operation on the stack
|
||||
func dup*(stack: EvmStack, position: int): EvmResultVoid =
|
||||
## Push copy of item at `top - position`
|
||||
if position in 1 .. stack.len:
|
||||
stack.push(stack.values[^position])
|
||||
stack.push(stack[^position])
|
||||
else:
|
||||
err(stackErr(StackInsufficient))
|
||||
|
||||
func peek*(stack: EvmStack): EvmResult[UInt256] =
|
||||
if stack.values.len == 0:
|
||||
return err(stackErr(StackInsufficient))
|
||||
ok(fromStackElem(stack.values[^1], UInt256))
|
||||
? ensurePop(stack, 1)
|
||||
ok(fromStackElem(stack[^1], UInt256))
|
||||
|
||||
func peekSafeInt*(stack: EvmStack): EvmResult[int] =
|
||||
if stack.values.len == 0:
|
||||
return err(stackErr(StackInsufficient))
|
||||
ok(fromStackElem(stack.values[^1], UInt256).safeInt)
|
||||
? ensurePop(stack, 1)
|
||||
ok(fromStackElem(stack[^1], UInt256).safeInt)
|
||||
|
||||
func `[]`*(stack: EvmStack, i: BackwardsIndex, T: typedesc): EvmResult[T] =
|
||||
? ensurePop(stack, int(i))
|
||||
ok(fromStackElem(stack.values[i], T))
|
||||
ok(fromStackElem(stack[i], T))
|
||||
|
||||
func peekInt*(stack: EvmStack): EvmResult[UInt256] =
|
||||
? ensurePop(stack, 1)
|
||||
ok(fromStackElem(stack.values[^1], UInt256))
|
||||
ok(fromStackElem(stack[^1], UInt256))
|
||||
|
||||
func peekAddress*(stack: EvmStack): EvmResult[Address] =
|
||||
? ensurePop(stack, 1)
|
||||
ok(fromStackElem(stack.values[^1], Address))
|
||||
ok(fromStackElem(stack[^1], Address))
|
||||
|
||||
func top*(stack: EvmStack,
|
||||
value: EvmStackInts | UInt256 | Address | Hash32): EvmResultVoid =
|
||||
if stack.values.len == 0:
|
||||
return err(stackErr(StackInsufficient))
|
||||
toStackElem(value, stack.values[^1])
|
||||
? ensurePop(stack, 1)
|
||||
toStackElem(value, stack[^1])
|
||||
ok()
|
||||
|
||||
iterator items*(stack: EvmStack): UInt256 =
|
||||
for v in stack.values:
|
||||
yield v
|
||||
for i in 0..<stack.len:
|
||||
yield stack[i].data
|
||||
|
||||
iterator pairs*(stack: EvmStack): (int, UInt256) =
|
||||
for i, v in stack.values:
|
||||
yield (i, v)
|
||||
for i in 0..<stack.len:
|
||||
yield (i, stack[i].data)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions with less safety
|
||||
@ -194,63 +212,77 @@ template lsCheck*(stack: EvmStack, expected: int): EvmResultVoid =
|
||||
|
||||
func lsTop*(stack: EvmStack,
|
||||
value: EvmStackInts | UInt256 | Address | Hash32) =
|
||||
toStackElem(value, stack.values[^1])
|
||||
toStackElem(value, stack[^1])
|
||||
|
||||
func lsTop*(stack: var EvmStack, value: openArray[byte]) =
|
||||
toStackElem(value, stack.values[^1])
|
||||
func lsTop*(stack: EvmStack, value: openArray[byte]) =
|
||||
toStackElem(value, stack[^1])
|
||||
|
||||
func lsPeekInt*(stack: EvmStack, i: BackwardsIndex): UInt256 =
|
||||
fromStackElem(stack.values[i], UInt256)
|
||||
fromStackElem(stack[i], UInt256)
|
||||
|
||||
func lsPeekAddress*(stack: EvmStack, i: BackwardsIndex): Address =
|
||||
fromStackElem(stack.values[i], Address)
|
||||
fromStackElem(stack[i], Address)
|
||||
|
||||
func lsPeekMemRef*(stack: EvmStack, i: BackwardsIndex): int =
|
||||
fromStackElem(stack.values[i], UInt256).cleanMemRef
|
||||
fromStackElem(stack[i], UInt256).cleanMemRef
|
||||
|
||||
func lsPeekSafeInt*(stack: EvmStack, i: BackwardsIndex): int =
|
||||
fromStackElem(stack.values[i], UInt256).safeInt
|
||||
fromStackElem(stack[i], UInt256).safeInt
|
||||
|
||||
func lsPeekTopic*(stack: EvmStack, i: BackwardsIndex): EvmStackBytes32 =
|
||||
fromStackElem(stack.values[i], EvmStackBytes32)
|
||||
func lsPeekTopic*(stack: EvmStack, i: BackwardsIndex): Bytes32 =
|
||||
fromStackElem(stack[i], Bytes32)
|
||||
|
||||
func lsShrink*(stack: EvmStack, x: int) =
|
||||
stack.values.setLen(stack.values.len - x)
|
||||
stack.len -= x
|
||||
|
||||
template binaryOp*(stack: EvmStack, binOp): EvmResultVoid =
|
||||
if stack.values.len >= 2:
|
||||
stack.values[^2] = binOp(stack.values[^1], stack.values[^2])
|
||||
stack.values.setLen(stack.values.len - 1)
|
||||
let len = stack.len
|
||||
if len >= 2:
|
||||
let
|
||||
l1 = len - 1
|
||||
l2 = len - 2
|
||||
stack[l2].data = binOp(stack[l1].data, stack[l2].data)
|
||||
stack.len = l1
|
||||
EvmResultVoid.ok()
|
||||
else:
|
||||
EvmResultVoid.err(stackErr(StackInsufficient))
|
||||
|
||||
template unaryOp*(stack: EvmStack, unOp): EvmResultVoid =
|
||||
if stack.values.len >= 1:
|
||||
stack.values[^1] = unOp(stack.values[^1])
|
||||
let len = stack.len
|
||||
if len >= 1:
|
||||
let l1 = len - 1
|
||||
stack[l1].data = unOp(stack[l1].data)
|
||||
EvmResultVoid.ok()
|
||||
else:
|
||||
EvmResultVoid.err(stackErr(StackInsufficient))
|
||||
|
||||
template binaryWithTop*(stack: EvmStack, binOp): EvmResultVoid =
|
||||
if stack.values.len >= 2:
|
||||
binOp(stack.values[^2], stack.values[^1], stack.values[^2])
|
||||
stack.values.setLen(stack.values.len - 1)
|
||||
let len = stack.len
|
||||
if len >= 2:
|
||||
let
|
||||
l1 = len - 1
|
||||
l2 = len - 2
|
||||
binOp(stack[l2].data, stack[l1].data, stack[l2].data)
|
||||
stack.len = l1
|
||||
EvmResultVoid.ok()
|
||||
else:
|
||||
EvmResultVoid.err(stackErr(StackInsufficient))
|
||||
|
||||
template unaryWithTop*(stack: EvmStack, unOp): EvmResultVoid =
|
||||
if stack.values.len >= 1:
|
||||
unOp(stack.values[^1], stack.values[^1], toStackElem)
|
||||
let len = stack.len
|
||||
if len >= 1:
|
||||
let l1 = len - 1
|
||||
unOp(stack[l1], stack[l1].data, toStackElem)
|
||||
EvmResultVoid.ok()
|
||||
else:
|
||||
EvmResultVoid.err(stackErr(StackInsufficient))
|
||||
|
||||
template unaryAddress*(stack: EvmStack, unOp): EvmResultVoid =
|
||||
if stack.values.len >= 1:
|
||||
let address = fromStackElem(stack.values[^1], Address)
|
||||
toStackElem(unOp(address), stack.values[^1])
|
||||
let len = stack.len
|
||||
if len >= 1:
|
||||
let l1 = len - 1
|
||||
let address = fromStackElem(stack[l1], Address)
|
||||
toStackElem(unOp(address), stack[l1])
|
||||
EvmResultVoid.ok()
|
||||
else:
|
||||
EvmResultVoid.err(stackErr(StackInsufficient))
|
||||
|
@ -14,6 +14,8 @@ import
|
||||
../db/ledger,
|
||||
../common/[common, evmforks]
|
||||
|
||||
export stack, memory
|
||||
|
||||
# this import not guarded by `when defined(evmc_enabled)`
|
||||
# because we want to use evmc types such as evmc_call_kind
|
||||
# and evmc_flags
|
||||
@ -76,7 +78,6 @@ type
|
||||
msg*: Message
|
||||
memory*: EvmMemory
|
||||
stack*: EvmStack
|
||||
returnStack*: seq[int]
|
||||
gasMeter*: GasMeter
|
||||
code*: CodeStream
|
||||
output*: seq[byte]
|
||||
@ -93,6 +94,8 @@ type
|
||||
parent*, child*: Computation
|
||||
continuation*: proc(): EvmResultVoid {.gcsafe, raises: [].}
|
||||
sysCall*: bool
|
||||
keepStack*: bool
|
||||
finalStack*: seq[UInt256]
|
||||
|
||||
Error* = ref object
|
||||
evmcStatus*: evmc_status_code
|
||||
|
@ -132,7 +132,7 @@ proc preExecComputation(vmState: BaseVMState, call: CallParams): int64 =
|
||||
|
||||
gasRefund
|
||||
|
||||
proc setupHost(call: CallParams): TransactionHost =
|
||||
proc setupHost(call: CallParams, keepStack: bool): TransactionHost =
|
||||
let vmState = call.vmState
|
||||
vmState.txCtx = TxContext(
|
||||
origin : call.origin.get(call.sender),
|
||||
@ -162,6 +162,8 @@ proc setupHost(call: CallParams): TransactionHost =
|
||||
|
||||
let gasRefund = if call.sysCall: 0
|
||||
else: preExecComputation(vmState, call)
|
||||
let isPrecompile =
|
||||
not call.isCreate and vmState.fork.getPrecompile(host.msg.code_address.fromEvmc).isSome()
|
||||
|
||||
# Generate new contract address, prepare code, and update message `recipient`
|
||||
# with the contract address. This differs from the previous Nimbus EVM API.
|
||||
@ -179,7 +181,9 @@ proc setupHost(call: CallParams): TransactionHost =
|
||||
else:
|
||||
# TODO: Share the underlying data, but only after checking this does not
|
||||
# cause problems with the database.
|
||||
if host.vmState.fork >= FkPrague:
|
||||
if isPrecompile:
|
||||
code = nil
|
||||
elif host.vmState.fork >= FkPrague:
|
||||
code = host.vmState.readOnlyStateDB.resolveCode(host.msg.code_address.fromEvmc)
|
||||
else:
|
||||
code = host.vmState.readOnlyStateDB.getCode(host.msg.code_address.fromEvmc)
|
||||
@ -190,8 +194,10 @@ proc setupHost(call: CallParams): TransactionHost =
|
||||
host.input = call.input
|
||||
host.msg.input_data = host.input[0].addr
|
||||
|
||||
let cMsg = hostToComputationMessage(host.msg)
|
||||
host.computation = newComputation(vmState, call.sysCall, cMsg, code)
|
||||
let
|
||||
cMsg = hostToComputationMessage(host.msg)
|
||||
host.computation = newComputation(
|
||||
vmState, call.sysCall, cMsg, code, isPrecompile = isPrecompile, keepStack = keepStack)
|
||||
host.code = code
|
||||
|
||||
else:
|
||||
@ -202,8 +208,10 @@ proc setupHost(call: CallParams): TransactionHost =
|
||||
host.input = call.input
|
||||
host.msg.input_data = host.input[0].addr
|
||||
|
||||
let cMsg = hostToComputationMessage(host.msg)
|
||||
host.computation = newComputation(vmState, call.sysCall, cMsg)
|
||||
let
|
||||
cMsg = hostToComputationMessage(host.msg)
|
||||
host.computation = newComputation(
|
||||
vmState, call.sysCall, cMsg, isPrecompile = isPrecompile, keepStack = keepStack)
|
||||
|
||||
host.computation.gasMeter.refundGas(gasRefund)
|
||||
vmState.captureStart(host.computation, call.sender, call.to,
|
||||
@ -290,7 +298,7 @@ proc finishRunningComputation(
|
||||
let gasUsed = host.msg.gas.GasInt - gasRemaining
|
||||
host.vmState.captureEnd(c, c.output, gasUsed, c.errorOpt)
|
||||
|
||||
when T is CallResult:
|
||||
when T is CallResult|DebugCallResult:
|
||||
# Collecting the result can be unnecessarily expensive when (re)-processing
|
||||
# transactions
|
||||
if c.isError:
|
||||
@ -299,8 +307,10 @@ proc finishRunningComputation(
|
||||
result.output = system.move(c.output)
|
||||
result.contractAddress = if call.isCreate: c.msg.contractAddress
|
||||
else: default(HostAddress)
|
||||
result.stack = move(c.stack)
|
||||
result.memory = move(c.memory)
|
||||
|
||||
when T is DebugCallResult:
|
||||
result.stack = move(c.finalStack)
|
||||
result.memory = move(c.memory)
|
||||
elif T is GasInt:
|
||||
result = call.gasLimit - gasRemaining
|
||||
elif T is string:
|
||||
@ -312,7 +322,7 @@ proc finishRunningComputation(
|
||||
{.error: "Unknown computation output".}
|
||||
|
||||
proc runComputation*(call: CallParams, T: type): T =
|
||||
let host = setupHost(call)
|
||||
let host = setupHost(call, keepStack = T is DebugCallResult)
|
||||
prepareToRunComputation(host, call)
|
||||
|
||||
when defined(evmc_enabled):
|
||||
|
@ -204,6 +204,6 @@ proc txCallEvm*(tx: Transaction,
|
||||
|
||||
proc testCallEvm*(tx: Transaction,
|
||||
sender: Address,
|
||||
vmState: BaseVMState): CallResult =
|
||||
vmState: BaseVMState): DebugCallResult =
|
||||
let call = callParamsForTest(tx, sender, vmState)
|
||||
runComputation(call, CallResult)
|
||||
runComputation(call, DebugCallResult)
|
||||
|
@ -17,6 +17,8 @@ import
|
||||
../core/eip7702,
|
||||
./host_types
|
||||
|
||||
export types
|
||||
|
||||
type
|
||||
# Standard call parameters.
|
||||
CallParams* = object
|
||||
@ -40,12 +42,14 @@ type
|
||||
|
||||
# Standard call result. (Some fields are beyond what EVMC can return,
|
||||
# and must only be used from tests because they will not always be set).
|
||||
CallResult* = object
|
||||
CallResult* = object of RootObj
|
||||
error*: string # Something if the call failed.
|
||||
gasUsed*: GasInt # Gas used by the call.
|
||||
contractAddress*: Address # Created account (when `isCreate`).
|
||||
output*: seq[byte] # Output data.
|
||||
stack*: EvmStack # EVM stack on return (for test only).
|
||||
|
||||
DebugCallResult* = object of CallResult
|
||||
stack*: seq[UInt256] # EVM stack on return (for test only).
|
||||
memory*: EvmMemory # EVM memory on return (for test only).
|
||||
|
||||
template isCreate(tx: Transaction): bool =
|
||||
|
@ -129,9 +129,9 @@ proc evmcExecComputation*(host: TransactionHost): EvmcResult =
|
||||
|
||||
result = vm.execute(vm, hostInterface.unsafeAddr, hostContext,
|
||||
evmc_revision(host.vmState.fork.ord), host.msg,
|
||||
if host.code.len > 0: host.code.bytes[0].unsafeAddr
|
||||
if host.code != nil and host.code.len > 0: host.code.bytes[0].unsafeAddr
|
||||
else: nil,
|
||||
host.code.len.csize_t)
|
||||
if host.code != nil: host.code.len.csize_t else: 0)
|
||||
|
||||
host.showCallReturn(result)
|
||||
|
||||
|
@ -13,7 +13,7 @@ import
|
||||
stew/ptrops,
|
||||
stew/saturation_arith,
|
||||
stint,
|
||||
../evm/types,
|
||||
../evm/[types, precompiles],
|
||||
../evm/interpreter_dispatch,
|
||||
../utils/utils,
|
||||
"."/[host_types, host_trace]
|
||||
@ -34,7 +34,8 @@ proc beforeExecCreateEvmcNested(host: TransactionHost,
|
||||
value: m.value.fromEvmc,
|
||||
data: @(makeOpenArray(m.input_data, m.input_size.int))
|
||||
)
|
||||
return newComputation(host.vmState, false, childMsg,
|
||||
return newComputation(host.vmState, false, childMsg, isPrecompile = false,
|
||||
keepStack = false,
|
||||
cast[ContractSalt](m.create2_salt))
|
||||
|
||||
proc afterExecCreateEvmcNested(host: TransactionHost, child: Computation,
|
||||
@ -71,7 +72,8 @@ proc beforeExecCallEvmcNested(host: TransactionHost,
|
||||
data: @(makeOpenArray(m.input_data, m.input_size.int)),
|
||||
flags: m.flags,
|
||||
)
|
||||
return newComputation(host.vmState, false, childMsg)
|
||||
let isPrecompile = getPrecompile(host.vmState.fork, childMsg.codeAddress).isSome()
|
||||
newComputation(host.vmState, false, childMsg, isPrecompile = isPrecompile, keepStack = false)
|
||||
|
||||
proc afterExecCallEvmcNested(host: TransactionHost, child: Computation,
|
||||
res: var EvmcResult) {.inline.} =
|
||||
|
@ -40,8 +40,7 @@ func calcRequestsHash*(requests: varargs[seq[byte]]): Hash32 =
|
||||
var ctx: sha256
|
||||
ctx.init()
|
||||
for i, data in requests:
|
||||
if data.len > 0:
|
||||
ctx.update(calcHash(i.byte, data).data)
|
||||
ctx.update(calcHash(i.byte, data).data)
|
||||
ctx.finish(result.data)
|
||||
ctx.clear()
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -2,7 +2,7 @@
|
||||
"payload": {
|
||||
"baseFeePerGas": "0x7",
|
||||
"blobGasUsed": "0x40000",
|
||||
"blockHash": "0x2ad74d1c5c12bcdedbdc821ae5d18f44e732b4096b6496a23bd9483d202003c5",
|
||||
"blockHash": "0x187307d7dc9beb87af2a1d8340e9f17a3bbe4738963daeaf6d8e13b27b2d6a7f",
|
||||
"blockNumber": "0x94b2",
|
||||
"excessBlobGas": "0x0",
|
||||
"extraData": "0xd883010e0c846765746888676f312e32332e32856c696e7578",
|
||||
|
@ -281,7 +281,7 @@ proc initVMEnv*(network: string): BaseVMState =
|
||||
|
||||
BaseVMState.new(parent, header, com)
|
||||
|
||||
proc verifyAsmResult(vmState: BaseVMState, boa: Assembler, asmResult: CallResult): bool =
|
||||
proc verifyAsmResult(vmState: BaseVMState, boa: Assembler, asmResult: DebugCallResult): bool =
|
||||
let com = vmState.com
|
||||
if not asmResult.isError:
|
||||
if boa.success == false:
|
||||
|
@ -26,24 +26,20 @@ import
|
||||
template testPush(value: untyped, expected: untyped): untyped =
|
||||
privateAccess(EvmStack)
|
||||
var stack = EvmStack.init()
|
||||
defer: stack.dispose()
|
||||
check stack.push(value).isOk
|
||||
check(stack.values == @[expected])
|
||||
|
||||
func toBytes(s: string): seq[byte] =
|
||||
cast[seq[byte]](s)
|
||||
|
||||
func bigEndianToInt(value: openArray[byte]): UInt256 =
|
||||
result.initFromBytesBE(value)
|
||||
check(toSeq(stack.items()) == @[expected])
|
||||
|
||||
proc runStackTests() =
|
||||
suite "Stack tests":
|
||||
test "push only valid":
|
||||
testPush(0'u, 0.u256)
|
||||
testPush(UINT_256_MAX, UINT_256_MAX)
|
||||
testPush("ves".toBytes, "ves".toBytes.bigEndianToInt)
|
||||
# testPush("ves".toBytes, "ves".toBytes.bigEndianToInt)
|
||||
|
||||
test "push does not allow stack to exceed 1024":
|
||||
var stack = EvmStack.init()
|
||||
defer: stack.dispose()
|
||||
for z in 0 ..< 1024:
|
||||
check stack.push(z.uint).isOk
|
||||
check(stack.len == 1024)
|
||||
@ -51,6 +47,7 @@ proc runStackTests() =
|
||||
|
||||
test "dup does not allow stack to exceed 1024":
|
||||
var stack = EvmStack.init()
|
||||
defer: stack.dispose()
|
||||
check stack.push(1.u256).isOk
|
||||
for z in 0 ..< 1023:
|
||||
check stack.dup(1).isOk
|
||||
@ -59,6 +56,7 @@ proc runStackTests() =
|
||||
|
||||
test "pop returns latest stack item":
|
||||
var stack = EvmStack.init()
|
||||
defer: stack.dispose()
|
||||
for element in @[1'u, 2'u, 3'u]:
|
||||
check stack.push(element).isOk
|
||||
check(stack.popInt.get == 3.u256)
|
||||
@ -66,35 +64,40 @@ proc runStackTests() =
|
||||
test "swap correct":
|
||||
privateAccess(EvmStack)
|
||||
var stack = EvmStack.init()
|
||||
defer: stack.dispose()
|
||||
for z in 0 ..< 5:
|
||||
check stack.push(z.uint).isOk
|
||||
check(stack.values == @[0.u256, 1.u256, 2.u256, 3.u256, 4.u256])
|
||||
check(toSeq(stack.items()) == @[0.u256, 1.u256, 2.u256, 3.u256, 4.u256])
|
||||
check stack.swap(3).isOk
|
||||
check(stack.values == @[0.u256, 4.u256, 2.u256, 3.u256, 1.u256])
|
||||
check(toSeq(stack.items()) == @[0.u256, 4.u256, 2.u256, 3.u256, 1.u256])
|
||||
check stack.swap(1).isOk
|
||||
check(stack.values == @[0.u256, 4.u256, 2.u256, 1.u256, 3.u256])
|
||||
check(toSeq(stack.items()) == @[0.u256, 4.u256, 2.u256, 1.u256, 3.u256])
|
||||
|
||||
test "dup correct":
|
||||
privateAccess(EvmStack)
|
||||
var stack = EvmStack.init()
|
||||
defer: stack.dispose()
|
||||
for z in 0 ..< 5:
|
||||
check stack.push(z.uint).isOk
|
||||
check(stack.values == @[0.u256, 1.u256, 2.u256, 3.u256, 4.u256])
|
||||
check(toSeq(stack.items()) == @[0.u256, 1.u256, 2.u256, 3.u256, 4.u256])
|
||||
check stack.dup(1).isOk
|
||||
check(stack.values == @[0.u256, 1.u256, 2.u256, 3.u256, 4.u256, 4.u256])
|
||||
check(toSeq(stack.items()) == @[0.u256, 1.u256, 2.u256, 3.u256, 4.u256, 4.u256])
|
||||
check stack.dup(5).isOk
|
||||
check(stack.values == @[0.u256, 1.u256, 2.u256, 3.u256, 4.u256, 4.u256, 1.u256])
|
||||
check(toSeq(stack.items()) == @[0.u256, 1.u256, 2.u256, 3.u256, 4.u256, 4.u256, 1.u256])
|
||||
|
||||
test "pop raises InsufficientStack appropriately":
|
||||
var stack = EvmStack.init()
|
||||
defer: stack.dispose()
|
||||
check stack.popInt().error.code == EvmErrorCode.StackInsufficient
|
||||
|
||||
test "swap raises InsufficientStack appropriately":
|
||||
var stack = EvmStack.init()
|
||||
defer: stack.dispose()
|
||||
check stack.swap(0).error.code == EvmErrorCode.StackInsufficient
|
||||
|
||||
test "dup raises InsufficientStack appropriately":
|
||||
var stack = EvmStack.init()
|
||||
defer: stack.dispose()
|
||||
check stack.dup(0).error.code == EvmErrorCode.StackInsufficient
|
||||
|
||||
test "binary operations raises InsufficientStack appropriately":
|
||||
@ -102,8 +105,9 @@ proc runStackTests() =
|
||||
# ./tests/fixtures/VMTests/vmArithmeticTest/mulUnderFlow.json
|
||||
|
||||
var stack = EvmStack.init()
|
||||
defer: stack.dispose()
|
||||
check stack.push(123).isOk
|
||||
check stack.popInt(2).error.code == EvmErrorCode.StackInsufficient
|
||||
check stack.binaryOp(`+`).error.code == EvmErrorCode.StackInsufficient
|
||||
|
||||
proc memory32: EvmMemory =
|
||||
result = EvmMemory.init(32)
|
||||
|
@ -12,8 +12,7 @@ import
|
||||
std/[os],
|
||||
unittest2,
|
||||
../nimbus/config,
|
||||
../nimbus/common/common,
|
||||
../nimbus/utils/utils
|
||||
../nimbus/common/common
|
||||
|
||||
const
|
||||
baseDir = [".", "tests", ".."/"tests", $DirSep] # path containg repo
|
||||
@ -133,21 +132,6 @@ proc customGenesisTest() =
|
||||
check com.genesisHeader.blockHash == genesisHash
|
||||
check com.chainId == 17000.ChainId
|
||||
|
||||
test "Prague genesis":
|
||||
# pre Prague
|
||||
var cg: NetworkParams
|
||||
check loadNetworkParams("mekong.json".findFilePath, cg)
|
||||
var com = CommonRef.new(newCoreDbRef DefaultDbMemory, params = cg)
|
||||
check com.genesisHeader.requestsHash.isNone
|
||||
|
||||
# post prague
|
||||
const EmptyRequestsHash = hash32"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
check loadNetworkParams("prague.json".findFilePath, cg)
|
||||
com = CommonRef.new(newCoreDbRef DefaultDbMemory, params = cg)
|
||||
check com.genesisHeader.requestsHash.isSome
|
||||
check com.genesisHeader.requestsHash.get == EmptyRequestsHash
|
||||
check calcRequestsHash(default(seq[byte]), default(seq[byte]), default(seq[byte])) == EmptyRequestsHash
|
||||
|
||||
proc genesisMain*() =
|
||||
genesisTest()
|
||||
customGenesisTest()
|
||||
|
2
tools/t8n/testdata/00-525/exp1.json
vendored
2
tools/t8n/testdata/00-525/exp1.json
vendored
@ -18,7 +18,7 @@
|
||||
"withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"currentExcessBlobGas": "0x2b80000",
|
||||
"blobGasUsed": "0x0",
|
||||
"requestsHash": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"requestsHash": "0x6036c41849da9c076ed79654d434017387a88fb833c2856b32e18218b3341c5f",
|
||||
"requests": [
|
||||
"0x",
|
||||
"0x",
|
||||
|
2
tools/t8n/testdata/00-525/exp2.json
vendored
2
tools/t8n/testdata/00-525/exp2.json
vendored
@ -34,7 +34,7 @@
|
||||
"withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"currentExcessBlobGas": "0x2b80000",
|
||||
"blobGasUsed": "0x0",
|
||||
"requestsHash": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"requestsHash": "0x6036c41849da9c076ed79654d434017387a88fb833c2856b32e18218b3341c5f",
|
||||
"requests": [
|
||||
"0x",
|
||||
"0x",
|
||||
|
2
tools/t8n/testdata/00-525/exp3.json
vendored
2
tools/t8n/testdata/00-525/exp3.json
vendored
@ -34,7 +34,7 @@
|
||||
"withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"currentExcessBlobGas": "0x2b80000",
|
||||
"blobGasUsed": "0x0",
|
||||
"requestsHash": "0xf34c7b46f404c6c6f91b540c098b6dfe3f59b7e50ad155807c8c7d2221e52241",
|
||||
"requestsHash": "0xa5c19ed76c01fe25a67b7ef8c227caa34951e8c7e74168408b5be0861dac686d",
|
||||
"requests": [
|
||||
"0x81521c60874daf5b425c21e44caf045c4d475e8b33a557a28cee3c46ef9cf9bd95b4c75a0bb629981b40d0102452dd4c020000000000000000000000332e43696a505ef45b9319973785f837ce5267b9000065cd1d0000008c8f2647f342d2c3e8fd07c6b3b9b16383ac11c4be6a6962c7fc18a789daee5fac20ee0bbe4a10383759aaffacacb72b0d67f998730cdf4995fe73afe434dfce2803b343606f67fc4995597c0af9e0fe9ed00006e5889bec29171f670e7d9be20000000000000000",
|
||||
"0x",
|
||||
|
2
tools/t8n/testdata/33/exp.json
vendored
2
tools/t8n/testdata/33/exp.json
vendored
@ -60,7 +60,7 @@
|
||||
"gasUsed": "0x15fa9",
|
||||
"currentBaseFee": "0x7",
|
||||
"withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"requestsHash": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"requestsHash": "0x6036c41849da9c076ed79654d434017387a88fb833c2856b32e18218b3341c5f",
|
||||
"requests": [
|
||||
"0x",
|
||||
"0x",
|
||||
|
Loading…
x
Reference in New Issue
Block a user