-
Notifications
You must be signed in to change notification settings - Fork 107
/
evmc_api.nim
182 lines (154 loc) · 8.71 KB
/
evmc_api.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# Nimbus
# Copyright (c) 2019-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http:https://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http:https://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import evmc/evmc, ./evmc_helpers, eth/common, ../constants
{.push raises: [].}
type
# we are not using EVMC original signature here
# because we want to trick the compiler
# and reduce unnecessary conversion/typecast
# TODO: move this type definition to nim-evmc
# after we have implemented ABI compatibility test
# TODO: investigate the possibility to use Big Endian VMWord
# directly if it's not involving stint computation
# and we can reduce unecessary conversion further
nimbus_tx_context* = object
tx_gas_price* : evmc_uint256be # The transaction gas price.
tx_origin* : EthAddress # The transaction origin account.
block_coinbase* : EthAddress # The miner of the block.
block_number* : int64 # The block number.
block_timestamp* : int64 # The block timestamp.
block_gas_limit* : int64 # The block gas limit.
block_prev_randao*: evmc_uint256be # The block difficulty.
chain_id* : evmc_uint256be # The blockchain's ChainID.
block_base_fee* : evmc_uint256be # The block base fee.
blob_hashes* : ptr evmc_bytes32 # The array of blob hashes (EIP-4844).
blob_hashes_count*: csize_t # The number of blob hashes (EIP-4844).
blob_base_fee* : evmc_uint256be # The blob base fee (EIP-7516).
initcodes* : ptr evmc_tx_initcode # The array of transaction initcodes (TXCREATE).
initcodes_count* : csize_t # The number of transaction initcodes (TXCREATE).
nimbus_message* = object
kind* : evmc_call_kind
flags* : evmc_flags
depth* : int32
gas* : int64
recipient* : EthAddress
sender* : EthAddress
input_data* : ptr byte
input_size* : uint
value* : evmc_uint256be
create2_salt*: evmc_bytes32
code_address*: EthAddress
code* : ptr byte
code_size* : csize_t
nimbus_result* = object
status_code* : evmc_status_code
gas_left* : int64
gas_refund* : int64
output_data* : ptr byte
output_size* : uint
release* : proc(result: var nimbus_result)
{.cdecl, gcsafe, raises: [].}
create_address*: EthAddress
padding* : array[4, byte]
nimbus_host_interface* = object
account_exists*: proc(context: evmc_host_context, address: EthAddress): bool {.cdecl, gcsafe, raises: [].}
get_storage*: proc(context: evmc_host_context, address: EthAddress, key: ptr evmc_uint256be): evmc_uint256be {.cdecl, gcsafe, raises: [].}
set_storage*: proc(context: evmc_host_context, address: EthAddress,
key, value: ptr evmc_uint256be): evmc_storage_status {.cdecl, gcsafe, raises: [].}
get_balance*: proc(context: evmc_host_context, address: EthAddress): evmc_uint256be {.cdecl, gcsafe, raises: [].}
get_code_size*: proc(context: evmc_host_context, address: EthAddress): uint {.cdecl, gcsafe, raises: [].}
get_code_hash*: proc(context: evmc_host_context, address: EthAddress): Hash256 {.cdecl, gcsafe, raises: [].}
copy_code*: proc(context: evmc_host_context, address: EthAddress,
code_offset: int, buffer_data: ptr byte,
buffer_size: int): int {.cdecl, gcsafe, raises: [].}
selfdestruct*: proc(context: evmc_host_context, address, beneficiary: EthAddress) {.cdecl, gcsafe, raises: [].}
call*: proc(context: evmc_host_context, msg: ptr nimbus_message): nimbus_result {.cdecl, gcsafe, raises: [].}
get_tx_context*: proc(context: evmc_host_context): nimbus_tx_context {.cdecl, gcsafe, raises: [].}
get_block_hash*: proc(context: evmc_host_context, number: int64): Hash256 {.cdecl, gcsafe, raises: [].}
emit_log*: proc(context: evmc_host_context, address: EthAddress,
data: ptr byte, data_size: uint,
topics: ptr evmc_bytes32, topics_count: uint) {.cdecl, gcsafe, raises: [].}
access_account*: proc(context: evmc_host_context,
address: EthAddress): evmc_access_status {.cdecl, gcsafe, raises: [].}
access_storage*: proc(context: evmc_host_context, address: EthAddress,
key: var evmc_bytes32): evmc_access_status {.cdecl, gcsafe, raises: [].}
get_transient_storage*: proc(context: evmc_host_context, address: EthAddress,
key: ptr evmc_uint256be): evmc_uint256be {.cdecl, gcsafe, raises: [].}
set_transient_storage*: proc(context: evmc_host_context, address: EthAddress,
key, value: ptr evmc_uint256be) {.cdecl, gcsafe, raises: [].}
proc nim_host_get_interface*(): ptr nimbus_host_interface {.importc, cdecl.}
proc nim_host_create_context*(vmstate: pointer, msg: ptr evmc_message): evmc_host_context {.importc, cdecl.}
proc nim_host_destroy_context*(ctx: evmc_host_context) {.importc, cdecl.}
proc nim_create_nimbus_vm*(): ptr evmc_vm {.importc, cdecl.}
type
HostContext* = object
host*: ptr nimbus_host_interface
context*: evmc_host_context
proc init*(x: var HostContext, host: ptr nimbus_host_interface, context: evmc_host_context) =
x.host = host
x.context = context
proc init*(x: typedesc[HostContext], host: ptr nimbus_host_interface, context: evmc_host_context): HostContext =
result.init(host, context)
proc getTxContext*(ctx: HostContext): nimbus_tx_context =
ctx.host.get_tx_context(ctx.context)
proc getBlockHash*(ctx: HostContext, number: BlockNumber): Hash256 =
ctx.host.get_block_hash(ctx.context, number.int64)
proc accountExists*(ctx: HostContext, address: EthAddress): bool =
ctx.host.account_exists(ctx.context, address)
proc getStorage*(ctx: HostContext, address: EthAddress, key: UInt256): UInt256 =
var key = toEvmc(key)
UInt256.fromEvmc ctx.host.get_storage(ctx.context, address, key.addr)
proc setStorage*(ctx: HostContext, address: EthAddress,
key, value: UInt256): evmc_storage_status =
var
key = toEvmc(key)
value = toEvmc(value)
ctx.host.set_storage(ctx.context, address, key.addr, value.addr)
proc getBalance*(ctx: HostContext, address: EthAddress): UInt256 =
UInt256.fromEvmc ctx.host.get_balance(ctx.context, address)
proc getCodeSize*(ctx: HostContext, address: EthAddress): uint =
ctx.host.get_code_size(ctx.context, address)
proc getCodeHash*(ctx: HostContext, address: EthAddress): Hash256 =
ctx.host.get_code_hash(ctx.context, address)
proc copyCode*(ctx: HostContext, address: EthAddress, codeOffset: int = 0): seq[byte] =
let size = ctx.getCodeSize(address).int
if size - codeOffset > 0:
result = newSeq[byte](size - codeOffset)
let read = ctx.host.copy_code(ctx.context, address,
codeOffset, result[0].addr, result.len)
doAssert(read == result.len)
proc selfDestruct*(ctx: HostContext, address, beneficiary: EthAddress) =
ctx.host.selfdestruct(ctx.context, address, beneficiary)
proc emitLog*(ctx: HostContext, address: EthAddress, data: openArray[byte],
topics: ptr evmc_bytes32, topicsCount: int) =
ctx.host.emit_log(ctx.context, address, if data.len > 0: data[0].unsafeAddr else: nil,
data.len.uint, topics, topicsCount.uint)
proc call*(ctx: HostContext, msg: nimbus_message): nimbus_result =
ctx.host.call(ctx.context, msg.unsafeAddr)
proc accessAccount*(ctx: HostContext,
address: EthAddress): evmc_access_status =
ctx.host.access_account(ctx.context, address)
proc accessStorage*(ctx: HostContext, address: EthAddress,
key: UInt256): evmc_access_status =
var key = toEvmc(key)
ctx.host.access_storage(ctx.context, address, key)
proc getTransientStorage*(ctx: HostContext, address: EthAddress, key: UInt256): UInt256 =
var key = toEvmc(key)
UInt256.fromEvmc ctx.host.get_transient_storage(ctx.context, address, key.addr)
proc setTransientStorage*(ctx: HostContext, address: EthAddress,
key, value: UInt256) =
var
key = toEvmc(key)
value = toEvmc(value)
ctx.host.set_transient_storage(ctx.context, address, key.addr, value.addr)
# The following two templates put here because the stupid style checker
# complaints about block_number vs blockNumber and chain_id vs chainId
# if they are written directly in computation.nim
template getBlockNumber*(ctx: HostContext): uint64 =
ctx.getTxContext().block_number.uint64
template getChainId*(ctx: HostContext): uint64 =
UInt256.fromEvmc(ctx.getTxContext().chain_id).truncate(uint64)