Skip to content

Commit 9244cc9

Browse files
authored
Fluffy: Make portal evm backend configurable (#3165)
* Make portal evm backend functions configurable. * Make chain config configurable. * Remove history network and state network imports and exports and remove usage of Bytecode type.
1 parent 43dbd23 commit 9244cc9

File tree

6 files changed

+78
-58
lines changed

6 files changed

+78
-58
lines changed

fluffy/evm/portal_evm.nim

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,12 @@ import
1818
../../execution_chain/db/ledger,
1919
../../execution_chain/common/common,
2020
../../execution_chain/transaction/call_evm,
21-
../../execution_chain/evm/[types, state, evm_errors],
22-
../network/history/history_network,
23-
../network/state/[state_endpoints, state_network]
21+
../../execution_chain/evm/[types, state, evm_errors]
2422

2523
from web3/eth_api_types import TransactionArgs
2624

2725
export
28-
results, chronos, hashes, history_network, state_network, TransactionArgs, CallResult
26+
results, chronos, hashes, addresses, accounts, headers, TransactionArgs, CallResult
2927

3028
logScope:
3129
topics = "portal_evm"
@@ -72,12 +70,25 @@ type
7270

7371
CodeQuery = object
7472
address: Address
75-
codeFut: Future[Opt[Bytecode]]
73+
codeFut: Future[Opt[seq[byte]]]
74+
75+
GetAccountProc* = proc(stateRoot: Hash32, address: Address): Future[Opt[Account]] {.
76+
async: (raises: [CancelledError])
77+
.}
78+
79+
GetStorageProc* = proc(
80+
stateRoot: Hash32, address: Address, slotKey: UInt256
81+
): Future[Opt[UInt256]] {.async: (raises: [CancelledError]).}
82+
83+
GetCodeProc* = proc(stateRoot: Hash32, address: Address): Future[Opt[seq[byte]]] {.
84+
async: (raises: [CancelledError])
85+
.}
7686

7787
PortalEvm* = ref object
78-
historyNetwork: HistoryNetwork
79-
stateNetwork: StateNetwork
8088
com: CommonRef
89+
getAccount: GetAccountProc
90+
getStorage: GetStorageProc
91+
getCode: GetCodeProc
8192

8293
func init(T: type AccountQuery, adr: Address, fut: Future[Opt[Account]]): T =
8394
T(address: adr, accFut: fut)
@@ -87,42 +98,36 @@ func init(
8798
): T =
8899
T(address: adr, slotKey: slotKey, storageFut: fut)
89100

90-
func init(T: type CodeQuery, adr: Address, fut: Future[Opt[Bytecode]]): T =
101+
func init(T: type CodeQuery, adr: Address, fut: Future[Opt[seq[byte]]]): T =
91102
T(address: adr, codeFut: fut)
92103

93-
proc init*(T: type PortalEvm, hn: HistoryNetwork, sn: StateNetwork): T =
94-
let config =
95-
try:
96-
networkParams(MainNet).config
97-
except ValueError as e:
98-
raiseAssert(e.msg) # Should not fail
99-
except RlpError as e:
100-
raiseAssert(e.msg) # Should not fail
101-
104+
proc init*(
105+
T: type PortalEvm,
106+
accProc: GetAccountProc,
107+
storageProc: GetStorageProc,
108+
codeProc: GetCodeProc,
109+
networkId: NetworkId = MainNet,
110+
): T =
102111
let com = CommonRef.new(
103112
DefaultDbMemory.newCoreDbRef(),
104113
taskpool = nil,
105-
config = config,
114+
config = chainConfigForNetwork(networkId),
106115
initializeDb = false,
107116
)
108117

109-
PortalEvm(historyNetwork: hn, stateNetwork: sn, com: com)
118+
PortalEvm(com: com, getAccount: accProc, getStorage: storageProc, getCode: codeProc)
110119

111120
proc call*(
112-
evm: PortalEvm,
113-
tx: TransactionArgs,
114-
blockNumOrHash: uint64 | Hash32,
115-
optimisticStateFetch = true,
121+
evm: PortalEvm, header: Header, tx: TransactionArgs, optimisticStateFetch = true
116122
): Future[Result[CallResult, string]] {.async: (raises: [CancelledError]).} =
117123
let
118124
to = tx.to.valueOr:
119125
return err("to address is required")
120-
header = (await evm.historyNetwork.getVerifiedBlockHeader(blockNumOrHash)).valueOr:
121-
return err("Unable to get block header")
126+
122127
# Start fetching code in the background while setting up the EVM
123-
codeFut = evm.stateNetwork.getCodeByStateRoot(header.stateRoot, to)
128+
codeFut = evm.getCode(header.stateRoot, to)
124129

125-
debug "Executing call", to, blockNumOrHash
130+
debug "Executing call", blockNumber = header.number, to
126131

127132
let txFrame = evm.com.db.baseTxFrame().txFrameBegin()
128133
defer:
@@ -141,9 +146,9 @@ proc call*(
141146
# Set code of the 'to' address in the EVM so that we can execute the transaction
142147
let code = (await codeFut).valueOr:
143148
return err("Unable to get code")
144-
vmState.ledger.setCode(to, code.asSeq())
149+
vmState.ledger.setCode(to, code)
145150
fetchedCode.incl(to)
146-
debug "Code to be executed", code = code.asSeq().to0xHex()
151+
debug "Code to be executed", code = code.to0xHex()
147152

148153
var
149154
lastWitnessKeys: WitnessTable
@@ -187,9 +192,7 @@ proc call*(
187192
let slotIdx = (adr, v.storageSlot)
188193
if slotIdx notin fetchedStorage:
189194
debug "Fetching storage slot", address = adr, slotKey = v.storageSlot
190-
let storageFut = evm.stateNetwork.getStorageAtByStateRoot(
191-
header.stateRoot, adr, v.storageSlot
192-
)
195+
let storageFut = evm.getStorage(header.stateRoot, adr, v.storageSlot)
193196
if not stateFetchDone:
194197
storageQueries.add(StorageQuery.init(adr, v.storageSlot, storageFut))
195198
if not optimisticStateFetch:
@@ -199,15 +202,15 @@ proc call*(
199202

200203
if adr notin fetchedAccounts:
201204
debug "Fetching account", address = adr
202-
let accFut = evm.stateNetwork.getAccount(header.stateRoot, adr)
205+
let accFut = evm.getAccount(header.stateRoot, adr)
203206
if not stateFetchDone:
204207
accountQueries.add(AccountQuery.init(adr, accFut))
205208
if not optimisticStateFetch:
206209
stateFetchDone = true
207210

208211
if v.codeTouched and adr notin fetchedCode:
209212
debug "Fetching code", address = adr
210-
let codeFut = evm.stateNetwork.getCodeByStateRoot(header.stateRoot, adr)
213+
let codeFut = evm.getCode(header.stateRoot, adr)
211214
if not stateFetchDone:
212215
codeQueries.add(CodeQuery.init(adr, codeFut))
213216
if not optimisticStateFetch:
@@ -244,7 +247,7 @@ proc call*(
244247
for q in codeQueries:
245248
let code = (await q.codeFut).valueOr:
246249
return err("Unable to get code")
247-
vmState.ledger.setCode(q.address, code.asSeq())
250+
vmState.ledger.setCode(q.address, code)
248251
fetchedCode.incl(q.address)
249252
except CatchableError as e:
250253
# TODO: why do the above futures throw a CatchableError and not CancelledError?

fluffy/network/state/state_endpoints.nim

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -258,18 +258,18 @@ proc getCodeByStateRoot*(
258258
stateRoot: Hash32,
259259
address: Address,
260260
maybeBlockHash = Opt.none(Hash32),
261-
): Future[Opt[Bytecode]] {.async: (raises: [CancelledError]).} =
261+
): Future[Opt[seq[byte]]] {.async: (raises: [CancelledError]).} =
262262
let (accountProof, exists) = (
263263
await n.getAccountProof(stateRoot, address, maybeBlockHash)
264264
).valueOr:
265265
warn "Failed to get account proof", error = error
266-
return Opt.none(Bytecode)
266+
return Opt.none(seq[byte])
267267

268268
let account =
269269
if exists:
270270
accountProof.toAccount().valueOr:
271271
error "Failed to get account from accountProof"
272-
return Opt.none(Bytecode)
272+
return Opt.none(seq[byte])
273273
else:
274274
info "Account doesn't exist, returning default account"
275275
# return an empty account if the account doesn't exist
@@ -278,7 +278,7 @@ proc getCodeByStateRoot*(
278278
if account.codeHash == EMPTY_CODE_HASH:
279279
info "Code doesn't exist, returning default code value"
280280
# return empty bytecode if the code doesn't exist
281-
return Opt.some(Bytecode.empty())
281+
return Opt.some(Bytecode.empty().asSeq())
282282

283283
let
284284
contractCodeKey = ContractCodeKey.init(keccak256(address.data), account.codeHash)
@@ -291,9 +291,9 @@ proc getCodeByStateRoot*(
291291
Opt.none(ContractCodeOffer)
292292
contractCodeRetrieval = (await n.getContractCode(contractCodeKey, maybeParentOffer)).valueOr:
293293
warn "Failed to get contract code"
294-
return Opt.none(Bytecode)
294+
return Opt.none(seq[byte])
295295

296-
Opt.some(contractCodeRetrieval.code)
296+
Opt.some(contractCodeRetrieval.code.asSeq())
297297

298298
type Proofs* = ref object
299299
account*: Account
@@ -394,10 +394,10 @@ proc getStorageAt*(
394394
# Used by: eth_getCode
395395
proc getCode*(
396396
n: StateNetwork, blockNumOrHash: uint64 | Hash32, address: Address
397-
): Future[Opt[Bytecode]] {.async: (raises: [CancelledError]).} =
397+
): Future[Opt[seq[byte]]] {.async: (raises: [CancelledError]).} =
398398
let header = (await n.getBlockHeaderByBlockNumOrHash(blockNumOrHash)).valueOr:
399399
warn "Failed to get block header by block number or hash", blockNumOrHash
400-
return Opt.none(Bytecode)
400+
return Opt.none(seq[byte])
401401

402402
await n.getCodeByStateRoot(header.stateRoot, address, Opt.some(header.rlpHash()))
403403

fluffy/rpc/rpc_debug_api.nim

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Fluffy
2-
# Copyright (c) 2021-2024 Status Research & Development GmbH
2+
# Copyright (c) 2021-2025 Status Research & Development GmbH
33
# Licensed and distributed under either of
44
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
55
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@@ -79,10 +79,10 @@ proc installDebugApiHandlers*(rpcServer: RpcServer, stateNetwork: Opt[StateNetwo
7979

8080
let
8181
sn = stateNetwork.getOrRaise()
82-
bytecode = (await sn.getCodeByStateRoot(stateRoot, address)).valueOr:
82+
code = (await sn.getCodeByStateRoot(stateRoot, address)).valueOr:
8383
raise newException(ValueError, "Unable to get code")
8484

85-
return bytecode.asSeq()
85+
return code
8686

8787
rpcServer.rpc("debug_getProofByStateRoot") do(
8888
address: Address, slots: seq[UInt256], stateRoot: Hash32

fluffy/rpc/rpc_eth_api.nim

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ template getOrRaise(stateNetwork: Opt[StateNetwork]): StateNetwork =
128128

129129
template getOrRaise(portalEvm: Opt[PortalEvm]): PortalEvm =
130130
let evm = portalEvm.valueOr:
131-
raise newException(ValueError, "portal evm not enabled")
131+
raise
132+
newException(ValueError, "portal evm requires state sub-network to be enabled")
132133
evm
133134

134135
proc installEthApiHandlers*(
@@ -138,8 +139,23 @@ proc installEthApiHandlers*(
138139
stateNetwork: Opt[StateNetwork],
139140
) =
140141
let portalEvm =
141-
if historyNetwork.isSome() and stateNetwork.isSome():
142-
Opt.some(PortalEvm.init(historyNetwork.get(), stateNetwork.get()))
142+
if stateNetwork.isSome():
143+
Opt.some(
144+
PortalEvm.init(
145+
proc(
146+
stateRoot: Hash32, address: Address
147+
): Future[Opt[Account]] {.async: (raw: true, raises: [CancelledError]).} =
148+
stateNetwork.get().getAccount(stateRoot, address),
149+
proc(
150+
stateRoot: Hash32, address: Address, slotKey: UInt256
151+
): Future[Opt[UInt256]] {.async: (raw: true, raises: [CancelledError]).} =
152+
stateNetwork.get().getStorageAtByStateRoot(stateRoot, address, slotKey),
153+
proc(
154+
stateRoot: Hash32, address: Address
155+
): Future[Opt[seq[byte]]] {.async: (raw: true, raises: [CancelledError]).} =
156+
stateNetwork.get().getCodeByStateRoot(stateRoot, address),
157+
)
158+
)
143159
else:
144160
Opt.none(PortalEvm)
145161

@@ -380,9 +396,9 @@ proc installEthApiHandlers*(
380396
let
381397
sn = stateNetwork.getOrRaise()
382398
blockNumber = quantityTag.number.uint64
383-
bytecode = (await sn.getCode(blockNumber, data)).valueOr:
399+
code = (await sn.getCode(blockNumber, data)).valueOr:
384400
raise newException(ValueError, "Unable to get code")
385-
return bytecode.asSeq()
401+
return code
386402

387403
rpcServer.rpc("eth_getProof") do(
388404
data: Address, slots: seq[UInt256], quantityTag: RtBlockIdentifier
@@ -444,13 +460,14 @@ proc installEthApiHandlers*(
444460

445461
let
446462
hn = historyNetwork.getOrRaise()
447-
sn = stateNetwork.getOrRaise()
448463
evm = portalEvm.getOrRaise()
464+
header = (await hn.getVerifiedBlockHeader(quantityTag.number.uint64)).valueOr:
465+
raise newException(ValueError, "Unable to get block header")
449466

450467
let callResult = (
451468
await evm.call(
469+
header,
452470
tx,
453-
quantityTag.number.uint64,
454471
if optimisticStateFetch.isNone():
455472
true
456473
else:

fluffy/tests/state_network_tests/test_state_endpoints_genesis.nim

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ suite "State Endpoints - Genesis JSON Files":
157157
# get code of existing account
158158
let codeRes = await stateNode.stateNetwork.getCode(blockNumber, address)
159159
check:
160-
codeRes.get().asSeq() == account.code
160+
codeRes.get() == account.code
161161

162162
let storageState = storageStates.getOrDefault(address)
163163
for slotKey, slotValue in account.storage:
@@ -177,7 +177,7 @@ suite "State Endpoints - Genesis JSON Files":
177177
slotRes1 =
178178
await stateNode.stateNetwork.getStorageAt(blockNumber, address, 1.u256)
179179
check:
180-
codeRes.get().asSeq().len() == 0
180+
codeRes.get().len() == 0
181181
slotRes0.get() == 0.u256
182182
slotRes1.get() == 0.u256
183183

@@ -197,7 +197,7 @@ suite "State Endpoints - Genesis JSON Files":
197197
check:
198198
balanceRes.get() == 0.u256
199199
nonceRes.get() == 0.uint64
200-
codeRes.get().asSeq().len() == 0
200+
codeRes.get().len() == 0
201201
slotRes.get() == 0.u256
202202

203203
await stateNode.stop()

fluffy/tests/state_network_tests/test_state_endpoints_vectors.nim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Fluffy
2-
# Copyright (c) 2021-2024 Status Research & Development GmbH
2+
# Copyright (c) 2021-2025 Status Research & Development GmbH
33
# Licensed and distributed under either of
44
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
55
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@@ -273,7 +273,7 @@ procSuite "State Endpoints":
273273
addresses.Address.fromHex("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")
274274
badAddress =
275275
addresses.Address.fromHex("0xbadaaa39b223fe8d0a0e5c4f27ead9083c756cc2")
276-
expectedCode = contentValue.code
276+
expectedCode = contentValue.code.asSeq()
277277

278278
codeRes = await stateNode2.stateNetwork.getCode(contentValue.blockHash, address)
279279
badCodeRes =

0 commit comments

Comments
 (0)