diff --git a/execution_chain/core/chain/forked_chain/chain_private.nim b/execution_chain/core/chain/forked_chain/chain_private.nim index 32e493d7c2..490ccc4b3a 100644 --- a/execution_chain/core/chain/forked_chain/chain_private.nim +++ b/execution_chain/core/chain/forked_chain/chain_private.nim @@ -118,6 +118,7 @@ proc processBlock*( # witness keys and block hashes when processing the block as these will be used # when building the witness. vmState.ledger.clearWitnessKeys() + vmState.ledger.clearDeployedCodeHashes() vmState.ledger.clearBlockHashesCache() processBlock() diff --git a/execution_chain/core/chain/persist_blocks.nim b/execution_chain/core/chain/persist_blocks.nim index 71fa3cb642..c48f740c1a 100644 --- a/execution_chain/core/chain/persist_blocks.nim +++ b/execution_chain/core/chain/persist_blocks.nim @@ -188,6 +188,7 @@ proc persistBlock*(p: var Persister, blk: Block): Result[void, string] = # witness keys and block hashes when processing the block as these will be used # when building the witness. vmState.ledger.clearWitnessKeys() + vmState.ledger.clearDeployedCodeHashes() vmState.ledger.clearBlockHashesCache() processBlock() diff --git a/execution_chain/db/ledger.nim b/execution_chain/db/ledger.nim index a29680c615..ba397615dc 100644 --- a/execution_chain/db/ledger.nim +++ b/execution_chain/db/ledger.nim @@ -110,6 +110,8 @@ type dirty: Table[Address, AccountRef] selfDestruct: HashSet[Address] accessList: ac_access_list.AccessList + deployedCodeHashes: HashSet[Hash32] + ## Caches codeHashes deployed via CREATE in this savepoint. const resetFlags = { @@ -376,6 +378,7 @@ proc commit*(ledger: LedgerRef, savePoint: LedgerSpRef) = ledger.savePoint.dirty.mergeAndReset(savePoint.dirty) ledger.savePoint.accessList.mergeAndReset(savePoint.accessList) ledger.savePoint.selfDestruct.mergeAndReset(savePoint.selfDestruct) + ledger.savePoint.deployedCodeHashes.mergeAndReset(savePoint.deployedCodeHashes) savePoint.parentSavePoint = nil # Release memory @@ -408,16 +411,30 @@ proc getNonce*(ledger: LedgerRef, address: Address): AccountNonce = if acc.isNil: EMPTY_ACCOUNT.nonce else: acc.statement.nonce +func isDeployedCode(ledger: LedgerRef, codeHash: Hash32): bool = + ## Check if codeHash was deployed in any currently active save point. + var sp = ledger.savePoint + while sp != nil: + if codeHash in sp.deployedCodeHashes: + return true + sp = sp.parentSavePoint + false + proc getCode*(ledger: LedgerRef, address: Address, returnHash: static[bool] = false): auto = + let acc = ledger.getAccount(address, false) + if ledger.collectWitness: let lookupKey = (address, Opt.none(UInt256)) - # We overwrite any existing record here so that codeTouched is always set to - # true even if an account was previously accessed without touching the code - ledger.witnessKeys[lookupKey] = true + # Only mark codeTouched if the code isn't deployed in this block. + # Deployed code can be recovered from tx data directly. + # We overwrite any existing false entry so codeTouched is set to true + # even if the account was previously accessed without touching the code. + if acc.isNil or acc.statement.codeHash == EMPTY_CODE_HASH or + not ledger.isDeployedCode(acc.statement.codeHash): + ledger.witnessKeys[lookupKey] = true - let acc = ledger.getAccount(address, false) if acc.isNil: when returnHash: return (EMPTY_CODE_HASH, CodeBytesRef()) @@ -445,13 +462,14 @@ proc getCode*(ledger: LedgerRef, acc.code proc getCodeSize*(ledger: LedgerRef, address: Address): int = + let acc = ledger.getAccount(address, false) + if ledger.collectWitness: let lookupKey = (address, Opt.none(UInt256)) - # We overwrite any existing record here so that codeTouched is always set to - # true even if an account was previously accessed without touching the code - ledger.witnessKeys[lookupKey] = true + if acc.isNil or acc.statement.codeHash == EMPTY_CODE_HASH or + not ledger.isDeployedCode(acc.statement.codeHash): + ledger.witnessKeys[lookupKey] = true - let acc = ledger.getAccount(address, false) if acc.isNil: return 0 @@ -575,6 +593,8 @@ proc setCode*(ledger: LedgerRef, address: Address, code: seq[byte]) = # a given that it will be executed within LRU range acc.code = ledger.code.get(codeHash).valueOr(CodeBytesRef.init(code)) acc.flags.incl CodeChanged + if ledger.collectWitness and code.len > 0: + ledger.savePoint.deployedCodeHashes.incl(codeHash) proc setStorage*(ledger: LedgerRef, address: Address, slot, value: UInt256) = let acc = ledger.getAccount(address) @@ -663,6 +683,9 @@ template getWitnessKeys*(ledger: LedgerRef): WitnessTable = template clearWitnessKeys*(ledger: LedgerRef) = ledger.witnessKeys.clear() +template clearDeployedCodeHashes*(ledger: LedgerRef) = + ledger.savePoint.deployedCodeHashes.clear() + proc getBlockHash*(ledger: LedgerRef, blockNumber: BlockNumber): Hash32 = ledger.blockHashes.get(blockNumber).valueOr: let blockHash = ledger.txFrame.getBlockHash(blockNumber).valueOr: @@ -742,6 +765,7 @@ proc persist*(ledger: LedgerRef, if clearWitness: ledger.clearWitnessKeys() + ledger.clearDeployedCodeHashes() ledger.clearBlockHashesCache() iterator addresses*(ledger: LedgerRef): Address = diff --git a/tests/eest/eest_stateless_execution_test.nim b/tests/eest/eest_stateless_execution_test.nim index 8b5cb13ba4..a86b874a19 100644 --- a/tests/eest/eest_stateless_execution_test.nim +++ b/tests/eest/eest_stateless_execution_test.nim @@ -61,7 +61,6 @@ const skipFiles = [ "varying_calldata_costs.json", "bal_7002_partial_sweep.json", "witness_codes_delegated_eoa_insufficient_balance.json", - "witness_codes_create_same_hash_then_read.json", "witness_headers_blockhash_at_offset.json", "witness_headers_blockhash_boundary.json", "witness_headers_blockhash_in_reverted_tx.json",