diff --git a/core/rawdb/accessors_history.go b/core/rawdb/accessors_history.go index 50512b7d1a..4de6bb6954 100644 --- a/core/rawdb/accessors_history.go +++ b/core/rawdb/accessors_history.go @@ -47,8 +47,8 @@ func DeleteStateHistoryIndexMetadata(db ethdb.KeyValueWriter) { // ReadAccountHistoryIndex retrieves the account history index with the provided // account address. -func ReadAccountHistoryIndex(db ethdb.KeyValueReader, address common.Address) []byte { - data, err := db.Get(accountHistoryIndexKey(address)) +func ReadAccountHistoryIndex(db ethdb.KeyValueReader, addressHash common.Hash) []byte { + data, err := db.Get(accountHistoryIndexKey(addressHash)) if err != nil || len(data) == 0 { return nil } @@ -56,24 +56,24 @@ func ReadAccountHistoryIndex(db ethdb.KeyValueReader, address common.Address) [] } // WriteAccountHistoryIndex writes the provided account history index into database. -func WriteAccountHistoryIndex(db ethdb.KeyValueWriter, address common.Address, data []byte) { - if err := db.Put(accountHistoryIndexKey(address), data); err != nil { +func WriteAccountHistoryIndex(db ethdb.KeyValueWriter, addressHash common.Hash, data []byte) { + if err := db.Put(accountHistoryIndexKey(addressHash), data); err != nil { log.Crit("Failed to store account history index", "err", err) } } // DeleteAccountHistoryIndex deletes the specified account history index from // the database. -func DeleteAccountHistoryIndex(db ethdb.KeyValueWriter, address common.Address) { - if err := db.Delete(accountHistoryIndexKey(address)); err != nil { +func DeleteAccountHistoryIndex(db ethdb.KeyValueWriter, addressHash common.Hash) { + if err := db.Delete(accountHistoryIndexKey(addressHash)); err != nil { log.Crit("Failed to delete account history index", "err", err) } } // ReadStorageHistoryIndex retrieves the storage history index with the provided // account address and storage key hash. -func ReadStorageHistoryIndex(db ethdb.KeyValueReader, address common.Address, storageHash common.Hash) []byte { - data, err := db.Get(storageHistoryIndexKey(address, storageHash)) +func ReadStorageHistoryIndex(db ethdb.KeyValueReader, addressHash common.Hash, storageHash common.Hash) []byte { + data, err := db.Get(storageHistoryIndexKey(addressHash, storageHash)) if err != nil || len(data) == 0 { return nil } @@ -81,23 +81,23 @@ func ReadStorageHistoryIndex(db ethdb.KeyValueReader, address common.Address, st } // WriteStorageHistoryIndex writes the provided storage history index into database. -func WriteStorageHistoryIndex(db ethdb.KeyValueWriter, address common.Address, storageHash common.Hash, data []byte) { - if err := db.Put(storageHistoryIndexKey(address, storageHash), data); err != nil { +func WriteStorageHistoryIndex(db ethdb.KeyValueWriter, addressHash common.Hash, storageHash common.Hash, data []byte) { + if err := db.Put(storageHistoryIndexKey(addressHash, storageHash), data); err != nil { log.Crit("Failed to store storage history index", "err", err) } } // DeleteStorageHistoryIndex deletes the specified state index from the database. -func DeleteStorageHistoryIndex(db ethdb.KeyValueWriter, address common.Address, storageHash common.Hash) { - if err := db.Delete(storageHistoryIndexKey(address, storageHash)); err != nil { +func DeleteStorageHistoryIndex(db ethdb.KeyValueWriter, addressHash common.Hash, storageHash common.Hash) { + if err := db.Delete(storageHistoryIndexKey(addressHash, storageHash)); err != nil { log.Crit("Failed to delete storage history index", "err", err) } } // ReadAccountHistoryIndexBlock retrieves the index block with the provided // account address along with the block id. -func ReadAccountHistoryIndexBlock(db ethdb.KeyValueReader, address common.Address, blockID uint32) []byte { - data, err := db.Get(accountHistoryIndexBlockKey(address, blockID)) +func ReadAccountHistoryIndexBlock(db ethdb.KeyValueReader, addressHash common.Hash, blockID uint32) []byte { + data, err := db.Get(accountHistoryIndexBlockKey(addressHash, blockID)) if err != nil || len(data) == 0 { return nil } @@ -105,23 +105,23 @@ func ReadAccountHistoryIndexBlock(db ethdb.KeyValueReader, address common.Addres } // WriteAccountHistoryIndexBlock writes the provided index block into database. -func WriteAccountHistoryIndexBlock(db ethdb.KeyValueWriter, address common.Address, blockID uint32, data []byte) { - if err := db.Put(accountHistoryIndexBlockKey(address, blockID), data); err != nil { +func WriteAccountHistoryIndexBlock(db ethdb.KeyValueWriter, addressHash common.Hash, blockID uint32, data []byte) { + if err := db.Put(accountHistoryIndexBlockKey(addressHash, blockID), data); err != nil { log.Crit("Failed to store account index block", "err", err) } } // DeleteAccountHistoryIndexBlock deletes the specified index block from the database. -func DeleteAccountHistoryIndexBlock(db ethdb.KeyValueWriter, address common.Address, blockID uint32) { - if err := db.Delete(accountHistoryIndexBlockKey(address, blockID)); err != nil { +func DeleteAccountHistoryIndexBlock(db ethdb.KeyValueWriter, addressHash common.Hash, blockID uint32) { + if err := db.Delete(accountHistoryIndexBlockKey(addressHash, blockID)); err != nil { log.Crit("Failed to delete account index block", "err", err) } } // ReadStorageHistoryIndexBlock retrieves the index block with the provided state // identifier along with the block id. -func ReadStorageHistoryIndexBlock(db ethdb.KeyValueReader, address common.Address, storageHash common.Hash, blockID uint32) []byte { - data, err := db.Get(storageHistoryIndexBlockKey(address, storageHash, blockID)) +func ReadStorageHistoryIndexBlock(db ethdb.KeyValueReader, addressHash common.Hash, storageHash common.Hash, blockID uint32) []byte { + data, err := db.Get(storageHistoryIndexBlockKey(addressHash, storageHash, blockID)) if err != nil || len(data) == 0 { return nil } @@ -129,15 +129,15 @@ func ReadStorageHistoryIndexBlock(db ethdb.KeyValueReader, address common.Addres } // WriteStorageHistoryIndexBlock writes the provided index block into database. -func WriteStorageHistoryIndexBlock(db ethdb.KeyValueWriter, address common.Address, storageHash common.Hash, id uint32, data []byte) { - if err := db.Put(storageHistoryIndexBlockKey(address, storageHash, id), data); err != nil { +func WriteStorageHistoryIndexBlock(db ethdb.KeyValueWriter, addressHash common.Hash, storageHash common.Hash, id uint32, data []byte) { + if err := db.Put(storageHistoryIndexBlockKey(addressHash, storageHash, id), data); err != nil { log.Crit("Failed to store storage index block", "err", err) } } // DeleteStorageHistoryIndexBlock deletes the specified index block from the database. -func DeleteStorageHistoryIndexBlock(db ethdb.KeyValueWriter, address common.Address, state common.Hash, id uint32) { - if err := db.Delete(storageHistoryIndexBlockKey(address, state, id)); err != nil { +func DeleteStorageHistoryIndexBlock(db ethdb.KeyValueWriter, addressHash common.Hash, storageHash common.Hash, id uint32) { + if err := db.Delete(storageHistoryIndexBlockKey(addressHash, storageHash, id)); err != nil { log.Crit("Failed to delete storage index block", "err", err) } } diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 51ccb524b4..9681c39c58 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -493,7 +493,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { bloomBits.Add(size) // Path-based historic state indexes - case bytes.HasPrefix(key, StateHistoryIndexPrefix) && len(key) >= len(StateHistoryIndexPrefix)+common.AddressLength: + case bytes.HasPrefix(key, StateHistoryIndexPrefix) && len(key) >= len(StateHistoryIndexPrefix)+common.HashLength: stateIndex.Add(size) // Verkle trie data is detected, determine the sub-category diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 864a65ceeb..5379e66c4c 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -122,7 +122,7 @@ var ( stateIDPrefix = []byte("L") // stateIDPrefix + state root -> state id // State history indexing within path-based storage scheme - StateHistoryIndexPrefix = []byte("m") // StateHistoryIndexPrefix + account address or (account address + slotHash) -> index + StateHistoryIndexPrefix = []byte("m") // StateHistoryIndexPrefix + account address hash or (account address hash + slotHash) -> index // VerklePrefix is the database prefix for Verkle trie data, which includes: // (a) Trie nodes @@ -370,26 +370,26 @@ func filterMapBlockLVKey(number uint64) []byte { return key } -// accountHistoryIndexKey = StateHistoryIndexPrefix + address -func accountHistoryIndexKey(address common.Address) []byte { - return append(StateHistoryIndexPrefix, address.Bytes()...) +// accountHistoryIndexKey = StateHistoryIndexPrefix + addressHash +func accountHistoryIndexKey(addressHash common.Hash) []byte { + return append(StateHistoryIndexPrefix, addressHash.Bytes()...) } -// storageHistoryIndexKey = StateHistoryIndexPrefix + address + storageHash -func storageHistoryIndexKey(address common.Address, storageHash common.Hash) []byte { - return append(append(StateHistoryIndexPrefix, address.Bytes()...), storageHash.Bytes()...) +// storageHistoryIndexKey = StateHistoryIndexPrefix + addressHash + storageHash +func storageHistoryIndexKey(addressHash common.Hash, storageHash common.Hash) []byte { + return append(append(StateHistoryIndexPrefix, addressHash.Bytes()...), storageHash.Bytes()...) } -// accountHistoryIndexBlockKey = StateHistoryIndexPrefix + address + blockID -func accountHistoryIndexBlockKey(address common.Address, blockID uint32) []byte { +// accountHistoryIndexBlockKey = StateHistoryIndexPrefix + addressHash + blockID +func accountHistoryIndexBlockKey(addressHash common.Hash, blockID uint32) []byte { var buf [4]byte binary.BigEndian.PutUint32(buf[:], blockID) - return append(append(StateHistoryIndexPrefix, address.Bytes()...), buf[:]...) + return append(append(StateHistoryIndexPrefix, addressHash.Bytes()...), buf[:]...) } -// storageHistoryIndexBlockKey = StateHistoryIndexPrefix + address + storageHash + blockID -func storageHistoryIndexBlockKey(address common.Address, storageHash common.Hash, blockID uint32) []byte { +// storageHistoryIndexBlockKey = StateHistoryIndexPrefix + addressHash + storageHash + blockID +func storageHistoryIndexBlockKey(addressHash common.Hash, storageHash common.Hash, blockID uint32) []byte { var buf [4]byte binary.BigEndian.PutUint32(buf[:], blockID) - return append(append(append(StateHistoryIndexPrefix, address.Bytes()...), storageHash.Bytes()...), buf[:]...) + return append(append(append(StateHistoryIndexPrefix, addressHash.Bytes()...), storageHash.Bytes()...), buf[:]...) } diff --git a/triedb/pathdb/history_index.go b/triedb/pathdb/history_index.go index 0f79fe671c..f79581b38b 100644 --- a/triedb/pathdb/history_index.go +++ b/triedb/pathdb/history_index.go @@ -80,9 +80,9 @@ type indexReader struct { func loadIndexData(db ethdb.KeyValueReader, state stateIdent) ([]*indexBlockDesc, error) { var blob []byte if state.account { - blob = rawdb.ReadAccountHistoryIndex(db, state.address) + blob = rawdb.ReadAccountHistoryIndex(db, state.addressHash) } else { - blob = rawdb.ReadStorageHistoryIndex(db, state.address, state.storageHash) + blob = rawdb.ReadStorageHistoryIndex(db, state.addressHash, state.storageHash) } if len(blob) == 0 { return nil, nil @@ -142,9 +142,9 @@ func (r *indexReader) readGreaterThan(id uint64) (uint64, error) { blob []byte ) if r.state.account { - blob = rawdb.ReadAccountHistoryIndexBlock(r.db, r.state.address, desc.id) + blob = rawdb.ReadAccountHistoryIndexBlock(r.db, r.state.addressHash, desc.id) } else { - blob = rawdb.ReadStorageHistoryIndexBlock(r.db, r.state.address, r.state.storageHash, desc.id) + blob = rawdb.ReadStorageHistoryIndexBlock(r.db, r.state.addressHash, r.state.storageHash, desc.id) } br, err = newBlockReader(blob) if err != nil { @@ -176,9 +176,9 @@ type indexWriter struct { func newIndexWriter(db ethdb.KeyValueReader, state stateIdent) (*indexWriter, error) { var blob []byte if state.account { - blob = rawdb.ReadAccountHistoryIndex(db, state.address) + blob = rawdb.ReadAccountHistoryIndex(db, state.addressHash) } else { - blob = rawdb.ReadStorageHistoryIndex(db, state.address, state.storageHash) + blob = rawdb.ReadStorageHistoryIndex(db, state.addressHash, state.storageHash) } if len(blob) == 0 { desc := newIndexBlockDesc(0) @@ -199,9 +199,9 @@ func newIndexWriter(db ethdb.KeyValueReader, state stateIdent) (*indexWriter, er lastDesc = descList[len(descList)-1] ) if state.account { - indexBlock = rawdb.ReadAccountHistoryIndexBlock(db, state.address, lastDesc.id) + indexBlock = rawdb.ReadAccountHistoryIndexBlock(db, state.addressHash, lastDesc.id) } else { - indexBlock = rawdb.ReadStorageHistoryIndexBlock(db, state.address, state.storageHash, lastDesc.id) + indexBlock = rawdb.ReadStorageHistoryIndexBlock(db, state.addressHash, state.storageHash, lastDesc.id) } bw, err := newBlockWriter(indexBlock, lastDesc) if err != nil { @@ -271,9 +271,9 @@ func (w *indexWriter) finish(batch ethdb.Batch) { } for _, bw := range writers { if w.state.account { - rawdb.WriteAccountHistoryIndexBlock(batch, w.state.address, bw.desc.id, bw.finish()) + rawdb.WriteAccountHistoryIndexBlock(batch, w.state.addressHash, bw.desc.id, bw.finish()) } else { - rawdb.WriteStorageHistoryIndexBlock(batch, w.state.address, w.state.storageHash, bw.desc.id, bw.finish()) + rawdb.WriteStorageHistoryIndexBlock(batch, w.state.addressHash, w.state.storageHash, bw.desc.id, bw.finish()) } } w.frozen = nil // release all the frozen writers @@ -283,9 +283,9 @@ func (w *indexWriter) finish(batch ethdb.Batch) { buf = append(buf, desc.encode()...) } if w.state.account { - rawdb.WriteAccountHistoryIndex(batch, w.state.address, buf) + rawdb.WriteAccountHistoryIndex(batch, w.state.addressHash, buf) } else { - rawdb.WriteStorageHistoryIndex(batch, w.state.address, w.state.storageHash, buf) + rawdb.WriteStorageHistoryIndex(batch, w.state.addressHash, w.state.storageHash, buf) } } @@ -303,9 +303,9 @@ type indexDeleter struct { func newIndexDeleter(db ethdb.KeyValueReader, state stateIdent) (*indexDeleter, error) { var blob []byte if state.account { - blob = rawdb.ReadAccountHistoryIndex(db, state.address) + blob = rawdb.ReadAccountHistoryIndex(db, state.addressHash) } else { - blob = rawdb.ReadStorageHistoryIndex(db, state.address, state.storageHash) + blob = rawdb.ReadStorageHistoryIndex(db, state.addressHash, state.storageHash) } if len(blob) == 0 { // TODO(rjl493456442) we can probably return an error here, @@ -328,9 +328,9 @@ func newIndexDeleter(db ethdb.KeyValueReader, state stateIdent) (*indexDeleter, lastDesc = descList[len(descList)-1] ) if state.account { - indexBlock = rawdb.ReadAccountHistoryIndexBlock(db, state.address, lastDesc.id) + indexBlock = rawdb.ReadAccountHistoryIndexBlock(db, state.addressHash, lastDesc.id) } else { - indexBlock = rawdb.ReadStorageHistoryIndexBlock(db, state.address, state.storageHash, lastDesc.id) + indexBlock = rawdb.ReadStorageHistoryIndexBlock(db, state.addressHash, state.storageHash, lastDesc.id) } bw, err := newBlockWriter(indexBlock, lastDesc) if err != nil { @@ -381,9 +381,9 @@ func (d *indexDeleter) pop(id uint64) error { lastDesc = d.descList[len(d.descList)-1] ) if d.state.account { - indexBlock = rawdb.ReadAccountHistoryIndexBlock(d.db, d.state.address, lastDesc.id) + indexBlock = rawdb.ReadAccountHistoryIndexBlock(d.db, d.state.addressHash, lastDesc.id) } else { - indexBlock = rawdb.ReadStorageHistoryIndexBlock(d.db, d.state.address, d.state.storageHash, lastDesc.id) + indexBlock = rawdb.ReadStorageHistoryIndexBlock(d.db, d.state.addressHash, d.state.storageHash, lastDesc.id) } bw, err := newBlockWriter(indexBlock, lastDesc) if err != nil { @@ -400,9 +400,9 @@ func (d *indexDeleter) pop(id uint64) error { func (d *indexDeleter) finish(batch ethdb.Batch) { for _, id := range d.dropped { if d.state.account { - rawdb.DeleteAccountHistoryIndexBlock(batch, d.state.address, id) + rawdb.DeleteAccountHistoryIndexBlock(batch, d.state.addressHash, id) } else { - rawdb.DeleteStorageHistoryIndexBlock(batch, d.state.address, d.state.storageHash, id) + rawdb.DeleteStorageHistoryIndexBlock(batch, d.state.addressHash, d.state.storageHash, id) } } d.dropped = nil @@ -410,17 +410,17 @@ func (d *indexDeleter) finish(batch ethdb.Batch) { // Flush the content of last block writer, regardless it's dirty or not if !d.bw.empty() { if d.state.account { - rawdb.WriteAccountHistoryIndexBlock(batch, d.state.address, d.bw.desc.id, d.bw.finish()) + rawdb.WriteAccountHistoryIndexBlock(batch, d.state.addressHash, d.bw.desc.id, d.bw.finish()) } else { - rawdb.WriteStorageHistoryIndexBlock(batch, d.state.address, d.state.storageHash, d.bw.desc.id, d.bw.finish()) + rawdb.WriteStorageHistoryIndexBlock(batch, d.state.addressHash, d.state.storageHash, d.bw.desc.id, d.bw.finish()) } } // Flush the index metadata into the supplied batch if d.empty() { if d.state.account { - rawdb.DeleteAccountHistoryIndex(batch, d.state.address) + rawdb.DeleteAccountHistoryIndex(batch, d.state.addressHash) } else { - rawdb.DeleteStorageHistoryIndex(batch, d.state.address, d.state.storageHash) + rawdb.DeleteStorageHistoryIndex(batch, d.state.addressHash, d.state.storageHash) } } else { buf := make([]byte, 0, indexBlockDescSize*len(d.descList)) @@ -428,9 +428,9 @@ func (d *indexDeleter) finish(batch ethdb.Batch) { buf = append(buf, desc.encode()...) } if d.state.account { - rawdb.WriteAccountHistoryIndex(batch, d.state.address, buf) + rawdb.WriteAccountHistoryIndex(batch, d.state.addressHash, buf) } else { - rawdb.WriteStorageHistoryIndex(batch, d.state.address, d.state.storageHash, buf) + rawdb.WriteStorageHistoryIndex(batch, d.state.addressHash, d.state.storageHash, buf) } } } diff --git a/triedb/pathdb/history_index_test.go b/triedb/pathdb/history_index_test.go index 84f4a5cd41..7b24b86fd6 100644 --- a/triedb/pathdb/history_index_test.go +++ b/triedb/pathdb/history_index_test.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/crypto" ) func TestIndexReaderBasic(t *testing.T) { @@ -32,7 +33,7 @@ func TestIndexReaderBasic(t *testing.T) { 1, 5, 10, 11, 20, } db := rawdb.NewMemoryDatabase() - bw, _ := newIndexWriter(db, newAccountIdent(common.Address{0xa})) + bw, _ := newIndexWriter(db, newAccountIdent(common.Hash{0xa})) for i := 0; i < len(elements); i++ { bw.append(elements[i]) } @@ -40,7 +41,7 @@ func TestIndexReaderBasic(t *testing.T) { bw.finish(batch) batch.Write() - br, err := newIndexReader(db, newAccountIdent(common.Address{0xa})) + br, err := newIndexReader(db, newAccountIdent(common.Hash{0xa})) if err != nil { t.Fatalf("Failed to construct the index reader, %v", err) } @@ -74,7 +75,7 @@ func TestIndexReaderLarge(t *testing.T) { slices.Sort(elements) db := rawdb.NewMemoryDatabase() - bw, _ := newIndexWriter(db, newAccountIdent(common.Address{0xa})) + bw, _ := newIndexWriter(db, newAccountIdent(common.Hash{0xa})) for i := 0; i < len(elements); i++ { bw.append(elements[i]) } @@ -82,7 +83,7 @@ func TestIndexReaderLarge(t *testing.T) { bw.finish(batch) batch.Write() - br, err := newIndexReader(db, newAccountIdent(common.Address{0xa})) + br, err := newIndexReader(db, newAccountIdent(common.Hash{0xa})) if err != nil { t.Fatalf("Failed to construct the index reader, %v", err) } @@ -106,7 +107,7 @@ func TestIndexReaderLarge(t *testing.T) { } func TestEmptyIndexReader(t *testing.T) { - br, err := newIndexReader(rawdb.NewMemoryDatabase(), newAccountIdent(common.Address{0xa})) + br, err := newIndexReader(rawdb.NewMemoryDatabase(), newAccountIdent(common.Hash{0xa})) if err != nil { t.Fatalf("Failed to construct the index reader, %v", err) } @@ -121,7 +122,7 @@ func TestEmptyIndexReader(t *testing.T) { func TestIndexWriterBasic(t *testing.T) { db := rawdb.NewMemoryDatabase() - iw, _ := newIndexWriter(db, newAccountIdent(common.Address{0xa})) + iw, _ := newIndexWriter(db, newAccountIdent(common.Hash{0xa})) iw.append(2) if err := iw.append(1); err == nil { t.Fatal("out-of-order insertion is not expected") @@ -133,7 +134,7 @@ func TestIndexWriterBasic(t *testing.T) { iw.finish(batch) batch.Write() - iw, err := newIndexWriter(db, newAccountIdent(common.Address{0xa})) + iw, err := newIndexWriter(db, newAccountIdent(common.Hash{0xa})) if err != nil { t.Fatalf("Failed to construct the block writer, %v", err) } @@ -147,7 +148,7 @@ func TestIndexWriterBasic(t *testing.T) { func TestIndexWriterDelete(t *testing.T) { db := rawdb.NewMemoryDatabase() - iw, _ := newIndexWriter(db, newAccountIdent(common.Address{0xa})) + iw, _ := newIndexWriter(db, newAccountIdent(common.Hash{0xa})) for i := 0; i < indexBlockEntriesCap*4; i++ { iw.append(uint64(i + 1)) } @@ -156,7 +157,7 @@ func TestIndexWriterDelete(t *testing.T) { batch.Write() // Delete unknown id, the request should be rejected - id, _ := newIndexDeleter(db, newAccountIdent(common.Address{0xa})) + id, _ := newIndexDeleter(db, newAccountIdent(common.Hash{0xa})) if err := id.pop(indexBlockEntriesCap * 5); err == nil { t.Fatal("Expect error to occur for unknown id") } @@ -194,23 +195,24 @@ func TestBatchIndexerWrite(t *testing.T) { t.Fatal("Unexpected index position") } var ( - accounts = make(map[common.Address][]uint64) - storages = make(map[common.Address]map[common.Hash][]uint64) + accounts = make(map[common.Hash][]uint64) + storages = make(map[common.Hash]map[common.Hash][]uint64) ) for i, h := range histories { for _, addr := range h.accountList { - accounts[addr] = append(accounts[addr], uint64(i+1)) + addrHash := crypto.Keccak256Hash(addr.Bytes()) + accounts[addrHash] = append(accounts[addrHash], uint64(i+1)) - if _, ok := storages[addr]; !ok { - storages[addr] = make(map[common.Hash][]uint64) + if _, ok := storages[addrHash]; !ok { + storages[addrHash] = make(map[common.Hash][]uint64) } for _, slot := range h.storageList[addr] { - storages[addr][slot] = append(storages[addr][slot], uint64(i+1)) + storages[addrHash][slot] = append(storages[addrHash][slot], uint64(i+1)) } } } - for addr, indexes := range accounts { - ir, _ := newIndexReader(db, newAccountIdent(addr)) + for addrHash, indexes := range accounts { + ir, _ := newIndexReader(db, newAccountIdent(addrHash)) for i := 0; i < len(indexes)-1; i++ { n, err := ir.readGreaterThan(indexes[i]) if err != nil { @@ -228,9 +230,9 @@ func TestBatchIndexerWrite(t *testing.T) { t.Fatalf("Unexpected result, want math.MaxUint64, got %d", n) } } - for addr, slots := range storages { + for addrHash, slots := range storages { for slotHash, indexes := range slots { - ir, _ := newIndexReader(db, newStorageIdent(addr, slotHash)) + ir, _ := newIndexReader(db, newStorageIdent(addrHash, slotHash)) for i := 0; i < len(indexes)-1; i++ { n, err := ir.readGreaterThan(indexes[i]) if err != nil { diff --git a/triedb/pathdb/history_indexer.go b/triedb/pathdb/history_indexer.go index e32550500f..c958bb3573 100644 --- a/triedb/pathdb/history_indexer.go +++ b/triedb/pathdb/history_indexer.go @@ -71,19 +71,19 @@ func storeIndexMetadata(db ethdb.KeyValueWriter, last uint64) { // batchIndexer is a structure designed to perform batch indexing or unindexing // of state histories atomically. type batchIndexer struct { - accounts map[common.Address][]uint64 // History ID list, Keyed by account address - storages map[common.Address]map[common.Hash][]uint64 // History ID list, Keyed by account address and the hash of raw storage key - counter int // The counter of processed states - delete bool // Index or unindex mode - lastID uint64 // The ID of latest processed history + accounts map[common.Hash][]uint64 // History ID list, Keyed by account address + storages map[common.Hash]map[common.Hash][]uint64 // History ID list, Keyed by account address and the hash of raw storage key + counter int // The counter of processed states + delete bool // Index or unindex mode + lastID uint64 // The ID of latest processed history db ethdb.KeyValueStore } // newBatchIndexer constructs the batch indexer with the supplied mode. func newBatchIndexer(db ethdb.KeyValueStore, delete bool) *batchIndexer { return &batchIndexer{ - accounts: make(map[common.Address][]uint64), - storages: make(map[common.Address]map[common.Hash][]uint64), + accounts: make(map[common.Hash][]uint64), + storages: make(map[common.Hash]map[common.Hash][]uint64), delete: delete, db: db, } @@ -93,13 +93,14 @@ func newBatchIndexer(db ethdb.KeyValueStore, delete bool) *batchIndexer { // state history, tracking the mapping between state and history IDs. func (b *batchIndexer) process(h *history, historyID uint64) error { for _, address := range h.accountList { + addrHash := crypto.Keccak256Hash(address.Bytes()) b.counter += 1 - b.accounts[address] = append(b.accounts[address], historyID) + b.accounts[addrHash] = append(b.accounts[addrHash], historyID) for _, slotKey := range h.storageList[address] { b.counter += 1 - if _, ok := b.storages[address]; !ok { - b.storages[address] = make(map[common.Hash][]uint64) + if _, ok := b.storages[addrHash]; !ok { + b.storages[addrHash] = make(map[common.Hash][]uint64) } // The hash of the storage slot key is used as the identifier because the // legacy history does not include the raw storage key, therefore, the @@ -108,7 +109,7 @@ func (b *batchIndexer) process(h *history, historyID uint64) error { if h.meta.version != stateHistoryV0 { slotHash = crypto.Keccak256Hash(slotKey.Bytes()) } - b.storages[address][slotHash] = append(b.storages[address][slotHash], historyID) + b.storages[addrHash][slotHash] = append(b.storages[addrHash][slotHash], historyID) } } b.lastID = historyID @@ -125,9 +126,9 @@ func (b *batchIndexer) finish(force bool) error { return nil } batch := b.db.NewBatch() - for address, idList := range b.accounts { + for addrHash, idList := range b.accounts { if !b.delete { - iw, err := newIndexWriter(b.db, newAccountIdent(address)) + iw, err := newIndexWriter(b.db, newAccountIdent(addrHash)) if err != nil { return err } @@ -138,7 +139,7 @@ func (b *batchIndexer) finish(force bool) error { } iw.finish(batch) } else { - id, err := newIndexDeleter(b.db, newAccountIdent(address)) + id, err := newIndexDeleter(b.db, newAccountIdent(addrHash)) if err != nil { return err } @@ -150,10 +151,10 @@ func (b *batchIndexer) finish(force bool) error { id.finish(batch) } } - for address, slots := range b.storages { + for addrHash, slots := range b.storages { for storageHash, idList := range slots { if !b.delete { - iw, err := newIndexWriter(b.db, newStorageIdent(address, storageHash)) + iw, err := newIndexWriter(b.db, newStorageIdent(addrHash, storageHash)) if err != nil { return err } @@ -164,7 +165,7 @@ func (b *batchIndexer) finish(force bool) error { } iw.finish(batch) } else { - id, err := newIndexDeleter(b.db, newStorageIdent(address, storageHash)) + id, err := newIndexDeleter(b.db, newStorageIdent(addrHash, storageHash)) if err != nil { return err } @@ -191,8 +192,8 @@ func (b *batchIndexer) finish(force bool) error { return err } b.counter = 0 - b.accounts = make(map[common.Address][]uint64) - b.storages = make(map[common.Address]map[common.Hash][]uint64) + b.accounts = make(map[common.Hash][]uint64) + b.storages = make(map[common.Hash]map[common.Hash][]uint64) return nil } diff --git a/triedb/pathdb/history_reader.go b/triedb/pathdb/history_reader.go index 486df7d86c..9471ab423d 100644 --- a/triedb/pathdb/history_reader.go +++ b/triedb/pathdb/history_reader.go @@ -33,13 +33,19 @@ import ( // either an account or a storage slot. type stateIdent struct { account bool - address common.Address + + // The hash of the account address. This is used instead of the raw account + // address is to align the traversal order with the Merkle-Patricia-Trie. + addressHash common.Hash // The hash of the storage slot key. This is used instead of the raw slot key // because, in legacy state histories (prior to the Cancun fork), the slot // identifier is the hash of the key, and the original key (preimage) cannot // be recovered. To maintain backward compatibility, the key hash is used. // + // Meanwhile, using the storage key hash also preserve the traversal order + // with Merkle-Patricia-Trie. + // // This field is null if the identifier refers to account data. storageHash common.Hash } @@ -47,25 +53,25 @@ type stateIdent struct { // String returns the string format state identifier. func (ident stateIdent) String() string { if ident.account { - return ident.address.Hex() + return ident.addressHash.Hex() } - return ident.address.Hex() + ident.storageHash.Hex() + return ident.addressHash.Hex() + ident.storageHash.Hex() } // newAccountIdent constructs a state identifier for an account. -func newAccountIdent(address common.Address) stateIdent { +func newAccountIdent(addressHash common.Hash) stateIdent { return stateIdent{ - account: true, - address: address, + account: true, + addressHash: addressHash, } } // newStorageIdent constructs a state identifier for a storage slot. // The address denotes the address of the associated account; // the storageHash denotes the hash of the raw storage slot key; -func newStorageIdent(address common.Address, storageHash common.Hash) stateIdent { +func newStorageIdent(addressHash common.Hash, storageHash common.Hash) stateIdent { return stateIdent{ - address: address, + addressHash: addressHash, storageHash: storageHash, } } @@ -73,29 +79,34 @@ func newStorageIdent(address common.Address, storageHash common.Hash) stateIdent // stateIdentQuery is the extension of stateIdent by adding the raw storage key. type stateIdentQuery struct { stateIdent + + address common.Address storageKey common.Hash } // newAccountIdentQuery constructs a state identifier for an account. -func newAccountIdentQuery(address common.Address) stateIdentQuery { +func newAccountIdentQuery(address common.Address, addressHash common.Hash) stateIdentQuery { return stateIdentQuery{ stateIdent: stateIdent{ - account: true, - address: address, + account: true, + addressHash: addressHash, }, + address: address, } } // newStorageIdentQuery constructs a state identifier for a storage slot. -// The address denotes the address of the associated account; +// the address denotes the address of the associated account; +// the addressHash denotes the address hash of the associated account; // the storageKey denotes the raw storage slot key; // the storageHash denotes the hash of the raw storage slot key; -func newStorageIdentQuery(address common.Address, storageKey common.Hash, storageHash common.Hash) stateIdentQuery { +func newStorageIdentQuery(address common.Address, addressHash common.Hash, storageKey common.Hash, storageHash common.Hash) stateIdentQuery { return stateIdentQuery{ stateIdent: stateIdent{ - address: address, + addressHash: addressHash, storageHash: storageHash, }, + address: address, storageKey: storageKey, } } diff --git a/triedb/pathdb/history_reader_test.go b/triedb/pathdb/history_reader_test.go index f58263f618..4356490f23 100644 --- a/triedb/pathdb/history_reader_test.go +++ b/triedb/pathdb/history_reader_test.go @@ -49,7 +49,7 @@ func checkHistoricState(env *tester, root common.Hash, hr *historyReader) error ) for addrHash, accountData := range accounts { latest, _ := dl.account(addrHash, 0) - blob, err := hr.read(newAccountIdentQuery(env.accountPreimage(addrHash)), *stateID, dl.stateID(), latest) + blob, err := hr.read(newAccountIdentQuery(env.accountPreimage(addrHash), addrHash), *stateID, dl.stateID(), latest) if err != nil { return err } @@ -65,7 +65,7 @@ func checkHistoricState(env *tester, root common.Hash, hr *historyReader) error for addrHash := range env.snapAccounts[env.roots[i]] { if _, ok := accounts[addrHash]; !ok { latest, _ := dl.account(addrHash, 0) - blob, err := hr.read(newAccountIdentQuery(env.accountPreimage(addrHash)), *stateID, dl.stateID(), latest) + blob, err := hr.read(newAccountIdentQuery(env.accountPreimage(addrHash), addrHash), *stateID, dl.stateID(), latest) if err != nil { return err } @@ -78,7 +78,7 @@ func checkHistoricState(env *tester, root common.Hash, hr *historyReader) error for addrHash, slots := range storages { for slotHash, slotData := range slots { latest, _ := dl.storage(addrHash, slotHash, 0) - blob, err := hr.read(newStorageIdentQuery(env.accountPreimage(addrHash), env.hashPreimage(slotHash), slotHash), *stateID, dl.stateID(), latest) + blob, err := hr.read(newStorageIdentQuery(env.accountPreimage(addrHash), addrHash, env.hashPreimage(slotHash), slotHash), *stateID, dl.stateID(), latest) if err != nil { return err } @@ -100,7 +100,7 @@ func checkHistoricState(env *tester, root common.Hash, hr *historyReader) error } if !ok { latest, _ := dl.storage(addrHash, slotHash, 0) - blob, err := hr.read(newStorageIdentQuery(env.accountPreimage(addrHash), env.hashPreimage(slotHash), slotHash), *stateID, dl.stateID(), latest) + blob, err := hr.read(newStorageIdentQuery(env.accountPreimage(addrHash), addrHash, env.hashPreimage(slotHash), slotHash), *stateID, dl.stateID(), latest) if err != nil { return err } diff --git a/triedb/pathdb/reader.go b/triedb/pathdb/reader.go index b1a7fdd926..b7b18f13f9 100644 --- a/triedb/pathdb/reader.go +++ b/triedb/pathdb/reader.go @@ -256,11 +256,12 @@ func (r *HistoricalStateReader) AccountRLP(address common.Address) ([]byte, erro // and try to define a low granularity lock if the current approach doesn't // work later. dl := r.db.tree.bottom() - latest, err := dl.account(crypto.Keccak256Hash(address.Bytes()), 0) + hash := crypto.Keccak256Hash(address.Bytes()) + latest, err := dl.account(hash, 0) if err != nil { return nil, err } - return r.reader.read(newAccountIdentQuery(address), r.id, dl.stateID(), latest) + return r.reader.read(newAccountIdentQuery(address, hash), r.id, dl.stateID(), latest) } // Account directly retrieves the account associated with a particular address in @@ -305,10 +306,11 @@ func (r *HistoricalStateReader) Storage(address common.Address, key common.Hash) // and try to define a low granularity lock if the current approach doesn't // work later. dl := r.db.tree.bottom() + addrHash := crypto.Keccak256Hash(address.Bytes()) keyHash := crypto.Keccak256Hash(key.Bytes()) - latest, err := dl.storage(crypto.Keccak256Hash(address.Bytes()), keyHash, 0) + latest, err := dl.storage(addrHash, keyHash, 0) if err != nil { return nil, err } - return r.reader.read(newStorageIdentQuery(address, key, keyHash), r.id, dl.stateID(), latest) + return r.reader.read(newStorageIdentQuery(address, addrHash, key, keyHash), r.id, dl.stateID(), latest) }