2021-04-08 14:52:10 +00:00
|
|
|
# Nimbus
|
2024-03-21 11:24:32 +00:00
|
|
|
# Copyright (c) 2018-2024 Status Research & Development GmbH
|
2021-04-08 14:52:10 +00:00
|
|
|
# Licensed under either of
|
2024-06-07 08:24:32 +00:00
|
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0)
|
|
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
|
|
|
# http://opensource.org/licenses/MIT)
|
|
|
|
# at your option. This file may not be copied, modified, or distributed except
|
|
|
|
# according to those terms.
|
2021-04-08 14:52:10 +00:00
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
{.push raises: [].}
|
2021-04-08 14:52:10 +00:00
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
import
|
|
|
|
std/[macros],
|
|
|
|
eth/common,
|
|
|
|
./evm_errors,
|
|
|
|
./interpreter/utils/utils_numeric
|
2021-04-08 14:52:10 +00:00
|
|
|
|
2021-04-23 09:45:50 +00:00
|
|
|
type
|
2024-06-07 08:24:32 +00:00
|
|
|
EvmStackRef* = ref object
|
|
|
|
values: seq[EvmStackElement]
|
2021-04-23 09:45:50 +00:00
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
EvmStackElement = UInt256
|
|
|
|
EvmStackInts = uint64 | uint | int | GasInt
|
|
|
|
EvmStackBytes32 = array[32, byte]
|
2021-04-23 09:45:50 +00:00
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
func len*(stack: EvmStackRef): int {.inline.} =
|
2023-04-24 20:59:38 +00:00
|
|
|
len(stack.values)
|
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Private functions
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
template toStackElem(v: UInt256, elem: EvmStackElement) =
|
|
|
|
elem = v
|
2021-04-08 14:52:10 +00:00
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
template toStackElem(v: EvmStackInts, elem: EvmStackElement) =
|
|
|
|
elem = v.u256
|
2021-04-08 14:52:10 +00:00
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
template toStackElem(v: EthAddress, elem: EvmStackElement) =
|
2023-04-24 20:59:38 +00:00
|
|
|
elem.initFromBytesBE(v)
|
2021-04-08 14:52:10 +00:00
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
template toStackElem(v: MDigest, elem: EvmStackElement) =
|
|
|
|
elem.initFromBytesBE(v.data)
|
2021-04-08 14:52:10 +00:00
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
template toStackElem(v: openArray[byte], elem: EvmStackElement) =
|
|
|
|
doAssert(v.len <= 32)
|
|
|
|
elem.initFromBytesBE(v)
|
2021-04-08 14:52:10 +00:00
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
template fromStackElem(elem: EvmStackElement, _: type UInt256): UInt256 =
|
|
|
|
elem
|
2021-04-08 14:52:10 +00:00
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
func fromStackElem(elem: EvmStackElement, _: type EthAddress): EthAddress =
|
|
|
|
result[0 .. ^1] = elem.toBytesBE().toOpenArray(12, 31)
|
2021-04-08 14:52:10 +00:00
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
template fromStackElem(elem: EvmStackElement, _: type Hash256): Hash256 =
|
|
|
|
Hash256(data: elem.toBytesBE())
|
|
|
|
|
|
|
|
template fromStackElem(elem: EvmStackElement, _: type EvmStackBytes32): EvmStackBytes32 =
|
|
|
|
elem.toBytesBE()
|
|
|
|
|
|
|
|
func pushAux[T](stack: EvmStackRef, 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()
|
|
|
|
|
|
|
|
func ensurePop(stack: EvmStackRef, expected: int): EvmResultVoid =
|
|
|
|
if stack.values.len < expected:
|
|
|
|
return err(stackErr(StackInsufficient))
|
|
|
|
ok()
|
|
|
|
|
|
|
|
func popAux(stack: EvmStackRef, T: type): EvmResult[T] =
|
|
|
|
? ensurePop(stack, 1)
|
|
|
|
result = ok(fromStackElem(stack.values[^1], T))
|
2023-04-24 20:59:38 +00:00
|
|
|
stack.values.setLen(stack.values.len - 1)
|
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
func internalPopTuple(stack: EvmStackRef, T: type, tupleLen: static[int]): EvmResult[T] =
|
|
|
|
? ensurePop(stack, tupleLen)
|
|
|
|
var
|
|
|
|
i = 0
|
|
|
|
v: T
|
2023-04-24 20:59:38 +00:00
|
|
|
let sz = stack.values.high
|
2021-04-08 14:52:10 +00:00
|
|
|
for f in fields(v):
|
2024-06-07 08:24:32 +00:00
|
|
|
f = fromStackElem(stack.values[sz - i], UInt256)
|
2021-04-08 14:52:10 +00:00
|
|
|
inc i
|
2023-04-24 20:59:38 +00:00
|
|
|
stack.values.setLen(sz - tupleLen + 1)
|
2024-06-07 08:24:32 +00:00
|
|
|
ok(v)
|
2023-04-24 20:59:38 +00:00
|
|
|
|
|
|
|
macro genTupleType(len: static[int], elemType: untyped): untyped =
|
2021-04-08 14:52:10 +00:00
|
|
|
result = nnkTupleConstr.newNimNode()
|
|
|
|
for i in 0 ..< len: result.add(elemType)
|
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Public functions
|
|
|
|
# ------------------------------------------------------------------------------
|
2021-04-08 14:52:10 +00:00
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
func push*(stack: EvmStackRef,
|
|
|
|
value: EvmStackInts | UInt256 | EthAddress | Hash256): EvmResultVoid =
|
|
|
|
pushAux(stack, value)
|
2021-04-08 14:52:10 +00:00
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
func push*(stack: EvmStackRef, value: openArray[byte]): EvmResultVoid =
|
|
|
|
pushAux(stack, value)
|
|
|
|
|
|
|
|
func popInt*(stack: EvmStackRef): EvmResult[UInt256] =
|
|
|
|
popAux(stack, UInt256)
|
|
|
|
|
|
|
|
func popSafeInt*(stack: EvmStackRef): EvmResult[int] =
|
|
|
|
? ensurePop(stack, 1)
|
|
|
|
result = ok(fromStackElem(stack.values[^1], UInt256).safeInt)
|
|
|
|
stack.values.setLen(stack.values.len - 1)
|
|
|
|
|
|
|
|
func popMemRef*(stack: EvmStackRef): EvmResult[int] =
|
|
|
|
? ensurePop(stack, 1)
|
|
|
|
result = ok(fromStackElem(stack.values[^1], UInt256).cleanMemRef)
|
|
|
|
stack.values.setLen(stack.values.len - 1)
|
|
|
|
|
|
|
|
func popInt*(stack: EvmStackRef, numItems: static[int]): auto =
|
|
|
|
type T = genTupleType(numItems, UInt256)
|
|
|
|
stack.internalPopTuple(T, numItems)
|
|
|
|
|
|
|
|
func popAddress*(stack: EvmStackRef): EvmResult[EthAddress] =
|
|
|
|
popAux(stack, EthAddress)
|
2021-04-08 14:52:10 +00:00
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
func popTopic*(stack: EvmStackRef): EvmResult[EvmStackBytes32] =
|
|
|
|
popAux(stack, EvmStackBytes32)
|
|
|
|
|
|
|
|
func new*(_: type EvmStackRef): EvmStackRef =
|
2021-04-08 14:52:10 +00:00
|
|
|
new(result)
|
2023-04-24 20:59:38 +00:00
|
|
|
result.values = @[]
|
2021-04-08 14:52:10 +00:00
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
func swap*(stack: EvmStackRef, position: int): EvmResultVoid =
|
2021-04-08 14:52:10 +00:00
|
|
|
## Perform a SWAP operation on the stack
|
2024-06-07 08:24:32 +00:00
|
|
|
let idx = position + 1
|
|
|
|
if idx < stack.values.len + 1:
|
2023-04-24 20:59:38 +00:00
|
|
|
(stack.values[^1], stack.values[^idx]) = (stack.values[^idx], stack.values[^1])
|
2024-06-07 08:24:32 +00:00
|
|
|
ok()
|
2021-04-08 14:52:10 +00:00
|
|
|
else:
|
2024-06-07 08:24:32 +00:00
|
|
|
err(stackErr(StackInsufficient))
|
2021-04-08 14:52:10 +00:00
|
|
|
|
2024-06-07 08:24:32 +00:00
|
|
|
func dup*(stack: EvmStackRef, position: int): EvmResultVoid =
|
2021-04-08 14:52:10 +00:00
|
|
|
## Perform a DUP operation on the stack
|
|
|
|
if position in 1 .. stack.len:
|
2023-04-24 20:59:38 +00:00
|
|
|
stack.push(stack.values[^position])
|
2021-04-08 14:52:10 +00:00
|
|
|
else:
|
2024-06-07 08:24:32 +00:00
|
|
|
err(stackErr(StackInsufficient))
|
|
|
|
|
|
|
|
func peek*(stack: EvmStackRef): EvmResult[UInt256] =
|
|
|
|
if stack.values.len == 0:
|
|
|
|
return err(stackErr(StackInsufficient))
|
|
|
|
ok(fromStackElem(stack.values[^1], UInt256))
|
|
|
|
|
|
|
|
func peekSafeInt*(stack: EvmStackRef): EvmResult[int] =
|
|
|
|
if stack.values.len == 0:
|
|
|
|
return err(stackErr(StackInsufficient))
|
|
|
|
ok(fromStackElem(stack.values[^1], UInt256).safeInt)
|
|
|
|
|
|
|
|
func `[]`*(stack: EvmStackRef, i: BackwardsIndex, T: typedesc): EvmResult[T] =
|
|
|
|
? ensurePop(stack, int(i))
|
|
|
|
ok(fromStackElem(stack.values[i], T))
|
|
|
|
|
|
|
|
func peekInt*(stack: EvmStackRef): EvmResult[UInt256] =
|
|
|
|
? ensurePop(stack, 1)
|
|
|
|
ok(fromStackElem(stack.values[^1], Uint256))
|
|
|
|
|
|
|
|
func peekAddress*(stack: EvmStackRef): EvmResult[EthAddress] =
|
|
|
|
? ensurePop(stack, 1)
|
|
|
|
ok(fromStackElem(stack.values[^1], EthAddress))
|
|
|
|
|
|
|
|
func top*(stack: EvmStackRef,
|
|
|
|
value: EvmStackInts | UInt256 | EthAddress | Hash256): EvmResultVoid =
|
|
|
|
if stack.values.len == 0:
|
|
|
|
return err(stackErr(StackInsufficient))
|
|
|
|
toStackElem(value, stack.values[^1])
|
|
|
|
ok()
|
|
|
|
|
|
|
|
iterator items*(stack: EvmStackRef): UInt256 =
|
|
|
|
for v in stack.values:
|
|
|
|
yield v
|
|
|
|
|
|
|
|
iterator pairs*(stack: EvmStackRef): (int, UInt256) =
|
|
|
|
for i, v in stack.values:
|
|
|
|
yield (i, v)
|