Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
09317e7
Add bal tracker to BaseVMState.
bhartnett Nov 18, 2025
d85f27c
Set bal indexes.
bhartnett Nov 18, 2025
934722b
Begin, commit and rollback block access list tracker call frames.
bhartnett Nov 18, 2025
663c0ce
Track addresses of accessed precompiles as reads.
bhartnett Nov 18, 2025
373b7d3
Add bal tracking in evm.
bhartnett Nov 18, 2025
446000e
Minor update.
bhartnett Nov 18, 2025
e753f66
Fixes.
bhartnett Nov 20, 2025
d14b419
Merge branch 'master' into BALs_EIP-7928_evm-tracker
bhartnett Nov 20, 2025
08d1f79
Use templates to inline small functions in tracker.
bhartnett Nov 20, 2025
b18563d
Don't track address when calling trackSubBalanceChange and delta is z…
bhartnett Nov 21, 2025
e833fc0
Merge branch 'master' into BALs_EIP-7928_evm-tracker
bhartnett Nov 21, 2025
f890f18
Enable bal tracker in forked chain when fork is amsterdam or later.
bhartnett Nov 21, 2025
6ef8d42
Validate bal in procBlkEpilogue.
bhartnett Nov 21, 2025
625bf8b
Fetch and write bal to database after processing block.
bhartnett Nov 21, 2025
4c3c0f0
Allow missing bal in import block.
bhartnett Nov 21, 2025
cb24c54
Update eest_bal version.
bhartnett Nov 22, 2025
ea17f19
Fixes.
bhartnett Nov 24, 2025
589d544
Handle self destruct reverts in tracker.
bhartnett Nov 24, 2025
b8999ec
Add pre nonce and pre code caches.
bhartnett Nov 24, 2025
e83d368
Fix withdraws balance tracking.
bhartnett Nov 25, 2025
d29fbee
Update getCallCode.
bhartnett Nov 25, 2025
85a79ad
Return ref BlockAccessList from builder to reduce copies and improve …
bhartnett Nov 26, 2025
0ae60c1
Return ref BlockAccessList from builder to reduce copies and improve …
bhartnett Nov 26, 2025
3ec9e8d
Merge branch 'master' into BALs_EIP-7928_evm-tracker
bhartnett Nov 26, 2025
e6f0d7e
Update bal eest tests to v1.8.0
bhartnett Nov 26, 2025
30195bd
Ignore 5 failing tests for now.
bhartnett Nov 26, 2025
7bcb0ea
Add bal mismatch debug log.
bhartnett Nov 26, 2025
1ba9993
Remove unneeded shouldSelfDestruct6780 from ledger.
bhartnett Nov 27, 2025
2386748
EIP-7928: Engine API changes introduced in Amsterdam (#3801)
bhartnett Nov 27, 2025
a0c8fa5
Collect block access list in tx pool assemble block.
bhartnett Nov 27, 2025
2798547
Fix new payload validation.
bhartnett Nov 28, 2025
fbeeeaf
Update engine tests to include eest_bal.
bhartnett Nov 28, 2025
1c71167
Merge branch 'master' into BALs_EIP-7928_evm-tracker
bhartnett Nov 28, 2025
5e7f279
Support rollback of reads in bal tracker.
bhartnett Nov 28, 2025
b8b2571
Minor bal tracker improvements.
bhartnett Nov 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions execution_chain/beacon/api_handler.nim
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export
getPayloadV3,
getPayloadV4,
getPayloadV5,
getPayloadV6,
getPayloadBodiesByHash,
getPayloadBodiesByRange,
newPayload,
Expand Down
36 changes: 33 additions & 3 deletions execution_chain/beacon/api_handler/api_getpayload.nim
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ proc getPayload*(ben: BeaconEngineRef,
let bundle = ben.getPayloadBundle(id).valueOr:
raise unknownPayload("Unknown bundle")

let
let
version = bundle.payload.version
com = ben.com

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

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

if com.isAmsterdamOrLater(ethTime bundle.payload.timestamp):
raise unsupportedFork("bundle timestamp greater than Amsterdam must use getPayloadV6")

GetPayloadV5Response(
executionPayload: bundle.payload.V3,
blockValue: bundle.blockValue,
blobsBundle: bundle.blobsBundle.V2,
shouldOverrideBuilder: false,
executionRequests: bundle.executionRequests.get,
)
)

proc getPayloadV6*(ben: BeaconEngineRef, id: Bytes8): GetPayloadV6Response =
trace "Engine API request received",
meth = "GetPayload", id

let bundle = ben.getPayloadBundle(id).valueOr:
raise unknownPayload("Unknown bundle")

let version = bundle.payload.version
if version != Version.V4:
raise unsupportedFork("getPayloadV6 expect ExecutionPayloadV4 but got ExecutionPayload" & $version)
if bundle.blobsBundle.isNil:
raise unsupportedFork("getPayloadV6 is missing BlobsBundleV2")
if bundle.executionRequests.isNone:
raise unsupportedFork("getPayloadV6 is missing executionRequests")

let com = ben.com
if not com.isAmsterdamOrLater(ethTime bundle.payload.timestamp):
raise unsupportedFork("bundle timestamp is less than Amsterdam activation")

GetPayloadV6Response(
executionPayload: bundle.payload.V4,
blockValue: bundle.blockValue,
blobsBundle: bundle.blobsBundle.V2,
shouldOverrideBuilder: false,
executionRequests: bundle.executionRequests.get,
)
47 changes: 33 additions & 14 deletions execution_chain/beacon/api_handler/api_newpayload.nim
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,41 @@ func validateVersionedHashed(payload: ExecutionPayload,
true

template validateVersion(com, timestamp, payloadVersion, apiVersion) =
if apiVersion == Version.V4:
if apiVersion == Version.V5:
if not com.isAmsterdamOrLater(timestamp):
raise unsupportedFork("newPayloadV5 expect payload timestamp fall within Amsterdam")
if payloadVersion != Version.V4:
raise invalidParams("newPayload" & $apiVersion &
" expect ExecutionPayloadV4" &
" but got ExecutionPayload" & $payloadVersion)

elif apiVersion == Version.V4:
if not com.isPragueOrLater(timestamp):
raise unsupportedFork("newPayloadV4 expect payload timestamp fall within Prague")

if com.isPragueOrLater(timestamp):
if payloadVersion != Version.V3:
raise invalidParams("if timestamp is Prague or later, " &
"payload must be ExecutionPayloadV3, got ExecutionPayload" & $payloadVersion)
raise invalidParams("newPayload" & $apiVersion &
" expect ExecutionPayloadV3" &
" but got ExecutionPayload" & $payloadVersion)

if apiVersion == Version.V3:
elif apiVersion == Version.V3:
if not com.isCancunOrLater(timestamp):
raise unsupportedFork("newPayloadV3 expect payload timestamp fall within Cancun")
if payloadVersion != Version.V3:
raise invalidParams("newPayload" & $apiVersion &
" expect ExecutionPayloadV3" &
" but got ExecutionPayload" & $payloadVersion)

if com.isCancunOrLater(timestamp):
if com.isAmsterdamOrLater(timestamp):
if payloadVersion != Version.V4:
raise invalidParams("if timestamp is Amsterdam or later, " &
"payload must be ExecutionPayloadV4, got ExecutionPayload" & $payloadVersion)

elif com.isPragueOrLater(timestamp):
if payloadVersion != Version.V3:
raise invalidParams("if timestamp is Prague or later, " &
"payload must be ExecutionPayloadV3, got ExecutionPayload" & $payloadVersion)

elif com.isCancunOrLater(timestamp):
if payloadVersion != Version.V3:
raise invalidParams("if timestamp is Cancun or later, " &
"payload must be ExecutionPayloadV3, got ExecutionPayload" & $payloadVersion)
Expand All @@ -68,13 +89,6 @@ template validateVersion(com, timestamp, payloadVersion, apiVersion) =
raise invalidParams("if timestamp is earlier than Shanghai, " &
"payload must be ExecutionPayloadV1, got ExecutionPayload" & $payloadVersion)

if apiVersion == Version.V3 or apiVersion == Version.V4:
# both newPayloadV3 and newPayloadV4 expect ExecutionPayloadV3
if payloadVersion != Version.V3:
raise invalidParams("newPayload" & $apiVersion &
" expect ExecutionPayload3" &
" but got ExecutionPayload" & $payloadVersion)

template validatePayload(apiVersion, payloadVersion, payload) =
if payloadVersion >= Version.V2:
if payload.withdrawals.isNone:
Expand All @@ -89,6 +103,11 @@ template validatePayload(apiVersion, payloadVersion, payload) =
raise invalidParams("newPayload" & $apiVersion &
"excessBlobGas is expected from execution payload")

if apiVersion >= Version.V5 or payloadVersion >= Version.V4:
if payload.blockAccessList.isNone:
raise invalidParams("newPayload" & $apiVersion &
"blockAccessList is expected from execution payload")

# https://github.com/ethereum/execution-apis/blob/40088597b8b4f48c45184da002e27ffc3c37641f/src/engine/prague.md#request
func validateExecutionRequest(blockHash: Hash32,
requests: openArray[seq[byte]], apiVersion: Version):
Expand Down
14 changes: 12 additions & 2 deletions execution_chain/beacon/payload_conv.nim
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ func wdRoot(x: Opt[seq[WithdrawalV1]]): Opt[Hash32] =
func txRoot(list: openArray[Web3Tx]): Hash32 =
orderedTrieRoot(list)

func balHash(bal: Opt[seq[byte]]): Opt[Hash32] =
if bal.isNone():
Opt.none(Hash32)
else:
Opt.some(keccak256(bal.get))

# ------------------------------------------------------------------------------
# Public functions
# ------------------------------------------------------------------------------
Expand All @@ -63,6 +69,7 @@ func executionPayload*(blk: Block): ExecutionPayload =
withdrawals : w3Withdrawals blk.withdrawals,
blobGasUsed : w3Qty blk.header.blobGasUsed,
excessBlobGas: w3Qty blk.header.excessBlobGas,
blockAccessList: w3BlockAccessList blk.blockAccessList
)

func executionPayloadV1V2*(blk: Block): ExecutionPayloadV1OrV2 =
Expand Down Expand Up @@ -110,23 +117,26 @@ func blockHeader*(p: ExecutionPayload,
excessBlobGas : u64(p.excessBlobGas),
parentBeaconBlockRoot: parentBeaconBlockRoot,
requestsHash : requestsHash,
blockAccessListHash: balHash p.blockAccessList,
)

func blockBody*(p: ExecutionPayload):
BlockBody {.gcsafe, raises:[RlpError].} =
BlockBody {.gcsafe, raises: [RlpError].} =
BlockBody(
uncles : @[],
transactions: ethTxs p.transactions,
withdrawals : ethWithdrawals p.withdrawals,
blockAccessList: ethBlockAccessList p.blockAccessList,
)

func ethBlock*(p: ExecutionPayload,
parentBeaconBlockRoot: Opt[Hash32],
requestsHash: Opt[Hash32]):
Block {.gcsafe, raises:[RlpError].} =
Block {.gcsafe, raises: [RlpError].} =
Block(
header : blockHeader(p, parentBeaconBlockRoot, requestsHash),
uncles : @[],
transactions: ethTxs p.transactions,
withdrawals : ethWithdrawals p.withdrawals,
blockAccessList: ethBlockAccessList p.blockAccessList,
)
24 changes: 22 additions & 2 deletions execution_chain/beacon/web3_eth_conv.nim
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,26 @@ func ethWithdrawals*(x: Opt[seq[WithdrawalV1]]):
if x.isNone: Opt.none(seq[Withdrawal])
else: Opt.some(ethWithdrawals x.get)

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

func ethTxs*(list: openArray[Web3Tx]):
seq[common.Transaction] {.gcsafe, raises:[RlpError].} =
seq[common.Transaction] {.gcsafe, raises: [RlpError].} =
result = newSeqOfCap[common.Transaction](list.len)
for x in list:
result.add ethTx(x)

func ethBlockAccessList*(
bal: openArray[byte]): BlockAccessList {.gcsafe, raises: [RlpError].} =
rlp.decode(bal, BlockAccessList)

func ethBlockAccessList*(
bal: Opt[seq[byte]]): Opt[BlockAccessList] {.gcsafe, raises: [RlpError].} =
if bal.isNone():
Opt.none(BlockAccessList)
else:
Opt.some(ethBlockAccessList(bal.get))

# ------------------------------------------------------------------------------
# Eth types to Web3 types
# ------------------------------------------------------------------------------
Expand Down Expand Up @@ -154,4 +165,13 @@ func w3Txs*(list: openArray[common.Transaction]): seq[Web3Tx] =
for tx in list:
result.add w3Tx(tx)

func w3BlockAccessList*(bal: BlockAccessList): seq[byte] =
bal.encode()

func w3BlockAccessList*(bal: Opt[BlockAccessList]): Opt[seq[byte]] =
if bal.isNone():
Opt.none(seq[byte])
else:
Opt.some(w3BlockAccessList(bal.get))

chronicles.formatIt(Quantity): $(distinctBase it)
12 changes: 7 additions & 5 deletions execution_chain/block_access_list/block_access_list_builder.nim
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ type
accounts*: Table[Address, AccountData]
## Maps address -> account data

BlockAccessListRef* = ref BlockAccessList

template init*(T: type AccountData): T =
AccountData()

Expand Down Expand Up @@ -119,11 +121,11 @@ func slotCmp(x, y: StorageKey | StorageValue): int =
func slotChangesCmp(x, y: SlotChanges): int =
cmp(x.slot.data.toHex(), y.slot.data.toHex())

func addressCmp(x, y: AccountChanges): int =
func accChangesCmp(x, y: AccountChanges): int =
cmp(x.address.data.toHex(), y.address.data.toHex())

func buildBlockAccessList*(builder: BlockAccessListBuilderRef): BlockAccessList =
var blockAccessList: BlockAccessList
func buildBlockAccessList*(builder: BlockAccessListBuilderRef): BlockAccessListRef =
let blockAccessList: BlockAccessListRef = new BlockAccessList

for address, accData in builder.accounts.mpairs():
# Collect and sort storageChanges
Expand Down Expand Up @@ -163,7 +165,7 @@ func buildBlockAccessList*(builder: BlockAccessListBuilderRef): BlockAccessList
codeChanges.add((BlockAccessIndex(balIndex), Bytecode(code)))
codeChanges.sort(balIndexCmp)

blockAccessList.add(AccountChanges(
blockAccessList[].add(AccountChanges(
address: address,
storageChanges: storageChanges,
storageReads: storageReads,
Expand All @@ -172,6 +174,6 @@ func buildBlockAccessList*(builder: BlockAccessListBuilderRef): BlockAccessList
codeChanges: codeChanges
))

blockAccessList.sort(addressCmp)
blockAccessList[].sort(accChangesCmp)

blockAccessList
Loading