diff --git a/execution_chain/common/genesis.nim b/execution_chain/common/genesis.nim index 68377f7dc5..882ce9e939 100644 --- a/execution_chain/common/genesis.nim +++ b/execution_chain/common/genesis.nim @@ -83,6 +83,9 @@ proc toGenesisHeader*( const EmptyRequestsHash = calcRequestsHash() result.requestsHash = Opt.some(EmptyRequestsHash) + if fork >= Amsterdam: + result.blockAccessListHash = Opt.some(EMPTY_BLOCK_ACCESS_LIST_HASH) + proc toGenesisHeader*( genesis: Genesis; fork: HardFork; diff --git a/execution_chain/core/chain/forked_chain.nim b/execution_chain/core/chain/forked_chain.nim index 379d2c44d4..4655360e0b 100644 --- a/execution_chain/core/chain/forked_chain.nim +++ b/execution_chain/core/chain/forked_chain.nim @@ -502,6 +502,7 @@ proc validateBlock(c: ForkedChainRef, excessBlobGas: blk.header.excessBlobGas, parentBeaconBlockRoot: blk.header.parentBeaconBlockRoot, requestsHash: blk.header.requestsHash, + blockAccessListHash: blk.header.blockAccessListHash ), parentTxFrame=cast[uint](parentFrame), txFrame=cast[uint](txFrame) @@ -947,6 +948,7 @@ proc blockBodyByHash*(c: ForkedChainRef, blockHash: Hash32): Result[BlockBody, s transactions: blk.transactions, uncles: blk.uncles, withdrawals: blk.withdrawals, + blockAccessList: blk.blockAccessList, )) c.baseTxFrame.getBlockBody(blockHash) diff --git a/execution_chain/core/chain/forked_chain/chain_private.nim b/execution_chain/core/chain/forked_chain/chain_private.nim index 7360f2bb66..f53f83c921 100644 --- a/execution_chain/core/chain/forked_chain/chain_private.nim +++ b/execution_chain/core/chain/forked_chain/chain_private.nim @@ -34,6 +34,10 @@ proc writeBaggage*(c: ForkedChainRef, txFrame.persistWithdrawals( header.withdrawalsRoot.expect("WithdrawalsRoot should be verified before"), blk.withdrawals.get) + if blk.blockAccessList.isSome: + txFrame.persistBlockAccessList( + header.blockAccessListHash.expect("blockAccessListHash should be verified before"), + blk.blockAccessList.get) proc processBlock*(c: ForkedChainRef, parentBlk: BlockRef, diff --git a/execution_chain/core/chain/persist_blocks.nim b/execution_chain/core/chain/persist_blocks.nim index 11a6e12729..6293a85f47 100644 --- a/execution_chain/core/chain/persist_blocks.nim +++ b/execution_chain/core/chain/persist_blocks.nim @@ -39,6 +39,7 @@ type NoPersistWithdrawals NoPersistReceipts NoPersistSlotHashes + NoPersistBlockAccessList PersistBlockFlags* = set[PersistBlockFlag] @@ -51,7 +52,7 @@ type PersistStats* = tuple[blocks: int, txs: int, gas: GasInt] -const NoPersistBodies* = {NoPersistTransactions, NoPersistUncles, NoPersistWithdrawals} +const NoPersistBodies* = {NoPersistTransactions, NoPersistUncles, NoPersistWithdrawals, NoPersistBlockAccessList} # ------------------------------------------------------------------------------ # Private @@ -208,6 +209,11 @@ proc persistBlock*(p: var Persister, blk: Block): Result[void, string] = blk.withdrawals.get, ) + if NoPersistBlockAccessList notin p.flags and blk.blockAccessList.isSome: + txFrame.persistBlockAccessList( + header.blockAccessListHash.expect("blockAccessListHash should be verified before"), + blk.blockAccessList.get) + p.stats.blocks += 1 p.stats.txs += blk.transactions.len p.stats.gas += blk.header.gasUsed diff --git a/execution_chain/core/executor/process_block.nim b/execution_chain/core/executor/process_block.nim index bc02358c5a..133fe3d2ef 100644 --- a/execution_chain/core/executor/process_block.nim +++ b/execution_chain/core/executor/process_block.nim @@ -18,6 +18,7 @@ import ../../transaction, ../../evm/state, ../../evm/types, + ../../block_access_list/block_access_list_validation, ../dao, ../eip6110, ./calculate_reward, @@ -140,6 +141,20 @@ proc procBlkPreamble( if header.parentBeaconBlockRoot.isSome: return err("Pre-Cancun block header must not have parentBeaconBlockRoot") + if com.isAmsterdamOrLater(header.timestamp): + if header.blockAccessListHash.isNone: + return err("Post-Amsterdam block header must have blockAccessListHash") + elif blk.blockAccessList.isNone: + return err("Post-Amsterdam block body must have blockAccessList") + elif not skipValidation: + if blk.blockAccessList.get.validate(header.blockAccessListHash.get).isErr(): + return err("Mismatched blockAccessListHash") + else: + if header.blockAccessListHash.isSome: + return err("Pre-Amsterdam block header must not have blockAccessListHash") + elif blk.blockAccessList.isSome: + return err("Pre-Amsterdam block body must not have blockAccessList") + if header.txRoot != EMPTY_ROOT_HASH: if blk.transactions.len == 0: return err("Transactions missing from body") diff --git a/execution_chain/core/validate.nim b/execution_chain/core/validate.nim index 94e30f7a49..2a571b6b28 100644 --- a/execution_chain/core/validate.nim +++ b/execution_chain/core/validate.nim @@ -18,7 +18,8 @@ import ../transaction/call_types, ../[transaction, constants], ../utils/utils, - "."/[dao, eip4844, eip7702, eip7691, gaslimit, withdrawals], + ../block_access_list/block_access_list_validation, + ./[dao, eip4844, eip7702, eip7691, gaslimit, withdrawals], ./pow/difficulty, stew/objects, results @@ -37,6 +38,28 @@ const # Private validator functions # ------------------------------------------------------------------------------ +# https://eips.ethereum.org/EIPS/eip-7928 +func validateBlockAccessList*( + com: CommonRef, + header: Header, + blockAccessList: Opt[BlockAccessList] + ): Result[void, string] = + if com.isAmsterdamOrLater(header.timestamp): + if header.blockAccessListHash.isNone: + return err("Post-Amsterdam block header must have blockAccessListHash") + elif blockAccessList.isNone: + return err("Post-Amsterdam block body must have blockAccessList") + else: + if blockAccessList.get.validate(header.blockAccessListHash.get).isErr(): + return err("Mismatched blockAccessListHash blockNumber =" & $header.number) + else: + if header.blockAccessListHash.isSome: + return err("Pre-Amsterdam block header must not have blockAccessListHash") + elif blockAccessList.isSome: + return err("Pre-Amsterdam block body must not have blockAccessList") + + return ok() + proc validateHeader( com: CommonRef; blk: Block; @@ -98,6 +121,7 @@ proc validateHeader( ? com.validateWithdrawals(header, blk.withdrawals) ? com.validateEip4844Header(header, parentHeader, blk.transactions) ? com.validateGasLimitOrBaseFee(header, parentHeader) + ? com.validateBlockAccessList(header, blk.blockAccessList) ok() diff --git a/execution_chain/db/core_db/core_apps.nim b/execution_chain/db/core_db/core_apps.nim index 299e0dbfc1..a1de407155 100644 --- a/execution_chain/db/core_db/core_apps.nim +++ b/execution_chain/db/core_db/core_apps.nim @@ -409,6 +409,22 @@ proc getTransactions*( return ok(move(res)) +proc persistBlockAccessList*( + db: CoreDbTxRef, blockAccessListHash: Hash32, bal: BlockAccessList) = + db.put(blockAccessListHashKey(blockAccessListHash).toOpenArray, bal.encode()) + .expect("persistBlockAccessList should succeed") + +proc getBlockAccessList*( + db: CoreDbTxRef, + blockAccessListHash: Hash32): Result[BlockAccessList, string] = + let balBytes = db.get(blockAccessListHashKey(blockAccessListHash).toOpenArray).valueOr: + return err("getBlockAccessList: " & $$error) + + let bal = BlockAccessList.decode(balBytes).valueOr: + return err("getBlockAccessList: " & $error) + + ok(bal) + proc getBlockBody*( db: CoreDbTxRef; header: Header; @@ -421,6 +437,11 @@ proc getBlockBody*( if header.withdrawalsRoot.isSome: let wds = ?db.getWithdrawals(header.withdrawalsRoot.get) body.withdrawals = Opt.some(wds) + + if header.blockAccessListHash.isSome: + let bal = ?db.getBlockAccessList(header.blockAccessListHash.get) + body.blockAccessList = Opt.some(bal) + return ok(move(body)) proc getBlockBody*( @@ -448,7 +469,6 @@ proc getEthBlock*( blockBody = ?db.getBlockBody(header) ok(EthBlock.init(move(header), move(blockBody))) - proc getUncleHashes*( db: CoreDbTxRef; blockHashes: openArray[Hash32]; @@ -641,18 +661,18 @@ proc getWitness*(db: CoreDbTxRef, blockHash: Hash32): Result[Witness, string] = Witness.decode(witnessBytes) +proc persistCodeByHash*(db: CoreDbTxRef, codeHash: Hash32, code: openArray[byte]): Result[void, string] = + db.put(contractHashKey(codeHash).toOpenArray, code).isOkOr: + return err("persistCodeByHash: " & $$error) + + ok() + proc getCodeByHash*(db: CoreDbTxRef, codeHash: Hash32): Result[seq[byte], string] = let code = db.get(contractHashKey(codeHash).toOpenArray).valueOr: return err("getCodeByHash: " & $$error) ok(code) -proc setCodeByHash*(db: CoreDbTxRef, codeHash: Hash32, code: openArray[byte]): Result[void, string] = - db.put(contractHashKey(codeHash).toOpenArray, code).isOkOr: - return err("setCodeByHash: " & $$error) - - ok() - # ------------------------------------------------------------------------------ # End # ------------------------------------------------------------------------------ diff --git a/execution_chain/db/storage_types.nim b/execution_chain/db/storage_types.nim index bffeb8341e..a2606fd6ec 100644 --- a/execution_chain/db/storage_types.nim +++ b/execution_chain/db/storage_types.nim @@ -29,6 +29,7 @@ type beaconHeader = 10 wdKey = 11 witness = 12 + blockAccessList = 13 DbKey* = object # The first byte stores the key type. The rest are key-specific values @@ -110,6 +111,11 @@ func blockHashToWitnessKey*(h: Hash32): DbKey {.inline.} = result.data[1 .. 32] = h.data result.dataEndPos = uint8 32 +func blockAccessListHashKey*(h: Hash32): DbKey {.inline.} = + result.data[0] = byte ord(blockAccessList) + result.data[1 .. 32] = h.data + result.dataEndPos = uint8 32 + template toOpenArray*(k: DbKey): openArray[byte] = k.data.toOpenArray(0, int(k.dataEndPos)) diff --git a/execution_chain/stateless/stateless_execution.nim b/execution_chain/stateless/stateless_execution.nim index e155d64a00..fe19b98916 100644 --- a/execution_chain/stateless/stateless_execution.nim +++ b/execution_chain/stateless/stateless_execution.nim @@ -57,7 +57,7 @@ proc statelessProcessBlock*( # Load the contract code into the database indexed by code hash. for c in witness.codes: - doAssert memoryTxFrame.setCodeByHash(keccak256(c), c).isOk() + doAssert memoryTxFrame.persistCodeByHash(keccak256(c), c).isOk() # Load the block hashes into the database indexed by block number. for h in verifiedHeaders: diff --git a/execution_chain/sync/beacon/worker/blocks/blocks_blocks.nim b/execution_chain/sync/beacon/worker/blocks/blocks_blocks.nim index 6285ae311e..8088106bf0 100644 --- a/execution_chain/sync/beacon/worker/blocks/blocks_blocks.nim +++ b/execution_chain/sync/beacon/worker/blocks/blocks_blocks.nim @@ -94,6 +94,11 @@ template blocksFetchCheckImpl( else: if bodies[n].transactions.len == 0: break checkTxLenOk + if blocks[n].header.blockAccessListHash.isSome(): + if bodies[n].blockAccessList.isSome(): + break checkTxLenOk + elif bodies[n].blockAccessList.isNone(): + break checkTxLenOk # Oops, cut off the rest blocks.setLen(n) # curb off junk buddy.bdyFetchRegisterError() @@ -112,8 +117,9 @@ template blocksFetchCheckImpl( # erroneously empty `transactions[]`.) # blocks[n].transactions = bodies[n].transactions - blocks[n].uncles = bodies[n].uncles - blocks[n].withdrawals = bodies[n].withdrawals + blocks[n].uncles = bodies[n].uncles + blocks[n].withdrawals = bodies[n].withdrawals + blocks[n].blockAccessList = bodies[n].blockAccessList if 0 < blocks.len.uint64: bodyRc = Opt[seq[EthBlock]].ok(blocks) # return ok() diff --git a/execution_chain/sync/wire_protocol/handler.nim b/execution_chain/sync/wire_protocol/handler.nim index bf246c0e79..09a066beba 100644 --- a/execution_chain/sync/wire_protocol/handler.nim +++ b/execution_chain/sync/wire_protocol/handler.nim @@ -157,7 +157,8 @@ proc getBlockBodies*(ctx: EthWireRef, BlockBody( transactions: blk.transactions, uncles: blk.uncles, - withdrawals: blk.withdrawals + withdrawals: blk.withdrawals, + blockAccessList: blk.blockAccessList, ) for blockHash in hashes: