Skip to content

Commit 8949cee

Browse files
authored
EIP-7928: Block level access lists (#3911)
1 parent 5b27469 commit 8949cee

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1377
-381
lines changed

execution_chain/beacon/api_handler.nim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export
2525
getPayloadV3,
2626
getPayloadV4,
2727
getPayloadV5,
28+
getPayloadV6,
2829
getPayloadBodiesByHash,
2930
getPayloadBodiesByRange,
3031
newPayload,

execution_chain/beacon/api_handler/api_getpayload.nim

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ proc getPayload*(ben: BeaconEngineRef,
2626
let bundle = ben.getPayloadBundle(id).valueOr:
2727
raise unknownPayload("Unknown bundle")
2828

29-
let
29+
let
3030
version = bundle.payload.version
3131
com = ben.com
3232

@@ -112,7 +112,7 @@ proc getPayloadV5*(ben: BeaconEngineRef, id: Bytes8): GetPayloadV5Response =
112112

113113
let version = bundle.payload.version
114114
if version != Version.V3:
115-
raise unsupportedFork("getPayloadV5 expect payloadV3 but get payload" & $version)
115+
raise unsupportedFork("getPayloadV5 expect ExecutionPayloadV3 but got ExecutionPayload" & $version)
116116
if bundle.blobsBundle.isNil:
117117
raise unsupportedFork("getPayloadV5 is missing BlobsBundleV2")
118118
if bundle.executionRequests.isNone:
@@ -122,10 +122,40 @@ proc getPayloadV5*(ben: BeaconEngineRef, id: Bytes8): GetPayloadV5Response =
122122
if not com.isOsakaOrLater(ethTime bundle.payload.timestamp):
123123
raise unsupportedFork("bundle timestamp is less than Osaka activation")
124124

125+
if com.isAmsterdamOrLater(ethTime bundle.payload.timestamp):
126+
raise unsupportedFork("bundle timestamp greater than Amsterdam must use getPayloadV6")
127+
125128
GetPayloadV5Response(
126129
executionPayload: bundle.payload.V3,
127130
blockValue: bundle.blockValue,
128131
blobsBundle: bundle.blobsBundle.V2,
129132
shouldOverrideBuilder: false,
130133
executionRequests: bundle.executionRequests.get,
131-
)
134+
)
135+
136+
proc getPayloadV6*(ben: BeaconEngineRef, id: Bytes8): GetPayloadV6Response =
137+
trace "Engine API request received",
138+
meth = "GetPayload", id
139+
140+
let bundle = ben.getPayloadBundle(id).valueOr:
141+
raise unknownPayload("Unknown bundle")
142+
143+
let version = bundle.payload.version
144+
if version != Version.V4:
145+
raise unsupportedFork("getPayloadV6 expect ExecutionPayloadV4 but got ExecutionPayload" & $version)
146+
if bundle.blobsBundle.isNil:
147+
raise unsupportedFork("getPayloadV6 is missing BlobsBundleV2")
148+
if bundle.executionRequests.isNone:
149+
raise unsupportedFork("getPayloadV6 is missing executionRequests")
150+
151+
let com = ben.com
152+
if not com.isAmsterdamOrLater(ethTime bundle.payload.timestamp):
153+
raise unsupportedFork("bundle timestamp is less than Amsterdam activation")
154+
155+
GetPayloadV6Response(
156+
executionPayload: bundle.payload.V4,
157+
blockValue: bundle.blockValue,
158+
blobsBundle: bundle.blobsBundle.V2,
159+
shouldOverrideBuilder: false,
160+
executionRequests: bundle.executionRequests.get,
161+
)

execution_chain/beacon/api_handler/api_newpayload.nim

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,41 @@ func validateVersionedHashed(payload: ExecutionPayload,
4141
true
4242

4343
template validateVersion(com, timestamp, payloadVersion, apiVersion) =
44-
if apiVersion == Version.V4:
44+
if apiVersion == Version.V5:
45+
if not com.isAmsterdamOrLater(timestamp):
46+
raise unsupportedFork("newPayloadV5 expect payload timestamp fall within Amsterdam")
47+
if payloadVersion != Version.V4:
48+
raise invalidParams("newPayload" & $apiVersion &
49+
" expect ExecutionPayloadV4" &
50+
" but got ExecutionPayload" & $payloadVersion)
51+
52+
elif apiVersion == Version.V4:
4553
if not com.isPragueOrLater(timestamp):
4654
raise unsupportedFork("newPayloadV4 expect payload timestamp fall within Prague")
47-
48-
if com.isPragueOrLater(timestamp):
4955
if payloadVersion != Version.V3:
50-
raise invalidParams("if timestamp is Prague or later, " &
51-
"payload must be ExecutionPayloadV3, got ExecutionPayload" & $payloadVersion)
56+
raise invalidParams("newPayload" & $apiVersion &
57+
" expect ExecutionPayloadV3" &
58+
" but got ExecutionPayload" & $payloadVersion)
5259

53-
if apiVersion == Version.V3:
60+
elif apiVersion == Version.V3:
5461
if not com.isCancunOrLater(timestamp):
5562
raise unsupportedFork("newPayloadV3 expect payload timestamp fall within Cancun")
63+
if payloadVersion != Version.V3:
64+
raise invalidParams("newPayload" & $apiVersion &
65+
" expect ExecutionPayloadV3" &
66+
" but got ExecutionPayload" & $payloadVersion)
5667

57-
if com.isCancunOrLater(timestamp):
68+
if com.isAmsterdamOrLater(timestamp):
69+
if payloadVersion != Version.V4:
70+
raise invalidParams("if timestamp is Amsterdam or later, " &
71+
"payload must be ExecutionPayloadV4, got ExecutionPayload" & $payloadVersion)
72+
73+
elif com.isPragueOrLater(timestamp):
74+
if payloadVersion != Version.V3:
75+
raise invalidParams("if timestamp is Prague or later, " &
76+
"payload must be ExecutionPayloadV3, got ExecutionPayload" & $payloadVersion)
77+
78+
elif com.isCancunOrLater(timestamp):
5879
if payloadVersion != Version.V3:
5980
raise invalidParams("if timestamp is Cancun or later, " &
6081
"payload must be ExecutionPayloadV3, got ExecutionPayload" & $payloadVersion)
@@ -68,13 +89,6 @@ template validateVersion(com, timestamp, payloadVersion, apiVersion) =
6889
raise invalidParams("if timestamp is earlier than Shanghai, " &
6990
"payload must be ExecutionPayloadV1, got ExecutionPayload" & $payloadVersion)
7091

71-
if apiVersion == Version.V3 or apiVersion == Version.V4:
72-
# both newPayloadV3 and newPayloadV4 expect ExecutionPayloadV3
73-
if payloadVersion != Version.V3:
74-
raise invalidParams("newPayload" & $apiVersion &
75-
" expect ExecutionPayload3" &
76-
" but got ExecutionPayload" & $payloadVersion)
77-
7892
template validatePayload(apiVersion, payloadVersion, payload) =
7993
if payloadVersion >= Version.V2:
8094
if payload.withdrawals.isNone:
@@ -89,6 +103,11 @@ template validatePayload(apiVersion, payloadVersion, payload) =
89103
raise invalidParams("newPayload" & $apiVersion &
90104
"excessBlobGas is expected from execution payload")
91105

106+
if apiVersion >= Version.V5 or payloadVersion >= Version.V4:
107+
if payload.blockAccessList.isNone:
108+
raise invalidParams("newPayload" & $apiVersion &
109+
"blockAccessList is expected from execution payload")
110+
92111
# https://github.com/ethereum/execution-apis/blob/40088597b8b4f48c45184da002e27ffc3c37641f/src/engine/prague.md#request
93112
func validateExecutionRequest(blockHash: Hash32,
94113
requests: openArray[seq[byte]], apiVersion: Version):
@@ -161,6 +180,13 @@ proc newPayload*(ben: BeaconEngineRef,
161180
warn "Failed to decode payload",
162181
error = e.msg
163182
return invalidStatus(payload.blockHash, "Failed to decode payload")
183+
blockAccessList =
184+
try:
185+
blockAccessList(payload)
186+
except RlpError as e:
187+
warn "Failed to decode payload",
188+
error = e.msg
189+
return invalidStatus(payload.blockHash, "Failed to decode payload")
164190

165191
template header: Header = blk.header
166192

@@ -194,7 +220,7 @@ proc newPayload*(ben: BeaconEngineRef,
194220
# will not trigger a sync cycle. That is fine though, if we get a fork choice
195221
# update after legit payload executions.
196222
let parent = chain.headerByHash(header.parentHash).valueOr:
197-
return ben.delayPayloadImport(blockHash, blk)
223+
return ben.delayPayloadImport(blockHash, blk, blockAccessList)
198224

199225
# We have an existing parent, do some sanity checks to avoid the beacon client
200226
# triggering too early
@@ -221,7 +247,7 @@ proc newPayload*(ben: BeaconEngineRef,
221247
return invalidStatus(parent.computeBlockHash, "Invalid timestamp")
222248

223249
if not chain.haveBlockAndState(header.parentHash):
224-
chain.quarantine.addOrphan(blockHash, blk)
250+
chain.quarantine.addOrphan(blockHash, blk, blockAccessList)
225251
warn "State not available, ignoring new payload",
226252
hash = blockHash,
227253
number = header.number
@@ -233,7 +259,7 @@ proc newPayload*(ben: BeaconEngineRef,
233259
trace "Importing block without sethead",
234260
hash = blockHash, number = header.number
235261

236-
let vres = await chain.queueImportBlock(blk)
262+
let vres = await chain.queueImportBlock(blk, blockAccessList)
237263
if vres.isErr:
238264
warn "Error importing block",
239265
number = header.number,

execution_chain/beacon/beacon_engine.nim

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,11 @@ func getPayloadBundle*(ben: BeaconEngineRef, id: Bytes8): Opt[ExecutionBundle] =
146146
# ------------------------------------------------------------------------------
147147
# Public functions
148148
# ------------------------------------------------------------------------------
149-
proc generateExecutionBundle*(ben: BeaconEngineRef,
150-
attrs: PayloadAttributes):
151-
Result[ExecutionBundle, string] =
149+
proc generateExecutionBundle*(
150+
ben: BeaconEngineRef,
151+
attrs: PayloadAttributes
152+
): Result[ExecutionBundle, string] =
153+
152154
wrapException:
153155
let
154156
xp = ben.txPool
@@ -175,7 +177,7 @@ proc generateExecutionBundle*(ben: BeaconEngineRef,
175177
return err "extraData length should not exceed 32 bytes"
176178

177179
ok ExecutionBundle(
178-
payload: executionPayload(bundle.blk),
180+
payload: executionPayload(bundle.blk, bundle.blockAccessList),
179181
blobsBundle: bundle.blobsBundle,
180182
blockValue: bundle.blockValue,
181183
executionRequests: bundle.executionRequests)
@@ -245,13 +247,18 @@ proc checkInvalidAncestor*(ben: BeaconEngineRef,
245247
# either via a forkchoice update or a sync extension. This method is meant to
246248
# be called by the newpayload command when the block seems to be ok, but some
247249
# prerequisite prevents it from being processed (e.g. no parent, or snap sync).
248-
proc delayPayloadImport*(ben: BeaconEngineRef, blockHash: Hash32, blk: Block): PayloadStatusV1 =
250+
proc delayPayloadImport*(
251+
ben: BeaconEngineRef,
252+
blockHash: Hash32,
253+
blk: Block,
254+
blockAccessList: Opt[BlockAccessListRef]
255+
): PayloadStatusV1 =
249256
# Sanity check that this block's parent is not on a previously invalidated
250257
# chain. If it is, mark the block as invalid too.
251258
ben.checkInvalidAncestor(blk.header.parentHash, blockHash).valueOr:
252259
# Stash the block away for a potential forced forkchoice update to it
253260
# at a later time.
254-
ben.chain.quarantine.addOrphan(blockHash, blk)
261+
ben.chain.quarantine.addOrphan(blockHash, blk, blockAccessList)
255262
return PayloadStatusV1(status: PayloadExecutionStatus.syncing)
256263

257264
func latestFork*(ben: BeaconEngineRef): HardFork =

execution_chain/beacon/payload_conv.nim

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,17 @@ func wdRoot(x: Opt[seq[WithdrawalV1]]): Opt[Hash32] =
4040
func txRoot(list: openArray[Web3Tx]): Hash32 =
4141
orderedTrieRoot(list)
4242

43+
func balHash(bal: Opt[seq[byte]]): Opt[Hash32] =
44+
if bal.isNone():
45+
Opt.none(Hash32)
46+
else:
47+
Opt.some(keccak256(bal.get))
48+
4349
# ------------------------------------------------------------------------------
4450
# Public functions
4551
# ------------------------------------------------------------------------------
4652

47-
func executionPayload*(blk: Block): ExecutionPayload =
53+
func executionPayload*(blk: Block, bal: Opt[BlockAccessListRef]): ExecutionPayload =
4854
ExecutionPayload(
4955
parentHash : blk.header.parentHash,
5056
feeRecipient : blk.header.coinbase,
@@ -63,6 +69,7 @@ func executionPayload*(blk: Block): ExecutionPayload =
6369
withdrawals : w3Withdrawals blk.withdrawals,
6470
blobGasUsed : w3Qty blk.header.blobGasUsed,
6571
excessBlobGas: w3Qty blk.header.excessBlobGas,
72+
blockAccessList: w3BlockAccessList bal
6673
)
6774

6875
func executionPayloadV1V2*(blk: Block): ExecutionPayloadV1OrV2 =
@@ -110,20 +117,28 @@ func blockHeader*(p: ExecutionPayload,
110117
excessBlobGas : u64(p.excessBlobGas),
111118
parentBeaconBlockRoot: parentBeaconBlockRoot,
112119
requestsHash : requestsHash,
120+
blockAccessListHash: balHash p.blockAccessList,
113121
)
114122

115-
func blockBody*(p: ExecutionPayload):
116-
BlockBody {.gcsafe, raises:[RlpError].} =
123+
func blockBody*(
124+
p: ExecutionPayload
125+
): BlockBody {.gcsafe, raises: [RlpError].} =
117126
BlockBody(
118127
uncles : @[],
119128
transactions: ethTxs p.transactions,
120129
withdrawals : ethWithdrawals p.withdrawals,
121130
)
122131

123-
func ethBlock*(p: ExecutionPayload,
124-
parentBeaconBlockRoot: Opt[Hash32],
125-
requestsHash: Opt[Hash32]):
126-
Block {.gcsafe, raises:[RlpError].} =
132+
template blockAccessList*(
133+
p: ExecutionPayload
134+
): Opt[BlockAccessListRef] =
135+
ethBlockAccessList p.blockAccessList
136+
137+
func ethBlock*(
138+
p: ExecutionPayload,
139+
parentBeaconBlockRoot: Opt[Hash32],
140+
requestsHash: Opt[Hash32]
141+
): Block {.gcsafe, raises: [RlpError].} =
127142
Block(
128143
header : blockHeader(p, parentBeaconBlockRoot, requestsHash),
129144
uncles : @[],

execution_chain/beacon/web3_eth_conv.nim

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,28 @@ func ethWithdrawals*(x: Opt[seq[WithdrawalV1]]):
8484
if x.isNone: Opt.none(seq[Withdrawal])
8585
else: Opt.some(ethWithdrawals x.get)
8686

87-
func ethTx*(x: Web3Tx): common.Transaction {.gcsafe, raises:[RlpError].} =
87+
func ethTx*(x: Web3Tx): common.Transaction {.gcsafe, raises: [RlpError].} =
8888
result = rlp.decode(distinctBase x, common.Transaction)
8989

9090
func ethTxs*(list: openArray[Web3Tx]):
91-
seq[common.Transaction] {.gcsafe, raises:[RlpError].} =
91+
seq[common.Transaction] {.gcsafe, raises: [RlpError].} =
9292
result = newSeqOfCap[common.Transaction](list.len)
9393
for x in list:
9494
result.add ethTx(x)
9595

96+
func ethBlockAccessList*(
97+
balRlpBytes: openArray[byte]): BlockAccessListRef {.gcsafe, raises: [RlpError].} =
98+
let bal: BlockAccessListRef = new BlockAccessList
99+
bal[] = rlp.decode(balRlpBytes, BlockAccessList)
100+
bal
101+
102+
func ethBlockAccessList*(
103+
bal: Opt[seq[byte]]): Opt[BlockAccessListRef] {.gcsafe, raises: [RlpError].} =
104+
if bal.isNone():
105+
Opt.none(BlockAccessListRef)
106+
else:
107+
Opt.some(ethBlockAccessList(bal.get))
108+
96109
# ------------------------------------------------------------------------------
97110
# Eth types to Web3 types
98111
# ------------------------------------------------------------------------------
@@ -154,4 +167,13 @@ func w3Txs*(list: openArray[common.Transaction]): seq[Web3Tx] =
154167
for tx in list:
155168
result.add w3Tx(tx)
156169

170+
func w3BlockAccessList*(bal: BlockAccessListRef): seq[byte] =
171+
bal[].encode()
172+
173+
func w3BlockAccessList*(bal: Opt[BlockAccessListRef]): Opt[seq[byte]] =
174+
if bal.isNone():
175+
Opt.none(seq[byte])
176+
else:
177+
Opt.some(w3BlockAccessList(bal.get))
178+
157179
chronicles.formatIt(Quantity): $(distinctBase it)

0 commit comments

Comments
 (0)