From d92543bdc267a4d2c40454d52c770ab0c1fe4c2b Mon Sep 17 00:00:00 2001 From: lightclient Date: Tue, 10 Jun 2025 13:53:47 +0200 Subject: [PATCH] core: add extra db table for code size Co-authored-by: lightclient Co-authored-by: Qi Zhou --- core/rawdb/accessors_state.go | 17 +++++++++++++++++ core/rawdb/schema.go | 6 ++++++ core/state/reader.go | 6 +++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/core/rawdb/accessors_state.go b/core/rawdb/accessors_state.go index 41e15debe9..97ec7057ba 100644 --- a/core/rawdb/accessors_state.go +++ b/core/rawdb/accessors_state.go @@ -65,6 +65,16 @@ func ReadCodeWithPrefix(db ethdb.KeyValueReader, hash common.Hash) []byte { return data } +// ReadCodeWithPrefix retrieves the contract code of the provided code hash. +// Return -1 if not found for legacy db. +func ReadCodeSizeWithPrefix(db ethdb.KeyValueReader, hash common.Hash) int { + data, _ := db.Get(codeSizeKey(hash)) + if len(data) != 4 { + return -1 + } + return int(binary.BigEndian.Uint32(data)) +} + // HasCode checks if the contract code corresponding to the // provided code hash is present in the db. func HasCode(db ethdb.KeyValueReader, hash common.Hash) bool { @@ -90,12 +100,19 @@ func WriteCode(db ethdb.KeyValueWriter, hash common.Hash, code []byte) { if err := db.Put(codeKey(hash), code); err != nil { log.Crit("Failed to store contract code", "err", err) } + var sizeData [4]byte + binary.BigEndian.PutUint32(sizeData[:], uint32(len(code))) + if err := db.Put(codeSizeKey(hash), sizeData[:]); err != nil { + log.Crit("Failed to store contract code size", "err", err) + } } // DeleteCode deletes the specified contract code from the database. func DeleteCode(db ethdb.KeyValueWriter, hash common.Hash) { if err := db.Delete(codeKey(hash)); err != nil { log.Crit("Failed to delete contract code", "err", err) + // Ignore error since the legacy db may not contain the size. + db.Delete(codeSizeKey(hash)) } } diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index fa125cecc0..24185ad2f4 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -110,6 +110,7 @@ var ( SnapshotAccountPrefix = []byte("a") // SnapshotAccountPrefix + account hash -> account trie value SnapshotStoragePrefix = []byte("o") // SnapshotStoragePrefix + account hash + storage hash -> storage trie value CodePrefix = []byte("c") // CodePrefix + code hash -> account code + CodeSizePrefix = []byte("s") /// CodeSizePrefx + code hash -> code size skeletonHeaderPrefix = []byte("S") // skeletonHeaderPrefix + num (uint64 big endian) -> header // Path-based storage scheme of merkle patricia trie. @@ -233,6 +234,11 @@ func codeKey(hash common.Hash) []byte { return append(CodePrefix, hash.Bytes()...) } +// codeSizeKey = CodeSizePrefix + hash +func codeSizeKey(hash common.Hash) []byte { + return append(CodeSizePrefix, hash.Bytes()...) +} + // IsCodeKey reports whether the given byte slice is the key of contract code, // if so return the raw code hash as well. func IsCodeKey(key []byte) (bool, []byte) { diff --git a/core/state/reader.go b/core/state/reader.go index 32645fbacd..64bea0c432 100644 --- a/core/state/reader.go +++ b/core/state/reader.go @@ -140,7 +140,11 @@ func (r *cachingCodeReader) CodeSize(addr common.Address, codeHash common.Hash) if cached, ok := r.codeSizeCache.Get(codeHash); ok { return cached, nil } - + codeSize := rawdb.ReadCodeSizeWithPrefix(r.db, codeHash) + if codeSize != -1 { + r.codeSizeCache.Add(codeHash, codeSize) + return codeSize, nil + } code, err := r.Code(addr, codeHash) if err != nil { return 0, err