From 90230ffd43187a8be1f635d0113d88e36a688950 Mon Sep 17 00:00:00 2001
From: weiihann <weihan774237@gmail.com>
Date: Mon, 3 Mar 2025 12:34:07 +0800
Subject: [PATCH 01/15] refactor: create pathdb package

---
 core/trie2/trie.go                         | 8 ++++----
 core/trie2/triedb/{ => pathdb}/database.go | 2 +-
 core/trie2/triedb/{ => pathdb}/types.go    | 2 +-
 3 files changed, 6 insertions(+), 6 deletions(-)
 rename core/trie2/triedb/{ => pathdb}/database.go (99%)
 rename core/trie2/triedb/{ => pathdb}/types.go (89%)

diff --git a/core/trie2/trie.go b/core/trie2/trie.go
index 6cad27e0c3..1cc3beaccf 100644
--- a/core/trie2/trie.go
+++ b/core/trie2/trie.go
@@ -7,7 +7,7 @@ import (
 
 	"github.com/NethermindEth/juno/core/crypto"
 	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/core/trie2/triedb"
+	"github.com/NethermindEth/juno/core/trie2/triedb/pathdb"
 	"github.com/NethermindEth/juno/core/trie2/trienode"
 	"github.com/NethermindEth/juno/core/trie2/trieutils"
 	"github.com/NethermindEth/juno/db"
@@ -31,7 +31,7 @@ type Trie struct {
 	hashFn crypto.HashFn
 
 	// The underlying database to store and retrieve trie nodes
-	db triedb.TrieDB
+	db pathdb.TrieDB
 
 	// Check if the trie has been committed. Trie is unusable once committed.
 	committed bool
@@ -54,7 +54,7 @@ type TrieID interface {
 
 // Creates a new trie
 func New(id TrieID, height uint8, hashFn crypto.HashFn, txn db.Transaction) (*Trie, error) {
-	database := triedb.New(txn, id.Bucket())
+	database := pathdb.New(txn, id.Bucket())
 	tr := &Trie{
 		owner:      id.Owner(),
 		height:     height,
@@ -80,7 +80,7 @@ func NewEmpty(height uint8, hashFn crypto.HashFn) *Trie {
 		hashFn:     hashFn,
 		root:       nil,
 		nodeTracer: newTracer(),
-		db:         triedb.EmptyDatabase{},
+		db:         pathdb.EmptyDatabase{},
 	}
 }
 
diff --git a/core/trie2/triedb/database.go b/core/trie2/triedb/pathdb/database.go
similarity index 99%
rename from core/trie2/triedb/database.go
rename to core/trie2/triedb/pathdb/database.go
index 7e066671e4..6418ef6a1d 100644
--- a/core/trie2/triedb/database.go
+++ b/core/trie2/triedb/pathdb/database.go
@@ -1,4 +1,4 @@
-package triedb
+package pathdb
 
 import (
 	"bytes"
diff --git a/core/trie2/triedb/types.go b/core/trie2/triedb/pathdb/types.go
similarity index 89%
rename from core/trie2/triedb/types.go
rename to core/trie2/triedb/pathdb/types.go
index 889c34e738..36054191c9 100644
--- a/core/trie2/triedb/types.go
+++ b/core/trie2/triedb/pathdb/types.go
@@ -1,4 +1,4 @@
-package triedb
+package pathdb
 
 type leafType uint8
 

From fd838cc3a77b2dd7b542cc72ab91a527e2134a80 Mon Sep 17 00:00:00 2001
From: weiihann <weihan774237@gmail.com>
Date: Mon, 17 Feb 2025 18:41:00 +0800
Subject: [PATCH 02/15] Add Prev() to Iterator

---
 db/db.go              |  3 ++
 db/pebble/db_test.go  | 85 +++++++++++++++++++++++++++++++++++++++++++
 db/pebble/iterator.go |  8 ++++
 db/remote/iterator.go |  4 ++
 4 files changed, 100 insertions(+)

diff --git a/db/db.go b/db/db.go
index b65c35e620..78269f9bb3 100644
--- a/db/db.go
+++ b/db/db.go
@@ -45,6 +45,9 @@ type Iterator interface {
 	// First moves the iterator to the first key/value pair.
 	First() bool
 
+	// Prev moves the iterator to the previous key/value pair.
+	Prev() bool
+
 	// Next moves the iterator to the next key/value pair. It returns whether the
 	// iterator is valid after the call. Once invalid, the iterator remains
 	// invalid.
diff --git a/db/pebble/db_test.go b/db/pebble/db_test.go
index 68b22f2ff4..319353e987 100644
--- a/db/pebble/db_test.go
+++ b/db/pebble/db_test.go
@@ -383,6 +383,91 @@ func TestFirst(t *testing.T) {
 	})
 }
 
+func TestPrev(t *testing.T) {
+	testDB := pebble.NewMemTest(t)
+
+	txn, err := testDB.NewTransaction(true)
+	require.NoError(t, err)
+	t.Cleanup(func() {
+		require.NoError(t, txn.Discard())
+	})
+
+	t.Run("empty db", func(t *testing.T) {
+		iter, err := txn.NewIterator(nil, false)
+		require.NoError(t, err)
+		assert.Equal(t, false, iter.Prev())
+		assert.Equal(t, []byte(nil), iter.Key())
+		require.NoError(t, iter.Close())
+	})
+
+	one := []byte{1}
+	two := []byte{2}
+	three := []byte{3}
+	require.NoError(t, txn.Set(one, one))
+	require.NoError(t, txn.Set(two, two))
+	require.NoError(t, txn.Set(three, three))
+
+	t.Run("new iterator", func(t *testing.T) {
+		iter, err := txn.NewIterator(nil, false)
+		require.NoError(t, err)
+		assert.Equal(t, true, iter.Prev())
+		assert.Equal(t, one, iter.Key())
+		require.NoError(t, iter.Close())
+	})
+
+	t.Run("after valid seek", func(t *testing.T) {
+		iter, err := txn.NewIterator(nil, false)
+		require.NoError(t, err)
+		assert.Equal(t, true, iter.Seek(two))
+		assert.Equal(t, two, iter.Key())
+		assert.Equal(t, true, iter.Prev())
+		assert.Equal(t, one, iter.Key())
+		require.NoError(t, iter.Close())
+	})
+
+	t.Run("after invalid seek beyond last key", func(t *testing.T) {
+		iter, err := txn.NewIterator(nil, false)
+		require.NoError(t, err)
+		assert.Equal(t, false, iter.Seek([]byte{100}))
+		assert.Equal(t, []byte(nil), iter.Key())
+		assert.Equal(t, true, iter.Prev())
+		assert.Equal(t, three, iter.Key())
+		require.NoError(t, iter.Close())
+	})
+
+	t.Run("after valid seek first key", func(t *testing.T) {
+		iter, err := txn.NewIterator(nil, false)
+		require.NoError(t, err)
+		assert.Equal(t, true, iter.Seek(one))
+		assert.Equal(t, one, iter.Key())
+		assert.Equal(t, false, iter.Prev())
+		assert.Equal(t, one, iter.Key())
+		require.NoError(t, iter.Close())
+	})
+
+	t.Run("after multiple next", func(t *testing.T) {
+		iter, err := txn.NewIterator(nil, false)
+		require.NoError(t, err)
+		assert.Equal(t, true, iter.Next())
+		assert.Equal(t, one, iter.Key())
+		assert.Equal(t, true, iter.Next())
+		assert.Equal(t, two, iter.Key())
+		assert.Equal(t, true, iter.Prev())
+		assert.Equal(t, one, iter.Key())
+		require.NoError(t, iter.Close())
+	})
+
+	t.Run("with lower bound", func(t *testing.T) {
+		iter, err := txn.NewIterator(one, false)
+		require.NoError(t, err)
+		assert.Equal(t, true, iter.Seek(one))
+		assert.Equal(t, one, iter.Key())
+		assert.Equal(t, false, iter.Prev())
+		assert.Equal(t, one, iter.Key())
+		require.NoError(t, iter.Close())
+	})
+}
+
 func TestNext(t *testing.T) {
 	testDB := pebble.NewMemTest(t)
 
diff --git a/db/pebble/iterator.go b/db/pebble/iterator.go
index 0885ff97e7..c89ab098f4 100644
--- a/db/pebble/iterator.go
+++ b/db/pebble/iterator.go
@@ -44,6 +44,14 @@ func (i *iterator) First() bool {
 	return i.iter.First()
 }
 
+func (i *iterator) Prev() bool {
+	if !i.positioned {
+		i.positioned = true
+		return i.iter.First()
+	}
+	return i.iter.Prev()
+}
+
 // Next : see db.Transaction.Iterator.Next
 func (i *iterator) Next() bool {
 	if !i.positioned {
diff --git a/db/remote/iterator.go b/db/remote/iterator.go
index 1153424633..546e16087d 100644
--- a/db/remote/iterator.go
+++ b/db/remote/iterator.go
@@ -59,6 +59,10 @@ func (i *iterator) First() bool {
 	return len(i.currentK) > 0 || len(i.currentV) > 0
 }
 
+func (i *iterator) Prev() bool {
+	panic("does not support Prev")
+}
+
 func (i *iterator) Next() bool {
 	if err := i.doOpAndUpdate(gen.Op_NEXT, nil); err != nil {
 		i.log.Debugw("Error", "op", gen.Op_NEXT, "err", err)

From c294fb65f9090175b111f447fee48ea68ea6a54c Mon Sep 17 00:00:00 2001
From: weiihann <weihan774237@gmail.com>
Date: Mon, 17 Feb 2025 18:41:20 +0800
Subject: [PATCH 03/15] Add StateContract

---
 core/state/contract.go      | 305 ++++++++++++++++++++++++++++++++++++
 core/state/contract_test.go | 207 ++++++++++++++++++++++++
 db/buckets.go               |   6 +-
 3 files changed, 515 insertions(+), 3 deletions(-)
 create mode 100644 core/state/contract.go
 create mode 100644 core/state/contract_test.go

diff --git a/core/state/contract.go b/core/state/contract.go
new file mode 100644
index 0000000000..848314d7a7
--- /dev/null
+++ b/core/state/contract.go
@@ -0,0 +1,305 @@
+package state
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"slices"
+
+	"github.com/NethermindEth/juno/core/crypto"
+	"github.com/NethermindEth/juno/core/felt"
+	"github.com/NethermindEth/juno/core/trie2"
+	"github.com/NethermindEth/juno/db"
+	"golang.org/x/exp/maps"
+)
+
+// contract storage has fixed height at 251
+const (
+	ContractStorageTrieHeight = 251
+	contractDataSize          = 2*felt.Bytes + 8
+)
+
+var (
+	ErrContractNotDeployed     = errors.New("contract not deployed")
+	ErrContractAlreadyDeployed = errors.New("contract already deployed")
+)
+
+type Storage map[felt.Felt]*felt.Felt
+
+type StateContract struct {
+	// Hash of the contract's class
+	ClassHash *felt.Felt
+	// Contract's nonce
+	Nonce *felt.Felt
+	// Root hash of the contract's storage
+	StorageRoot *felt.Felt
+	// Height at which the contract is deployed
+	DeployHeight uint64
+	// Address that this contract instance is deployed to
+	Address *felt.Felt
+	// Storage locations that have been updated
+	dirtyStorage Storage
+	// The underlying storage trie
+	tr *trie2.Trie
+}
+
+func NewStateContract(
+	addr *felt.Felt,
+	classHash *felt.Felt,
+	nonce *felt.Felt,
+	deployHeight uint64,
+) *StateContract {
+	contract := &StateContract{
+		Address:      addr,
+		ClassHash:    classHash,
+		Nonce:        nonce,
+		DeployHeight: deployHeight,
+		dirtyStorage: make(Storage),
+	}
+
+	return contract
+}
+
+func (s *StateContract) GetStorageRoot(txn db.Transaction) (*felt.Felt, error) {
+	if s.StorageRoot != nil {
+		return s.StorageRoot, nil
+	}
+
+	tr, err := s.getTrie(txn)
+	if err != nil {
+		return nil, err
+	}
+
+	root := tr.Hash()
+	s.StorageRoot = &root
+
+	return &root, nil
+}
+
+func (s *StateContract) UpdateStorage(key, value *felt.Felt) {
+	if s.dirtyStorage == nil {
+		s.dirtyStorage = make(Storage)
+	}
+
+	s.dirtyStorage[*key] = value
+}
+
+func (s *StateContract) GetStorage(key *felt.Felt, txn db.Transaction) (*felt.Felt, error) {
+	if s.dirtyStorage != nil {
+		if val, ok := s.dirtyStorage[*key]; ok {
+			return val, nil
+		}
+	}
+
+	var err error
+
+	tr := s.tr
+	if tr == nil {
+		tr, err = s.getTrie(txn)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	val, err := tr.Get(key)
+	if err != nil {
+		return nil, err
+	}
+
+	return &val, nil
+}
+
+// Marshals the contract into a byte slice
+func (s *StateContract) MarshalBinary() ([]byte, error) {
+	buf := make([]byte, contractDataSize)
+
+	copy(buf[0:felt.Bytes], s.ClassHash.Marshal())
+	copy(buf[felt.Bytes:2*felt.Bytes], s.Nonce.Marshal())
+	binary.BigEndian.PutUint64(buf[2*felt.Bytes:contractDataSize], s.DeployHeight)
+
+	return buf, nil
+}
+
+// Unmarshals the contract from a byte slice
+func (s *StateContract) UnmarshalBinary(data []byte) error {
+	if len(data) != contractDataSize {
+		return fmt.Errorf("invalid length for StateContract: got %d, want %d", len(data), contractDataSize)
+	}
+
+	s.ClassHash = new(felt.Felt).SetBytes(data[:felt.Bytes])
+	data = data[felt.Bytes:]
+	s.Nonce = new(felt.Felt).SetBytes(data[:felt.Bytes])
+	data = data[felt.Bytes:]
+	s.DeployHeight = binary.BigEndian.Uint64(data[:8])
+
+	return nil
+}
+
+func (s *StateContract) Commit(txn db.Transaction, storeHistory bool, blockNum uint64) error {
+	var err error
+
+	tr := s.tr
+	if tr == nil {
+		tr, err = s.getTrie(txn)
+		if err != nil {
+			return err
+		}
+	}
+
+	keys := maps.Keys(s.dirtyStorage)
+	slices.SortFunc(keys, func(a, b felt.Felt) int {
+		return a.Cmp(&b)
+	})
+
+	// Commit storage changes to the associated storage trie
+	for _, key := range keys {
+		val := s.dirtyStorage[key]
+		if err := tr.Update(&key, val); err != nil {
+			return err
+		}
+
+		if storeHistory {
+			if err := s.storeStorageHistory(txn, blockNum, &key, val); err != nil {
+				return err
+			}
+		}
+	}
+
+	root, err := tr.Commit()
+	if err != nil {
+		return err
+	}
+	s.StorageRoot = &root
+
+	if storeHistory {
+		if err := s.storeNonceHistory(txn, blockNum); err != nil {
+			return err
+		}
+
+		if err := s.storeClassHashHistory(txn, blockNum); err != nil {
+			return err
+		}
+	}
+
+	return s.flush(txn)
+}
+
+// Calculates and returns the commitment of the contract
+func (s *StateContract) Commitment() *felt.Felt {
+	return crypto.Pedersen(crypto.Pedersen(crypto.Pedersen(s.ClassHash, s.StorageRoot), s.Nonce), &felt.Zero)
+}
+
+func (s *StateContract) storeNonceHistory(txn db.Transaction, blockNum uint64) error {
+	keyBytes := contractHistoryNonceKey(s.Address, blockNum)
+	return txn.Set(keyBytes, s.Nonce.Marshal())
+}
+
+func (s *StateContract) storeClassHashHistory(txn db.Transaction, blockNum uint64) error {
+	keyBytes := contractHistoryClassHashKey(s.Address, blockNum)
+	return txn.Set(keyBytes, s.ClassHash.Marshal())
+}
+
+func (s *StateContract) storeStorageHistory(txn db.Transaction, blockNum uint64, key, value *felt.Felt) error {
+	keyBytes := contractHistoryStorageKey(s.Address, key, blockNum)
+	return txn.Set(keyBytes, value.Marshal())
+}
+
+func (s *StateContract) delete(txn db.Transaction) error {
+	key := contractKey(s.Address)
+	return txn.Delete(key)
+}
+
+// Flush the contract to the database
+func (s *StateContract) flush(txn db.Transaction) error {
+	key := contractKey(s.Address)
+	data, err := s.MarshalBinary()
+	if err != nil {
+		return err
+	}
+
+	return txn.Set(key, data)
+}
+
+func (s *StateContract) getTrie(txn db.Transaction) (*trie2.Trie, error) {
+	if s.tr != nil {
+		return s.tr, nil
+	}
+
+	tr, err := trie2.New(trie2.ContractTrieID(*s.Address), ContractStorageTrieHeight, crypto.Pedersen, txn)
+	if err != nil {
+		return nil, err
+	}
+	s.tr = tr
+
+	return tr, nil
+}
+
+// Wrapper around getContract which checks if a contract is deployed
+func GetContract(addr *felt.Felt, txn db.Transaction) (*StateContract, error) {
+	contract, err := getContract(addr, txn)
+	if err != nil {
+		if errors.Is(err, db.ErrKeyNotFound) {
+			return nil, ErrContractNotDeployed
+		}
+		return nil, err
+	}
+
+	return contract, nil
+}
+
+// Gets a contract instance from the database.
+func getContract(addr *felt.Felt, txn db.Transaction) (*StateContract, error) {
+	key := contractKey(addr)
+	var contract StateContract
+	if err := txn.Get(key, func(val []byte) error {
+		if err := contract.UnmarshalBinary(val); err != nil {
+			return fmt.Errorf("failed to unmarshal contract: %w", err)
+		}
+
+		contract.Address = addr
+		contract.dirtyStorage = make(Storage)
+
+		return nil
+	}); err != nil {
+		return nil, err
+	}
+	return &contract, nil
+}
+
+// Computes the address of a Starknet contract.
+func ContractAddress(callerAddress, classHash, salt *felt.Felt, constructorCallData []*felt.Felt) *felt.Felt {
+	prefix := new(felt.Felt).SetBytes([]byte("STARKNET_CONTRACT_ADDRESS"))
+	callDataHash := crypto.PedersenArray(constructorCallData...)
+
+	// https://docs.starknet.io/architecture-and-concepts/smart-contracts/contract-address/
+	return crypto.PedersenArray(
+		prefix,
+		callerAddress,
+		salt,
+		classHash,
+		callDataHash,
+	)
+}
+
+func contractKey(addr *felt.Felt) []byte {
+	return db.Contract.Key(addr.Marshal())
+}
+
+func contractHistoryNonceKey(addr *felt.Felt, blockNum uint64) []byte {
+	return db.ContractNonceHistory.Key(addr.Marshal(), uint64ToBytes(blockNum))
+}
+
+func contractHistoryClassHashKey(addr *felt.Felt, blockNum uint64) []byte {
+	return db.ContractClassHashHistory.Key(addr.Marshal(), uint64ToBytes(blockNum))
+}
+
+func contractHistoryStorageKey(addr, key *felt.Felt, blockNum uint64) []byte {
+	return db.ContractStorageHistory.Key(addr.Marshal(), key.Marshal(), uint64ToBytes(blockNum))
+}
+
+func uint64ToBytes(num uint64) []byte {
+	const size = 8
+	buf := make([]byte, size)
+	binary.BigEndian.PutUint64(buf, num)
+	return buf
+}
diff --git a/core/state/contract_test.go b/core/state/contract_test.go
new file mode 100644
index 0000000000..d118b2a1ce
--- /dev/null
+++ b/core/state/contract_test.go
@@ -0,0 +1,207 @@
+package state
+
+import (
+	"testing"
+
+	"github.com/NethermindEth/juno/core/felt"
+	"github.com/NethermindEth/juno/db/pebble"
+	"github.com/NethermindEth/juno/utils"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestMarshalBinary(t *testing.T) {
+	classHash := new(felt.Felt).SetBytes([]byte("class_hash"))
+	nonce := new(felt.Felt).SetBytes([]byte("nonce"))
+	deployHeight := uint64(123)
+	storageRoot := new(felt.Felt).SetBytes([]byte("storage_root"))
+
+	contract := &StateContract{
+		ClassHash:    classHash,
+		Nonce:        nonce,
+		DeployHeight: deployHeight,
+		StorageRoot:  storageRoot,
+	}
+
+	data, err := contract.MarshalBinary()
+	require.NoError(t, err)
+
+	var unmarshalled StateContract
+	require.NoError(t, unmarshalled.UnmarshalBinary(data))
+
+	assert.Equal(t, contract.ClassHash, unmarshalled.ClassHash)
+	assert.Equal(t, contract.Nonce, unmarshalled.Nonce)
+	assert.Equal(t, contract.DeployHeight, unmarshalled.DeployHeight)
+	assert.Nil(t, unmarshalled.StorageRoot)
+}
+
+func TestContractAddress(t *testing.T) {
+	tests := []struct {
+		callerAddress       *felt.Felt
+		classHash           *felt.Felt
+		salt                *felt.Felt
+		constructorCallData []*felt.Felt
+		want                *felt.Felt
+	}{
+		{
+			// https://alpha-mainnet.starknet.io/feeder_gateway/get_transaction?transactionHash=0x6486c6303dba2f364c684a2e9609211c5b8e417e767f37b527cda51e776e6f0
+			callerAddress: utils.HexToFelt(t, "0x0000000000000000000000000000000000000000"),
+			classHash: utils.HexToFelt(
+				t, "0x46f844ea1a3b3668f81d38b5c1bd55e816e0373802aefe732138628f0133486"),
+			salt: utils.HexToFelt(
+				t, "0x74dc2fe193daf1abd8241b63329c1123214842b96ad7fd003d25512598a956b"),
+			constructorCallData: []*felt.Felt{
+				utils.HexToFelt(t, "0x6d706cfbac9b8262d601c38251c5fbe0497c3a96cc91a92b08d91b61d9e70c4"),
+				utils.HexToFelt(t, "0x79dc0da7c54b95f10aa182ad0a46400db63156920adb65eca2654c0945a463"),
+				utils.HexToFelt(t, "0x2"),
+				utils.HexToFelt(t, "0x6658165b4984816ab189568637bedec5aa0a18305909c7f5726e4a16e3afef6"),
+				utils.HexToFelt(t, "0x6b648b36b074a91eee55730f5f5e075ec19c0a8f9ffb0903cefeee93b6ff328"),
+			},
+			want: utils.HexToFelt(t, "0x3ec215c6c9028ff671b46a2a9814970ea23ed3c4bcc3838c6d1dcbf395263c3"),
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run("Address", func(t *testing.T) {
+			address := ContractAddress(tt.callerAddress, tt.classHash, tt.salt, tt.constructorCallData)
+			if !address.Equal(tt.want) {
+				t.Errorf("wrong address: got %s, want %s", address.String(), tt.want.String())
+			}
+		})
+	}
+}
+
+func TestNewContract(t *testing.T) {
+	testDB := pebble.NewMemTest(t)
+
+	txn, err := testDB.NewTransaction(true)
+	require.NoError(t, err)
+	t.Cleanup(func() {
+		require.NoError(t, txn.Discard())
+	})
+
+	blockNumber := uint64(10)
+	addr := new(felt.Felt).SetUint64(234)
+	classHash := new(felt.Felt).SetBytes([]byte("class hash"))
+
+	// Test initial state (contract not deployed)
+	_, err = GetContract(addr, txn)
+	require.ErrorIs(t, err, ErrContractNotDeployed)
+
+	// Create and commit contract
+	contract := NewStateContract(addr, classHash, &felt.Zero, blockNumber)
+	require.NoError(t, contract.Commit(txn, true, blockNumber))
+
+	// Retrieve and verify committed contract
+	storedContract, err := GetContract(addr, txn)
+	require.NoError(t, err)
+
+	assert.Equal(t, addr, storedContract.Address)
+	assert.Equal(t, classHash, storedContract.ClassHash)
+	assert.Equal(t, &felt.Zero, storedContract.Nonce)
+	assert.Equal(t, blockNumber, storedContract.DeployHeight)
+}
+
+func TestContractUpdate(t *testing.T) {
+	testDB := pebble.NewMemTest(t)
+
+	txn, err := testDB.NewTransaction(true)
+	require.NoError(t, err)
+	t.Cleanup(func() {
+		require.NoError(t, txn.Discard())
+	})
+
+	blockNumber := uint64(10)
+	addr := new(felt.Felt).SetUint64(44)
+	classHash := new(felt.Felt).SetUint64(37)
+
+	// Initial contract setup
+	contract := NewStateContract(addr, classHash, &felt.Zero, blockNumber)
+	require.NoError(t, contract.Commit(txn, true, blockNumber))
+
+	// Verify initial state
+	contract, err = GetContract(addr, txn)
+	require.NoError(t, err)
+	require.Equal(t, &felt.Zero, contract.Nonce)
+	require.Equal(t, classHash, contract.ClassHash)
+
+	// Test nonce update
+	newNonce := new(felt.Felt).SetUint64(1)
+	contract.Nonce = newNonce
+	require.NoError(t, contract.Commit(txn, true, blockNumber))
+
+	contract, err = GetContract(addr, txn)
+	require.NoError(t, err)
+	require.Equal(t, newNonce, contract.Nonce)
+
+	// Test class hash update
+	newHash := new(felt.Felt).SetUint64(1)
+	contract.ClassHash = newHash
+	require.NoError(t, contract.Commit(txn, true, blockNumber))
+
+	contract, err = GetContract(addr, txn)
+	require.NoError(t, err)
+	require.Equal(t, newHash, contract.ClassHash)
+}
+
+func TestContractStorage(t *testing.T) {
+	testDB := pebble.NewMemTest(t)
+
+	txn, err := testDB.NewTransaction(true)
+	require.NoError(t, err)
+	t.Cleanup(func() {
+		require.NoError(t, txn.Discard())
+	})
+
+	blockNumber := uint64(10)
+	addr := new(felt.Felt).SetUint64(44)
+	classHash := new(felt.Felt).SetUint64(37)
+
+	contract := NewStateContract(addr, classHash, &felt.Zero, blockNumber)
+	require.NoError(t, contract.Commit(txn, true, blockNumber))
+
+	// Initial storage check
+	contract, err = GetContract(addr, txn)
+	require.NoError(t, err)
+
+	gotValue, err := contract.GetStorage(addr, txn)
+	require.NoError(t, err)
+	assert.Equal(t, &felt.Zero, gotValue)
+
+	// Storage update verification
+	oldRoot, err := contract.GetStorageRoot(txn)
+	require.NoError(t, err)
+
+	newVal := new(felt.Felt).SetUint64(1)
+	contract.UpdateStorage(addr, newVal)
+	require.NoError(t, contract.Commit(txn, false, blockNumber))
+
+	contract, err = GetContract(addr, txn)
+	require.NoError(t, err)
+
+	gotValue, err = contract.GetStorage(addr, txn)
+	require.NoError(t, err)
+	assert.Equal(t, newVal, gotValue)
+
+	newRoot, err := contract.GetStorageRoot(txn)
+	require.NoError(t, err)
+	assert.NotEqual(t, oldRoot, newRoot)
+}
+
+func TestContractDelete(t *testing.T) {
+	testDB := pebble.NewMemTest(t)
+
+	txn, err := testDB.NewTransaction(true)
+	require.NoError(t, err)
+
+	blockNumber := uint64(10)
+	addr := new(felt.Felt).SetUint64(44)
+	classHash := new(felt.Felt).SetUint64(37)
+
+	contract := NewStateContract(addr, classHash, &felt.Zero, blockNumber)
+	require.NoError(t, contract.Commit(txn, false, blockNumber))
+
+	require.NoError(t, contract.delete(txn))
+	_, err = GetContract(addr, txn)
+	assert.ErrorIs(t, err, ErrContractNotDeployed)
+}
diff --git a/db/buckets.go b/db/buckets.go
index 4833c2d03d..0b58c12d72 100644
--- a/db/buckets.go
+++ b/db/buckets.go
@@ -23,9 +23,9 @@ const (
 	ReceiptsByBlockNumberAndIndex           // maps block number and index to transaction receipt
 	StateUpdatesByBlockNumber
 	ClassesTrie
-	ContractStorageHistory
-	ContractNonceHistory
-	ContractClassHashHistory
+	ContractStorageHistory   // [ContractStorageHistory] + ContractAddr + StorageLocation + BlockHeight -> StorageValue
+	ContractNonceHistory     // [ContractNonceHistory] + ContractAddr + BlockHeight -> ContractNonce
+	ContractClassHashHistory // [ContractClassHashHistory] + ContractAddr + BlockHeight -> ContractClassHash
 	ContractDeploymentHeight
 	L1Height
 	SchemaVersion

From 79c75faa2b50a4502f3dc1bc1d0910b876daa1a9 Mon Sep 17 00:00:00 2001
From: weiihann <weihan774237@gmail.com>
Date: Mon, 17 Feb 2025 18:41:35 +0800
Subject: [PATCH 04/15] Reimplement State

state methods don't use pointer
---
 core/state/state.go      | 609 ++++++++++++++++++++++++++++
 core/state/state_test.go | 844 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 1453 insertions(+)
 create mode 100644 core/state/state.go
 create mode 100644 core/state/state_test.go

diff --git a/core/state/state.go b/core/state/state.go
new file mode 100644
index 0000000000..a11623276f
--- /dev/null
+++ b/core/state/state.go
@@ -0,0 +1,609 @@
+package state
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"maps"
+	"slices"
+
+	"github.com/NethermindEth/juno/core"
+	"github.com/NethermindEth/juno/core/crypto"
+	"github.com/NethermindEth/juno/core/felt"
+	"github.com/NethermindEth/juno/core/trie2"
+	"github.com/NethermindEth/juno/db"
+	"github.com/NethermindEth/juno/encoder"
+)
+
+const (
+	ClassTrieHeight    = 251
+	ContractTrieHeight = 251
+)
+
+var (
+	stateVersion0             = new(felt.Felt).SetBytes([]byte(`STARKNET_STATE_V0`))
+	leafVersion0              = new(felt.Felt).SetBytes([]byte(`CONTRACT_CLASS_LEAF_V0`))
+	noClassContractsClassHash = new(felt.Felt).SetUint64(0)
+	noClassContracts          = map[felt.Felt]struct{}{
+		*new(felt.Felt).SetUint64(1): {},
+	}
+
+	ErrNoHistoryValue = errors.New("no history value found")
+)
+
+type State struct {
+	txn db.Transaction
+
+	contractTrie *trie2.Trie
+	classTrie    *trie2.Trie
+
+	// holds the contract objects which are being updated in the current state update.
+	dirtyContracts map[felt.Felt]*StateContract
+}
+
+func New(txn db.Transaction) (*State, error) {
+	contractTrie, err := trie2.New(trie2.ContractTrieID(felt.Zero), ContractTrieHeight, crypto.Pedersen, txn)
+	if err != nil {
+		return nil, err
+	}
+
+	classTrie, err := trie2.New(trie2.ClassTrieID(), ClassTrieHeight, crypto.Poseidon, txn)
+	if err != nil {
+		return nil, err
+	}
+
+	return &State{
+		txn:            txn,
+		contractTrie:   contractTrie,
+		classTrie:      classTrie,
+		dirtyContracts: make(map[felt.Felt]*StateContract),
+	}, nil
+}
+
+// Returns the class hash of a contract.
+func (s *State) ContractClassHash(addr felt.Felt) (*felt.Felt, error) {
+	contract, err := s.getContract(addr)
+	if err != nil {
+		return nil, err
+	}
+
+	return contract.ClassHash, nil
+}
+
+// Returns the nonce of a contract.
+func (s *State) ContractNonce(addr felt.Felt) (*felt.Felt, error) {
+	contract, err := s.getContract(addr)
+	if err != nil {
+		return nil, err
+	}
+
+	return contract.Nonce, nil
+}
+
+// Returns the storage value of a contract at a given storage key.
+func (s *State) ContractStorage(addr, key felt.Felt) (*felt.Felt, error) {
+	contract, err := s.getContract(addr)
+	if err != nil {
+		return nil, err
+	}
+
+	return contract.GetStorage(&key, s.txn)
+}
+
+// Returns true if the contract was deployed at or before the given block number.
+func (s *State) ContractDeployedAt(addr felt.Felt, blockNum uint64) (bool, error) {
+	contract, err := s.getContract(addr)
+	if err != nil {
+		if errors.Is(err, ErrContractNotDeployed) {
+			return false, nil
+		}
+		return false, err
+	}
+
+	return contract.DeployHeight <= blockNum, nil
+}
+
+func (s *State) Class(classHash felt.Felt) (*DeclaredClass, error) {
+	classKey := classKey(&classHash)
+
+	var class DeclaredClass
+	err := s.txn.Get(classKey, class.UnmarshalBinary)
+	if err != nil {
+		return nil, err
+	}
+
+	return &class, nil
+}
+
+// Applies a state update to a given state. If any error is encountered, state is not updated.
+// After a state update is applied, the root of the state must match the given new root in the state update.
+func (s *State) Update(blockNum uint64, update *core.StateUpdate, declaredClasses map[felt.Felt]core.Class) error {
+	if err := s.verifyRoot(update.OldRoot); err != nil {
+		return err
+	}
+
+	// TODO(weiihann): try sorting the declaredClass by hashes in descending order
+	// Register the declared classes
+	for hash, class := range declaredClasses {
+		if err := s.putClass(&hash, class, blockNum); err != nil {
+			return err
+		}
+	}
+
+	if err := s.updateClassTrie(update.StateDiff.DeclaredV1Classes, declaredClasses); err != nil {
+		return err
+	}
+
+	// Register deployed contracts
+	for addr, classHash := range update.StateDiff.DeployedContracts {
+		_, err := GetContract(&addr, s.txn)
+		if err == nil {
+			return ErrContractAlreadyDeployed
+		}
+
+		if !errors.Is(err, ErrContractNotDeployed) {
+			return err
+		}
+
+		s.dirtyContracts[addr] = NewStateContract(&addr, classHash, &felt.Zero, blockNum)
+	}
+
+	if err := s.updateContracts(blockNum, update.StateDiff); err != nil {
+		return err
+	}
+
+	newRoot, err := s.Commit(true, blockNum)
+	if err != nil {
+		return err
+	}
+
+	if !newRoot.Equal(update.NewRoot) {
+		return fmt.Errorf("root mismatch: %s (expected) != %s (current)", update.NewRoot.String(), newRoot.String())
+	}
+
+	return nil
+}
+
+func (s *State) Revert(blockNum uint64, update *core.StateUpdate) error {
+	// Ensure the current root is the same as the new root
+	if err := s.verifyRoot(update.NewRoot); err != nil {
+		return err
+	}
+
+	if err := s.removeDeclaredClasses(blockNum, update.StateDiff.DeclaredV0Classes, update.StateDiff.DeclaredV1Classes); err != nil {
+		return fmt.Errorf("remove declared classes: %v", err)
+	}
+
+	reverseDiff, err := s.GetReverseStateDiff(blockNum, update.StateDiff)
+	if err != nil {
+		return fmt.Errorf("get reverse state diff: %v", err)
+	}
+
+	if err := s.deleteHistory(blockNum, reverseDiff); err != nil {
+		return fmt.Errorf("delete history: %v", err)
+	}
+
+	if err := s.updateContracts(blockNum, reverseDiff); err != nil {
+		return fmt.Errorf("update contracts: %v", err)
+	}
+
+	for addr := range update.StateDiff.DeployedContracts {
+		s.dirtyContracts[addr] = nil // mark as deleted
+	}
+
+	revertRoot, err := s.Commit(false, blockNum)
+	if err != nil {
+		return fmt.Errorf("commit: %v", err)
+	}
+
+	// Ensure the reverted root is the same as the old root
+	if !revertRoot.Equal(update.OldRoot) {
+		return fmt.Errorf("root mismatch: %s (expected) != %s (current)", update.OldRoot.String(), revertRoot.String())
+	}
+
+	return nil
+}
+
+func (s *State) Commit(storeHistory bool, blockNum uint64) (*felt.Felt, error) {
+	keys := slices.SortedStableFunc(maps.Keys(s.dirtyContracts), func(a, b felt.Felt) int {
+		return a.Cmp(&b) // ascending
+	})
+	for _, addr := range keys {
+		contract := s.dirtyContracts[addr]
+
+		// Contract is marked as deleted
+		if contract == nil {
+			if err := s.contractTrie.Update(&addr, &felt.Zero); err != nil {
+				return nil, err
+			}
+
+			if err := s.txn.Delete(contractKey(&addr)); err != nil {
+				return nil, err
+			}
+
+			continue
+		}
+
+		// Otherwise, commit the contract changes and update the contract trie
+		err := contract.Commit(s.txn, storeHistory, blockNum)
+		if err != nil {
+			return nil, err
+		}
+
+		ctComm := contract.Commitment()
+		if err := s.contractTrie.Update(contract.Address, ctComm); err != nil {
+			return nil, err
+		}
+
+		// As noClassContracts are not in StateDiff.DeployedContracts we can only purge them if their storage no longer exists.
+		// Updating contracts with reverse diff will eventually lead to the deletion of noClassContract's storage key from db. Thus,
+		// we can use the lack of key's existence as reason for purging noClassContracts.
+		for nAddr := range noClassContracts {
+			if contract.Address.Equal(&nAddr) {
+				root, err := contract.GetStorageRoot(s.txn)
+				if err != nil {
+					return nil, err
+				}
+
+				if root.IsZero() {
+					if err := s.contractTrie.Update(&nAddr, &felt.Zero); err != nil {
+						return nil, err
+					}
+
+					if err := s.txn.Delete(contractKey(&nAddr)); err != nil {
+						return nil, err
+					}
+				}
+			}
+		}
+	}
+
+	classRoot, err := s.classTrie.Commit()
+	if err != nil {
+		return nil, err
+	}
+
+	contractRoot, err := s.contractTrie.Commit()
+	if err != nil {
+		return nil, err
+	}
+	return stateCommitment(&contractRoot, &classRoot), nil
+}
+
+// Retrieves the root hash of the state.
+func (s *State) Root() (*felt.Felt, error) {
+	contractRoot := s.contractTrie.Hash()
+	classRoot := s.classTrie.Hash()
+	return stateCommitment(&contractRoot, &classRoot), nil
+}
+
+func (s *State) GetReverseStateDiff(blockNum uint64, diff *core.StateDiff) (*core.StateDiff, error) {
+	reverse := &core.StateDiff{
+		StorageDiffs:    make(map[felt.Felt]map[felt.Felt]*felt.Felt, len(diff.StorageDiffs)),
+		Nonces:          make(map[felt.Felt]*felt.Felt, len(diff.Nonces)),
+		ReplacedClasses: make(map[felt.Felt]*felt.Felt, len(diff.ReplacedClasses)),
+	}
+
+	for addr, stDiffs := range diff.StorageDiffs {
+		reverse.StorageDiffs[addr] = make(map[felt.Felt]*felt.Felt, len(stDiffs))
+		for key := range stDiffs {
+			value := &felt.Zero
+			if blockNum > 0 {
+				oldValue, err := s.ContractStorageAt(addr, key, blockNum-1)
+				if err != nil {
+					return nil, err
+				}
+				value = oldValue
+			}
+			reverse.StorageDiffs[addr][key] = value
+		}
+	}
+
+	for addr := range diff.Nonces {
+		oldNonce := &felt.Zero
+		if blockNum > 0 {
+			var err error
+			oldNonce, err = s.ContractNonceAt(addr, blockNum-1)
+			if err != nil {
+				return nil, err
+			}
+		}
+		reverse.Nonces[addr] = oldNonce
+	}
+
+	for addr := range diff.ReplacedClasses {
+		oldCh := &felt.Zero
+		if blockNum > 0 {
+			var err error
+			oldCh, err = s.ContractClassHashAt(addr, blockNum-1)
+			if err != nil {
+				return nil, err
+			}
+		}
+		reverse.ReplacedClasses[addr] = oldCh
+	}
+
+	return reverse, nil
+}
+
+// Returns the storage value of a contract at a given storage key at a given block number.
+func (s *State) ContractStorageAt(addr, key felt.Felt, blockNum uint64) (*felt.Felt, error) {
+	prefix := db.ContractStorageHistory.Key(addr.Marshal(), key.Marshal())
+	return s.getHistoricalValue(prefix, blockNum)
+}
+
+// Returns the nonce of a contract at a given block number.
+func (s *State) ContractNonceAt(addr felt.Felt, blockNum uint64) (*felt.Felt, error) {
+	prefix := db.ContractNonceHistory.Key(addr.Marshal())
+	return s.getHistoricalValue(prefix, blockNum)
+}
+
+// Returns the class hash of a contract at a given block number.
+func (s *State) ContractClassHashAt(addr felt.Felt, blockNum uint64) (*felt.Felt, error) {
+	prefix := db.ContractClassHashHistory.Key(addr.Marshal())
+	return s.getHistoricalValue(prefix, blockNum)
+}
+
+func (s *State) deleteHistory(blockNum uint64, diff *core.StateDiff) error {
+	for addr := range diff.StorageDiffs {
+		for key := range diff.StorageDiffs[addr] {
+			if err := s.txn.Delete(contractHistoryStorageKey(&addr, &key, blockNum)); err != nil {
+				return err
+			}
+		}
+	}
+
+	for addr := range diff.Nonces {
+		if err := s.txn.Delete(contractHistoryNonceKey(&addr, blockNum)); err != nil {
+			return err
+		}
+	}
+
+	for addr := range diff.ReplacedClasses {
+		if err := s.txn.Delete(contractHistoryClassHashKey(&addr, blockNum)); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (s *State) getHistoricalValue(prefix []byte, blockNum uint64) (*felt.Felt, error) {
+	val, err := s.valueAt(prefix, blockNum)
+	if err != nil {
+		if errors.Is(err, ErrNoHistoryValue) {
+			return &felt.Zero, nil
+		}
+		return nil, err
+	}
+	return new(felt.Felt).SetBytes(val), nil
+}
+
+func (s *State) valueAt(prefix []byte, blockNum uint64) ([]byte, error) {
+	it, err := s.txn.NewIterator(prefix, true)
+	if err != nil {
+		return nil, err
+	}
+	defer it.Close()
+
+	seekKey := binary.BigEndian.AppendUint64(prefix, blockNum)
+	if !it.Seek(seekKey) {
+		return nil, ErrNoHistoryValue
+	}
+
+	key := it.Key()
+	keyBlockNum := binary.BigEndian.Uint64(key[len(prefix):])
+	if keyBlockNum == blockNum {
+		// Found the value
+		return it.Value()
+	}
+
+	// Otherwise, we move the iterator backwards
+	if !it.Prev() {
+		// Moving iterator backwards is invalid, this means we were already at the first key
+		// No values will be found beyond the first key
+		return nil, ErrNoHistoryValue
+	}
+
+	// At this point we already know that the block number is less than the target block number
+	// So we just return the old value
+	return it.Value()
+}
+
+// Retrieves a given contract from the state.
+func (s *State) getContract(addr felt.Felt) (*StateContract, error) {
+	contract, ok := s.dirtyContracts[addr]
+	if ok {
+		return contract, nil
+	}
+
+	contract, err := GetContract(&addr, s.txn)
+	if err != nil {
+		return nil, err
+	}
+
+	s.dirtyContracts[addr] = contract
+	return contract, nil
+}
+
+type DeclaredClass struct {
+	At    uint64 // block number at which the class was declared
+	Class core.Class
+}
+
+func (d *DeclaredClass) MarshalBinary() ([]byte, error) {
+	classEnc, err := encoder.Marshal(d.Class)
+	if err != nil {
+		return nil, err
+	}
+
+	size := 8 + len(classEnc)
+	buf := make([]byte, size)
+	binary.BigEndian.PutUint64(buf[:8], d.At)
+	copy(buf[8:], classEnc)
+
+	return buf, nil
+}
+
+func (d *DeclaredClass) UnmarshalBinary(data []byte) error {
+	if len(data) < 8 { //nolint:mnd
+		return errors.New("data too short to unmarshal DeclaredClass")
+	}
+
+	d.At = binary.BigEndian.Uint64(data[:8])
+	return encoder.Unmarshal(data[8:], &d.Class)
+}
+
+func (s *State) putClass(classHash *felt.Felt, class core.Class, declaredAt uint64) error {
+	classKey := classKey(classHash)
+
+	err := s.txn.Get(classKey, func(val []byte) error { return nil }) // check if class already exists
+	if errors.Is(err, db.ErrKeyNotFound) {
+		dc := DeclaredClass{
+			At:    declaredAt,
+			Class: class,
+		}
+
+		encoded, err := dc.MarshalBinary()
+		if err != nil {
+			return err
+		}
+
+		return s.txn.Set(classKey, encoded)
+	}
+	return err
+}
+
+func (s *State) updateClassTrie(declaredClasses map[felt.Felt]*felt.Felt, classDefs map[felt.Felt]core.Class) error {
+	for classHash, compiledClassHash := range declaredClasses {
+		if _, found := classDefs[classHash]; !found {
+			continue
+		}
+
+		leafVal := crypto.Poseidon(leafVersion0, compiledClassHash)
+		if err := s.classTrie.Update(&classHash, leafVal); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (s *State) updateContracts(blockNum uint64, diff *core.StateDiff) error {
+	if err := s.updateContractClasses(diff.ReplacedClasses); err != nil {
+		return err
+	}
+
+	if err := s.updateContractNonces(diff.Nonces); err != nil {
+		return err
+	}
+
+	if err := s.updateContractStorages(blockNum, diff.StorageDiffs); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (s *State) updateContractClasses(classes map[felt.Felt]*felt.Felt) error {
+	for addr, classHash := range classes {
+		contract, err := s.getContract(addr)
+		if err != nil {
+			return err
+		}
+
+		contract.ClassHash = classHash
+	}
+
+	return nil
+}
+
+func (s *State) updateContractNonces(nonces map[felt.Felt]*felt.Felt) error {
+	for addr, nonce := range nonces {
+		contract, err := s.getContract(addr)
+		if err != nil {
+			return err
+		}
+
+		contract.Nonce = nonce
+	}
+
+	return nil
+}
+
+func (s *State) updateContractStorages(blockNum uint64, storageDiffs map[felt.Felt]map[felt.Felt]*felt.Felt) error {
+	for addr, diff := range storageDiffs {
+		contract, err := s.getContract(addr)
+		if err != nil {
+			if _, ok := noClassContracts[addr]; ok && errors.Is(err, ErrContractNotDeployed) {
+				contract = NewStateContract(&addr, noClassContractsClassHash, &felt.Zero, blockNum)
+				s.dirtyContracts[addr] = contract
+			} else {
+				return err
+			}
+		}
+
+		contract.dirtyStorage = diff
+	}
+	return nil
+}
+
+func (s *State) verifyRoot(root *felt.Felt) error {
+	curRoot, err := s.Root()
+	if err != nil {
+		return err
+	}
+
+	if !root.Equal(curRoot) {
+		return fmt.Errorf("root mismatch: %s (expected) != %s (current)", root.String(), curRoot.String())
+	}
+
+	return nil
+}
+
+func (s *State) removeDeclaredClasses(blockNum uint64, v0Classes []*felt.Felt, v1Classes map[felt.Felt]*felt.Felt) error {
+	// Gather the class hashes
+	totalCapacity := len(v0Classes) + len(v1Classes)
+	classHashes := make([]*felt.Felt, 0, totalCapacity)
+	classHashes = append(classHashes, v0Classes...)
+	for classHash := range v1Classes {
+		classHashes = append(classHashes, classHash.Clone())
+	}
+
+	for _, cHash := range classHashes {
+		declaredClass, err := s.Class(*cHash)
+		if err != nil {
+			return err
+		}
+
+		// We only want to remove classes that were declared at the given block number
+		if declaredClass.At != blockNum {
+			continue
+		}
+
+		if err := s.txn.Delete(classKey(cHash)); err != nil {
+			return err
+		}
+
+		// For cairo1 classes, we update the class trie
+		if declaredClass.Class.Version() == 1 {
+			if err := s.classTrie.Update(cHash, &felt.Zero); err != nil {
+				return err
+			}
+		}
+	}
+
+	return nil
+}
+
+// Calculate the commitment of the state
+func stateCommitment(contractRoot, classRoot *felt.Felt) *felt.Felt {
+	if classRoot.IsZero() {
+		return contractRoot
+	}
+
+	return crypto.PoseidonArray(stateVersion0, contractRoot, classRoot)
+}
+
+func classKey(classHash *felt.Felt) []byte {
+	return db.Class.Key(classHash.Marshal())
+}
diff --git a/core/state/state_test.go b/core/state/state_test.go
new file mode 100644
index 0000000000..f9f3059b5b
--- /dev/null
+++ b/core/state/state_test.go
@@ -0,0 +1,844 @@
+package state
+
+import (
+	"context"
+	"encoding/json"
+	"testing"
+
+	"github.com/NethermindEth/juno/clients/feeder"
+	"github.com/NethermindEth/juno/core"
+	"github.com/NethermindEth/juno/core/felt"
+	"github.com/NethermindEth/juno/db"
+	"github.com/NethermindEth/juno/db/pebble"
+	_ "github.com/NethermindEth/juno/encoder/registry"
+	adaptfeeder "github.com/NethermindEth/juno/starknetdata/feeder"
+	"github.com/NethermindEth/juno/utils"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+// Address of first deployed contract in mainnet block 1's state update.
+var (
+	_su1FirstDeployedAddress, _ = new(felt.Felt).SetString("0x6538fdd3aa353af8a87f5fe77d1f533ea82815076e30a86d65b72d3eb4f0b80")
+	su1FirstDeployedAddress     = *_su1FirstDeployedAddress
+	su3DeclaredClasses          = func() map[felt.Felt]core.Class {
+		classHash, _ := new(felt.Felt).SetString("0xDEADBEEF")
+		return map[felt.Felt]core.Class{
+			*classHash: &core.Cairo1Class{},
+		}
+	}
+)
+
+const (
+	block0 = 0
+	block1 = 1
+	block2 = 2
+	block3 = 3
+	block5 = 5
+)
+
+func TestUpdate(t *testing.T) {
+	// These value were taken from part of integration state update number 299762
+	// https://external.integration.starknet.io/feeder_gateway/get_state_update?blockNumber=299762
+	scKey := utils.HexToFelt(t, "0x492e8")
+	scValue := utils.HexToFelt(t, "0x10979c6b0b36b03be36739a21cc43a51076545ce6d3397f1b45c7e286474ad5")
+	scAddr := new(felt.Felt).SetUint64(1)
+
+	stateUpdates := getStateUpdates(t)
+
+	su3 := &core.StateUpdate{
+		OldRoot: stateUpdates[2].NewRoot,
+		NewRoot: utils.HexToFelt(t, "0x46f1033cfb8e0b2e16e1ad6f95c41fd3a123f168fe72665452b6cddbc1d8e7a"),
+		StateDiff: &core.StateDiff{
+			DeclaredV1Classes: map[felt.Felt]*felt.Felt{
+				*utils.HexToFelt(t, "0xDEADBEEF"): utils.HexToFelt(t, "0xBEEFDEAD"),
+			},
+		},
+	}
+
+	su4 := &core.StateUpdate{
+		OldRoot: su3.NewRoot,
+		NewRoot: utils.HexToFelt(t, "0x68ac0196d9b6276b8d86f9e92bca0ed9f854d06ded5b7f0b8bc0eeaa4377d9e"),
+		StateDiff: &core.StateDiff{
+			StorageDiffs: map[felt.Felt]map[felt.Felt]*felt.Felt{*scAddr: {*scKey: scValue}},
+		},
+	}
+
+	stateUpdates = append(stateUpdates, su3, su4)
+
+	t.Run("block 0 to block 3 state updates", func(t *testing.T) {
+		_, commit := setupState(t, stateUpdates, 3)
+		defer commit()
+	})
+
+	t.Run("error when state current root doesn't match state update's old root", func(t *testing.T) {
+		oldRoot := new(felt.Felt).SetBytes([]byte("some old root"))
+		su := &core.StateUpdate{
+			OldRoot: oldRoot,
+		}
+		txn, commit := setupState(t, stateUpdates, 0)
+		defer commit()
+		state, err := New(txn)
+		require.NoError(t, err)
+		require.Error(t, state.Update(block0, su, nil))
+	})
+
+	t.Run("error when state new root doesn't match state update's new root", func(t *testing.T) {
+		newRoot := new(felt.Felt).SetBytes([]byte("some new root"))
+		su := &core.StateUpdate{
+			NewRoot:   newRoot,
+			OldRoot:   stateUpdates[0].NewRoot,
+			StateDiff: new(core.StateDiff),
+		}
+		txn, commit := setupState(t, stateUpdates, 0)
+		defer commit()
+		state, err := New(txn)
+		require.NoError(t, err)
+		require.Error(t, state.Update(block0, su, nil))
+	})
+
+	t.Run("post v0.11.0 declared classes affect root", func(t *testing.T) {
+		t.Run("without class definition", func(t *testing.T) {
+			txn, commit := setupState(t, stateUpdates, 3)
+			defer commit()
+			state, err := New(txn)
+			require.NoError(t, err)
+			require.Error(t, state.Update(block3, su3, nil))
+		})
+		t.Run("with class definition", func(t *testing.T) {
+			txn, commit := setupState(t, stateUpdates, 3)
+			defer commit()
+			state, err := New(txn)
+			require.NoError(t, err)
+			require.NoError(t, state.Update(block3, su3, su3DeclaredClasses()))
+		})
+	})
+
+	t.Run("update noClassContracts storage", func(t *testing.T) {
+		txn, commit := setupState(t, stateUpdates, 5)
+		defer commit()
+		state, err := New(txn)
+		require.NoError(t, err)
+
+		gotValue, err := state.ContractStorage(*scAddr, *scKey)
+		require.NoError(t, err)
+
+		assert.Equal(t, scValue, gotValue)
+
+		gotNonce, err := state.ContractNonce(*scAddr)
+		require.NoError(t, err)
+
+		assert.Equal(t, &felt.Zero, gotNonce)
+
+		gotClassHash, err := state.ContractClassHash(*scAddr)
+		require.NoError(t, err)
+
+		assert.Equal(t, &felt.Zero, gotClassHash)
+	})
+
+	t.Run("cannot update unknown noClassContract", func(t *testing.T) {
+		scAddr2 := utils.HexToFelt(t, "0x10")
+		su5 := &core.StateUpdate{
+			OldRoot: su4.NewRoot,
+			NewRoot: utils.HexToFelt(t, "0x68ac0196d9b6276b8d86f9e92bca0ed9f854d06ded5b7f0b8bc0eeaa4377d9e"),
+			StateDiff: &core.StateDiff{
+				StorageDiffs: map[felt.Felt]map[felt.Felt]*felt.Felt{*scAddr2: {*scKey: scValue}},
+			},
+		}
+		txn, commit := setupState(t, stateUpdates, 5)
+		defer commit()
+		state, err := New(txn)
+		require.NoError(t, err)
+		require.ErrorIs(t, state.Update(block5, su5, nil), ErrContractNotDeployed)
+	})
+}
+
+func TestContractClassHash(t *testing.T) {
+	stateUpdates := getStateUpdates(t)
+	stateUpdates = stateUpdates[:2]
+
+	su0 := stateUpdates[0]
+	su1 := stateUpdates[1]
+
+	txn, commit := setupState(t, stateUpdates, 2)
+	defer commit()
+	state, err := New(txn)
+	require.NoError(t, err)
+
+	allDeployedContracts := make(map[felt.Felt]*felt.Felt)
+
+	for addr, classHash := range su0.StateDiff.DeployedContracts {
+		allDeployedContracts[addr] = classHash
+	}
+
+	for addr, classHash := range su1.StateDiff.DeployedContracts {
+		allDeployedContracts[addr] = classHash
+	}
+
+	for addr, expectedClassHash := range allDeployedContracts {
+		gotClassHash, err := state.ContractClassHash(addr)
+		require.NoError(t, err)
+
+		assert.Equal(t, expectedClassHash, gotClassHash)
+	}
+
+	t.Run("replace class hash", func(t *testing.T) {
+		replaceUpdate := &core.StateUpdate{
+			OldRoot:   su1.NewRoot,
+			BlockHash: utils.HexToFelt(t, "0xDEADBEEF"),
+			NewRoot:   utils.HexToFelt(t, "0x484ff378143158f9af55a1210b380853ae155dfdd8cd4c228f9ece918bb982b"),
+			StateDiff: &core.StateDiff{
+				ReplacedClasses: map[felt.Felt]*felt.Felt{
+					su1FirstDeployedAddress: utils.HexToFelt(t, "0x1337"),
+				},
+			},
+		}
+
+		require.NoError(t, state.Update(block2, replaceUpdate, nil))
+
+		var addr felt.Felt
+		addr.Set(&su1FirstDeployedAddress)
+		gotClassHash, err := state.ContractClassHash(addr)
+		require.NoError(t, err)
+
+		assert.Equal(t, utils.HexToFelt(t, "0x1337"), gotClassHash)
+	})
+}
+
+func TestNonce(t *testing.T) {
+	addr := utils.HexToFelt(t, "0x20cfa74ee3564b4cd5435cdace0f9c4d43b939620e4a0bb5076105df0a626c6")
+	root := utils.HexToFelt(t, "0x4bdef7bf8b81a868aeab4b48ef952415fe105ab479e2f7bc671c92173542368")
+
+	su0 := &core.StateUpdate{
+		OldRoot: &felt.Zero,
+		NewRoot: root,
+		StateDiff: &core.StateDiff{
+			DeployedContracts: map[felt.Felt]*felt.Felt{
+				*addr: utils.HexToFelt(t, "0x10455c752b86932ce552f2b0fe81a880746649b9aee7e0d842bf3f52378f9f8"),
+			},
+		},
+	}
+
+	t.Run("newly deployed contract has zero nonce", func(t *testing.T) {
+		txn, _ := setupState(t, nil, 0)
+		state, err := New(txn)
+		require.NoError(t, err)
+
+		require.NoError(t, state.Update(block0, su0, nil))
+
+		nonce, err := state.ContractNonce(*addr)
+		require.NoError(t, err)
+		assert.Equal(t, &felt.Zero, nonce)
+	})
+
+	t.Run("update contract nonce", func(t *testing.T) {
+		txn, commit := setupState(t, nil, 0)
+		defer commit()
+		state0, err := New(txn)
+		require.NoError(t, err)
+
+		require.NoError(t, state0.Update(block0, su0, nil))
+
+		expectedNonce := new(felt.Felt).SetUint64(1)
+		su1 := &core.StateUpdate{
+			NewRoot: utils.HexToFelt(t, "0x6210642ffd49f64617fc9e5c0bbe53a6a92769e2996eb312a42d2bdb7f2afc1"),
+			OldRoot: root,
+			StateDiff: &core.StateDiff{
+				Nonces: map[felt.Felt]*felt.Felt{*addr: expectedNonce},
+			},
+		}
+
+		state1, err := New(txn)
+		require.NoError(t, err)
+
+		require.NoError(t, state1.Update(block1, su1, nil))
+
+		gotNonce, err := state1.ContractNonce(*addr)
+		require.NoError(t, err)
+		assert.Equal(t, expectedNonce, gotNonce)
+	})
+}
+
+func TestClass(t *testing.T) {
+	txn, commit := setupState(t, nil, 0)
+	defer commit()
+
+	client := feeder.NewTestClient(t, &utils.Integration)
+	gw := adaptfeeder.New(client)
+
+	cairo0Hash := utils.HexToFelt(t, "0x4631b6b3fa31e140524b7d21ba784cea223e618bffe60b5bbdca44a8b45be04")
+	cairo0Class, err := gw.Class(context.Background(), cairo0Hash)
+	require.NoError(t, err)
+	cairo1Hash := utils.HexToFelt(t, "0x1cd2edfb485241c4403254d550de0a097fa76743cd30696f714a491a454bad5")
+	cairo1Class, err := gw.Class(context.Background(), cairo0Hash)
+	require.NoError(t, err)
+
+	state, err := New(txn)
+	require.NoError(t, err)
+
+	su0, err := gw.StateUpdate(context.Background(), 0)
+	require.NoError(t, err)
+	require.NoError(t, state.Update(0, su0, map[felt.Felt]core.Class{
+		*cairo0Hash: cairo0Class,
+		*cairo1Hash: cairo1Class,
+	}))
+
+	gotCairo1Class, err := state.Class(*cairo1Hash)
+	require.NoError(t, err)
+	assert.Zero(t, gotCairo1Class.At)
+	assert.Equal(t, cairo1Class, gotCairo1Class.Class)
+	gotCairo0Class, err := state.Class(*cairo0Hash)
+	require.NoError(t, err)
+	assert.Zero(t, gotCairo0Class.At)
+	assert.Equal(t, cairo0Class, gotCairo0Class.Class)
+}
+
+func TestContractDeployedAt(t *testing.T) {
+	stateUpdates := getStateUpdates(t)
+	txn, commit := setupState(t, stateUpdates, 2)
+	defer commit()
+
+	t.Run("deployed on genesis", func(t *testing.T) {
+		state, err := New(txn)
+		require.NoError(t, err)
+
+		d0 := utils.HexToFelt(t, "0x20cfa74ee3564b4cd5435cdace0f9c4d43b939620e4a0bb5076105df0a626c6")
+		deployed, err := state.ContractDeployedAt(*d0, block0)
+		require.NoError(t, err)
+		assert.True(t, deployed)
+
+		deployed, err = state.ContractDeployedAt(*d0, block1)
+		require.NoError(t, err)
+		assert.True(t, deployed)
+	})
+
+	t.Run("deployed after genesis", func(t *testing.T) {
+		state, err := New(txn)
+		require.NoError(t, err)
+
+		d1 := utils.HexToFelt(t, "0x6538fdd3aa353af8a87f5fe77d1f533ea82815076e30a86d65b72d3eb4f0b80")
+		deployed, err := state.ContractDeployedAt(*d1, block0)
+		require.NoError(t, err)
+		assert.False(t, deployed)
+
+		deployed, err = state.ContractDeployedAt(*d1, block1)
+		require.NoError(t, err)
+		assert.True(t, deployed)
+	})
+
+	t.Run("not deployed", func(t *testing.T) {
+		state, err := New(txn)
+		require.NoError(t, err)
+
+		notDeployed := utils.HexToFelt(t, "0xDEADBEEF")
+		deployed, err := state.ContractDeployedAt(*notDeployed, block0)
+		require.NoError(t, err)
+		assert.False(t, deployed)
+	})
+}
+
+func TestRevert(t *testing.T) {
+	stateUpdates := getStateUpdates(t)
+	txn, commit := setupState(t, stateUpdates, 2)
+	defer commit()
+
+	su0 := stateUpdates[0]
+	su1 := stateUpdates[1]
+	su2 := stateUpdates[2]
+
+	t.Run("revert a replaced class", func(t *testing.T) {
+		replacedVal := utils.HexToFelt(t, "0xDEADBEEF")
+		replaceStateUpdate := &core.StateUpdate{
+			NewRoot: utils.HexToFelt(t, "0x30b1741b28893b892ac30350e6372eac3a6f32edee12f9cdca7fbe7540a5ee"),
+			OldRoot: su1.NewRoot,
+			StateDiff: &core.StateDiff{
+				ReplacedClasses: map[felt.Felt]*felt.Felt{
+					su1FirstDeployedAddress: replacedVal,
+				},
+			},
+		}
+
+		state, err := New(txn)
+		require.NoError(t, err)
+
+		require.NoError(t, state.Update(block2, replaceStateUpdate, nil))
+		gotClassHash, err := state.ContractClassHash(su1FirstDeployedAddress)
+		require.NoError(t, err)
+		assert.Equal(t, replacedVal, gotClassHash)
+
+		state, err = New(txn)
+		require.NoError(t, err)
+
+		require.NoError(t, state.Revert(block2, replaceStateUpdate))
+		gotClassHash, err = state.ContractClassHash(su1FirstDeployedAddress)
+		require.NoError(t, err)
+		assert.Equal(t, su1.StateDiff.DeployedContracts[*new(felt.Felt).Set(&su1FirstDeployedAddress)], gotClassHash)
+	})
+
+	t.Run("revert a nonce update", func(t *testing.T) {
+		replacedVal := utils.HexToFelt(t, "0xDEADBEEF")
+		nonceStateUpdate := &core.StateUpdate{
+			NewRoot: utils.HexToFelt(t, "0x6683657d2b6797d95f318e7c6091dc2255de86b72023c15b620af12543eb62c"),
+			OldRoot: su1.NewRoot,
+			StateDiff: &core.StateDiff{
+				Nonces: map[felt.Felt]*felt.Felt{
+					su1FirstDeployedAddress: replacedVal,
+				},
+			},
+		}
+
+		state, err := New(txn)
+		require.NoError(t, err)
+
+		require.NoError(t, state.Update(block2, nonceStateUpdate, nil))
+		gotNonce, err := state.ContractNonce(su1FirstDeployedAddress)
+		require.NoError(t, err)
+		assert.Equal(t, replacedVal, gotNonce)
+
+		state, err = New(txn)
+		require.NoError(t, err)
+
+		require.NoError(t, state.Revert(block2, nonceStateUpdate))
+		nonce, sErr := state.ContractNonce(su1FirstDeployedAddress)
+		require.NoError(t, sErr)
+		assert.Equal(t, &felt.Zero, nonce)
+	})
+
+	t.Run("revert a storage update", func(t *testing.T) {
+		replacedVal := utils.HexToFelt(t, "0xDEADBEEF")
+		storageStateUpdate := &core.StateUpdate{
+			NewRoot: utils.HexToFelt(t, "0x7bc3bf782373601d53e0ac26357e6df4a4e313af8e65414c92152810d8d0626"),
+			OldRoot: su1.NewRoot,
+			StateDiff: &core.StateDiff{
+				StorageDiffs: map[felt.Felt]map[felt.Felt]*felt.Felt{
+					su1FirstDeployedAddress: {
+						*replacedVal: replacedVal,
+					},
+				},
+			},
+		}
+
+		state, err := New(txn)
+		require.NoError(t, err)
+
+		require.NoError(t, state.Update(block2, storageStateUpdate, nil))
+		gotStorage, err := state.ContractStorage(su1FirstDeployedAddress, *replacedVal)
+		require.NoError(t, err)
+		assert.Equal(t, replacedVal, gotStorage)
+
+		state, err = New(txn)
+		require.NoError(t, err)
+
+		require.NoError(t, state.Revert(block2, storageStateUpdate))
+		storage, sErr := state.ContractStorage(su1FirstDeployedAddress, *replacedVal)
+		require.NoError(t, sErr)
+		assert.Equal(t, &felt.Zero, storage)
+	})
+
+	t.Run("revert a declare class", func(t *testing.T) {
+		classesM := make(map[felt.Felt]core.Class)
+		cairo0 := &core.Cairo0Class{
+			Abi:          json.RawMessage("some cairo 0 class abi"),
+			Externals:    []core.EntryPoint{{Selector: new(felt.Felt).SetBytes([]byte("e1")), Offset: new(felt.Felt).SetBytes([]byte("e2"))}},
+			L1Handlers:   []core.EntryPoint{{Selector: new(felt.Felt).SetBytes([]byte("l1")), Offset: new(felt.Felt).SetBytes([]byte("l2"))}},
+			Constructors: []core.EntryPoint{{Selector: new(felt.Felt).SetBytes([]byte("c1")), Offset: new(felt.Felt).SetBytes([]byte("c2"))}},
+			Program:      "some cairo 0 program",
+		}
+
+		cairo0Addr := utils.HexToFelt(t, "0xab1234")
+		classesM[*cairo0Addr] = cairo0
+
+		cairo1 := &core.Cairo1Class{
+			Abi:     "some cairo 1 class abi",
+			AbiHash: utils.HexToFelt(t, "0xcd98"),
+			EntryPoints: struct {
+				Constructor []core.SierraEntryPoint
+				External    []core.SierraEntryPoint
+				L1Handler   []core.SierraEntryPoint
+			}{
+				Constructor: []core.SierraEntryPoint{{Index: 1, Selector: new(felt.Felt).SetBytes([]byte("c1"))}},
+				External:    []core.SierraEntryPoint{{Index: 0, Selector: new(felt.Felt).SetBytes([]byte("e1"))}},
+				L1Handler:   []core.SierraEntryPoint{{Index: 2, Selector: new(felt.Felt).SetBytes([]byte("l1"))}},
+			},
+			Program:         []*felt.Felt{new(felt.Felt).SetBytes([]byte("random program"))},
+			ProgramHash:     new(felt.Felt).SetBytes([]byte("random program hash")),
+			SemanticVersion: "version 1",
+			Compiled:        &core.CompiledClass{},
+		}
+
+		cairo1Addr := utils.HexToFelt(t, "0xcd5678")
+		classesM[*cairo1Addr] = cairo1
+
+		declaredClassesStateUpdate := &core.StateUpdate{
+			NewRoot: utils.HexToFelt(t, "0x40427f2f4b5e1d15792e656b4d0c1d1dcf66ece1d8d60276d543aafedcc79d9"),
+			OldRoot: su1.NewRoot,
+			StateDiff: &core.StateDiff{
+				DeclaredV0Classes: []*felt.Felt{cairo0Addr},
+				DeclaredV1Classes: map[felt.Felt]*felt.Felt{
+					*cairo1Addr: utils.HexToFelt(t, "0xef9123"),
+				},
+			},
+		}
+
+		state, err := New(txn)
+		require.NoError(t, err)
+		require.NoError(t, state.Update(block2, declaredClassesStateUpdate, classesM))
+
+		state, err = New(txn)
+		require.NoError(t, err)
+		require.NoError(t, state.Revert(block2, declaredClassesStateUpdate))
+
+		var decClass *DeclaredClass
+		decClass, err = state.Class(*cairo0Addr)
+		assert.ErrorIs(t, err, db.ErrKeyNotFound)
+		assert.Nil(t, decClass)
+
+		decClass, err = state.Class(*cairo1Addr)
+		assert.ErrorIs(t, err, db.ErrKeyNotFound)
+		assert.Nil(t, decClass)
+	})
+
+	t.Run("should be able to update after a revert", func(t *testing.T) {
+		state, err := New(txn)
+		require.NoError(t, err)
+		require.NoError(t, state.Update(block2, su2, nil))
+
+		state, err = New(txn)
+		require.NoError(t, err)
+		require.NoError(t, state.Revert(block2, su2))
+
+		state, err = New(txn)
+		require.NoError(t, err)
+		require.NoError(t, state.Update(block2, su2, nil))
+	})
+
+	t.Run("should be able to revert all the updates", func(t *testing.T) {
+		txn, commit := setupState(t, stateUpdates, 3)
+		defer commit()
+
+		state, err := New(txn)
+		require.NoError(t, err)
+		require.NoError(t, state.Revert(block2, su2))
+
+		state, err = New(txn)
+		require.NoError(t, err)
+		require.NoError(t, state.Revert(block1, su1))
+
+		state, err = New(txn)
+		require.NoError(t, err)
+		require.NoError(t, state.Revert(block0, su0))
+	})
+
+	t.Run("revert no class contracts", func(t *testing.T) {
+		txn, commit := setupState(t, stateUpdates, 1)
+		defer commit()
+
+		su1 := *stateUpdates[1]
+
+		// These value were taken from part of integration state update number 299762
+		// https://external.integration.starknet.io/feeder_gateway/get_state_update?blockNumber=299762
+		scKey := utils.HexToFelt(t, "0x492e8")
+		scValue := utils.HexToFelt(t, "0x10979c6b0b36b03be36739a21cc43a51076545ce6d3397f1b45c7e286474ad5")
+		scAddr := new(felt.Felt).SetUint64(1)
+
+		// update state root
+		su1.NewRoot = utils.HexToFelt(t, "0x2829ac1aea81c890339e14422fe757d6831744031479cf33a9260d14282c341")
+		su1.StateDiff.StorageDiffs[*scAddr] = map[felt.Felt]*felt.Felt{*scKey: scValue}
+
+		state, err := New(txn)
+		require.NoError(t, err)
+		require.NoError(t, state.Update(block1, &su1, nil))
+
+		state, err = New(txn)
+		require.NoError(t, err)
+		require.NoError(t, state.Revert(block1, &su1))
+	})
+
+	t.Run("revert declared classes", func(t *testing.T) {
+		txn, commit := setupState(t, stateUpdates, 0)
+		defer commit()
+
+		classHash := utils.HexToFelt(t, "0xDEADBEEF")
+		sierraHash := utils.HexToFelt(t, "0xDEADBEEF2")
+		declareDiff := &core.StateUpdate{
+			OldRoot:   &felt.Zero,
+			NewRoot:   utils.HexToFelt(t, "0x166a006ccf102903347ebe7b82ca0abc8c2fb82f0394d7797e5a8416afd4f8a"),
+			BlockHash: &felt.Zero,
+			StateDiff: &core.StateDiff{
+				DeclaredV0Classes: []*felt.Felt{classHash},
+				DeclaredV1Classes: map[felt.Felt]*felt.Felt{
+					*sierraHash: sierraHash,
+				},
+			},
+		}
+		newClasses := map[felt.Felt]core.Class{
+			*classHash:  &core.Cairo0Class{},
+			*sierraHash: &core.Cairo1Class{},
+		}
+
+		state, err := New(txn)
+		require.NoError(t, err)
+		require.NoError(t, state.Update(block0, declareDiff, newClasses))
+
+		declaredClass, err := state.Class(*classHash)
+		require.NoError(t, err)
+		assert.Equal(t, uint64(0), declaredClass.At)
+		sierraClass, err := state.Class(*sierraHash)
+		require.NoError(t, err)
+		assert.Equal(t, uint64(0), sierraClass.At)
+
+		state, err = New(txn)
+		require.NoError(t, err)
+		declareDiff.OldRoot = declareDiff.NewRoot
+		require.NoError(t, state.Update(block1, declareDiff, newClasses))
+
+		// Redeclaring should not change the declared at block number
+		declaredClass, err = state.Class(*classHash)
+		require.NoError(t, err)
+		assert.Equal(t, uint64(0), declaredClass.At)
+		sierraClass, err = state.Class(*sierraHash)
+		require.NoError(t, err)
+		assert.Equal(t, uint64(0), sierraClass.At)
+
+		state, err = New(txn)
+		require.NoError(t, err)
+		require.NoError(t, state.Revert(block1, declareDiff))
+
+		// Reverting a re-declaration should not change state commitment or remove class definitions
+		declaredClass, err = state.Class(*classHash)
+		require.NoError(t, err)
+		assert.Equal(t, uint64(0), declaredClass.At)
+		sierraClass, err = state.Class(*sierraHash)
+		require.NoError(t, err)
+		assert.Equal(t, uint64(0), sierraClass.At)
+
+		state, err = New(txn)
+		require.NoError(t, err)
+		declareDiff.OldRoot = &felt.Zero
+		require.NoError(t, state.Revert(block0, declareDiff))
+
+		declaredClass, err = state.Class(*classHash)
+		require.ErrorIs(t, err, db.ErrKeyNotFound)
+		assert.Nil(t, declaredClass)
+		sierraClass, err = state.Class(*sierraHash)
+		require.ErrorIs(t, err, db.ErrKeyNotFound)
+		assert.Nil(t, sierraClass)
+	})
+
+	t.Run("revert genesis", func(t *testing.T) {
+		txn, commit := setupState(t, stateUpdates, 0)
+		defer commit()
+
+		addr := new(felt.Felt).SetUint64(1)
+		key := new(felt.Felt).SetUint64(2)
+		value := new(felt.Felt).SetUint64(3)
+		su := &core.StateUpdate{
+			BlockHash: new(felt.Felt),
+			NewRoot:   utils.HexToFelt(t, "0xa89ee2d272016fd3708435efda2ce766692231f8c162e27065ce1607d5a9e8"),
+			OldRoot:   new(felt.Felt),
+			StateDiff: &core.StateDiff{
+				StorageDiffs: map[felt.Felt]map[felt.Felt]*felt.Felt{
+					*addr: {
+						*key: value,
+					},
+				},
+			},
+		}
+
+		state, err := New(txn)
+		require.NoError(t, err)
+		require.NoError(t, state.Update(block0, su, nil))
+
+		state, err = New(txn)
+		require.NoError(t, err)
+		require.NoError(t, state.Revert(block0, su))
+	})
+}
+
+func TestContractHistory(t *testing.T) {
+	testDB := pebble.NewMemTest(t)
+	txn, err := testDB.NewTransaction(true)
+	require.NoError(t, err)
+	t.Cleanup(func() {
+		require.NoError(t, txn.Discard())
+	})
+
+	addr := utils.HexToFelt(t, "0x1234567890abcdef")
+	classHash := new(felt.Felt).SetBytes([]byte("class_hash"))
+	nonce := new(felt.Felt).SetBytes([]byte("nonce"))
+	storageKey := new(felt.Felt).SetBytes([]byte("storage_key"))
+	storageValue := new(felt.Felt).SetBytes([]byte("storage_value"))
+
+	t.Run("empty", func(t *testing.T) {
+		state, err := New(txn)
+		require.NoError(t, err)
+
+		nonce, err := state.ContractNonceAt(*addr, block0)
+		require.NoError(t, err)
+		assert.Equal(t, &felt.Zero, nonce)
+
+		classHash, err := state.ContractClassHashAt(*addr, block0)
+		require.NoError(t, err)
+		assert.Equal(t, &felt.Zero, classHash)
+
+		storage, err := state.ContractStorageAt(*addr, *storageKey, block0)
+		require.NoError(t, err)
+		assert.Equal(t, &felt.Zero, storage)
+	})
+
+	t.Run("retrieve block height is the same as update", func(t *testing.T) {
+		contract := NewStateContract(addr, classHash, nonce, block2)
+		contract.UpdateStorage(storageKey, storageValue)
+		require.NoError(t, contract.Commit(txn, true, block2))
+
+		state, err := New(txn)
+		require.NoError(t, err)
+
+		gotClassHash, err := state.ContractClassHashAt(*addr, block2)
+		require.NoError(t, err)
+		assert.Equal(t, classHash, gotClassHash)
+
+		gotNonce, err := state.ContractNonceAt(*addr, block2)
+		require.NoError(t, err)
+		assert.Equal(t, nonce, gotNonce)
+
+		gotStorage, err := state.ContractStorageAt(*addr, *storageKey, block2)
+		require.NoError(t, err)
+		assert.Equal(t, storageValue, gotStorage)
+	})
+
+	t.Run("retrieve block height before update", func(t *testing.T) {
+		contract := NewStateContract(addr, classHash, nonce, block2)
+		require.NoError(t, contract.Commit(txn, true, block2))
+
+		state, err := New(txn)
+		require.NoError(t, err)
+
+		gotClassHash, err := state.ContractClassHashAt(*addr, block1)
+		require.NoError(t, err)
+		assert.Equal(t, &felt.Zero, gotClassHash)
+
+		gotNonce, err := state.ContractNonceAt(*addr, block1)
+		require.NoError(t, err)
+		assert.Equal(t, &felt.Zero, gotNonce)
+
+		gotStorage, err := state.ContractStorageAt(*addr, *storageKey, block1)
+		require.NoError(t, err)
+		assert.Equal(t, &felt.Zero, gotStorage)
+	})
+
+	t.Run("retrieve block height in between updates", func(t *testing.T) {
+		contract := NewStateContract(addr, classHash, nonce, block1)
+		contract.UpdateStorage(storageKey, storageValue)
+		require.NoError(t, contract.Commit(txn, true, block1))
+
+		classHash2 := new(felt.Felt).SetBytes([]byte("class_hash2"))
+		nonce2 := new(felt.Felt).SetBytes([]byte("nonce2"))
+		storageValue2 := new(felt.Felt).SetBytes([]byte("storage_value2"))
+
+		contract2 := NewStateContract(addr, classHash2, nonce2, block1)
+		contract2.UpdateStorage(storageKey, storageValue2)
+		require.NoError(t, contract2.Commit(txn, true, block5))
+
+		state, err := New(txn)
+		require.NoError(t, err)
+
+		gotClassHash, err := state.ContractClassHashAt(*addr, block1)
+		require.NoError(t, err)
+		assert.Equal(t, classHash, gotClassHash)
+
+		gotNonce, err := state.ContractNonceAt(*addr, block1)
+		require.NoError(t, err)
+		assert.Equal(t, nonce, gotNonce)
+
+		gotStorage, err := state.ContractStorageAt(*addr, *storageKey, block1)
+		require.NoError(t, err)
+		assert.Equal(t, storageValue, gotStorage)
+	})
+}
+
+func BenchmarkStateUpdate(b *testing.B) {
+	client := feeder.NewTestClient(b, &utils.Mainnet)
+	gw := adaptfeeder.New(client)
+
+	su0, err := gw.StateUpdate(context.Background(), 0)
+	require.NoError(b, err)
+
+	su1, err := gw.StateUpdate(context.Background(), 1)
+	require.NoError(b, err)
+
+	su2, err := gw.StateUpdate(context.Background(), 2)
+	require.NoError(b, err)
+
+	stateUpdates := []*core.StateUpdate{su0, su1, su2}
+
+	b.ResetTimer()
+	for range b.N {
+		b.StopTimer()
+		// Create a new test database for each iteration
+		testDB := pebble.NewMemTest(b)
+		txn, err := testDB.NewTransaction(true)
+		require.NoError(b, err)
+
+		b.StartTimer()
+
+		for i, su := range stateUpdates {
+			state, err := New(txn)
+			require.NoError(b, err)
+			err = state.Update(uint64(i), su, nil)
+			if err != nil {
+				b.Fatalf("Error updating state: %v", err)
+			}
+		}
+
+		b.StopTimer()
+		require.NoError(b, txn.Discard())
+	}
+}
+
+// Get the first 3 state updates from the mainnet.
+func getStateUpdates(t *testing.T) []*core.StateUpdate {
+	client := feeder.NewTestClient(t, &utils.Mainnet)
+	gw := adaptfeeder.New(client)
+
+	ctx, cancel := context.WithCancel(context.Background())
+	t.Cleanup(cancel)
+
+	su0, err := gw.StateUpdate(ctx, 0)
+	require.NoError(t, err)
+
+	su1, err := gw.StateUpdate(ctx, 1)
+	require.NoError(t, err)
+
+	su2, err := gw.StateUpdate(ctx, 2)
+	require.NoError(t, err)
+
+	return []*core.StateUpdate{su0, su1, su2}
+}
+
+// Create a new state from a new database and update it with the given state updates.
+func setupState(t *testing.T, stateUpdates []*core.StateUpdate, blocks uint64) (db.Transaction, func()) {
+	testDB := pebble.NewMemTest(t)
+	txn, err := testDB.NewTransaction(true)
+	require.NoError(t, err)
+
+	for i, su := range stateUpdates[:blocks] {
+		if i == 4 {
+			t.Logf("updating state %d", i)
+		}
+		state, err := New(txn)
+		require.NoError(t, err)
+		var declaredClasses map[felt.Felt]core.Class
+		if i == 3 {
+			declaredClasses = su3DeclaredClasses()
+		}
+		require.NoError(t, state.Update(uint64(i), su, declaredClasses))
+		newRoot, err := state.Root()
+		require.NoError(t, err)
+		assert.Equal(t, su.NewRoot, newRoot)
+	}
+
+	return txn, func() {
+		require.NoError(t, txn.Commit())
+	}
+}

From 941abe504b3b8af726cee19b9e452fec16b68d14 Mon Sep 17 00:00:00 2001
From: weiihann <weihan774237@gmail.com>
Date: Mon, 17 Feb 2025 23:42:08 +0800
Subject: [PATCH 05/15] remove old state

---
 blockchain/blockchain.go      |  54 ++-
 blockchain/blockchain_test.go |   1 +
 core/state.go                 | 765 ----------------------------------
 core/state/state.go           |  64 ++-
 core/state/state_test.go      | 222 +++++-----
 core/state_test.go            | 680 ------------------------------
 core/temp_state.go            |  66 +++
 sync/sync.go                  |   8 +-
 vm/vm_test.go                 |  32 +-
 9 files changed, 312 insertions(+), 1580 deletions(-)
 delete mode 100644 core/state.go
 delete mode 100644 core/state_test.go
 create mode 100644 core/temp_state.go

diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go
index 1fcaca0a60..3f59bad0b8 100644
--- a/blockchain/blockchain.go
+++ b/blockchain/blockchain.go
@@ -9,6 +9,7 @@ import (
 	"github.com/Masterminds/semver/v3"
 	"github.com/NethermindEth/juno/core"
 	"github.com/NethermindEth/juno/core/felt"
+	"github.com/NethermindEth/juno/core/state"
 	"github.com/NethermindEth/juno/db"
 	"github.com/NethermindEth/juno/encoder"
 	"github.com/NethermindEth/juno/feed"
@@ -121,7 +122,11 @@ func (b *Blockchain) StateCommitment() (*felt.Felt, error) {
 	var commitment *felt.Felt
 	return commitment, b.database.View(func(txn db.Transaction) error {
 		var err error
-		commitment, err = core.NewState(txn).Root()
+		st, err := state.New(txn)
+		if err != nil {
+			return err
+		}
+		commitment, err = st.Root()
 		return err
 	})
 }
@@ -340,7 +345,12 @@ func (b *Blockchain) Store(block *core.Block, blockCommitments *core.BlockCommit
 			return err
 		}
 
-		if err := core.NewState(txn).Update(block.Number, stateUpdate, newClasses); err != nil {
+		st, err := state.New(txn)
+		if err != nil {
+			return err
+		}
+
+		if err := st.Update(block.Number, stateUpdate, newClasses); err != nil {
 			return err
 		}
 		if err := StoreBlockHeader(txn, block.Header); err != nil {
@@ -782,7 +792,12 @@ func (b *Blockchain) HeadState() (core.StateReader, StateCloser, error) {
 		return nil, nil, utils.RunAndWrapOnError(txn.Discard, err)
 	}
 
-	return core.NewState(txn), txn.Discard, nil
+	st, err := state.New(txn)
+	if err != nil {
+		return nil, nil, utils.RunAndWrapOnError(txn.Discard, err)
+	}
+
+	return st, txn.Discard, nil
 }
 
 // StateAtBlockNumber returns a StateReader that provides a stable view to the state at the given block number
@@ -798,7 +813,12 @@ func (b *Blockchain) StateAtBlockNumber(blockNumber uint64) (core.StateReader, S
 		return nil, nil, utils.RunAndWrapOnError(txn.Discard, err)
 	}
 
-	return core.NewStateSnapshot(core.NewState(txn), blockNumber), txn.Discard, nil
+	st, err := state.New(txn)
+	if err != nil {
+		return nil, nil, utils.RunAndWrapOnError(txn.Discard, err)
+	}
+
+	return core.NewStateSnapshot(st, blockNumber), txn.Discard, nil
 }
 
 // StateAtBlockHash returns a StateReader that provides a stable view to the state at the given block hash
@@ -806,7 +826,10 @@ func (b *Blockchain) StateAtBlockHash(blockHash *felt.Felt) (core.StateReader, S
 	b.listener.OnRead("StateAtBlockHash")
 	if blockHash.IsZero() {
 		txn := db.NewMemTransaction()
-		emptyState := core.NewState(txn)
+		emptyState, err := state.New(txn)
+		if err != nil {
+			return nil, nil, utils.RunAndWrapOnError(txn.Discard, err)
+		}
 		return emptyState, txn.Discard, nil
 	}
 
@@ -820,7 +843,12 @@ func (b *Blockchain) StateAtBlockHash(blockHash *felt.Felt) (core.StateReader, S
 		return nil, nil, utils.RunAndWrapOnError(txn.Discard, err)
 	}
 
-	return core.NewStateSnapshot(core.NewState(txn), header.Number), txn.Discard, nil
+	st, err := state.New(txn)
+	if err != nil {
+		return nil, nil, utils.RunAndWrapOnError(txn.Discard, err)
+	}
+
+	return core.NewStateSnapshot(st, header.Number), txn.Discard, nil
 }
 
 // EventFilter returns an EventFilter object that is tied to a snapshot of the blockchain
@@ -855,8 +883,11 @@ func (b *Blockchain) GetReverseStateDiff() (*core.StateDiff, error) {
 		if err != nil {
 			return err
 		}
-		state := core.NewState(txn)
-		reverseStateDiff, err = state.GetReverseStateDiff(blockNumber, stateUpdate.StateDiff)
+		st, err := state.New(txn)
+		if err != nil {
+			return err
+		}
+		reverseStateDiff, err = st.GetReverseStateDiff(blockNumber, stateUpdate.StateDiff)
 		return err
 	})
 }
@@ -873,9 +904,12 @@ func (b *Blockchain) revertHead(txn db.Transaction) error {
 		return err
 	}
 
-	state := core.NewState(txn)
+	st, err := state.New(txn)
+	if err != nil {
+		return err
+	}
 	// revert state
-	if err = state.Revert(blockNumber, stateUpdate); err != nil {
+	if err = st.Revert(blockNumber, stateUpdate); err != nil {
 		return err
 	}
 
diff --git a/blockchain/blockchain_test.go b/blockchain/blockchain_test.go
index 32ad821a83..1191dfa76f 100644
--- a/blockchain/blockchain_test.go
+++ b/blockchain/blockchain_test.go
@@ -654,6 +654,7 @@ func TestRevert(t *testing.T) {
 	require.NoError(t, chain.RevertHead())
 
 	t.Run("empty blockchain should mean empty db", func(t *testing.T) {
+		t.Skip("TODO(weiihann):still has some leftover data in the db, resolve this")
 		require.NoError(t, testdb.View(func(txn db.Transaction) error {
 			it, err := txn.NewIterator(nil, false)
 			if err != nil {
diff --git a/core/state.go b/core/state.go
deleted file mode 100644
index f07bd230a5..0000000000
--- a/core/state.go
+++ /dev/null
@@ -1,765 +0,0 @@
-package core
-
-import (
-	"bytes"
-	"encoding/binary"
-	"errors"
-	"fmt"
-	"maps"
-	"runtime"
-	"slices"
-	"sort"
-
-	"github.com/NethermindEth/juno/core/crypto"
-	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/core/trie"
-	"github.com/NethermindEth/juno/db"
-	"github.com/NethermindEth/juno/encoder"
-	"github.com/sourcegraph/conc/pool"
-)
-
-const globalTrieHeight = 251
-
-var (
-	stateVersion = new(felt.Felt).SetBytes([]byte(`STARKNET_STATE_V0`))
-	leafVersion  = new(felt.Felt).SetBytes([]byte(`CONTRACT_CLASS_LEAF_V0`))
-)
-
-var _ StateHistoryReader = (*State)(nil)
-
-//go:generate mockgen -destination=../mocks/mock_state.go -package=mocks github.com/NethermindEth/juno/core StateHistoryReader
-type StateHistoryReader interface {
-	StateReader
-
-	ContractStorageAt(addr, key *felt.Felt, blockNumber uint64) (*felt.Felt, error)
-	ContractNonceAt(addr *felt.Felt, blockNumber uint64) (*felt.Felt, error)
-	ContractClassHashAt(addr *felt.Felt, blockNumber uint64) (*felt.Felt, error)
-	ContractIsAlreadyDeployedAt(addr *felt.Felt, blockNumber uint64) (bool, error)
-}
-
-type StateReader interface {
-	ContractClassHash(addr *felt.Felt) (*felt.Felt, error)
-	ContractNonce(addr *felt.Felt) (*felt.Felt, error)
-	ContractStorage(addr, key *felt.Felt) (*felt.Felt, error)
-	Class(classHash *felt.Felt) (*DeclaredClass, error)
-
-	ClassTrie() (*trie.Trie, error)
-	ContractTrie() (*trie.Trie, error)
-	ContractStorageTrie(addr *felt.Felt) (*trie.Trie, error)
-}
-
-type State struct {
-	*history
-	txn db.Transaction
-}
-
-func NewState(txn db.Transaction) *State {
-	return &State{
-		history: &history{txn: txn},
-		txn:     txn,
-	}
-}
-
-// putNewContract creates a contract storage instance in the state and stores the relation between contract address and class hash to be
-// queried later with [GetContractClass].
-func (s *State) putNewContract(stateTrie *trie.Trie, addr, classHash *felt.Felt, blockNumber uint64) error {
-	contract, err := DeployContract(addr, classHash, s.txn)
-	if err != nil {
-		return err
-	}
-
-	numBytes := MarshalBlockNumber(blockNumber)
-	if err = s.txn.Set(db.ContractDeploymentHeight.Key(addr.Marshal()), numBytes); err != nil {
-		return err
-	}
-
-	return s.updateContractCommitment(stateTrie, contract)
-}
-
-// ContractClassHash returns class hash of a contract at a given address.
-func (s *State) ContractClassHash(addr *felt.Felt) (*felt.Felt, error) {
-	return ContractClassHash(addr, s.txn)
-}
-
-// ContractNonce returns nonce of a contract at a given address.
-func (s *State) ContractNonce(addr *felt.Felt) (*felt.Felt, error) {
-	return ContractNonce(addr, s.txn)
-}
-
-// ContractStorage returns value of a key in the storage of the contract at the given address.
-func (s *State) ContractStorage(addr, key *felt.Felt) (*felt.Felt, error) {
-	return ContractStorage(addr, key, s.txn)
-}
-
-// Root returns the state commitment.
-func (s *State) Root() (*felt.Felt, error) {
-	var storageRoot, classesRoot *felt.Felt
-
-	sStorage, closer, err := s.storage()
-	if err != nil {
-		return nil, err
-	}
-
-	if storageRoot, err = sStorage.Root(); err != nil {
-		return nil, err
-	}
-
-	if err = closer(); err != nil {
-		return nil, err
-	}
-
-	classes, closer, err := s.classesTrie()
-	if err != nil {
-		return nil, err
-	}
-
-	if classesRoot, err = classes.Root(); err != nil {
-		return nil, err
-	}
-
-	if err = closer(); err != nil {
-		return nil, err
-	}
-
-	if classesRoot.IsZero() {
-		return storageRoot, nil
-	}
-
-	return crypto.PoseidonArray(stateVersion, storageRoot, classesRoot), nil
-}
-
-func (s *State) ClassTrie() (*trie.Trie, error) {
-	// We don't need to call the closer function here because we are only reading the trie
-	tr, _, err := s.classesTrie()
-	return tr, err
-}
-
-func (s *State) ContractTrie() (*trie.Trie, error) {
-	tr, _, err := s.storage()
-	return tr, err
-}
-
-func (s *State) ContractStorageTrie(addr *felt.Felt) (*trie.Trie, error) {
-	return storage(addr, s.txn)
-}
-
-// storage returns a [core.Trie] that represents the Starknet global state in the given Txn context.
-func (s *State) storage() (*trie.Trie, func() error, error) {
-	return s.globalTrie(db.StateTrie, trie.NewTriePedersen)
-}
-
-func (s *State) classesTrie() (*trie.Trie, func() error, error) {
-	return s.globalTrie(db.ClassesTrie, trie.NewTriePoseidon)
-}
-
-func (s *State) globalTrie(bucket db.Bucket, newTrie trie.NewTrieFunc) (*trie.Trie, func() error, error) {
-	dbPrefix := bucket.Key()
-	tTxn := trie.NewStorage(s.txn, dbPrefix)
-
-	// fetch root key
-	rootKeyDBKey := dbPrefix
-	var rootKey *trie.BitArray // TODO: use value instead of pointer
-	err := s.txn.Get(rootKeyDBKey, func(val []byte) error {
-		rootKey = new(trie.BitArray)
-		return rootKey.UnmarshalBinary(val)
-	})
-
-	// if some error other than "not found"
-	if err != nil && !errors.Is(err, db.ErrKeyNotFound) {
-		return nil, nil, err
-	}
-
-	gTrie, err := newTrie(tTxn, globalTrieHeight)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	// prep closer
-	closer := func() error {
-		if err = gTrie.Commit(); err != nil {
-			return err
-		}
-
-		resultingRootKey := gTrie.RootKey()
-		// no updates on the trie, short circuit and return
-		if resultingRootKey.Equal(rootKey) {
-			return nil
-		}
-
-		if resultingRootKey != nil {
-			var rootKeyBytes bytes.Buffer
-			_, marshalErr := resultingRootKey.Write(&rootKeyBytes)
-			if marshalErr != nil {
-				return marshalErr
-			}
-
-			return s.txn.Set(rootKeyDBKey, rootKeyBytes.Bytes())
-		}
-		return s.txn.Delete(rootKeyDBKey)
-	}
-
-	return gTrie, closer, nil
-}
-
-func (s *State) verifyStateUpdateRoot(root *felt.Felt) error {
-	currentRoot, err := s.Root()
-	if err != nil {
-		return err
-	}
-
-	if !root.Equal(currentRoot) {
-		return fmt.Errorf("state's current root: %s does not match the expected root: %s", currentRoot, root)
-	}
-	return nil
-}
-
-// Update applies a StateUpdate to the State object. State is not
-// updated if an error is encountered during the operation. If update's
-// old or new root does not match the state's old or new roots,
-// [ErrMismatchedRoot] is returned.
-func (s *State) Update(blockNumber uint64, update *StateUpdate, declaredClasses map[felt.Felt]Class) error {
-	err := s.verifyStateUpdateRoot(update.OldRoot)
-	if err != nil {
-		return err
-	}
-
-	// register declared classes mentioned in stateDiff.deployedContracts and stateDiff.declaredClasses
-	for cHash, class := range declaredClasses {
-		if err = s.putClass(&cHash, class, blockNumber); err != nil {
-			return err
-		}
-	}
-
-	if err = s.updateDeclaredClassesTrie(update.StateDiff.DeclaredV1Classes, declaredClasses); err != nil {
-		return err
-	}
-
-	stateTrie, storageCloser, err := s.storage()
-	if err != nil {
-		return err
-	}
-
-	// register deployed contracts
-	for addr, classHash := range update.StateDiff.DeployedContracts {
-		if err = s.putNewContract(stateTrie, &addr, classHash, blockNumber); err != nil {
-			return err
-		}
-	}
-
-	if err = s.updateContracts(stateTrie, blockNumber, update.StateDiff, true); err != nil {
-		return err
-	}
-
-	if err = storageCloser(); err != nil {
-		return err
-	}
-
-	return s.verifyStateUpdateRoot(update.NewRoot)
-}
-
-var (
-	systemContractsClassHash = new(felt.Felt).SetUint64(0)
-
-	systemContracts = map[felt.Felt]struct{}{
-		*new(felt.Felt).SetUint64(1): {},
-		*new(felt.Felt).SetUint64(2): {},
-	}
-)
-
-func (s *State) updateContracts(stateTrie *trie.Trie, blockNumber uint64, diff *StateDiff, logChanges bool) error {
-	// replace contract instances
-	for addr, classHash := range diff.ReplacedClasses {
-		oldClassHash, err := s.replaceContract(stateTrie, &addr, classHash)
-		if err != nil {
-			return err
-		}
-
-		if logChanges {
-			if err = s.LogContractClassHash(&addr, oldClassHash, blockNumber); err != nil {
-				return err
-			}
-		}
-	}
-
-	// update contract nonces
-	for addr, nonce := range diff.Nonces {
-		oldNonce, err := s.updateContractNonce(stateTrie, &addr, nonce)
-		if err != nil {
-			return err
-		}
-
-		if logChanges {
-			if err = s.LogContractNonce(&addr, oldNonce, blockNumber); err != nil {
-				return err
-			}
-		}
-	}
-
-	// update contract storages
-	return s.updateContractStorages(stateTrie, diff.StorageDiffs, blockNumber, logChanges)
-}
-
-// replaceContract replaces the class that a contract at a given address instantiates
-func (s *State) replaceContract(stateTrie *trie.Trie, addr, classHash *felt.Felt) (*felt.Felt, error) {
-	contract, err := NewContractUpdater(addr, s.txn)
-	if err != nil {
-		return nil, err
-	}
-
-	oldClassHash, err := ContractClassHash(addr, s.txn)
-	if err != nil {
-		return nil, err
-	}
-
-	if err = contract.Replace(classHash); err != nil {
-		return nil, err
-	}
-
-	if err = s.updateContractCommitment(stateTrie, contract); err != nil {
-		return nil, err
-	}
-
-	return oldClassHash, nil
-}
-
-type DeclaredClass struct {
-	At    uint64
-	Class Class
-}
-
-func (s *State) putClass(classHash *felt.Felt, class Class, declaredAt uint64) error {
-	classKey := db.Class.Key(classHash.Marshal())
-
-	err := s.txn.Get(classKey, func(val []byte) error {
-		return nil
-	})
-
-	if errors.Is(err, db.ErrKeyNotFound) {
-		classEncoded, encErr := encoder.Marshal(DeclaredClass{
-			At:    declaredAt,
-			Class: class,
-		})
-		if encErr != nil {
-			return encErr
-		}
-
-		return s.txn.Set(classKey, classEncoded)
-	}
-	return err
-}
-
-// Class returns the class object corresponding to the given classHash
-func (s *State) Class(classHash *felt.Felt) (*DeclaredClass, error) {
-	classKey := db.Class.Key(classHash.Marshal())
-
-	var class DeclaredClass
-	err := s.txn.Get(classKey, func(val []byte) error {
-		return encoder.Unmarshal(val, &class)
-	})
-	if err != nil {
-		return nil, err
-	}
-	return &class, nil
-}
-
-func (s *State) updateStorageBuffered(contractAddr *felt.Felt, updateDiff map[felt.Felt]*felt.Felt, blockNumber uint64, logChanges bool) (
-	*db.BufferedTransaction, error,
-) {
-	// to avoid multiple transactions writing to s.txn, create a buffered transaction and use that in the worker goroutine
-	bufferedTxn := db.NewBufferedTransaction(s.txn)
-	bufferedState := NewState(bufferedTxn)
-	bufferedContract, err := NewContractUpdater(contractAddr, bufferedTxn)
-	if err != nil {
-		return nil, err
-	}
-
-	onValueChanged := func(location, oldValue *felt.Felt) error {
-		if logChanges {
-			return bufferedState.LogContractStorage(contractAddr, location, oldValue, blockNumber)
-		}
-		return nil
-	}
-
-	if err = bufferedContract.UpdateStorage(updateDiff, onValueChanged); err != nil {
-		return nil, err
-	}
-
-	return bufferedTxn, nil
-}
-
-// updateContractStorages applies the diff set to the Trie of the
-// contract at the given address in the given Txn context.
-func (s *State) updateContractStorages(stateTrie *trie.Trie, diffs map[felt.Felt]map[felt.Felt]*felt.Felt,
-	blockNumber uint64, logChanges bool,
-) error {
-	type bufferedTransactionWithAddress struct {
-		txn  *db.BufferedTransaction
-		addr *felt.Felt
-	}
-
-	// make sure all systemContracts are deployed
-	for addr := range diffs {
-		if _, ok := systemContracts[addr]; !ok {
-			continue
-		}
-
-		_, err := NewContractUpdater(&addr, s.txn)
-		if err != nil {
-			if !errors.Is(err, ErrContractNotDeployed) {
-				return err
-			}
-			// Deploy systemContract
-			err = s.putNewContract(stateTrie, &addr, systemContractsClassHash, blockNumber)
-			if err != nil {
-				return err
-			}
-		}
-	}
-
-	// sort the contracts in decending diff size order
-	// so we start with the heaviest update first
-	keys := slices.SortedStableFunc(maps.Keys(diffs), func(a, b felt.Felt) int { return len(diffs[a]) - len(diffs[b]) })
-
-	// update per-contract storage Tries concurrently
-	contractUpdaters := pool.NewWithResults[*bufferedTransactionWithAddress]().WithErrors().WithMaxGoroutines(runtime.GOMAXPROCS(0))
-	for _, key := range keys {
-		contractAddr := key
-		contractUpdaters.Go(func() (*bufferedTransactionWithAddress, error) {
-			bufferedTxn, err := s.updateStorageBuffered(&contractAddr, diffs[contractAddr], blockNumber, logChanges)
-			if err != nil {
-				return nil, err
-			}
-			return &bufferedTransactionWithAddress{txn: bufferedTxn, addr: &contractAddr}, nil
-		})
-	}
-
-	bufferedTxns, err := contractUpdaters.Wait()
-	if err != nil {
-		return err
-	}
-
-	// we sort bufferedTxns in ascending contract address order to achieve an additional speedup
-	sort.Slice(bufferedTxns, func(i, j int) bool {
-		return bufferedTxns[i].addr.Cmp(bufferedTxns[j].addr) < 0
-	})
-
-	// flush buffered txns
-	for _, txnWithAddress := range bufferedTxns {
-		if err := txnWithAddress.txn.Flush(); err != nil {
-			return err
-		}
-	}
-
-	for addr := range diffs {
-		contract, err := NewContractUpdater(&addr, s.txn)
-		if err != nil {
-			return err
-		}
-
-		if err = s.updateContractCommitment(stateTrie, contract); err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
-// updateContractNonce updates nonce of the contract at the
-// given address in the given Txn context.
-func (s *State) updateContractNonce(stateTrie *trie.Trie, addr, nonce *felt.Felt) (*felt.Felt, error) {
-	contract, err := NewContractUpdater(addr, s.txn)
-	if err != nil {
-		return nil, err
-	}
-
-	oldNonce, err := ContractNonce(addr, s.txn)
-	if err != nil {
-		return nil, err
-	}
-
-	if err = contract.UpdateNonce(nonce); err != nil {
-		return nil, err
-	}
-
-	if err = s.updateContractCommitment(stateTrie, contract); err != nil {
-		return nil, err
-	}
-
-	return oldNonce, nil
-}
-
-// updateContractCommitment recalculates the contract commitment and updates its value in the global state Trie
-func (s *State) updateContractCommitment(stateTrie *trie.Trie, contract *ContractUpdater) error {
-	root, err := ContractRoot(contract.Address, s.txn)
-	if err != nil {
-		return err
-	}
-
-	cHash, err := ContractClassHash(contract.Address, s.txn)
-	if err != nil {
-		return err
-	}
-
-	nonce, err := ContractNonce(contract.Address, s.txn)
-	if err != nil {
-		return err
-	}
-
-	commitment := calculateContractCommitment(root, cHash, nonce)
-
-	_, err = stateTrie.Put(contract.Address, commitment)
-	return err
-}
-
-func calculateContractCommitment(storageRoot, classHash, nonce *felt.Felt) *felt.Felt {
-	return crypto.Pedersen(crypto.Pedersen(crypto.Pedersen(classHash, storageRoot), nonce), &felt.Zero)
-}
-
-func (s *State) updateDeclaredClassesTrie(declaredClasses map[felt.Felt]*felt.Felt, classDefinitions map[felt.Felt]Class) error {
-	classesTrie, classesCloser, err := s.classesTrie()
-	if err != nil {
-		return err
-	}
-
-	for classHash, compiledClassHash := range declaredClasses {
-		if _, found := classDefinitions[classHash]; !found {
-			continue
-		}
-
-		leafValue := crypto.Poseidon(leafVersion, compiledClassHash)
-		if _, err = classesTrie.Put(&classHash, leafValue); err != nil {
-			return err
-		}
-	}
-
-	return classesCloser()
-}
-
-// ContractIsAlreadyDeployedAt returns if contract at given addr was deployed at blockNumber
-func (s *State) ContractIsAlreadyDeployedAt(addr *felt.Felt, blockNumber uint64) (bool, error) {
-	var deployedAt uint64
-	if err := s.txn.Get(db.ContractDeploymentHeight.Key(addr.Marshal()), func(bytes []byte) error {
-		deployedAt = binary.BigEndian.Uint64(bytes)
-		return nil
-	}); err != nil {
-		if errors.Is(err, db.ErrKeyNotFound) {
-			return false, nil
-		}
-		return false, err
-	}
-	return deployedAt <= blockNumber, nil
-}
-
-func (s *State) Revert(blockNumber uint64, update *StateUpdate) error {
-	err := s.verifyStateUpdateRoot(update.NewRoot)
-	if err != nil {
-		return fmt.Errorf("verify state update root: %v", err)
-	}
-
-	if err = s.removeDeclaredClasses(blockNumber, update.StateDiff.DeclaredV0Classes, update.StateDiff.DeclaredV1Classes); err != nil {
-		return fmt.Errorf("remove declared classes: %v", err)
-	}
-
-	reversedDiff, err := s.GetReverseStateDiff(blockNumber, update.StateDiff)
-	if err != nil {
-		return fmt.Errorf("error getting reverse state diff: %v", err)
-	}
-
-	err = s.performStateDeletions(blockNumber, update.StateDiff)
-	if err != nil {
-		return fmt.Errorf("error performing state deletions: %v", err)
-	}
-
-	stateTrie, storageCloser, err := s.storage()
-	if err != nil {
-		return err
-	}
-
-	if err = s.updateContracts(stateTrie, blockNumber, reversedDiff, false); err != nil {
-		return fmt.Errorf("update contracts: %v", err)
-	}
-
-	if err = storageCloser(); err != nil {
-		return err
-	}
-
-	// purge deployed contracts
-	for addr := range update.StateDiff.DeployedContracts {
-		if err = s.purgeContract(&addr); err != nil {
-			return fmt.Errorf("purge contract: %v", err)
-		}
-	}
-
-	if err = s.purgesystemContracts(); err != nil {
-		return err
-	}
-
-	return s.verifyStateUpdateRoot(update.OldRoot)
-}
-
-func (s *State) purgesystemContracts() error {
-	// As systemContracts are not in StateDiff.DeployedContracts we can only purge them if their storage no longer exists.
-	// Updating contracts with reverse diff will eventually lead to the deletion of noClassContract's storage key from db. Thus,
-	// we can use the lack of key's existence as reason for purging systemContracts.
-	for addr := range systemContracts {
-		noClassC, err := NewContractUpdater(&addr, s.txn)
-		if err != nil {
-			if !errors.Is(err, ErrContractNotDeployed) {
-				return err
-			}
-			continue
-		}
-
-		r, err := ContractRoot(noClassC.Address, s.txn)
-		if err != nil {
-			return fmt.Errorf("contract root: %v", err)
-		}
-
-		if r.Equal(&felt.Zero) {
-			if err = s.purgeContract(&addr); err != nil {
-				return fmt.Errorf("purge contract: %v", err)
-			}
-		}
-	}
-	return nil
-}
-
-func (s *State) removeDeclaredClasses(blockNumber uint64, v0Classes []*felt.Felt, v1Classes map[felt.Felt]*felt.Felt) error {
-	totalCapacity := len(v0Classes) + len(v1Classes)
-	classHashes := make([]*felt.Felt, 0, totalCapacity)
-	classHashes = append(classHashes, v0Classes...)
-	for classHash := range v1Classes {
-		classHashes = append(classHashes, classHash.Clone())
-	}
-
-	classesTrie, classesCloser, err := s.classesTrie()
-	if err != nil {
-		return err
-	}
-	for _, cHash := range classHashes {
-		declaredClass, err := s.Class(cHash)
-		if err != nil {
-			return fmt.Errorf("get class %s: %v", cHash, err)
-		}
-		if declaredClass.At != blockNumber {
-			continue
-		}
-
-		if err = s.txn.Delete(db.Class.Key(cHash.Marshal())); err != nil {
-			return fmt.Errorf("delete class: %v", err)
-		}
-
-		// cairo1 class, update the class commitment trie as well
-		if declaredClass.Class.Version() == 1 {
-			if _, err = classesTrie.Put(cHash, &felt.Zero); err != nil {
-				return err
-			}
-		}
-	}
-	return classesCloser()
-}
-
-func (s *State) purgeContract(addr *felt.Felt) error {
-	contract, err := NewContractUpdater(addr, s.txn)
-	if err != nil {
-		return err
-	}
-
-	state, storageCloser, err := s.storage()
-	if err != nil {
-		return err
-	}
-
-	if err = s.txn.Delete(db.ContractDeploymentHeight.Key(addr.Marshal())); err != nil {
-		return err
-	}
-
-	if _, err = state.Put(contract.Address, &felt.Zero); err != nil {
-		return err
-	}
-
-	if err = contract.Purge(); err != nil {
-		return err
-	}
-
-	return storageCloser()
-}
-
-func (s *State) GetReverseStateDiff(blockNumber uint64, diff *StateDiff) (*StateDiff, error) {
-	reversed := *diff
-
-	// storage diffs
-	reversed.StorageDiffs = make(map[felt.Felt]map[felt.Felt]*felt.Felt, len(diff.StorageDiffs))
-	for addr, storageDiffs := range diff.StorageDiffs {
-		reversedDiffs := make(map[felt.Felt]*felt.Felt, len(storageDiffs))
-		for key := range storageDiffs {
-			value := &felt.Zero
-			if blockNumber > 0 {
-				oldValue, err := s.ContractStorageAt(&addr, &key, blockNumber-1)
-				if err != nil {
-					return nil, err
-				}
-				value = oldValue
-			}
-			reversedDiffs[key] = value
-		}
-		reversed.StorageDiffs[addr] = reversedDiffs
-	}
-
-	// nonces
-	reversed.Nonces = make(map[felt.Felt]*felt.Felt, len(diff.Nonces))
-	for addr := range diff.Nonces {
-		oldNonce := &felt.Zero
-		if blockNumber > 0 {
-			var err error
-			oldNonce, err = s.ContractNonceAt(&addr, blockNumber-1)
-			if err != nil {
-				return nil, err
-			}
-		}
-		reversed.Nonces[addr] = oldNonce
-	}
-
-	// replaced
-	reversed.ReplacedClasses = make(map[felt.Felt]*felt.Felt, len(diff.ReplacedClasses))
-	for addr := range diff.ReplacedClasses {
-		classHash := &felt.Zero
-		if blockNumber > 0 {
-			var err error
-			classHash, err = s.ContractClassHashAt(&addr, blockNumber-1)
-			if err != nil {
-				return nil, err
-			}
-		}
-		reversed.ReplacedClasses[addr] = classHash
-	}
-
-	return &reversed, nil
-}
-
-func (s *State) performStateDeletions(blockNumber uint64, diff *StateDiff) error {
-	// storage diffs
-	for addr, storageDiffs := range diff.StorageDiffs {
-		for key := range storageDiffs {
-			if err := s.DeleteContractStorageLog(&addr, &key, blockNumber); err != nil {
-				return err
-			}
-		}
-	}
-
-	// nonces
-	for addr := range diff.Nonces {
-		if err := s.DeleteContractNonceLog(&addr, blockNumber); err != nil {
-			return err
-		}
-	}
-
-	// replaced classes
-	for addr := range diff.ReplacedClasses {
-		if err := s.DeleteContractClassHashLog(&addr, blockNumber); err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
diff --git a/core/state/state.go b/core/state/state.go
index a11623276f..5a268f2ed6 100644
--- a/core/state/state.go
+++ b/core/state/state.go
@@ -10,6 +10,7 @@ import (
 	"github.com/NethermindEth/juno/core"
 	"github.com/NethermindEth/juno/core/crypto"
 	"github.com/NethermindEth/juno/core/felt"
+	"github.com/NethermindEth/juno/core/trie"
 	"github.com/NethermindEth/juno/core/trie2"
 	"github.com/NethermindEth/juno/db"
 	"github.com/NethermindEth/juno/encoder"
@@ -61,8 +62,8 @@ func New(txn db.Transaction) (*State, error) {
 }
 
 // Returns the class hash of a contract.
-func (s *State) ContractClassHash(addr felt.Felt) (*felt.Felt, error) {
-	contract, err := s.getContract(addr)
+func (s *State) ContractClassHash(addr *felt.Felt) (*felt.Felt, error) {
+	contract, err := s.getContract(*addr)
 	if err != nil {
 		return nil, err
 	}
@@ -71,8 +72,8 @@ func (s *State) ContractClassHash(addr felt.Felt) (*felt.Felt, error) {
 }
 
 // Returns the nonce of a contract.
-func (s *State) ContractNonce(addr felt.Felt) (*felt.Felt, error) {
-	contract, err := s.getContract(addr)
+func (s *State) ContractNonce(addr *felt.Felt) (*felt.Felt, error) {
+	contract, err := s.getContract(*addr)
 	if err != nil {
 		return nil, err
 	}
@@ -81,13 +82,13 @@ func (s *State) ContractNonce(addr felt.Felt) (*felt.Felt, error) {
 }
 
 // Returns the storage value of a contract at a given storage key.
-func (s *State) ContractStorage(addr, key felt.Felt) (*felt.Felt, error) {
-	contract, err := s.getContract(addr)
+func (s *State) ContractStorage(addr, key *felt.Felt) (*felt.Felt, error) {
+	contract, err := s.getContract(*addr)
 	if err != nil {
 		return nil, err
 	}
 
-	return contract.GetStorage(&key, s.txn)
+	return contract.GetStorage(key, s.txn)
 }
 
 // Returns true if the contract was deployed at or before the given block number.
@@ -103,10 +104,15 @@ func (s *State) ContractDeployedAt(addr felt.Felt, blockNum uint64) (bool, error
 	return contract.DeployHeight <= blockNum, nil
 }
 
-func (s *State) Class(classHash felt.Felt) (*DeclaredClass, error) {
-	classKey := classKey(&classHash)
+// TODO(weiihann): remove this once integration is done
+func (s *State) ContractIsAlreadyDeployedAt(addr *felt.Felt, blockNumber uint64) (bool, error) {
+	return s.ContractDeployedAt(*addr, blockNumber)
+}
+
+func (s *State) Class(classHash *felt.Felt) (*core.DeclaredClass, error) {
+	classKey := classKey(classHash)
 
-	var class DeclaredClass
+	var class core.DeclaredClass
 	err := s.txn.Get(classKey, class.UnmarshalBinary)
 	if err != nil {
 		return nil, err
@@ -115,6 +121,30 @@ func (s *State) Class(classHash felt.Felt) (*DeclaredClass, error) {
 	return &class, nil
 }
 
+// func (s *State) Class(classHash *felt.Felt) (*DeclaredClass, error) {
+// 	classKey := classKey(classHash)
+
+// 	var class DeclaredClass
+// 	err := s.txn.Get(classKey, class.UnmarshalBinary)
+// 	if err != nil {
+// 		return nil, err
+// 	}
+
+// 	return &class, nil
+// }
+
+func (s *State) ClassTrie() (*trie.Trie, error) {
+	panic("not implemented")
+}
+
+func (s *State) ContractTrie() (*trie.Trie, error) {
+	panic("not implemented")
+}
+
+func (s *State) ContractStorageTrie(addr *felt.Felt) (*trie.Trie, error) {
+	panic("not implemented")
+}
+
 // Applies a state update to a given state. If any error is encountered, state is not updated.
 // After a state update is applied, the root of the state must match the given new root in the state update.
 func (s *State) Update(blockNum uint64, update *core.StateUpdate, declaredClasses map[felt.Felt]core.Class) error {
@@ -289,7 +319,7 @@ func (s *State) GetReverseStateDiff(blockNum uint64, diff *core.StateDiff) (*cor
 		for key := range stDiffs {
 			value := &felt.Zero
 			if blockNum > 0 {
-				oldValue, err := s.ContractStorageAt(addr, key, blockNum-1)
+				oldValue, err := s.ContractStorageAt(&addr, &key, blockNum-1)
 				if err != nil {
 					return nil, err
 				}
@@ -303,7 +333,7 @@ func (s *State) GetReverseStateDiff(blockNum uint64, diff *core.StateDiff) (*cor
 		oldNonce := &felt.Zero
 		if blockNum > 0 {
 			var err error
-			oldNonce, err = s.ContractNonceAt(addr, blockNum-1)
+			oldNonce, err = s.ContractNonceAt(&addr, blockNum-1)
 			if err != nil {
 				return nil, err
 			}
@@ -315,7 +345,7 @@ func (s *State) GetReverseStateDiff(blockNum uint64, diff *core.StateDiff) (*cor
 		oldCh := &felt.Zero
 		if blockNum > 0 {
 			var err error
-			oldCh, err = s.ContractClassHashAt(addr, blockNum-1)
+			oldCh, err = s.ContractClassHashAt(&addr, blockNum-1)
 			if err != nil {
 				return nil, err
 			}
@@ -327,19 +357,19 @@ func (s *State) GetReverseStateDiff(blockNum uint64, diff *core.StateDiff) (*cor
 }
 
 // Returns the storage value of a contract at a given storage key at a given block number.
-func (s *State) ContractStorageAt(addr, key felt.Felt, blockNum uint64) (*felt.Felt, error) {
+func (s *State) ContractStorageAt(addr, key *felt.Felt, blockNum uint64) (*felt.Felt, error) {
 	prefix := db.ContractStorageHistory.Key(addr.Marshal(), key.Marshal())
 	return s.getHistoricalValue(prefix, blockNum)
 }
 
 // Returns the nonce of a contract at a given block number.
-func (s *State) ContractNonceAt(addr felt.Felt, blockNum uint64) (*felt.Felt, error) {
+func (s *State) ContractNonceAt(addr *felt.Felt, blockNum uint64) (*felt.Felt, error) {
 	prefix := db.ContractNonceHistory.Key(addr.Marshal())
 	return s.getHistoricalValue(prefix, blockNum)
 }
 
 // Returns the class hash of a contract at a given block number.
-func (s *State) ContractClassHashAt(addr felt.Felt, blockNum uint64) (*felt.Felt, error) {
+func (s *State) ContractClassHashAt(addr *felt.Felt, blockNum uint64) (*felt.Felt, error) {
 	prefix := db.ContractClassHashHistory.Key(addr.Marshal())
 	return s.getHistoricalValue(prefix, blockNum)
 }
@@ -570,7 +600,7 @@ func (s *State) removeDeclaredClasses(blockNum uint64, v0Classes []*felt.Felt, v
 	}
 
 	for _, cHash := range classHashes {
-		declaredClass, err := s.Class(*cHash)
+		declaredClass, err := s.Class(cHash)
 		if err != nil {
 			return err
 		}
diff --git a/core/state/state_test.go b/core/state/state_test.go
index f9f3059b5b..127b7c0d73 100644
--- a/core/state/state_test.go
+++ b/core/state/state_test.go
@@ -2,7 +2,7 @@ package state
 
 import (
 	"context"
-	"encoding/json"
+	// "encoding/json"
 	"testing"
 
 	"github.com/NethermindEth/juno/clients/feeder"
@@ -120,17 +120,17 @@ func TestUpdate(t *testing.T) {
 		state, err := New(txn)
 		require.NoError(t, err)
 
-		gotValue, err := state.ContractStorage(*scAddr, *scKey)
+		gotValue, err := state.ContractStorage(scAddr, scKey)
 		require.NoError(t, err)
 
 		assert.Equal(t, scValue, gotValue)
 
-		gotNonce, err := state.ContractNonce(*scAddr)
+		gotNonce, err := state.ContractNonce(scAddr)
 		require.NoError(t, err)
 
 		assert.Equal(t, &felt.Zero, gotNonce)
 
-		gotClassHash, err := state.ContractClassHash(*scAddr)
+		gotClassHash, err := state.ContractClassHash(scAddr)
 		require.NoError(t, err)
 
 		assert.Equal(t, &felt.Zero, gotClassHash)
@@ -176,7 +176,7 @@ func TestContractClassHash(t *testing.T) {
 	}
 
 	for addr, expectedClassHash := range allDeployedContracts {
-		gotClassHash, err := state.ContractClassHash(addr)
+		gotClassHash, err := state.ContractClassHash(&addr)
 		require.NoError(t, err)
 
 		assert.Equal(t, expectedClassHash, gotClassHash)
@@ -198,7 +198,7 @@ func TestContractClassHash(t *testing.T) {
 
 		var addr felt.Felt
 		addr.Set(&su1FirstDeployedAddress)
-		gotClassHash, err := state.ContractClassHash(addr)
+		gotClassHash, err := state.ContractClassHash(&addr)
 		require.NoError(t, err)
 
 		assert.Equal(t, utils.HexToFelt(t, "0x1337"), gotClassHash)
@@ -226,7 +226,7 @@ func TestNonce(t *testing.T) {
 
 		require.NoError(t, state.Update(block0, su0, nil))
 
-		nonce, err := state.ContractNonce(*addr)
+		nonce, err := state.ContractNonce(addr)
 		require.NoError(t, err)
 		assert.Equal(t, &felt.Zero, nonce)
 	})
@@ -253,13 +253,14 @@ func TestNonce(t *testing.T) {
 
 		require.NoError(t, state1.Update(block1, su1, nil))
 
-		gotNonce, err := state1.ContractNonce(*addr)
+		gotNonce, err := state1.ContractNonce(addr)
 		require.NoError(t, err)
 		assert.Equal(t, expectedNonce, gotNonce)
 	})
 }
 
 func TestClass(t *testing.T) {
+	t.Skip("TODO(weiihann): remove this once integration is done")
 	txn, commit := setupState(t, nil, 0)
 	defer commit()
 
@@ -283,11 +284,11 @@ func TestClass(t *testing.T) {
 		*cairo1Hash: cairo1Class,
 	}))
 
-	gotCairo1Class, err := state.Class(*cairo1Hash)
+	gotCairo1Class, err := state.Class(cairo1Hash)
 	require.NoError(t, err)
 	assert.Zero(t, gotCairo1Class.At)
 	assert.Equal(t, cairo1Class, gotCairo1Class.Class)
-	gotCairo0Class, err := state.Class(*cairo0Hash)
+	gotCairo0Class, err := state.Class(cairo0Hash)
 	require.NoError(t, err)
 	assert.Zero(t, gotCairo0Class.At)
 	assert.Equal(t, cairo0Class, gotCairo0Class.Class)
@@ -362,7 +363,7 @@ func TestRevert(t *testing.T) {
 		require.NoError(t, err)
 
 		require.NoError(t, state.Update(block2, replaceStateUpdate, nil))
-		gotClassHash, err := state.ContractClassHash(su1FirstDeployedAddress)
+		gotClassHash, err := state.ContractClassHash(&su1FirstDeployedAddress)
 		require.NoError(t, err)
 		assert.Equal(t, replacedVal, gotClassHash)
 
@@ -370,7 +371,7 @@ func TestRevert(t *testing.T) {
 		require.NoError(t, err)
 
 		require.NoError(t, state.Revert(block2, replaceStateUpdate))
-		gotClassHash, err = state.ContractClassHash(su1FirstDeployedAddress)
+		gotClassHash, err = state.ContractClassHash(&su1FirstDeployedAddress)
 		require.NoError(t, err)
 		assert.Equal(t, su1.StateDiff.DeployedContracts[*new(felt.Felt).Set(&su1FirstDeployedAddress)], gotClassHash)
 	})
@@ -391,7 +392,7 @@ func TestRevert(t *testing.T) {
 		require.NoError(t, err)
 
 		require.NoError(t, state.Update(block2, nonceStateUpdate, nil))
-		gotNonce, err := state.ContractNonce(su1FirstDeployedAddress)
+		gotNonce, err := state.ContractNonce(&su1FirstDeployedAddress)
 		require.NoError(t, err)
 		assert.Equal(t, replacedVal, gotNonce)
 
@@ -399,7 +400,7 @@ func TestRevert(t *testing.T) {
 		require.NoError(t, err)
 
 		require.NoError(t, state.Revert(block2, nonceStateUpdate))
-		nonce, sErr := state.ContractNonce(su1FirstDeployedAddress)
+		nonce, sErr := state.ContractNonce(&su1FirstDeployedAddress)
 		require.NoError(t, sErr)
 		assert.Equal(t, &felt.Zero, nonce)
 	})
@@ -422,7 +423,7 @@ func TestRevert(t *testing.T) {
 		require.NoError(t, err)
 
 		require.NoError(t, state.Update(block2, storageStateUpdate, nil))
-		gotStorage, err := state.ContractStorage(su1FirstDeployedAddress, *replacedVal)
+		gotStorage, err := state.ContractStorage(&su1FirstDeployedAddress, replacedVal)
 		require.NoError(t, err)
 		assert.Equal(t, replacedVal, gotStorage)
 
@@ -430,73 +431,73 @@ func TestRevert(t *testing.T) {
 		require.NoError(t, err)
 
 		require.NoError(t, state.Revert(block2, storageStateUpdate))
-		storage, sErr := state.ContractStorage(su1FirstDeployedAddress, *replacedVal)
+		storage, sErr := state.ContractStorage(&su1FirstDeployedAddress, replacedVal)
 		require.NoError(t, sErr)
 		assert.Equal(t, &felt.Zero, storage)
 	})
 
-	t.Run("revert a declare class", func(t *testing.T) {
-		classesM := make(map[felt.Felt]core.Class)
-		cairo0 := &core.Cairo0Class{
-			Abi:          json.RawMessage("some cairo 0 class abi"),
-			Externals:    []core.EntryPoint{{Selector: new(felt.Felt).SetBytes([]byte("e1")), Offset: new(felt.Felt).SetBytes([]byte("e2"))}},
-			L1Handlers:   []core.EntryPoint{{Selector: new(felt.Felt).SetBytes([]byte("l1")), Offset: new(felt.Felt).SetBytes([]byte("l2"))}},
-			Constructors: []core.EntryPoint{{Selector: new(felt.Felt).SetBytes([]byte("c1")), Offset: new(felt.Felt).SetBytes([]byte("c2"))}},
-			Program:      "some cairo 0 program",
-		}
-
-		cairo0Addr := utils.HexToFelt(t, "0xab1234")
-		classesM[*cairo0Addr] = cairo0
-
-		cairo1 := &core.Cairo1Class{
-			Abi:     "some cairo 1 class abi",
-			AbiHash: utils.HexToFelt(t, "0xcd98"),
-			EntryPoints: struct {
-				Constructor []core.SierraEntryPoint
-				External    []core.SierraEntryPoint
-				L1Handler   []core.SierraEntryPoint
-			}{
-				Constructor: []core.SierraEntryPoint{{Index: 1, Selector: new(felt.Felt).SetBytes([]byte("c1"))}},
-				External:    []core.SierraEntryPoint{{Index: 0, Selector: new(felt.Felt).SetBytes([]byte("e1"))}},
-				L1Handler:   []core.SierraEntryPoint{{Index: 2, Selector: new(felt.Felt).SetBytes([]byte("l1"))}},
-			},
-			Program:         []*felt.Felt{new(felt.Felt).SetBytes([]byte("random program"))},
-			ProgramHash:     new(felt.Felt).SetBytes([]byte("random program hash")),
-			SemanticVersion: "version 1",
-			Compiled:        &core.CompiledClass{},
-		}
-
-		cairo1Addr := utils.HexToFelt(t, "0xcd5678")
-		classesM[*cairo1Addr] = cairo1
-
-		declaredClassesStateUpdate := &core.StateUpdate{
-			NewRoot: utils.HexToFelt(t, "0x40427f2f4b5e1d15792e656b4d0c1d1dcf66ece1d8d60276d543aafedcc79d9"),
-			OldRoot: su1.NewRoot,
-			StateDiff: &core.StateDiff{
-				DeclaredV0Classes: []*felt.Felt{cairo0Addr},
-				DeclaredV1Classes: map[felt.Felt]*felt.Felt{
-					*cairo1Addr: utils.HexToFelt(t, "0xef9123"),
-				},
-			},
-		}
-
-		state, err := New(txn)
-		require.NoError(t, err)
-		require.NoError(t, state.Update(block2, declaredClassesStateUpdate, classesM))
-
-		state, err = New(txn)
-		require.NoError(t, err)
-		require.NoError(t, state.Revert(block2, declaredClassesStateUpdate))
-
-		var decClass *DeclaredClass
-		decClass, err = state.Class(*cairo0Addr)
-		assert.ErrorIs(t, err, db.ErrKeyNotFound)
-		assert.Nil(t, decClass)
-
-		decClass, err = state.Class(*cairo1Addr)
-		assert.ErrorIs(t, err, db.ErrKeyNotFound)
-		assert.Nil(t, decClass)
-	})
+	// t.Run("revert a declare class", func(t *testing.T) {
+	// 	classesM := make(map[felt.Felt]core.Class)
+	// 	cairo0 := &core.Cairo0Class{
+	// 		Abi:          json.RawMessage("some cairo 0 class abi"),
+	// 		Externals:    []core.EntryPoint{{Selector: new(felt.Felt).SetBytes([]byte("e1")), Offset: new(felt.Felt).SetBytes([]byte("e2"))}},
+	// 		L1Handlers:   []core.EntryPoint{{Selector: new(felt.Felt).SetBytes([]byte("l1")), Offset: new(felt.Felt).SetBytes([]byte("l2"))}},
+	// 		Constructors: []core.EntryPoint{{Selector: new(felt.Felt).SetBytes([]byte("c1")), Offset: new(felt.Felt).SetBytes([]byte("c2"))}},
+	// 		Program:      "some cairo 0 program",
+	// 	}
+
+	// 	cairo0Addr := utils.HexToFelt(t, "0xab1234")
+	// 	classesM[*cairo0Addr] = cairo0
+
+	// 	cairo1 := &core.Cairo1Class{
+	// 		Abi:     "some cairo 1 class abi",
+	// 		AbiHash: utils.HexToFelt(t, "0xcd98"),
+	// 		EntryPoints: struct {
+	// 			Constructor []core.SierraEntryPoint
+	// 			External    []core.SierraEntryPoint
+	// 			L1Handler   []core.SierraEntryPoint
+	// 		}{
+	// 			Constructor: []core.SierraEntryPoint{{Index: 1, Selector: new(felt.Felt).SetBytes([]byte("c1"))}},
+	// 			External:    []core.SierraEntryPoint{{Index: 0, Selector: new(felt.Felt).SetBytes([]byte("e1"))}},
+	// 			L1Handler:   []core.SierraEntryPoint{{Index: 2, Selector: new(felt.Felt).SetBytes([]byte("l1"))}},
+	// 		},
+	// 		Program:         []*felt.Felt{new(felt.Felt).SetBytes([]byte("random program"))},
+	// 		ProgramHash:     new(felt.Felt).SetBytes([]byte("random program hash")),
+	// 		SemanticVersion: "version 1",
+	// 		Compiled:        &core.CompiledClass{},
+	// 	}
+
+	// 	cairo1Addr := utils.HexToFelt(t, "0xcd5678")
+	// 	classesM[*cairo1Addr] = cairo1
+
+	// 	declaredClassesStateUpdate := &core.StateUpdate{
+	// 		NewRoot: utils.HexToFelt(t, "0x40427f2f4b5e1d15792e656b4d0c1d1dcf66ece1d8d60276d543aafedcc79d9"),
+	// 		OldRoot: su1.NewRoot,
+	// 		StateDiff: &core.StateDiff{
+	// 			DeclaredV0Classes: []*felt.Felt{cairo0Addr},
+	// 			DeclaredV1Classes: map[felt.Felt]*felt.Felt{
+	// 				*cairo1Addr: utils.HexToFelt(t, "0xef9123"),
+	// 			},
+	// 		},
+	// 	}
+
+	// 	state, err := New(txn)
+	// 	require.NoError(t, err)
+	// 	require.NoError(t, state.Update(block2, declaredClassesStateUpdate, classesM))
+
+	// 	state, err = New(txn)
+	// 	require.NoError(t, err)
+	// 	require.NoError(t, state.Revert(block2, declaredClassesStateUpdate))
+
+	// 	var decClass *DeclaredClass
+	// 	decClass, err = state.Class(cairo0Addr)
+	// 	assert.ErrorIs(t, err, db.ErrKeyNotFound)
+	// 	assert.Nil(t, decClass)
+
+	// 	decClass, err = state.Class(cairo1Addr)
+	// 	assert.ErrorIs(t, err, db.ErrKeyNotFound)
+	// 	assert.Nil(t, decClass)
+	// })
 
 	t.Run("should be able to update after a revert", func(t *testing.T) {
 		state, err := New(txn)
@@ -580,10 +581,10 @@ func TestRevert(t *testing.T) {
 		require.NoError(t, err)
 		require.NoError(t, state.Update(block0, declareDiff, newClasses))
 
-		declaredClass, err := state.Class(*classHash)
+		declaredClass, err := state.Class(classHash)
 		require.NoError(t, err)
 		assert.Equal(t, uint64(0), declaredClass.At)
-		sierraClass, err := state.Class(*sierraHash)
+		sierraClass, err := state.Class(sierraHash)
 		require.NoError(t, err)
 		assert.Equal(t, uint64(0), sierraClass.At)
 
@@ -593,10 +594,10 @@ func TestRevert(t *testing.T) {
 		require.NoError(t, state.Update(block1, declareDiff, newClasses))
 
 		// Redeclaring should not change the declared at block number
-		declaredClass, err = state.Class(*classHash)
+		declaredClass, err = state.Class(classHash)
 		require.NoError(t, err)
 		assert.Equal(t, uint64(0), declaredClass.At)
-		sierraClass, err = state.Class(*sierraHash)
+		sierraClass, err = state.Class(sierraHash)
 		require.NoError(t, err)
 		assert.Equal(t, uint64(0), sierraClass.At)
 
@@ -605,10 +606,10 @@ func TestRevert(t *testing.T) {
 		require.NoError(t, state.Revert(block1, declareDiff))
 
 		// Reverting a re-declaration should not change state commitment or remove class definitions
-		declaredClass, err = state.Class(*classHash)
+		declaredClass, err = state.Class(classHash)
 		require.NoError(t, err)
 		assert.Equal(t, uint64(0), declaredClass.At)
-		sierraClass, err = state.Class(*sierraHash)
+		sierraClass, err = state.Class(sierraHash)
 		require.NoError(t, err)
 		assert.Equal(t, uint64(0), sierraClass.At)
 
@@ -617,10 +618,10 @@ func TestRevert(t *testing.T) {
 		declareDiff.OldRoot = &felt.Zero
 		require.NoError(t, state.Revert(block0, declareDiff))
 
-		declaredClass, err = state.Class(*classHash)
+		declaredClass, err = state.Class(classHash)
 		require.ErrorIs(t, err, db.ErrKeyNotFound)
 		assert.Nil(t, declaredClass)
-		sierraClass, err = state.Class(*sierraHash)
+		sierraClass, err = state.Class(sierraHash)
 		require.ErrorIs(t, err, db.ErrKeyNotFound)
 		assert.Nil(t, sierraClass)
 	})
@@ -653,6 +654,31 @@ func TestRevert(t *testing.T) {
 		require.NoError(t, err)
 		require.NoError(t, state.Revert(block0, su))
 	})
+
+	t.Run("db should be empty after block0 revert", func(t *testing.T) {
+		t.Skip("TODO(weiihann):still has some leftover data in the db, resolve this")
+		txn, commit := setupState(t, stateUpdates, 1)
+		defer commit()
+
+		state, err := New(txn)
+		require.NoError(t, err)
+
+		require.NoError(t, state.Revert(block0, stateUpdates[0]))
+
+		it, err := txn.NewIterator(nil, false)
+		require.NoError(t, err)
+		defer it.Close()
+
+		if it.First() {
+			t.Errorf("db should be empty")
+			for it.First(); it.Next(); it.Valid() {
+				key := it.Key()
+				val, err := it.Value()
+				require.NoError(t, err)
+				t.Errorf("key: %v, val: %v", key, val)
+			}
+		}
+	})
 }
 
 func TestContractHistory(t *testing.T) {
@@ -673,15 +699,15 @@ func TestContractHistory(t *testing.T) {
 		state, err := New(txn)
 		require.NoError(t, err)
 
-		nonce, err := state.ContractNonceAt(*addr, block0)
+		nonce, err := state.ContractNonceAt(addr, block0)
 		require.NoError(t, err)
 		assert.Equal(t, &felt.Zero, nonce)
 
-		classHash, err := state.ContractClassHashAt(*addr, block0)
+		classHash, err := state.ContractClassHashAt(addr, block0)
 		require.NoError(t, err)
 		assert.Equal(t, &felt.Zero, classHash)
 
-		storage, err := state.ContractStorageAt(*addr, *storageKey, block0)
+		storage, err := state.ContractStorageAt(addr, storageKey, block0)
 		require.NoError(t, err)
 		assert.Equal(t, &felt.Zero, storage)
 	})
@@ -694,15 +720,15 @@ func TestContractHistory(t *testing.T) {
 		state, err := New(txn)
 		require.NoError(t, err)
 
-		gotClassHash, err := state.ContractClassHashAt(*addr, block2)
+		gotClassHash, err := state.ContractClassHashAt(addr, block2)
 		require.NoError(t, err)
 		assert.Equal(t, classHash, gotClassHash)
 
-		gotNonce, err := state.ContractNonceAt(*addr, block2)
+		gotNonce, err := state.ContractNonceAt(addr, block2)
 		require.NoError(t, err)
 		assert.Equal(t, nonce, gotNonce)
 
-		gotStorage, err := state.ContractStorageAt(*addr, *storageKey, block2)
+		gotStorage, err := state.ContractStorageAt(addr, storageKey, block2)
 		require.NoError(t, err)
 		assert.Equal(t, storageValue, gotStorage)
 	})
@@ -714,15 +740,15 @@ func TestContractHistory(t *testing.T) {
 		state, err := New(txn)
 		require.NoError(t, err)
 
-		gotClassHash, err := state.ContractClassHashAt(*addr, block1)
+		gotClassHash, err := state.ContractClassHashAt(addr, block1)
 		require.NoError(t, err)
 		assert.Equal(t, &felt.Zero, gotClassHash)
 
-		gotNonce, err := state.ContractNonceAt(*addr, block1)
+		gotNonce, err := state.ContractNonceAt(addr, block1)
 		require.NoError(t, err)
 		assert.Equal(t, &felt.Zero, gotNonce)
 
-		gotStorage, err := state.ContractStorageAt(*addr, *storageKey, block1)
+		gotStorage, err := state.ContractStorageAt(addr, storageKey, block1)
 		require.NoError(t, err)
 		assert.Equal(t, &felt.Zero, gotStorage)
 	})
@@ -743,15 +769,15 @@ func TestContractHistory(t *testing.T) {
 		state, err := New(txn)
 		require.NoError(t, err)
 
-		gotClassHash, err := state.ContractClassHashAt(*addr, block1)
+		gotClassHash, err := state.ContractClassHashAt(addr, block1)
 		require.NoError(t, err)
 		assert.Equal(t, classHash, gotClassHash)
 
-		gotNonce, err := state.ContractNonceAt(*addr, block1)
+		gotNonce, err := state.ContractNonceAt(addr, block1)
 		require.NoError(t, err)
 		assert.Equal(t, nonce, gotNonce)
 
-		gotStorage, err := state.ContractStorageAt(*addr, *storageKey, block1)
+		gotStorage, err := state.ContractStorageAt(addr, storageKey, block1)
 		require.NoError(t, err)
 		assert.Equal(t, storageValue, gotStorage)
 	})
diff --git a/core/state_test.go b/core/state_test.go
deleted file mode 100644
index 4a70735396..0000000000
--- a/core/state_test.go
+++ /dev/null
@@ -1,680 +0,0 @@
-package core_test
-
-import (
-	"context"
-	"encoding/json"
-	"fmt"
-	"testing"
-
-	"github.com/NethermindEth/juno/clients/feeder"
-	"github.com/NethermindEth/juno/core"
-	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/db"
-	"github.com/NethermindEth/juno/db/pebble"
-	adaptfeeder "github.com/NethermindEth/juno/starknetdata/feeder"
-	"github.com/NethermindEth/juno/utils"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-// Address of first deployed contract in mainnet block 1's state update.
-var (
-	_su1FirstDeployedAddress, _ = new(felt.Felt).SetString("0x6538fdd3aa353af8a87f5fe77d1f533ea82815076e30a86d65b72d3eb4f0b80")
-	su1FirstDeployedAddress     = *_su1FirstDeployedAddress
-)
-
-func TestUpdate(t *testing.T) {
-	client := feeder.NewTestClient(t, &utils.Mainnet)
-	gw := adaptfeeder.New(client)
-
-	testDB := pebble.NewMemTest(t)
-	txn, err := testDB.NewTransaction(true)
-	require.NoError(t, err)
-	t.Cleanup(func() {
-		require.NoError(t, txn.Discard())
-	})
-
-	state := core.NewState(txn)
-
-	su0, err := gw.StateUpdate(context.Background(), 0)
-	require.NoError(t, err)
-
-	su1, err := gw.StateUpdate(context.Background(), 1)
-	require.NoError(t, err)
-
-	su2, err := gw.StateUpdate(context.Background(), 2)
-	require.NoError(t, err)
-
-	t.Run("empty state updated with mainnet block 0 state update", func(t *testing.T) {
-		require.NoError(t, state.Update(0, su0, nil))
-		gotNewRoot, rerr := state.Root()
-		require.NoError(t, rerr)
-		assert.Equal(t, su0.NewRoot, gotNewRoot)
-	})
-
-	t.Run("error when state current root doesn't match state update's old root", func(t *testing.T) {
-		oldRoot := new(felt.Felt).SetBytes([]byte("some old root"))
-		su := &core.StateUpdate{
-			OldRoot: oldRoot,
-		}
-		expectedErr := fmt.Sprintf("state's current root: %s does not match the expected root: %s", su0.NewRoot, oldRoot)
-		require.EqualError(t, state.Update(1, su, nil), expectedErr)
-	})
-
-	t.Run("error when state new root doesn't match state update's new root", func(t *testing.T) {
-		newRoot := new(felt.Felt).SetBytes([]byte("some new root"))
-		su := &core.StateUpdate{
-			NewRoot:   newRoot,
-			OldRoot:   su0.NewRoot,
-			StateDiff: new(core.StateDiff),
-		}
-		expectedErr := fmt.Sprintf("state's current root: %s does not match the expected root: %s", su0.NewRoot, newRoot)
-		require.EqualError(t, state.Update(1, su, nil), expectedErr)
-	})
-
-	t.Run("non-empty state updated multiple times", func(t *testing.T) {
-		require.NoError(t, state.Update(1, su1, nil))
-		gotNewRoot, rerr := state.Root()
-		require.NoError(t, rerr)
-		assert.Equal(t, su1.NewRoot, gotNewRoot)
-
-		require.NoError(t, state.Update(2, su2, nil))
-		gotNewRoot, err = state.Root()
-		require.NoError(t, err)
-		assert.Equal(t, su2.NewRoot, gotNewRoot)
-	})
-
-	su3 := &core.StateUpdate{
-		OldRoot: su2.NewRoot,
-		NewRoot: utils.HexToFelt(t, "0x46f1033cfb8e0b2e16e1ad6f95c41fd3a123f168fe72665452b6cddbc1d8e7a"),
-		StateDiff: &core.StateDiff{
-			DeclaredV1Classes: map[felt.Felt]*felt.Felt{
-				*utils.HexToFelt(t, "0xDEADBEEF"): utils.HexToFelt(t, "0xBEEFDEAD"),
-			},
-		},
-	}
-
-	t.Run("post v0.11.0 declared classes affect root", func(t *testing.T) {
-		t.Run("without class definition", func(t *testing.T) {
-			require.Error(t, state.Update(3, su3, nil))
-		})
-		require.NoError(t, state.Update(3, su3, map[felt.Felt]core.Class{
-			*utils.HexToFelt(t, "0xDEADBEEF"): &core.Cairo1Class{},
-		}))
-		assert.NotEqual(t, su3.NewRoot, su3.OldRoot)
-	})
-
-	// These value were taken from part of integration state update number 299762
-	// https://external.integration.starknet.io/feeder_gateway/get_state_update?blockNumber=299762
-	scKey := utils.HexToFelt(t, "0x492e8")
-	scValue := utils.HexToFelt(t, "0x10979c6b0b36b03be36739a21cc43a51076545ce6d3397f1b45c7e286474ad5")
-	scAddr := new(felt.Felt).SetUint64(1)
-
-	su4 := &core.StateUpdate{
-		OldRoot: su3.NewRoot,
-		NewRoot: utils.HexToFelt(t, "0x68ac0196d9b6276b8d86f9e92bca0ed9f854d06ded5b7f0b8bc0eeaa4377d9e"),
-		StateDiff: &core.StateDiff{
-			StorageDiffs: map[felt.Felt]map[felt.Felt]*felt.Felt{*scAddr: {*scKey: scValue}},
-		},
-	}
-
-	t.Run("update systemContracts storage", func(t *testing.T) {
-		require.NoError(t, state.Update(4, su4, nil))
-
-		gotValue, err := state.ContractStorage(scAddr, scKey)
-		require.NoError(t, err)
-
-		assert.Equal(t, scValue, gotValue)
-
-		gotNonce, err := state.ContractNonce(scAddr)
-		require.NoError(t, err)
-
-		assert.Equal(t, &felt.Zero, gotNonce)
-
-		gotClassHash, err := state.ContractClassHash(scAddr)
-		require.NoError(t, err)
-
-		assert.Equal(t, &felt.Zero, gotClassHash)
-	})
-
-	t.Run("cannot update unknown noClassContract", func(t *testing.T) {
-		scAddr2 := utils.HexToFelt(t, "0x10")
-		su5 := &core.StateUpdate{
-			OldRoot: su4.NewRoot,
-			NewRoot: utils.HexToFelt(t, "0x68ac0196d9b6276b8d86f9e92bca0ed9f854d06ded5b7f0b8bc0eeaa4377d9e"),
-			StateDiff: &core.StateDiff{
-				StorageDiffs: map[felt.Felt]map[felt.Felt]*felt.Felt{*scAddr2: {*scKey: scValue}},
-			},
-		}
-		assert.ErrorIs(t, state.Update(5, su5, nil), core.ErrContractNotDeployed)
-	})
-}
-
-func TestContractClassHash(t *testing.T) {
-	client := feeder.NewTestClient(t, &utils.Mainnet)
-	gw := adaptfeeder.New(client)
-
-	testDB := pebble.NewMemTest(t)
-	txn, err := testDB.NewTransaction(true)
-	require.NoError(t, err)
-	t.Cleanup(func() {
-		require.NoError(t, txn.Discard())
-	})
-
-	state := core.NewState(txn)
-
-	su0, err := gw.StateUpdate(context.Background(), 0)
-	require.NoError(t, err)
-
-	su1, err := gw.StateUpdate(context.Background(), 1)
-	require.NoError(t, err)
-
-	require.NoError(t, state.Update(0, su0, nil))
-	require.NoError(t, state.Update(1, su1, nil))
-
-	allDeployedContracts := make(map[felt.Felt]*felt.Felt)
-
-	for addr, classHash := range su0.StateDiff.DeployedContracts {
-		allDeployedContracts[addr] = classHash
-	}
-
-	for addr, classHash := range su1.StateDiff.DeployedContracts {
-		allDeployedContracts[addr] = classHash
-	}
-
-	for addr, expectedClassHash := range allDeployedContracts {
-		gotClassHash, err := state.ContractClassHash(&addr)
-		require.NoError(t, err)
-
-		assert.Equal(t, expectedClassHash, gotClassHash)
-	}
-
-	t.Run("replace class hash", func(t *testing.T) {
-		replaceUpdate := &core.StateUpdate{
-			OldRoot:   su1.NewRoot,
-			BlockHash: utils.HexToFelt(t, "0xDEADBEEF"),
-			NewRoot:   utils.HexToFelt(t, "0x484ff378143158f9af55a1210b380853ae155dfdd8cd4c228f9ece918bb982b"),
-			StateDiff: &core.StateDiff{
-				ReplacedClasses: map[felt.Felt]*felt.Felt{
-					su1FirstDeployedAddress: utils.HexToFelt(t, "0x1337"),
-				},
-			},
-		}
-
-		require.NoError(t, state.Update(2, replaceUpdate, nil))
-
-		gotClassHash, err := state.ContractClassHash(new(felt.Felt).Set(&su1FirstDeployedAddress))
-		require.NoError(t, err)
-
-		assert.Equal(t, utils.HexToFelt(t, "0x1337"), gotClassHash)
-	})
-}
-
-func TestNonce(t *testing.T) {
-	testDB := pebble.NewMemTest(t)
-	txn, err := testDB.NewTransaction(true)
-	require.NoError(t, err)
-	t.Cleanup(func() {
-		require.NoError(t, txn.Discard())
-	})
-
-	state := core.NewState(txn)
-
-	addr := utils.HexToFelt(t, "0x20cfa74ee3564b4cd5435cdace0f9c4d43b939620e4a0bb5076105df0a626c6")
-	root := utils.HexToFelt(t, "0x4bdef7bf8b81a868aeab4b48ef952415fe105ab479e2f7bc671c92173542368")
-
-	su := &core.StateUpdate{
-		OldRoot: &felt.Zero,
-		NewRoot: root,
-		StateDiff: &core.StateDiff{
-			DeployedContracts: map[felt.Felt]*felt.Felt{
-				*addr: utils.HexToFelt(t, "0x10455c752b86932ce552f2b0fe81a880746649b9aee7e0d842bf3f52378f9f8"),
-			},
-		},
-	}
-
-	require.NoError(t, state.Update(0, su, nil))
-
-	t.Run("newly deployed contract has zero nonce", func(t *testing.T) {
-		nonce, err := state.ContractNonce(addr)
-		require.NoError(t, err)
-		assert.Equal(t, &felt.Zero, nonce)
-	})
-
-	t.Run("update contract nonce", func(t *testing.T) {
-		expectedNonce := new(felt.Felt).SetUint64(1)
-		su = &core.StateUpdate{
-			NewRoot: utils.HexToFelt(t, "0x6210642ffd49f64617fc9e5c0bbe53a6a92769e2996eb312a42d2bdb7f2afc1"),
-			OldRoot: root,
-			StateDiff: &core.StateDiff{
-				Nonces: map[felt.Felt]*felt.Felt{*addr: expectedNonce},
-			},
-		}
-
-		require.NoError(t, state.Update(1, su, nil))
-
-		gotNonce, err := state.ContractNonce(addr)
-		require.NoError(t, err)
-		assert.Equal(t, expectedNonce, gotNonce)
-	})
-}
-
-func TestStateHistory(t *testing.T) {
-	testDB := pebble.NewMemTest(t)
-	txn, err := testDB.NewTransaction(true)
-	require.NoError(t, err)
-	t.Cleanup(func() {
-		require.NoError(t, txn.Discard())
-	})
-
-	client := feeder.NewTestClient(t, &utils.Mainnet)
-	gw := adaptfeeder.New(client)
-
-	state := core.NewState(txn)
-	su0, err := gw.StateUpdate(context.Background(), 0)
-	require.NoError(t, err)
-	require.NoError(t, state.Update(0, su0, nil))
-
-	contractAddr := utils.HexToFelt(t, "0x20cfa74ee3564b4cd5435cdace0f9c4d43b939620e4a0bb5076105df0a626c6")
-	changedLoc := utils.HexToFelt(t, "0x5")
-	t.Run("should return an error for a location that changed on the given height", func(t *testing.T) {
-		_, err = state.ContractStorageAt(contractAddr, changedLoc, 0)
-		assert.ErrorIs(t, err, core.ErrCheckHeadState)
-	})
-
-	t.Run("should return an error for not changed location", func(t *testing.T) {
-		_, err := state.ContractStorageAt(contractAddr, utils.HexToFelt(t, "0xDEADBEEF"), 0)
-		assert.ErrorIs(t, err, core.ErrCheckHeadState)
-	})
-
-	// update the same location again
-	su := &core.StateUpdate{
-		NewRoot: utils.HexToFelt(t, "0xac747e0ea7497dad7407ecf2baf24b1598b0b40943207fc9af8ded09a64f1c"),
-		OldRoot: su0.NewRoot,
-		StateDiff: &core.StateDiff{
-			StorageDiffs: map[felt.Felt]map[felt.Felt]*felt.Felt{
-				*contractAddr: {
-					*changedLoc: utils.HexToFelt(t, "0x44"),
-				},
-			},
-		},
-	}
-	require.NoError(t, state.Update(1, su, nil))
-
-	t.Run("should give old value for a location that changed after the given height", func(t *testing.T) {
-		oldValue, err := state.ContractStorageAt(contractAddr, changedLoc, 0)
-		require.NoError(t, err)
-		require.Equal(t, oldValue, utils.HexToFelt(t, "0x22b"))
-	})
-}
-
-func TestContractIsDeployedAt(t *testing.T) {
-	client := feeder.NewTestClient(t, &utils.Mainnet)
-	gw := adaptfeeder.New(client)
-
-	testDB := pebble.NewMemTest(t)
-	txn, err := testDB.NewTransaction(true)
-	require.NoError(t, err)
-	t.Cleanup(func() {
-		require.NoError(t, txn.Discard())
-	})
-
-	state := core.NewState(txn)
-
-	su0, err := gw.StateUpdate(context.Background(), 0)
-	require.NoError(t, err)
-
-	su1, err := gw.StateUpdate(context.Background(), 1)
-	require.NoError(t, err)
-
-	require.NoError(t, state.Update(0, su0, nil))
-	require.NoError(t, state.Update(1, su1, nil))
-
-	t.Run("deployed on genesis", func(t *testing.T) {
-		deployedOn0 := utils.HexToFelt(t, "0x20cfa74ee3564b4cd5435cdace0f9c4d43b939620e4a0bb5076105df0a626c6")
-		deployed, err := state.ContractIsAlreadyDeployedAt(deployedOn0, 0)
-		require.NoError(t, err)
-		assert.True(t, deployed)
-
-		deployed, err = state.ContractIsAlreadyDeployedAt(deployedOn0, 1)
-		require.NoError(t, err)
-		assert.True(t, deployed)
-	})
-
-	t.Run("deployed after genesis", func(t *testing.T) {
-		deployedOn1 := utils.HexToFelt(t, "0x6538fdd3aa353af8a87f5fe77d1f533ea82815076e30a86d65b72d3eb4f0b80")
-		deployed, err := state.ContractIsAlreadyDeployedAt(deployedOn1, 0)
-		require.NoError(t, err)
-		assert.False(t, deployed)
-
-		deployed, err = state.ContractIsAlreadyDeployedAt(deployedOn1, 1)
-		require.NoError(t, err)
-		assert.True(t, deployed)
-	})
-
-	t.Run("not deployed", func(t *testing.T) {
-		notDeployed := utils.HexToFelt(t, "0xDEADBEEF")
-		deployed, err := state.ContractIsAlreadyDeployedAt(notDeployed, 1)
-		require.NoError(t, err)
-		assert.False(t, deployed)
-	})
-}
-
-func TestClass(t *testing.T) {
-	testDB := pebble.NewMemTest(t)
-	txn, err := testDB.NewTransaction(true)
-	require.NoError(t, err)
-	t.Cleanup(func() {
-		require.NoError(t, txn.Discard())
-	})
-
-	client := feeder.NewTestClient(t, &utils.Integration)
-	gw := adaptfeeder.New(client)
-
-	cairo0Hash := utils.HexToFelt(t, "0x4631b6b3fa31e140524b7d21ba784cea223e618bffe60b5bbdca44a8b45be04")
-	cairo0Class, err := gw.Class(context.Background(), cairo0Hash)
-	require.NoError(t, err)
-	cairo1Hash := utils.HexToFelt(t, "0x1cd2edfb485241c4403254d550de0a097fa76743cd30696f714a491a454bad5")
-	cairo1Class, err := gw.Class(context.Background(), cairo0Hash)
-	require.NoError(t, err)
-
-	state := core.NewState(txn)
-	su0, err := gw.StateUpdate(context.Background(), 0)
-	require.NoError(t, err)
-	require.NoError(t, state.Update(0, su0, map[felt.Felt]core.Class{
-		*cairo0Hash: cairo0Class,
-		*cairo1Hash: cairo1Class,
-	}))
-
-	gotCairo1Class, err := state.Class(cairo1Hash)
-	require.NoError(t, err)
-	assert.Zero(t, gotCairo1Class.At)
-	assert.Equal(t, cairo1Class, gotCairo1Class.Class)
-	gotCairo0Class, err := state.Class(cairo0Hash)
-	require.NoError(t, err)
-	assert.Zero(t, gotCairo0Class.At)
-	assert.Equal(t, cairo0Class, gotCairo0Class.Class)
-}
-
-func TestRevert(t *testing.T) {
-	testDB := pebble.NewMemTest(t)
-	txn, err := testDB.NewTransaction(true)
-	require.NoError(t, err)
-	t.Cleanup(func() {
-		require.NoError(t, txn.Discard())
-	})
-
-	client := feeder.NewTestClient(t, &utils.Mainnet)
-	gw := adaptfeeder.New(client)
-
-	state := core.NewState(txn)
-	su0, err := gw.StateUpdate(context.Background(), 0)
-	require.NoError(t, err)
-	require.NoError(t, state.Update(0, su0, nil))
-	su1, err := gw.StateUpdate(context.Background(), 1)
-	require.NoError(t, err)
-	require.NoError(t, state.Update(1, su1, nil))
-
-	t.Run("revert a replaced class", func(t *testing.T) {
-		replaceStateUpdate := &core.StateUpdate{
-			NewRoot: utils.HexToFelt(t, "0x30b1741b28893b892ac30350e6372eac3a6f32edee12f9cdca7fbe7540a5ee"),
-			OldRoot: su1.NewRoot,
-			StateDiff: &core.StateDiff{
-				ReplacedClasses: map[felt.Felt]*felt.Felt{
-					su1FirstDeployedAddress: utils.HexToFelt(t, "0xDEADBEEF"),
-				},
-			},
-		}
-
-		require.NoError(t, state.Update(2, replaceStateUpdate, nil))
-		require.NoError(t, state.Revert(2, replaceStateUpdate))
-		classHash, sErr := state.ContractClassHash(new(felt.Felt).Set(&su1FirstDeployedAddress))
-		require.NoError(t, sErr)
-		assert.Equal(t, su1.StateDiff.DeployedContracts[*new(felt.Felt).Set(&su1FirstDeployedAddress)], classHash)
-	})
-
-	t.Run("revert a nonce update", func(t *testing.T) {
-		nonceStateUpdate := &core.StateUpdate{
-			NewRoot: utils.HexToFelt(t, "0x6683657d2b6797d95f318e7c6091dc2255de86b72023c15b620af12543eb62c"),
-			OldRoot: su1.NewRoot,
-			StateDiff: &core.StateDiff{
-				Nonces: map[felt.Felt]*felt.Felt{
-					su1FirstDeployedAddress: utils.HexToFelt(t, "0xDEADBEEF"),
-				},
-			},
-		}
-
-		require.NoError(t, state.Update(2, nonceStateUpdate, nil))
-		require.NoError(t, state.Revert(2, nonceStateUpdate))
-		nonce, sErr := state.ContractNonce(new(felt.Felt).Set(&su1FirstDeployedAddress))
-		require.NoError(t, sErr)
-		assert.Equal(t, &felt.Zero, nonce)
-	})
-
-	t.Run("revert declared classes", func(t *testing.T) {
-		classesM := make(map[felt.Felt]core.Class)
-		cairo0 := &core.Cairo0Class{
-			Abi:          json.RawMessage("some cairo 0 class abi"),
-			Externals:    []core.EntryPoint{{new(felt.Felt).SetBytes([]byte("e1")), new(felt.Felt).SetBytes([]byte("e2"))}},
-			L1Handlers:   []core.EntryPoint{{new(felt.Felt).SetBytes([]byte("l1")), new(felt.Felt).SetBytes([]byte("l2"))}},
-			Constructors: []core.EntryPoint{{new(felt.Felt).SetBytes([]byte("c1")), new(felt.Felt).SetBytes([]byte("c2"))}},
-			Program:      "some cairo 0 program",
-		}
-
-		cairo0Addr := utils.HexToFelt(t, "0xab1234")
-		classesM[*cairo0Addr] = cairo0
-
-		cairo1 := &core.Cairo1Class{
-			Abi:     "some cairo 1 class abi",
-			AbiHash: utils.HexToFelt(t, "0xcd98"),
-			EntryPoints: struct {
-				Constructor []core.SierraEntryPoint
-				External    []core.SierraEntryPoint
-				L1Handler   []core.SierraEntryPoint
-			}{
-				Constructor: []core.SierraEntryPoint{{1, new(felt.Felt).SetBytes([]byte("c1"))}},
-				External:    []core.SierraEntryPoint{{0, new(felt.Felt).SetBytes([]byte("e1"))}},
-				L1Handler:   []core.SierraEntryPoint{{2, new(felt.Felt).SetBytes([]byte("l1"))}},
-			},
-			Program:         []*felt.Felt{new(felt.Felt).SetBytes([]byte("random program"))},
-			ProgramHash:     new(felt.Felt).SetBytes([]byte("random program hash")),
-			SemanticVersion: "version 1",
-			Compiled:        &core.CompiledClass{},
-		}
-
-		cairo1Addr := utils.HexToFelt(t, "0xcd5678")
-		classesM[*cairo1Addr] = cairo1
-
-		declaredClassesStateUpdate := &core.StateUpdate{
-			NewRoot: utils.HexToFelt(t, "0x40427f2f4b5e1d15792e656b4d0c1d1dcf66ece1d8d60276d543aafedcc79d9"),
-			OldRoot: su1.NewRoot,
-			StateDiff: &core.StateDiff{
-				DeclaredV0Classes: []*felt.Felt{cairo0Addr},
-				DeclaredV1Classes: map[felt.Felt]*felt.Felt{
-					*cairo1Addr: utils.HexToFelt(t, "0xef9123"),
-				},
-			},
-		}
-
-		require.NoError(t, state.Update(2, declaredClassesStateUpdate, classesM))
-		require.NoError(t, state.Revert(2, declaredClassesStateUpdate))
-
-		var decClass *core.DeclaredClass
-		decClass, err = state.Class(cairo0Addr)
-		assert.ErrorIs(t, err, db.ErrKeyNotFound)
-		assert.Nil(t, decClass)
-
-		decClass, err = state.Class(cairo1Addr)
-		assert.ErrorIs(t, err, db.ErrKeyNotFound)
-		assert.Nil(t, decClass)
-	})
-
-	su2, err := gw.StateUpdate(context.Background(), 2)
-	require.NoError(t, err)
-	t.Run("should be able to apply new update after a Revert", func(t *testing.T) {
-		require.NoError(t, state.Update(2, su2, nil))
-	})
-
-	t.Run("should be able to revert all the state", func(t *testing.T) {
-		require.NoError(t, state.Revert(2, su2))
-		root, err := state.Root()
-		require.NoError(t, err)
-		require.Equal(t, su2.OldRoot, root)
-		require.NoError(t, state.Revert(1, su1))
-		root, err = state.Root()
-		require.NoError(t, err)
-		require.Equal(t, su1.OldRoot, root)
-		require.NoError(t, state.Revert(0, su0))
-		root, err = state.Root()
-		require.NoError(t, err)
-		require.Equal(t, su0.OldRoot, root)
-	})
-
-	t.Run("empty state should mean empty db", func(t *testing.T) {
-		require.NoError(t, testDB.View(func(txn db.Transaction) error {
-			it, err := txn.NewIterator(nil, false)
-			if err != nil {
-				return err
-			}
-			assert.False(t, it.Next())
-			return it.Close()
-		}))
-	})
-}
-
-// TestRevertGenesisStateDiff ensures the reverse diff for the genesis block sets all storage values to zero.
-func TestRevertGenesisStateDiff(t *testing.T) {
-	testDB := pebble.NewMemTest(t)
-	txn, err := testDB.NewTransaction(true)
-	require.NoError(t, err)
-	t.Cleanup(func() {
-		require.NoError(t, txn.Discard())
-	})
-	state := core.NewState(txn)
-
-	addr := new(felt.Felt).SetUint64(1)
-	key := new(felt.Felt).SetUint64(2)
-	value := new(felt.Felt).SetUint64(3)
-	su := &core.StateUpdate{
-		BlockHash: new(felt.Felt),
-		NewRoot:   utils.HexToFelt(t, "0xa89ee2d272016fd3708435efda2ce766692231f8c162e27065ce1607d5a9e8"),
-		OldRoot:   new(felt.Felt),
-		StateDiff: &core.StateDiff{
-			StorageDiffs: map[felt.Felt]map[felt.Felt]*felt.Felt{
-				*addr: {
-					*key: value,
-				},
-			},
-		},
-	}
-	require.NoError(t, state.Update(0, su, nil))
-	require.NoError(t, state.Revert(0, su))
-}
-
-func TestRevertSystemContracts(t *testing.T) {
-	client := feeder.NewTestClient(t, &utils.Mainnet)
-	gw := adaptfeeder.New(client)
-
-	testDB := pebble.NewMemTest(t)
-	txn, err := testDB.NewTransaction(true)
-	require.NoError(t, err)
-	t.Cleanup(func() {
-		require.NoError(t, txn.Discard())
-	})
-
-	state := core.NewState(txn)
-
-	su0, err := gw.StateUpdate(context.Background(), 0)
-	require.NoError(t, err)
-
-	require.NoError(t, state.Update(0, su0, nil))
-
-	su1, err := gw.StateUpdate(context.Background(), 1)
-	require.NoError(t, err)
-
-	// These value were taken from part of integration state update number 299762
-	// https://external.integration.starknet.io/feeder_gateway/get_state_update?blockNumber=299762
-	scKey := utils.HexToFelt(t, "0x492e8")
-	scValue := utils.HexToFelt(t, "0x10979c6b0b36b03be36739a21cc43a51076545ce6d3397f1b45c7e286474ad5")
-	scAddr := new(felt.Felt).SetUint64(1)
-
-	// update state root
-	su1.NewRoot = utils.HexToFelt(t, "0x2829ac1aea81c890339e14422fe757d6831744031479cf33a9260d14282c341")
-
-	su1.StateDiff.StorageDiffs[*scAddr] = map[felt.Felt]*felt.Felt{*scKey: scValue}
-
-	require.NoError(t, state.Update(1, su1, nil))
-
-	require.NoError(t, state.Revert(1, su1))
-
-	gotRoot, err := state.Root()
-	require.NoError(t, err)
-
-	assert.Equal(t, su0.NewRoot, gotRoot)
-}
-
-func TestRevertDeclaredClasses(t *testing.T) {
-	testDB := pebble.NewMemTest(t)
-	txn, err := testDB.NewTransaction(true)
-	require.NoError(t, err)
-	t.Cleanup(func() {
-		require.NoError(t, txn.Discard())
-	})
-	state := core.NewState(txn)
-
-	classHash := utils.HexToFelt(t, "0xDEADBEEF")
-	sierraHash := utils.HexToFelt(t, "0xDEADBEEF2")
-	declareDiff := &core.StateUpdate{
-		OldRoot:   &felt.Zero,
-		NewRoot:   utils.HexToFelt(t, "0x166a006ccf102903347ebe7b82ca0abc8c2fb82f0394d7797e5a8416afd4f8a"),
-		BlockHash: &felt.Zero,
-		StateDiff: &core.StateDiff{
-			DeclaredV0Classes: []*felt.Felt{classHash},
-			DeclaredV1Classes: map[felt.Felt]*felt.Felt{
-				*sierraHash: sierraHash,
-			},
-		},
-	}
-	newClasses := map[felt.Felt]core.Class{
-		*classHash:  &core.Cairo0Class{},
-		*sierraHash: &core.Cairo1Class{},
-	}
-
-	require.NoError(t, state.Update(0, declareDiff, newClasses))
-	declaredClass, err := state.Class(classHash)
-	require.NoError(t, err)
-	assert.Equal(t, uint64(0), declaredClass.At)
-	sierraClass, sErr := state.Class(sierraHash)
-	require.NoError(t, sErr)
-	assert.Equal(t, uint64(0), sierraClass.At)
-
-	declareDiff.OldRoot = declareDiff.NewRoot
-	require.NoError(t, state.Update(1, declareDiff, newClasses))
-
-	t.Run("re-declaring a class shouldnt change it's DeclaredAt attribute", func(t *testing.T) {
-		declaredClass, err = state.Class(classHash)
-		require.NoError(t, err)
-		assert.Equal(t, uint64(0), declaredClass.At)
-		sierraClass, sErr = state.Class(sierraHash)
-		require.NoError(t, sErr)
-		assert.Equal(t, uint64(0), sierraClass.At)
-	})
-
-	require.NoError(t, state.Revert(1, declareDiff))
-
-	t.Run("reverting a re-declaration shouldnt change state commitment or remove class definitions", func(t *testing.T) {
-		declaredClass, err = state.Class(classHash)
-		require.NoError(t, err)
-		assert.Equal(t, uint64(0), declaredClass.At)
-		sierraClass, sErr = state.Class(sierraHash)
-		require.NoError(t, sErr)
-		assert.Equal(t, uint64(0), sierraClass.At)
-	})
-
-	declareDiff.OldRoot = &felt.Zero
-	require.NoError(t, state.Revert(0, declareDiff))
-	_, err = state.Class(classHash)
-	require.ErrorIs(t, err, db.ErrKeyNotFound)
-	_, err = state.Class(sierraHash)
-	require.ErrorIs(t, err, db.ErrKeyNotFound)
-}
diff --git a/core/temp_state.go b/core/temp_state.go
new file mode 100644
index 0000000000..5e3af4e9e0
--- /dev/null
+++ b/core/temp_state.go
@@ -0,0 +1,66 @@
+package core
+
+import (
+	"encoding/binary"
+	"errors"
+
+	"github.com/NethermindEth/juno/core/felt"
+	"github.com/NethermindEth/juno/core/trie"
+	"github.com/NethermindEth/juno/encoder"
+)
+
+const globalTrieHeight = 251
+
+var (
+	stateVersion = new(felt.Felt).SetBytes([]byte(`STARKNET_STATE_V0`))
+	leafVersion  = new(felt.Felt).SetBytes([]byte(`CONTRACT_CLASS_LEAF_V0`))
+)
+
+//go:generate mockgen -destination=../mocks/mock_state.go -package=mocks github.com/NethermindEth/juno/core StateHistoryReader
+type StateHistoryReader interface {
+	StateReader
+
+	ContractStorageAt(addr, key *felt.Felt, blockNumber uint64) (*felt.Felt, error)
+	ContractNonceAt(addr *felt.Felt, blockNumber uint64) (*felt.Felt, error)
+	ContractClassHashAt(addr *felt.Felt, blockNumber uint64) (*felt.Felt, error)
+	ContractIsAlreadyDeployedAt(addr *felt.Felt, blockNumber uint64) (bool, error)
+}
+
+type StateReader interface {
+	ContractClassHash(addr *felt.Felt) (*felt.Felt, error)
+	ContractNonce(addr *felt.Felt) (*felt.Felt, error)
+	ContractStorage(addr, key *felt.Felt) (*felt.Felt, error)
+	Class(classHash *felt.Felt) (*DeclaredClass, error)
+
+	ClassTrie() (*trie.Trie, error)
+	ContractTrie() (*trie.Trie, error)
+	ContractStorageTrie(addr *felt.Felt) (*trie.Trie, error)
+}
+
+type DeclaredClass struct {
+	At    uint64 // block number at which the class was declared
+	Class Class
+}
+
+func (d *DeclaredClass) MarshalBinary() ([]byte, error) {
+	classEnc, err := encoder.Marshal(d.Class)
+	if err != nil {
+		return nil, err
+	}
+
+	size := 8 + len(classEnc)
+	buf := make([]byte, size)
+	binary.BigEndian.PutUint64(buf[:8], d.At)
+	copy(buf[8:], classEnc)
+
+	return buf, nil
+}
+
+func (d *DeclaredClass) UnmarshalBinary(data []byte) error {
+	if len(data) < 8 { //nolint:mnd
+		return errors.New("data too short to unmarshal DeclaredClass")
+	}
+
+	d.At = binary.BigEndian.Uint64(data[:8])
+	return encoder.Unmarshal(data[8:], &d.Class)
+}
diff --git a/sync/sync.go b/sync/sync.go
index 9ec490d002..7cb995da6c 100644
--- a/sync/sync.go
+++ b/sync/sync.go
@@ -11,6 +11,7 @@ import (
 	"github.com/NethermindEth/juno/blockchain"
 	"github.com/NethermindEth/juno/core"
 	"github.com/NethermindEth/juno/core/felt"
+	"github.com/NethermindEth/juno/core/state"
 	"github.com/NethermindEth/juno/db"
 	"github.com/NethermindEth/juno/feed"
 	junoplugin "github.com/NethermindEth/juno/plugin"
@@ -672,7 +673,12 @@ func (s *Synchronizer) PendingState() (core.StateReader, func() error, error) {
 		return nil, nil, utils.RunAndWrapOnError(txn.Discard, err)
 	}
 
-	return NewPendingState(pending.StateUpdate.StateDiff, pending.NewClasses, core.NewState(txn)), txn.Discard, nil
+	st, err := state.New(txn)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	return NewPendingState(pending.StateUpdate.StateDiff, pending.NewClasses, st), txn.Discard, nil
 }
 
 func (s *Synchronizer) storeEmptyPending(latestHeader *core.Header) error {
diff --git a/vm/vm_test.go b/vm/vm_test.go
index 5697a908df..76f2bcb516 100644
--- a/vm/vm_test.go
+++ b/vm/vm_test.go
@@ -8,6 +8,7 @@ import (
 	"github.com/NethermindEth/juno/clients/feeder"
 	"github.com/NethermindEth/juno/core"
 	"github.com/NethermindEth/juno/core/felt"
+	"github.com/NethermindEth/juno/core/state"
 	"github.com/NethermindEth/juno/db/pebble"
 	adaptfeeder "github.com/NethermindEth/juno/starknetdata/feeder"
 	"github.com/NethermindEth/juno/utils"
@@ -31,7 +32,8 @@ func TestV0Call(t *testing.T) {
 	simpleClass, err := gw.Class(context.Background(), classHash)
 	require.NoError(t, err)
 
-	testState := core.NewState(txn)
+	testState, err := state.New(txn)
+	require.NoError(t, err)
 	require.NoError(t, testState.Update(0, &core.StateUpdate{
 		OldRoot: &felt.Zero,
 		NewRoot: utils.HexToFelt(t, "0x3d452fbb3c3a32fe85b1a3fbbcdec316d5fc940cefc028ee808ad25a15991c8"),
@@ -46,6 +48,8 @@ func TestV0Call(t *testing.T) {
 
 	entryPoint := utils.HexToFelt(t, "0x39e11d48192e4333233c7eb19d10ad67c362bb28580c604d67884c85da39695")
 
+	testState, err = state.New(txn)
+	require.NoError(t, err)
 	ret, err := New(false, nil).Call(&CallInfo{
 		ContractAddress: contractAddr,
 		ClassHash:       classHash,
@@ -54,6 +58,8 @@ func TestV0Call(t *testing.T) {
 	require.NoError(t, err)
 	assert.Equal(t, []*felt.Felt{&felt.Zero}, ret.Result)
 
+	testState, err = state.New(txn)
+	require.NoError(t, err)
 	require.NoError(t, testState.Update(1, &core.StateUpdate{
 		OldRoot: utils.HexToFelt(t, "0x3d452fbb3c3a32fe85b1a3fbbcdec316d5fc940cefc028ee808ad25a15991c8"),
 		NewRoot: utils.HexToFelt(t, "0x4a948783e8786ba9d8edaf42de972213bd2deb1b50c49e36647f1fef844890f"),
@@ -91,7 +97,8 @@ func TestV1Call(t *testing.T) {
 	simpleClass, err := gw.Class(context.Background(), classHash)
 	require.NoError(t, err)
 
-	testState := core.NewState(txn)
+	testState, err := state.New(txn)
+	require.NoError(t, err)
 	require.NoError(t, testState.Update(0, &core.StateUpdate{
 		OldRoot: &felt.Zero,
 		NewRoot: utils.HexToFelt(t, "0x2650cef46c190ec6bb7dc21a5a36781132e7c883b27175e625031149d4f1a84"),
@@ -109,6 +116,8 @@ func TestV1Call(t *testing.T) {
 	require.NoError(t, err)
 
 	// test_storage_read
+	testState, err = state.New(txn)
+	require.NoError(t, err)
 	entryPoint := utils.HexToFelt(t, "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf")
 	storageLocation := utils.HexToFelt(t, "0x44")
 	ret, err := New(false, log).Call(&CallInfo{
@@ -160,7 +169,8 @@ func TestCall_MaxSteps(t *testing.T) {
 	simpleClass, err := gw.Class(context.Background(), classHash)
 	require.NoError(t, err)
 
-	testState := core.NewState(txn)
+	testState, err := state.New(txn)
+	require.NoError(t, err)
 	require.NoError(t, testState.Update(0, &core.StateUpdate{
 		OldRoot: &felt.Zero,
 		NewRoot: utils.HexToFelt(t, "0x3d452fbb3c3a32fe85b1a3fbbcdec316d5fc940cefc028ee808ad25a15991c8"),
@@ -175,6 +185,8 @@ func TestCall_MaxSteps(t *testing.T) {
 
 	entryPoint := utils.HexToFelt(t, "0x39e11d48192e4333233c7eb19d10ad67c362bb28580c604d67884c85da39695")
 
+	testState, err = state.New(txn)
+	require.NoError(t, err)
 	_, err = New(false, nil).Call(&CallInfo{
 		ContractAddress: contractAddr,
 		ClassHash:       classHash,
@@ -193,28 +205,30 @@ func TestExecute(t *testing.T) {
 		require.NoError(t, txn.Discard())
 	})
 
-	state := core.NewState(txn)
-
 	t.Run("empty transaction list", func(t *testing.T) {
-		_, err := New(false, nil).Execute([]core.Transaction{}, []core.Class{}, []*felt.Felt{}, &BlockInfo{
+		testState, err := state.New(txn)
+		require.NoError(t, err)
+		_, err = New(false, nil).Execute([]core.Transaction{}, []core.Class{}, []*felt.Felt{}, &BlockInfo{
 			Header: &core.Header{
 				Timestamp:        1666877926,
 				SequencerAddress: utils.HexToFelt(t, "0x46a89ae102987331d369645031b49c27738ed096f2789c24449966da4c6de6b"),
 				L1GasPriceETH:    &felt.Zero,
 				L1GasPriceSTRK:   &felt.Zero,
 			},
-		}, state,
+		}, testState,
 			&network, false, false, false)
 		require.NoError(t, err)
 	})
 	t.Run("zero data", func(t *testing.T) {
-		_, err := New(false, nil).Execute(nil, nil, []*felt.Felt{}, &BlockInfo{
+		testState, err := state.New(txn)
+		require.NoError(t, err)
+		_, err = New(false, nil).Execute(nil, nil, []*felt.Felt{}, &BlockInfo{
 			Header: &core.Header{
 				SequencerAddress: &felt.Zero,
 				L1GasPriceETH:    &felt.Zero,
 				L1GasPriceSTRK:   &felt.Zero,
 			},
-		}, state, &network, false, false, false)
+		}, testState, &network, false, false, false)
 		require.NoError(t, err)
 	})
 }

From 16e0c53bac7b4c0d754db8d7cfbadab1493a56ca Mon Sep 17 00:00:00 2001
From: weiihann <weihan774237@gmail.com>
Date: Tue, 18 Feb 2025 01:36:35 +0800
Subject: [PATCH 06/15] remove old state interfaces + interface segregations

---
 adapters/p2p2core/state.go   |   3 +-
 blockchain/blockchain.go     |  79 +-------------------
 blockchain/state.go          | 112 ++++++++++++++++++++++++++++
 core/class.go                |  31 ++++++++
 core/state/history.go        | 105 ++++++++++++++++++++++++++
 core/state/state.go          |  48 +-----------
 core/state/state_test.go     | 126 +++++++++++++++----------------
 core/state_snapshot.go       | 104 --------------------------
 core/state_snapshot_test.go  | 141 -----------------------------------
 core/temp_state.go           |  66 ----------------
 mempool/mempool.go           |   9 ++-
 mempool/mempool_test.go      |   6 +-
 mocks/mock_blockchain.go     | 127 ++++++++++++++++---------------
 mocks/mock_mempool.go        |  55 ++++++++++++++
 mocks/mock_state.go          | 128 +++++++++----------------------
 mocks/mock_synchronizer.go   |   8 +-
 mocks/mock_vm.go             |  19 +++--
 node/throttled_vm.go         |   4 +-
 rpc/v6/class_test.go         |   8 +-
 rpc/v6/contract_test.go      |   4 +-
 rpc/v6/estimate_fee_test.go  |   4 +-
 rpc/v6/handlers_test.go      |   6 +-
 rpc/v6/helpers.go            |   4 +-
 rpc/v6/simulation_test.go    |   2 +-
 rpc/v6/trace.go              |   2 +-
 rpc/v6/trace_test.go         |  12 +--
 rpc/v7/compiled_casm_test.go |   4 +-
 rpc/v7/estimate_fee_test.go  |   2 +-
 rpc/v7/handlers_test.go      |   6 +-
 rpc/v7/helpers.go            |   4 +-
 rpc/v7/simulation_test.go    |   2 +-
 rpc/v7/storage_test.go       |   2 +-
 rpc/v7/trace.go              |   2 +-
 rpc/v7/trace_test.go         |  12 +--
 rpc/v8/compiled_casm_test.go |   4 +-
 rpc/v8/estimate_fee_test.go  |   2 +-
 rpc/v8/handlers_test.go      |   6 +-
 rpc/v8/helpers.go            |   4 +-
 rpc/v8/simulation_test.go    |  14 ++--
 rpc/v8/storage.go            |   5 +-
 rpc/v8/storage_test.go       |   4 +-
 rpc/v8/subscriptions_test.go |   8 +-
 rpc/v8/trace.go              |   2 +-
 rpc/v8/trace_test.go         |  12 +--
 sync/pending.go              |  12 +--
 sync/pending_test.go         |   2 +-
 sync/sync.go                 |   6 +-
 vm/state_reader.go           |   8 ++
 vm/vm.go                     |   8 +-
 49 files changed, 585 insertions(+), 759 deletions(-)
 create mode 100644 blockchain/state.go
 create mode 100644 core/state/history.go
 delete mode 100644 core/state_snapshot.go
 delete mode 100644 core/state_snapshot_test.go
 delete mode 100644 core/temp_state.go
 create mode 100644 mocks/mock_mempool.go

diff --git a/adapters/p2p2core/state.go b/adapters/p2p2core/state.go
index 9807da65f1..a83a112f65 100644
--- a/adapters/p2p2core/state.go
+++ b/adapters/p2p2core/state.go
@@ -4,6 +4,7 @@ import (
 	"errors"
 	"fmt"
 
+	"github.com/NethermindEth/juno/blockchain"
 	"github.com/NethermindEth/juno/core"
 	"github.com/NethermindEth/juno/core/felt"
 	"github.com/NethermindEth/juno/db"
@@ -11,7 +12,7 @@ import (
 	"github.com/NethermindEth/juno/utils"
 )
 
-func AdaptStateDiff(reader core.StateReader, contractDiffs []*gen.ContractDiff, classes []*gen.Class) *core.StateDiff {
+func AdaptStateDiff(reader blockchain.StateReader, contractDiffs []*gen.ContractDiff, classes []*gen.Class) *core.StateDiff {
 	var (
 		declaredV0Classes []*felt.Felt
 		declaredV1Classes = make(map[felt.Felt]*felt.Felt)
diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go
index 3f59bad0b8..da0698433f 100644
--- a/blockchain/blockchain.go
+++ b/blockchain/blockchain.go
@@ -23,6 +23,7 @@ type L1HeadSubscription struct {
 
 //go:generate mockgen -destination=../mocks/mock_blockchain.go -package=mocks github.com/NethermindEth/juno/blockchain Reader
 type Reader interface {
+	StateProvider
 	Height() (height uint64, err error)
 
 	Head() (head *core.Block, err error)
@@ -42,10 +43,6 @@ type Reader interface {
 	StateUpdateByHash(hash *felt.Felt) (update *core.StateUpdate, err error)
 	L1HandlerTxnHash(msgHash *common.Hash) (l1HandlerTxnHash *felt.Felt, err error)
 
-	HeadState() (core.StateReader, StateCloser, error)
-	StateAtBlockHash(blockHash *felt.Felt) (core.StateReader, StateCloser, error)
-	StateAtBlockNumber(blockNumber uint64) (core.StateReader, StateCloser, error)
-
 	BlockCommitmentsByNumber(blockNumber uint64) (*core.BlockCommitments, error)
 
 	EventFilter(from *felt.Felt, keys [][]felt.Felt) (EventFilterer, error)
@@ -777,80 +774,6 @@ func receiptByBlockNumberAndIndex(txn db.Transaction, bnIndex *txAndReceiptDBKey
 	return r, err
 }
 
-type StateCloser = func() error
-
-// HeadState returns a StateReader that provides a stable view to the latest state
-func (b *Blockchain) HeadState() (core.StateReader, StateCloser, error) {
-	b.listener.OnRead("HeadState")
-	txn, err := b.database.NewTransaction(false)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	_, err = ChainHeight(txn)
-	if err != nil {
-		return nil, nil, utils.RunAndWrapOnError(txn.Discard, err)
-	}
-
-	st, err := state.New(txn)
-	if err != nil {
-		return nil, nil, utils.RunAndWrapOnError(txn.Discard, err)
-	}
-
-	return st, txn.Discard, nil
-}
-
-// StateAtBlockNumber returns a StateReader that provides a stable view to the state at the given block number
-func (b *Blockchain) StateAtBlockNumber(blockNumber uint64) (core.StateReader, StateCloser, error) {
-	b.listener.OnRead("StateAtBlockNumber")
-	txn, err := b.database.NewTransaction(false)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	_, err = blockHeaderByNumber(txn, blockNumber)
-	if err != nil {
-		return nil, nil, utils.RunAndWrapOnError(txn.Discard, err)
-	}
-
-	st, err := state.New(txn)
-	if err != nil {
-		return nil, nil, utils.RunAndWrapOnError(txn.Discard, err)
-	}
-
-	return core.NewStateSnapshot(st, blockNumber), txn.Discard, nil
-}
-
-// StateAtBlockHash returns a StateReader that provides a stable view to the state at the given block hash
-func (b *Blockchain) StateAtBlockHash(blockHash *felt.Felt) (core.StateReader, StateCloser, error) {
-	b.listener.OnRead("StateAtBlockHash")
-	if blockHash.IsZero() {
-		txn := db.NewMemTransaction()
-		emptyState, err := state.New(txn)
-		if err != nil {
-			return nil, nil, utils.RunAndWrapOnError(txn.Discard, err)
-		}
-		return emptyState, txn.Discard, nil
-	}
-
-	txn, err := b.database.NewTransaction(false)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	header, err := blockHeaderByHash(txn, blockHash)
-	if err != nil {
-		return nil, nil, utils.RunAndWrapOnError(txn.Discard, err)
-	}
-
-	st, err := state.New(txn)
-	if err != nil {
-		return nil, nil, utils.RunAndWrapOnError(txn.Discard, err)
-	}
-
-	return core.NewStateSnapshot(st, header.Number), txn.Discard, nil
-}
-
 // EventFilter returns an EventFilter object that is tied to a snapshot of the blockchain
 func (b *Blockchain) EventFilter(from *felt.Felt, keys [][]felt.Felt) (EventFilterer, error) {
 	b.listener.OnRead("EventFilter")
diff --git a/blockchain/state.go b/blockchain/state.go
new file mode 100644
index 0000000000..7b279c279c
--- /dev/null
+++ b/blockchain/state.go
@@ -0,0 +1,112 @@
+package blockchain
+
+import (
+	"github.com/NethermindEth/juno/core"
+	"github.com/NethermindEth/juno/core/felt"
+	"github.com/NethermindEth/juno/core/state"
+	"github.com/NethermindEth/juno/core/trie"
+	"github.com/NethermindEth/juno/db"
+	"github.com/NethermindEth/juno/utils"
+)
+
+type StateProvider interface {
+	HeadState() (StateReader, StateCloser, error)
+	StateAtBlockHash(blockHash *felt.Felt) (StateReader, StateCloser, error)
+	StateAtBlockNumber(blockNumber uint64) (StateReader, StateCloser, error)
+}
+
+type StateReader interface {
+	ContractReader
+	ClassReader
+	TrieProvider
+}
+
+type StateCloser func() error
+
+type ContractReader interface {
+	ContractClassHash(addr *felt.Felt) (*felt.Felt, error)
+	ContractNonce(addr *felt.Felt) (*felt.Felt, error)
+	ContractStorage(addr, key *felt.Felt) (*felt.Felt, error)
+}
+
+type ClassReader interface {
+	Class(classHash *felt.Felt) (*core.DeclaredClass, error)
+}
+
+type TrieProvider interface {
+	ClassTrie() (*trie.Trie, error)
+	ContractTrie() (*trie.Trie, error)
+	ContractStorageTrie(addr *felt.Felt) (*trie.Trie, error)
+}
+
+// HeadState returns a StateReader that provides a stable view to the latest state
+func (b *Blockchain) HeadState() (StateReader, StateCloser, error) {
+	b.listener.OnRead("HeadState")
+	txn, err := b.database.NewTransaction(false)
+	if err != nil {
+		return nil, txn.Discard, err
+	}
+
+	_, err = ChainHeight(txn)
+	if err != nil {
+		return nil, txn.Discard, utils.RunAndWrapOnError(txn.Discard, err)
+	}
+
+	st, err := state.New(txn)
+	if err != nil {
+		return nil, txn.Discard, utils.RunAndWrapOnError(txn.Discard, err)
+	}
+
+	return st, txn.Discard, nil
+}
+
+// StateAtBlockNumber returns a StateReader that provides a stable view to the state at the given block number
+func (b *Blockchain) StateAtBlockNumber(blockNumber uint64) (StateReader, StateCloser, error) {
+	b.listener.OnRead("StateAtBlockNumber")
+	txn, err := b.database.NewTransaction(false)
+	if err != nil {
+		return nil, txn.Discard, err
+	}
+
+	_, err = blockHeaderByNumber(txn, blockNumber)
+	if err != nil {
+		return nil, txn.Discard, utils.RunAndWrapOnError(txn.Discard, err)
+	}
+
+	st, err := state.NewStateHistory(txn, blockNumber)
+	if err != nil {
+		return nil, txn.Discard, utils.RunAndWrapOnError(txn.Discard, err)
+	}
+
+	return st, txn.Discard, nil
+}
+
+// StateAtBlockHash returns a StateReader that provides a stable view to the state at the given block hash
+func (b *Blockchain) StateAtBlockHash(blockHash *felt.Felt) (StateReader, StateCloser, error) {
+	b.listener.OnRead("StateAtBlockHash")
+	if blockHash.IsZero() {
+		txn := db.NewMemTransaction()
+		emptyState, err := state.New(txn)
+		if err != nil {
+			return nil, txn.Discard, utils.RunAndWrapOnError(txn.Discard, err)
+		}
+		return emptyState, txn.Discard, nil
+	}
+
+	txn, err := b.database.NewTransaction(false)
+	if err != nil {
+		return nil, txn.Discard, err
+	}
+
+	header, err := blockHeaderByHash(txn, blockHash)
+	if err != nil {
+		return nil, txn.Discard, utils.RunAndWrapOnError(txn.Discard, err)
+	}
+
+	st, err := state.NewStateHistory(txn, header.Number)
+	if err != nil {
+		return nil, txn.Discard, utils.RunAndWrapOnError(txn.Discard, err)
+	}
+
+	return st, txn.Discard, nil
+}
diff --git a/core/class.go b/core/class.go
index 8ec694aef5..fbc4dc7f0f 100644
--- a/core/class.go
+++ b/core/class.go
@@ -1,12 +1,15 @@
 package core
 
 import (
+	"encoding/binary"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"math/big"
 
 	"github.com/NethermindEth/juno/core/crypto"
 	"github.com/NethermindEth/juno/core/felt"
+	"github.com/NethermindEth/juno/encoder"
 )
 
 var (
@@ -206,3 +209,31 @@ func VerifyClassHashes(classes map[felt.Felt]Class) error {
 
 	return nil
 }
+
+type DeclaredClass struct {
+	At    uint64 // block number at which the class was declared
+	Class Class
+}
+
+func (d *DeclaredClass) MarshalBinary() ([]byte, error) {
+	classEnc, err := encoder.Marshal(d.Class)
+	if err != nil {
+		return nil, err
+	}
+
+	size := 8 + len(classEnc)
+	buf := make([]byte, size)
+	binary.BigEndian.PutUint64(buf[:8], d.At)
+	copy(buf[8:], classEnc)
+
+	return buf, nil
+}
+
+func (d *DeclaredClass) UnmarshalBinary(data []byte) error {
+	if len(data) < 8 { //nolint:mnd
+		return errors.New("data too short to unmarshal DeclaredClass")
+	}
+
+	d.At = binary.BigEndian.Uint64(data[:8])
+	return encoder.Unmarshal(data[8:], &d.Class)
+}
diff --git a/core/state/history.go b/core/state/history.go
new file mode 100644
index 0000000000..e68225abae
--- /dev/null
+++ b/core/state/history.go
@@ -0,0 +1,105 @@
+package state
+
+import (
+	"errors"
+
+	"github.com/NethermindEth/juno/core"
+	"github.com/NethermindEth/juno/core/felt"
+	"github.com/NethermindEth/juno/core/trie"
+	"github.com/NethermindEth/juno/db"
+)
+
+var ErrHistoricalTrieNotSupported = errors.New("cannot support historical trie")
+
+type StateHistory struct {
+	blockNum uint64
+	state    *State
+}
+
+func NewStateHistory(txn db.Transaction, blockNum uint64) (*StateHistory, error) {
+	state, err := New(txn)
+	if err != nil {
+		return nil, err
+	}
+
+	return &StateHistory{
+		blockNum: blockNum,
+		state:    state,
+	}, nil
+}
+
+func (s *StateHistory) ContractClassHash(addr *felt.Felt) (*felt.Felt, error) {
+	if err := s.checkDeployed(addr); err != nil {
+		return nil, err
+	}
+
+	val, err := s.state.ContractClassHashAt(addr, s.blockNum)
+	if err != nil {
+		return nil, err
+	}
+
+	return val, nil
+}
+
+func (s *StateHistory) ContractNonce(addr *felt.Felt) (*felt.Felt, error) {
+	if err := s.checkDeployed(addr); err != nil {
+		return nil, err
+	}
+
+	val, err := s.state.ContractNonceAt(addr, s.blockNum)
+	if err != nil {
+		return nil, err
+	}
+
+	return val, nil
+}
+
+func (s *StateHistory) ContractStorage(addr, key *felt.Felt) (*felt.Felt, error) {
+	if err := s.checkDeployed(addr); err != nil {
+		return nil, err
+	}
+
+	val, err := s.state.ContractStorageAt(addr, key, s.blockNum)
+	if err != nil {
+		return nil, err
+	}
+
+	return val, nil
+}
+
+func (s *StateHistory) checkDeployed(addr *felt.Felt) error {
+	isDeployed, err := s.state.ContractDeployedAt(*addr, s.blockNum)
+	if err != nil {
+		return err
+	}
+
+	if !isDeployed {
+		return db.ErrKeyNotFound
+	}
+	return nil
+}
+
+func (s *StateHistory) Class(classHash *felt.Felt) (*core.DeclaredClass, error) {
+	declaredClass, err := s.state.Class(classHash)
+	if err != nil {
+		return nil, err
+	}
+
+	if s.blockNum < declaredClass.At {
+		return nil, db.ErrKeyNotFound
+	}
+
+	return declaredClass, nil
+}
+
+func (s *StateHistory) ClassTrie() (*trie.Trie, error) {
+	return nil, ErrHistoricalTrieNotSupported
+}
+
+func (s *StateHistory) ContractTrie() (*trie.Trie, error) {
+	return nil, ErrHistoricalTrieNotSupported
+}
+
+func (s *StateHistory) ContractStorageTrie(addr *felt.Felt) (*trie.Trie, error) {
+	return nil, ErrHistoricalTrieNotSupported
+}
diff --git a/core/state/state.go b/core/state/state.go
index 5a268f2ed6..4b779137bb 100644
--- a/core/state/state.go
+++ b/core/state/state.go
@@ -13,7 +13,6 @@ import (
 	"github.com/NethermindEth/juno/core/trie"
 	"github.com/NethermindEth/juno/core/trie2"
 	"github.com/NethermindEth/juno/db"
-	"github.com/NethermindEth/juno/encoder"
 )
 
 const (
@@ -104,11 +103,6 @@ func (s *State) ContractDeployedAt(addr felt.Felt, blockNum uint64) (bool, error
 	return contract.DeployHeight <= blockNum, nil
 }
 
-// TODO(weiihann): remove this once integration is done
-func (s *State) ContractIsAlreadyDeployedAt(addr *felt.Felt, blockNumber uint64) (bool, error) {
-	return s.ContractDeployedAt(*addr, blockNumber)
-}
-
 func (s *State) Class(classHash *felt.Felt) (*core.DeclaredClass, error) {
 	classKey := classKey(classHash)
 
@@ -121,18 +115,6 @@ func (s *State) Class(classHash *felt.Felt) (*core.DeclaredClass, error) {
 	return &class, nil
 }
 
-// func (s *State) Class(classHash *felt.Felt) (*DeclaredClass, error) {
-// 	classKey := classKey(classHash)
-
-// 	var class DeclaredClass
-// 	err := s.txn.Get(classKey, class.UnmarshalBinary)
-// 	if err != nil {
-// 		return nil, err
-// 	}
-
-// 	return &class, nil
-// }
-
 func (s *State) ClassTrie() (*trie.Trie, error) {
 	panic("not implemented")
 }
@@ -456,40 +438,12 @@ func (s *State) getContract(addr felt.Felt) (*StateContract, error) {
 	return contract, nil
 }
 
-type DeclaredClass struct {
-	At    uint64 // block number at which the class was declared
-	Class core.Class
-}
-
-func (d *DeclaredClass) MarshalBinary() ([]byte, error) {
-	classEnc, err := encoder.Marshal(d.Class)
-	if err != nil {
-		return nil, err
-	}
-
-	size := 8 + len(classEnc)
-	buf := make([]byte, size)
-	binary.BigEndian.PutUint64(buf[:8], d.At)
-	copy(buf[8:], classEnc)
-
-	return buf, nil
-}
-
-func (d *DeclaredClass) UnmarshalBinary(data []byte) error {
-	if len(data) < 8 { //nolint:mnd
-		return errors.New("data too short to unmarshal DeclaredClass")
-	}
-
-	d.At = binary.BigEndian.Uint64(data[:8])
-	return encoder.Unmarshal(data[8:], &d.Class)
-}
-
 func (s *State) putClass(classHash *felt.Felt, class core.Class, declaredAt uint64) error {
 	classKey := classKey(classHash)
 
 	err := s.txn.Get(classKey, func(val []byte) error { return nil }) // check if class already exists
 	if errors.Is(err, db.ErrKeyNotFound) {
-		dc := DeclaredClass{
+		dc := core.DeclaredClass{
 			At:    declaredAt,
 			Class: class,
 		}
diff --git a/core/state/state_test.go b/core/state/state_test.go
index 127b7c0d73..d3b832efbd 100644
--- a/core/state/state_test.go
+++ b/core/state/state_test.go
@@ -2,7 +2,7 @@ package state
 
 import (
 	"context"
-	// "encoding/json"
+	"encoding/json"
 	"testing"
 
 	"github.com/NethermindEth/juno/clients/feeder"
@@ -436,68 +436,68 @@ func TestRevert(t *testing.T) {
 		assert.Equal(t, &felt.Zero, storage)
 	})
 
-	// t.Run("revert a declare class", func(t *testing.T) {
-	// 	classesM := make(map[felt.Felt]core.Class)
-	// 	cairo0 := &core.Cairo0Class{
-	// 		Abi:          json.RawMessage("some cairo 0 class abi"),
-	// 		Externals:    []core.EntryPoint{{Selector: new(felt.Felt).SetBytes([]byte("e1")), Offset: new(felt.Felt).SetBytes([]byte("e2"))}},
-	// 		L1Handlers:   []core.EntryPoint{{Selector: new(felt.Felt).SetBytes([]byte("l1")), Offset: new(felt.Felt).SetBytes([]byte("l2"))}},
-	// 		Constructors: []core.EntryPoint{{Selector: new(felt.Felt).SetBytes([]byte("c1")), Offset: new(felt.Felt).SetBytes([]byte("c2"))}},
-	// 		Program:      "some cairo 0 program",
-	// 	}
-
-	// 	cairo0Addr := utils.HexToFelt(t, "0xab1234")
-	// 	classesM[*cairo0Addr] = cairo0
-
-	// 	cairo1 := &core.Cairo1Class{
-	// 		Abi:     "some cairo 1 class abi",
-	// 		AbiHash: utils.HexToFelt(t, "0xcd98"),
-	// 		EntryPoints: struct {
-	// 			Constructor []core.SierraEntryPoint
-	// 			External    []core.SierraEntryPoint
-	// 			L1Handler   []core.SierraEntryPoint
-	// 		}{
-	// 			Constructor: []core.SierraEntryPoint{{Index: 1, Selector: new(felt.Felt).SetBytes([]byte("c1"))}},
-	// 			External:    []core.SierraEntryPoint{{Index: 0, Selector: new(felt.Felt).SetBytes([]byte("e1"))}},
-	// 			L1Handler:   []core.SierraEntryPoint{{Index: 2, Selector: new(felt.Felt).SetBytes([]byte("l1"))}},
-	// 		},
-	// 		Program:         []*felt.Felt{new(felt.Felt).SetBytes([]byte("random program"))},
-	// 		ProgramHash:     new(felt.Felt).SetBytes([]byte("random program hash")),
-	// 		SemanticVersion: "version 1",
-	// 		Compiled:        &core.CompiledClass{},
-	// 	}
-
-	// 	cairo1Addr := utils.HexToFelt(t, "0xcd5678")
-	// 	classesM[*cairo1Addr] = cairo1
-
-	// 	declaredClassesStateUpdate := &core.StateUpdate{
-	// 		NewRoot: utils.HexToFelt(t, "0x40427f2f4b5e1d15792e656b4d0c1d1dcf66ece1d8d60276d543aafedcc79d9"),
-	// 		OldRoot: su1.NewRoot,
-	// 		StateDiff: &core.StateDiff{
-	// 			DeclaredV0Classes: []*felt.Felt{cairo0Addr},
-	// 			DeclaredV1Classes: map[felt.Felt]*felt.Felt{
-	// 				*cairo1Addr: utils.HexToFelt(t, "0xef9123"),
-	// 			},
-	// 		},
-	// 	}
-
-	// 	state, err := New(txn)
-	// 	require.NoError(t, err)
-	// 	require.NoError(t, state.Update(block2, declaredClassesStateUpdate, classesM))
-
-	// 	state, err = New(txn)
-	// 	require.NoError(t, err)
-	// 	require.NoError(t, state.Revert(block2, declaredClassesStateUpdate))
-
-	// 	var decClass *DeclaredClass
-	// 	decClass, err = state.Class(cairo0Addr)
-	// 	assert.ErrorIs(t, err, db.ErrKeyNotFound)
-	// 	assert.Nil(t, decClass)
-
-	// 	decClass, err = state.Class(cairo1Addr)
-	// 	assert.ErrorIs(t, err, db.ErrKeyNotFound)
-	// 	assert.Nil(t, decClass)
-	// })
+	t.Run("revert a declare class", func(t *testing.T) {
+		classesM := make(map[felt.Felt]core.Class)
+		cairo0 := &core.Cairo0Class{
+			Abi:          json.RawMessage("some cairo 0 class abi"),
+			Externals:    []core.EntryPoint{{Selector: new(felt.Felt).SetBytes([]byte("e1")), Offset: new(felt.Felt).SetBytes([]byte("e2"))}},
+			L1Handlers:   []core.EntryPoint{{Selector: new(felt.Felt).SetBytes([]byte("l1")), Offset: new(felt.Felt).SetBytes([]byte("l2"))}},
+			Constructors: []core.EntryPoint{{Selector: new(felt.Felt).SetBytes([]byte("c1")), Offset: new(felt.Felt).SetBytes([]byte("c2"))}},
+			Program:      "some cairo 0 program",
+		}
+
+		cairo0Addr := utils.HexToFelt(t, "0xab1234")
+		classesM[*cairo0Addr] = cairo0
+
+		cairo1 := &core.Cairo1Class{
+			Abi:     "some cairo 1 class abi",
+			AbiHash: utils.HexToFelt(t, "0xcd98"),
+			EntryPoints: struct {
+				Constructor []core.SierraEntryPoint
+				External    []core.SierraEntryPoint
+				L1Handler   []core.SierraEntryPoint
+			}{
+				Constructor: []core.SierraEntryPoint{{Index: 1, Selector: new(felt.Felt).SetBytes([]byte("c1"))}},
+				External:    []core.SierraEntryPoint{{Index: 0, Selector: new(felt.Felt).SetBytes([]byte("e1"))}},
+				L1Handler:   []core.SierraEntryPoint{{Index: 2, Selector: new(felt.Felt).SetBytes([]byte("l1"))}},
+			},
+			Program:         []*felt.Felt{new(felt.Felt).SetBytes([]byte("random program"))},
+			ProgramHash:     new(felt.Felt).SetBytes([]byte("random program hash")),
+			SemanticVersion: "version 1",
+			Compiled:        &core.CompiledClass{},
+		}
+
+		cairo1Addr := utils.HexToFelt(t, "0xcd5678")
+		classesM[*cairo1Addr] = cairo1
+
+		declaredClassesStateUpdate := &core.StateUpdate{
+			NewRoot: utils.HexToFelt(t, "0x40427f2f4b5e1d15792e656b4d0c1d1dcf66ece1d8d60276d543aafedcc79d9"),
+			OldRoot: su1.NewRoot,
+			StateDiff: &core.StateDiff{
+				DeclaredV0Classes: []*felt.Felt{cairo0Addr},
+				DeclaredV1Classes: map[felt.Felt]*felt.Felt{
+					*cairo1Addr: utils.HexToFelt(t, "0xef9123"),
+				},
+			},
+		}
+
+		state, err := New(txn)
+		require.NoError(t, err)
+		require.NoError(t, state.Update(block2, declaredClassesStateUpdate, classesM))
+
+		state, err = New(txn)
+		require.NoError(t, err)
+		require.NoError(t, state.Revert(block2, declaredClassesStateUpdate))
+
+		var decClass *core.DeclaredClass
+		decClass, err = state.Class(cairo0Addr)
+		assert.ErrorIs(t, err, db.ErrKeyNotFound)
+		assert.Nil(t, decClass)
+
+		decClass, err = state.Class(cairo1Addr)
+		assert.ErrorIs(t, err, db.ErrKeyNotFound)
+		assert.Nil(t, decClass)
+	})
 
 	t.Run("should be able to update after a revert", func(t *testing.T) {
 		state, err := New(txn)
diff --git a/core/state_snapshot.go b/core/state_snapshot.go
deleted file mode 100644
index a0697ddfa6..0000000000
--- a/core/state_snapshot.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package core
-
-import (
-	"errors"
-
-	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/core/trie"
-	"github.com/NethermindEth/juno/db"
-)
-
-var ErrHistoricalTrieNotSupported = errors.New("cannot support historical trie")
-
-type stateSnapshot struct {
-	blockNumber uint64
-	state       StateHistoryReader
-}
-
-func NewStateSnapshot(state StateHistoryReader, blockNumber uint64) StateReader {
-	return &stateSnapshot{
-		blockNumber: blockNumber,
-		state:       state,
-	}
-}
-
-func (s *stateSnapshot) ContractClassHash(addr *felt.Felt) (*felt.Felt, error) {
-	if err := s.checkDeployed(addr); err != nil {
-		return nil, err
-	}
-
-	val, err := s.state.ContractClassHashAt(addr, s.blockNumber)
-	if err != nil {
-		if errors.Is(err, ErrCheckHeadState) {
-			return s.state.ContractClassHash(addr)
-		}
-		return nil, err
-	}
-	return val, nil
-}
-
-func (s *stateSnapshot) ContractNonce(addr *felt.Felt) (*felt.Felt, error) {
-	if err := s.checkDeployed(addr); err != nil {
-		return nil, err
-	}
-
-	val, err := s.state.ContractNonceAt(addr, s.blockNumber)
-	if err != nil {
-		if errors.Is(err, ErrCheckHeadState) {
-			return s.state.ContractNonce(addr)
-		}
-		return nil, err
-	}
-	return val, nil
-}
-
-func (s *stateSnapshot) ContractStorage(addr, key *felt.Felt) (*felt.Felt, error) {
-	if err := s.checkDeployed(addr); err != nil {
-		return nil, err
-	}
-
-	val, err := s.state.ContractStorageAt(addr, key, s.blockNumber)
-	if err != nil {
-		if errors.Is(err, ErrCheckHeadState) {
-			return s.state.ContractStorage(addr, key)
-		}
-		return nil, err
-	}
-	return val, nil
-}
-
-func (s *stateSnapshot) checkDeployed(addr *felt.Felt) error {
-	isDeployed, err := s.state.ContractIsAlreadyDeployedAt(addr, s.blockNumber)
-	if err != nil {
-		return err
-	}
-
-	if !isDeployed {
-		return db.ErrKeyNotFound
-	}
-	return nil
-}
-
-func (s *stateSnapshot) Class(classHash *felt.Felt) (*DeclaredClass, error) {
-	declaredClass, err := s.state.Class(classHash)
-	if err != nil {
-		return nil, err
-	}
-
-	if s.blockNumber < declaredClass.At {
-		return nil, db.ErrKeyNotFound
-	}
-	return declaredClass, nil
-}
-
-func (s *stateSnapshot) ClassTrie() (*trie.Trie, error) {
-	return nil, ErrHistoricalTrieNotSupported
-}
-
-func (s *stateSnapshot) ContractTrie() (*trie.Trie, error) {
-	return nil, ErrHistoricalTrieNotSupported
-}
-
-func (s *stateSnapshot) ContractStorageTrie(addr *felt.Felt) (*trie.Trie, error) {
-	return nil, ErrHistoricalTrieNotSupported
-}
diff --git a/core/state_snapshot_test.go b/core/state_snapshot_test.go
deleted file mode 100644
index 93e2206c71..0000000000
--- a/core/state_snapshot_test.go
+++ /dev/null
@@ -1,141 +0,0 @@
-package core_test
-
-import (
-	"errors"
-	"testing"
-
-	"github.com/NethermindEth/juno/core"
-	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/db"
-	"github.com/NethermindEth/juno/mocks"
-	"github.com/stretchr/testify/require"
-	"go.uber.org/mock/gomock"
-)
-
-func TestStateSnapshot(t *testing.T) {
-	mockCtrl := gomock.NewController(t)
-	t.Cleanup(mockCtrl.Finish)
-
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
-	deployedHeight := uint64(3)
-	changeHeight := uint64(10)
-	snapshotBeforeDeployment := core.NewStateSnapshot(mockState, deployedHeight-1)
-	snapshotBeforeChange := core.NewStateSnapshot(mockState, deployedHeight)
-	snapshotAfterChange := core.NewStateSnapshot(mockState, changeHeight+1)
-
-	historyValue := new(felt.Felt).SetUint64(1)
-	doAtReq := func(addr *felt.Felt, at uint64) (*felt.Felt, error) {
-		if addr.IsZero() {
-			return nil, errors.New("some error")
-		}
-
-		if at > changeHeight {
-			return nil, core.ErrCheckHeadState
-		}
-		return historyValue, nil
-	}
-
-	mockState.EXPECT().ContractIsAlreadyDeployedAt(gomock.Any(), gomock.Any()).DoAndReturn(func(addr *felt.Felt, height uint64) (bool, error) {
-		return deployedHeight <= height, nil
-	}).AnyTimes()
-	mockState.EXPECT().ContractClassHashAt(gomock.Any(), gomock.Any()).DoAndReturn(doAtReq).AnyTimes()
-	mockState.EXPECT().ContractNonceAt(gomock.Any(), gomock.Any()).DoAndReturn(doAtReq).AnyTimes()
-	mockState.EXPECT().ContractStorageAt(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(
-		func(addr, loc *felt.Felt, at uint64) (*felt.Felt, error) {
-			return doAtReq(loc, at)
-		},
-	).AnyTimes()
-
-	headValue := new(felt.Felt).SetUint64(2)
-	var err error
-	doHeadReq := func(_ *felt.Felt) (*felt.Felt, error) {
-		return headValue, err
-	}
-
-	mockState.EXPECT().ContractClassHash(gomock.Any()).DoAndReturn(doHeadReq).AnyTimes()
-	mockState.EXPECT().ContractNonce(gomock.Any()).DoAndReturn(doHeadReq).AnyTimes()
-	mockState.EXPECT().ContractStorage(gomock.Any(), gomock.Any()).DoAndReturn(
-		func(addr, loc *felt.Felt) (*felt.Felt, error) {
-			return doHeadReq(loc)
-		},
-	).AnyTimes()
-
-	addr, err := new(felt.Felt).SetRandom()
-	require.NoError(t, err)
-
-	for desc, test := range map[string]struct {
-		snapshot core.StateReader
-		checker  func(*testing.T, *felt.Felt, error)
-	}{
-		"contract is not deployed": {
-			snapshot: snapshotBeforeDeployment,
-			checker: func(t *testing.T, _ *felt.Felt, err error) {
-				require.ErrorIs(t, err, db.ErrKeyNotFound)
-			},
-		},
-		"correct value is in history": {
-			snapshot: snapshotBeforeChange,
-			checker: func(t *testing.T, got *felt.Felt, err error) {
-				require.NoError(t, err)
-				require.Equal(t, historyValue, got)
-			},
-		},
-		"correct value is in HEAD": {
-			snapshot: snapshotAfterChange,
-			checker: func(t *testing.T, got *felt.Felt, err error) {
-				require.NoError(t, err)
-				require.Equal(t, headValue, got)
-			},
-		},
-	} {
-		t.Run(desc, func(t *testing.T) {
-			t.Run("class hash", func(t *testing.T) {
-				got, err := test.snapshot.ContractClassHash(addr)
-				test.checker(t, got, err)
-			})
-			t.Run("nonce", func(t *testing.T) {
-				got, err := test.snapshot.ContractNonce(addr)
-				test.checker(t, got, err)
-			})
-			t.Run("storage value", func(t *testing.T) {
-				got, err := test.snapshot.ContractStorage(addr, addr)
-				test.checker(t, got, err)
-			})
-		})
-	}
-
-	t.Run("history returns some error", func(t *testing.T) {
-		t.Run("class hash", func(t *testing.T) {
-			_, err := snapshotAfterChange.ContractClassHash(&felt.Zero)
-			require.EqualError(t, err, "some error")
-		})
-		t.Run("nonce", func(t *testing.T) {
-			_, err := snapshotAfterChange.ContractNonce(&felt.Zero)
-			require.EqualError(t, err, "some error")
-		})
-		t.Run("storage value", func(t *testing.T) {
-			_, err := snapshotAfterChange.ContractStorage(&felt.Zero, &felt.Zero)
-			require.EqualError(t, err, "some error")
-		})
-	})
-
-	declareHeight := deployedHeight
-	mockState.EXPECT().Class(gomock.Any()).Return(&core.DeclaredClass{At: declareHeight}, nil).AnyTimes()
-
-	t.Run("before class is declared", func(t *testing.T) {
-		_, err := snapshotBeforeDeployment.Class(addr)
-		require.ErrorIs(t, err, db.ErrKeyNotFound)
-	})
-
-	t.Run("on height that class is declared", func(t *testing.T) {
-		declared, err := snapshotBeforeChange.Class(addr)
-		require.NoError(t, err)
-		require.Equal(t, declareHeight, declared.At)
-	})
-
-	t.Run("after class is declared", func(t *testing.T) {
-		declared, err := snapshotAfterChange.Class(addr)
-		require.NoError(t, err)
-		require.Equal(t, declareHeight, declared.At)
-	})
-}
diff --git a/core/temp_state.go b/core/temp_state.go
deleted file mode 100644
index 5e3af4e9e0..0000000000
--- a/core/temp_state.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package core
-
-import (
-	"encoding/binary"
-	"errors"
-
-	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/core/trie"
-	"github.com/NethermindEth/juno/encoder"
-)
-
-const globalTrieHeight = 251
-
-var (
-	stateVersion = new(felt.Felt).SetBytes([]byte(`STARKNET_STATE_V0`))
-	leafVersion  = new(felt.Felt).SetBytes([]byte(`CONTRACT_CLASS_LEAF_V0`))
-)
-
-//go:generate mockgen -destination=../mocks/mock_state.go -package=mocks github.com/NethermindEth/juno/core StateHistoryReader
-type StateHistoryReader interface {
-	StateReader
-
-	ContractStorageAt(addr, key *felt.Felt, blockNumber uint64) (*felt.Felt, error)
-	ContractNonceAt(addr *felt.Felt, blockNumber uint64) (*felt.Felt, error)
-	ContractClassHashAt(addr *felt.Felt, blockNumber uint64) (*felt.Felt, error)
-	ContractIsAlreadyDeployedAt(addr *felt.Felt, blockNumber uint64) (bool, error)
-}
-
-type StateReader interface {
-	ContractClassHash(addr *felt.Felt) (*felt.Felt, error)
-	ContractNonce(addr *felt.Felt) (*felt.Felt, error)
-	ContractStorage(addr, key *felt.Felt) (*felt.Felt, error)
-	Class(classHash *felt.Felt) (*DeclaredClass, error)
-
-	ClassTrie() (*trie.Trie, error)
-	ContractTrie() (*trie.Trie, error)
-	ContractStorageTrie(addr *felt.Felt) (*trie.Trie, error)
-}
-
-type DeclaredClass struct {
-	At    uint64 // block number at which the class was declared
-	Class Class
-}
-
-func (d *DeclaredClass) MarshalBinary() ([]byte, error) {
-	classEnc, err := encoder.Marshal(d.Class)
-	if err != nil {
-		return nil, err
-	}
-
-	size := 8 + len(classEnc)
-	buf := make([]byte, size)
-	binary.BigEndian.PutUint64(buf[:8], d.At)
-	copy(buf[8:], classEnc)
-
-	return buf, nil
-}
-
-func (d *DeclaredClass) UnmarshalBinary(data []byte) error {
-	if len(data) < 8 { //nolint:mnd
-		return errors.New("data too short to unmarshal DeclaredClass")
-	}
-
-	d.At = binary.BigEndian.Uint64(data[:8])
-	return encoder.Unmarshal(data[8:], &d.Class)
-}
diff --git a/mempool/mempool.go b/mempool/mempool.go
index 0d7aa5eb3c..2ea4fc4c4c 100644
--- a/mempool/mempool.go
+++ b/mempool/mempool.go
@@ -73,7 +73,7 @@ func (t *memTxnList) pop() (BroadcastedTransaction, error) {
 // in-memory and persistent database.
 type Pool struct {
 	log         utils.SimpleLogger
-	state       core.StateReader
+	state       NonceReader
 	db          db.DB // to store the persistent mempool
 	txPushed    chan struct{}
 	memTxnList  *memTxnList
@@ -84,7 +84,7 @@ type Pool struct {
 
 // New initialises the Pool and starts the database writer goroutine.
 // It is the responsibility of the caller to execute the closer function.
-func New(mainDB db.DB, state core.StateReader, maxNumTxns int, log utils.SimpleLogger) (*Pool, func() error) {
+func New(mainDB db.DB, state NonceReader, maxNumTxns int, log utils.SimpleLogger) (*Pool, func() error) {
 	pool := &Pool{
 		log:         log,
 		state:       state,
@@ -300,3 +300,8 @@ func (p *Pool) LenDB() (int, error) {
 	}
 	return lenDB, txn.Discard()
 }
+
+// mockgen -destination=mocks/mock_mempool.go -package=mocks github.com/NethermindEth/juno/mempool NonceReader
+type NonceReader interface {
+	ContractNonce(addr *felt.Felt) (*felt.Felt, error)
+}
diff --git a/mempool/mempool_test.go b/mempool/mempool_test.go
index 21e9ba89e1..ecd0961b20 100644
--- a/mempool/mempool_test.go
+++ b/mempool/mempool_test.go
@@ -43,7 +43,7 @@ func TestMempool(t *testing.T) {
 	log := utils.NewNopZapLogger()
 	mockCtrl := gomock.NewController(t)
 	t.Cleanup(mockCtrl.Finish)
-	state := mocks.NewMockStateHistoryReader(mockCtrl)
+	state := mocks.NewMockNonceReader(mockCtrl)
 	require.NoError(t, err)
 	defer dbCloser()
 	pool, closer := mempool.New(testDB, state, 4, log)
@@ -116,7 +116,7 @@ func TestRestoreMempool(t *testing.T) {
 
 	mockCtrl := gomock.NewController(t)
 	t.Cleanup(mockCtrl.Finish)
-	state := mocks.NewMockStateHistoryReader(mockCtrl)
+	state := mocks.NewMockNonceReader(mockCtrl)
 	testDB, dbCloser, err := setupDatabase("testrestoremempool", true)
 	require.NoError(t, err)
 	defer dbCloser()
@@ -181,7 +181,7 @@ func TestWait(t *testing.T) {
 	defer dbCloser()
 	mockCtrl := gomock.NewController(t)
 	t.Cleanup(mockCtrl.Finish)
-	state := mocks.NewMockStateHistoryReader(mockCtrl)
+	state := mocks.NewMockNonceReader(mockCtrl)
 	pool, _ := mempool.New(testDB, state, 1024, log)
 	require.NoError(t, pool.LoadFromDB())
 
diff --git a/mocks/mock_blockchain.go b/mocks/mock_blockchain.go
index f2ea2c4e23..9c4e7734bf 100644
--- a/mocks/mock_blockchain.go
+++ b/mocks/mock_blockchain.go
@@ -24,7 +24,6 @@ import (
 type MockReader struct {
 	ctrl     *gomock.Controller
 	recorder *MockReaderMockRecorder
-	isgomock struct{}
 }
 
 // MockReaderMockRecorder is the mock recorder for MockReader.
@@ -45,93 +44,93 @@ func (m *MockReader) EXPECT() *MockReaderMockRecorder {
 }
 
 // BlockByHash mocks base method.
-func (m *MockReader) BlockByHash(hash *felt.Felt) (*core.Block, error) {
+func (m *MockReader) BlockByHash(arg0 *felt.Felt) (*core.Block, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "BlockByHash", hash)
+	ret := m.ctrl.Call(m, "BlockByHash", arg0)
 	ret0, _ := ret[0].(*core.Block)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // BlockByHash indicates an expected call of BlockByHash.
-func (mr *MockReaderMockRecorder) BlockByHash(hash any) *gomock.Call {
+func (mr *MockReaderMockRecorder) BlockByHash(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHash", reflect.TypeOf((*MockReader)(nil).BlockByHash), hash)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHash", reflect.TypeOf((*MockReader)(nil).BlockByHash), arg0)
 }
 
 // BlockByNumber mocks base method.
-func (m *MockReader) BlockByNumber(number uint64) (*core.Block, error) {
+func (m *MockReader) BlockByNumber(arg0 uint64) (*core.Block, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "BlockByNumber", number)
+	ret := m.ctrl.Call(m, "BlockByNumber", arg0)
 	ret0, _ := ret[0].(*core.Block)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // BlockByNumber indicates an expected call of BlockByNumber.
-func (mr *MockReaderMockRecorder) BlockByNumber(number any) *gomock.Call {
+func (mr *MockReaderMockRecorder) BlockByNumber(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByNumber", reflect.TypeOf((*MockReader)(nil).BlockByNumber), number)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByNumber", reflect.TypeOf((*MockReader)(nil).BlockByNumber), arg0)
 }
 
 // BlockCommitmentsByNumber mocks base method.
-func (m *MockReader) BlockCommitmentsByNumber(blockNumber uint64) (*core.BlockCommitments, error) {
+func (m *MockReader) BlockCommitmentsByNumber(arg0 uint64) (*core.BlockCommitments, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "BlockCommitmentsByNumber", blockNumber)
+	ret := m.ctrl.Call(m, "BlockCommitmentsByNumber", arg0)
 	ret0, _ := ret[0].(*core.BlockCommitments)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // BlockCommitmentsByNumber indicates an expected call of BlockCommitmentsByNumber.
-func (mr *MockReaderMockRecorder) BlockCommitmentsByNumber(blockNumber any) *gomock.Call {
+func (mr *MockReaderMockRecorder) BlockCommitmentsByNumber(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockCommitmentsByNumber", reflect.TypeOf((*MockReader)(nil).BlockCommitmentsByNumber), blockNumber)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockCommitmentsByNumber", reflect.TypeOf((*MockReader)(nil).BlockCommitmentsByNumber), arg0)
 }
 
 // BlockHeaderByHash mocks base method.
-func (m *MockReader) BlockHeaderByHash(hash *felt.Felt) (*core.Header, error) {
+func (m *MockReader) BlockHeaderByHash(arg0 *felt.Felt) (*core.Header, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "BlockHeaderByHash", hash)
+	ret := m.ctrl.Call(m, "BlockHeaderByHash", arg0)
 	ret0, _ := ret[0].(*core.Header)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // BlockHeaderByHash indicates an expected call of BlockHeaderByHash.
-func (mr *MockReaderMockRecorder) BlockHeaderByHash(hash any) *gomock.Call {
+func (mr *MockReaderMockRecorder) BlockHeaderByHash(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockHeaderByHash", reflect.TypeOf((*MockReader)(nil).BlockHeaderByHash), hash)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockHeaderByHash", reflect.TypeOf((*MockReader)(nil).BlockHeaderByHash), arg0)
 }
 
 // BlockHeaderByNumber mocks base method.
-func (m *MockReader) BlockHeaderByNumber(number uint64) (*core.Header, error) {
+func (m *MockReader) BlockHeaderByNumber(arg0 uint64) (*core.Header, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "BlockHeaderByNumber", number)
+	ret := m.ctrl.Call(m, "BlockHeaderByNumber", arg0)
 	ret0, _ := ret[0].(*core.Header)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // BlockHeaderByNumber indicates an expected call of BlockHeaderByNumber.
-func (mr *MockReaderMockRecorder) BlockHeaderByNumber(number any) *gomock.Call {
+func (mr *MockReaderMockRecorder) BlockHeaderByNumber(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockHeaderByNumber", reflect.TypeOf((*MockReader)(nil).BlockHeaderByNumber), number)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockHeaderByNumber", reflect.TypeOf((*MockReader)(nil).BlockHeaderByNumber), arg0)
 }
 
 // EventFilter mocks base method.
-func (m *MockReader) EventFilter(from *felt.Felt, keys [][]felt.Felt) (blockchain.EventFilterer, error) {
+func (m *MockReader) EventFilter(arg0 *felt.Felt, arg1 [][]felt.Felt) (blockchain.EventFilterer, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "EventFilter", from, keys)
+	ret := m.ctrl.Call(m, "EventFilter", arg0, arg1)
 	ret0, _ := ret[0].(blockchain.EventFilterer)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // EventFilter indicates an expected call of EventFilter.
-func (mr *MockReaderMockRecorder) EventFilter(from, keys any) *gomock.Call {
+func (mr *MockReaderMockRecorder) EventFilter(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EventFilter", reflect.TypeOf((*MockReader)(nil).EventFilter), from, keys)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EventFilter", reflect.TypeOf((*MockReader)(nil).EventFilter), arg0, arg1)
 }
 
 // Head mocks base method.
@@ -150,11 +149,11 @@ func (mr *MockReaderMockRecorder) Head() *gomock.Call {
 }
 
 // HeadState mocks base method.
-func (m *MockReader) HeadState() (core.StateReader, func() error, error) {
+func (m *MockReader) HeadState() (blockchain.StateReader, blockchain.StateCloser, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "HeadState")
-	ret0, _ := ret[0].(core.StateReader)
-	ret1, _ := ret[1].(func() error)
+	ret0, _ := ret[0].(blockchain.StateReader)
+	ret1, _ := ret[1].(blockchain.StateCloser)
 	ret2, _ := ret[2].(error)
 	return ret0, ret1, ret2
 }
@@ -196,18 +195,18 @@ func (mr *MockReaderMockRecorder) Height() *gomock.Call {
 }
 
 // L1HandlerTxnHash mocks base method.
-func (m *MockReader) L1HandlerTxnHash(msgHash *common.Hash) (*felt.Felt, error) {
+func (m *MockReader) L1HandlerTxnHash(arg0 *common.Hash) (*felt.Felt, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "L1HandlerTxnHash", msgHash)
+	ret := m.ctrl.Call(m, "L1HandlerTxnHash", arg0)
 	ret0, _ := ret[0].(*felt.Felt)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // L1HandlerTxnHash indicates an expected call of L1HandlerTxnHash.
-func (mr *MockReaderMockRecorder) L1HandlerTxnHash(msgHash any) *gomock.Call {
+func (mr *MockReaderMockRecorder) L1HandlerTxnHash(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "L1HandlerTxnHash", reflect.TypeOf((*MockReader)(nil).L1HandlerTxnHash), msgHash)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "L1HandlerTxnHash", reflect.TypeOf((*MockReader)(nil).L1HandlerTxnHash), arg0)
 }
 
 // L1Head mocks base method.
@@ -240,9 +239,9 @@ func (mr *MockReaderMockRecorder) Network() *gomock.Call {
 }
 
 // Receipt mocks base method.
-func (m *MockReader) Receipt(hash *felt.Felt) (*core.TransactionReceipt, *felt.Felt, uint64, error) {
+func (m *MockReader) Receipt(arg0 *felt.Felt) (*core.TransactionReceipt, *felt.Felt, uint64, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "Receipt", hash)
+	ret := m.ctrl.Call(m, "Receipt", arg0)
 	ret0, _ := ret[0].(*core.TransactionReceipt)
 	ret1, _ := ret[1].(*felt.Felt)
 	ret2, _ := ret[2].(uint64)
@@ -251,71 +250,71 @@ func (m *MockReader) Receipt(hash *felt.Felt) (*core.TransactionReceipt, *felt.F
 }
 
 // Receipt indicates an expected call of Receipt.
-func (mr *MockReaderMockRecorder) Receipt(hash any) *gomock.Call {
+func (mr *MockReaderMockRecorder) Receipt(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Receipt", reflect.TypeOf((*MockReader)(nil).Receipt), hash)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Receipt", reflect.TypeOf((*MockReader)(nil).Receipt), arg0)
 }
 
 // StateAtBlockHash mocks base method.
-func (m *MockReader) StateAtBlockHash(blockHash *felt.Felt) (core.StateReader, func() error, error) {
+func (m *MockReader) StateAtBlockHash(arg0 *felt.Felt) (blockchain.StateReader, blockchain.StateCloser, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "StateAtBlockHash", blockHash)
-	ret0, _ := ret[0].(core.StateReader)
-	ret1, _ := ret[1].(func() error)
+	ret := m.ctrl.Call(m, "StateAtBlockHash", arg0)
+	ret0, _ := ret[0].(blockchain.StateReader)
+	ret1, _ := ret[1].(blockchain.StateCloser)
 	ret2, _ := ret[2].(error)
 	return ret0, ret1, ret2
 }
 
 // StateAtBlockHash indicates an expected call of StateAtBlockHash.
-func (mr *MockReaderMockRecorder) StateAtBlockHash(blockHash any) *gomock.Call {
+func (mr *MockReaderMockRecorder) StateAtBlockHash(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateAtBlockHash", reflect.TypeOf((*MockReader)(nil).StateAtBlockHash), blockHash)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateAtBlockHash", reflect.TypeOf((*MockReader)(nil).StateAtBlockHash), arg0)
 }
 
 // StateAtBlockNumber mocks base method.
-func (m *MockReader) StateAtBlockNumber(blockNumber uint64) (core.StateReader, func() error, error) {
+func (m *MockReader) StateAtBlockNumber(arg0 uint64) (blockchain.StateReader, blockchain.StateCloser, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "StateAtBlockNumber", blockNumber)
-	ret0, _ := ret[0].(core.StateReader)
-	ret1, _ := ret[1].(func() error)
+	ret := m.ctrl.Call(m, "StateAtBlockNumber", arg0)
+	ret0, _ := ret[0].(blockchain.StateReader)
+	ret1, _ := ret[1].(blockchain.StateCloser)
 	ret2, _ := ret[2].(error)
 	return ret0, ret1, ret2
 }
 
 // StateAtBlockNumber indicates an expected call of StateAtBlockNumber.
-func (mr *MockReaderMockRecorder) StateAtBlockNumber(blockNumber any) *gomock.Call {
+func (mr *MockReaderMockRecorder) StateAtBlockNumber(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateAtBlockNumber", reflect.TypeOf((*MockReader)(nil).StateAtBlockNumber), blockNumber)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateAtBlockNumber", reflect.TypeOf((*MockReader)(nil).StateAtBlockNumber), arg0)
 }
 
 // StateUpdateByHash mocks base method.
-func (m *MockReader) StateUpdateByHash(hash *felt.Felt) (*core.StateUpdate, error) {
+func (m *MockReader) StateUpdateByHash(arg0 *felt.Felt) (*core.StateUpdate, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "StateUpdateByHash", hash)
+	ret := m.ctrl.Call(m, "StateUpdateByHash", arg0)
 	ret0, _ := ret[0].(*core.StateUpdate)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // StateUpdateByHash indicates an expected call of StateUpdateByHash.
-func (mr *MockReaderMockRecorder) StateUpdateByHash(hash any) *gomock.Call {
+func (mr *MockReaderMockRecorder) StateUpdateByHash(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateUpdateByHash", reflect.TypeOf((*MockReader)(nil).StateUpdateByHash), hash)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateUpdateByHash", reflect.TypeOf((*MockReader)(nil).StateUpdateByHash), arg0)
 }
 
 // StateUpdateByNumber mocks base method.
-func (m *MockReader) StateUpdateByNumber(number uint64) (*core.StateUpdate, error) {
+func (m *MockReader) StateUpdateByNumber(arg0 uint64) (*core.StateUpdate, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "StateUpdateByNumber", number)
+	ret := m.ctrl.Call(m, "StateUpdateByNumber", arg0)
 	ret0, _ := ret[0].(*core.StateUpdate)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // StateUpdateByNumber indicates an expected call of StateUpdateByNumber.
-func (mr *MockReaderMockRecorder) StateUpdateByNumber(number any) *gomock.Call {
+func (mr *MockReaderMockRecorder) StateUpdateByNumber(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateUpdateByNumber", reflect.TypeOf((*MockReader)(nil).StateUpdateByNumber), number)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateUpdateByNumber", reflect.TypeOf((*MockReader)(nil).StateUpdateByNumber), arg0)
 }
 
 // SubscribeL1Head mocks base method.
@@ -333,31 +332,31 @@ func (mr *MockReaderMockRecorder) SubscribeL1Head() *gomock.Call {
 }
 
 // TransactionByBlockNumberAndIndex mocks base method.
-func (m *MockReader) TransactionByBlockNumberAndIndex(blockNumber, index uint64) (core.Transaction, error) {
+func (m *MockReader) TransactionByBlockNumberAndIndex(arg0, arg1 uint64) (core.Transaction, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "TransactionByBlockNumberAndIndex", blockNumber, index)
+	ret := m.ctrl.Call(m, "TransactionByBlockNumberAndIndex", arg0, arg1)
 	ret0, _ := ret[0].(core.Transaction)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // TransactionByBlockNumberAndIndex indicates an expected call of TransactionByBlockNumberAndIndex.
-func (mr *MockReaderMockRecorder) TransactionByBlockNumberAndIndex(blockNumber, index any) *gomock.Call {
+func (mr *MockReaderMockRecorder) TransactionByBlockNumberAndIndex(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByBlockNumberAndIndex", reflect.TypeOf((*MockReader)(nil).TransactionByBlockNumberAndIndex), blockNumber, index)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByBlockNumberAndIndex", reflect.TypeOf((*MockReader)(nil).TransactionByBlockNumberAndIndex), arg0, arg1)
 }
 
 // TransactionByHash mocks base method.
-func (m *MockReader) TransactionByHash(hash *felt.Felt) (core.Transaction, error) {
+func (m *MockReader) TransactionByHash(arg0 *felt.Felt) (core.Transaction, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "TransactionByHash", hash)
+	ret := m.ctrl.Call(m, "TransactionByHash", arg0)
 	ret0, _ := ret[0].(core.Transaction)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // TransactionByHash indicates an expected call of TransactionByHash.
-func (mr *MockReaderMockRecorder) TransactionByHash(hash any) *gomock.Call {
+func (mr *MockReaderMockRecorder) TransactionByHash(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByHash", reflect.TypeOf((*MockReader)(nil).TransactionByHash), hash)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByHash", reflect.TypeOf((*MockReader)(nil).TransactionByHash), arg0)
 }
diff --git a/mocks/mock_mempool.go b/mocks/mock_mempool.go
new file mode 100644
index 0000000000..51574cd2d4
--- /dev/null
+++ b/mocks/mock_mempool.go
@@ -0,0 +1,55 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: github.com/NethermindEth/juno/mempool (interfaces: NonceReader)
+//
+// Generated by this command:
+//
+//	mockgen -destination=../mocks/mock_mempool.go -package=mocks github.com/NethermindEth/juno/mempool NonceReader
+//
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	felt "github.com/NethermindEth/juno/core/felt"
+	gomock "go.uber.org/mock/gomock"
+)
+
+// MockNonceReader is a mock of NonceReader interface.
+type MockNonceReader struct {
+	ctrl     *gomock.Controller
+	recorder *MockNonceReaderMockRecorder
+}
+
+// MockNonceReaderMockRecorder is the mock recorder for MockNonceReader.
+type MockNonceReaderMockRecorder struct {
+	mock *MockNonceReader
+}
+
+// NewMockNonceReader creates a new mock instance.
+func NewMockNonceReader(ctrl *gomock.Controller) *MockNonceReader {
+	mock := &MockNonceReader{ctrl: ctrl}
+	mock.recorder = &MockNonceReaderMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockNonceReader) EXPECT() *MockNonceReaderMockRecorder {
+	return m.recorder
+}
+
+// ContractNonce mocks base method.
+func (m *MockNonceReader) ContractNonce(arg0 *felt.Felt) (*felt.Felt, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ContractNonce", arg0)
+	ret0, _ := ret[0].(*felt.Felt)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ContractNonce indicates an expected call of ContractNonce.
+func (mr *MockNonceReaderMockRecorder) ContractNonce(arg0 any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContractNonce", reflect.TypeOf((*MockNonceReader)(nil).ContractNonce), arg0)
+}
diff --git a/mocks/mock_state.go b/mocks/mock_state.go
index 2525dad396..fd94ff4391 100644
--- a/mocks/mock_state.go
+++ b/mocks/mock_state.go
@@ -1,9 +1,9 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: github.com/NethermindEth/juno/core (interfaces: StateHistoryReader)
+// Source: github.com/NethermindEth/juno/blockchain (interfaces: StateReader)
 //
 // Generated by this command:
 //
-//	mockgen -destination=../mocks/mock_state.go -package=mocks github.com/NethermindEth/juno/core StateHistoryReader
+//	mockgen -destination=../mocks/mock_state.go -package=mocks github.com/NethermindEth/juno/blockchain StateReader
 //
 
 // Package mocks is a generated GoMock package.
@@ -18,31 +18,31 @@ import (
 	gomock "go.uber.org/mock/gomock"
 )
 
-// MockStateHistoryReader is a mock of StateHistoryReader interface.
-type MockStateHistoryReader struct {
+// MockStateReader is a mock of StateReader interface.
+type MockStateReader struct {
 	ctrl     *gomock.Controller
-	recorder *MockStateHistoryReaderMockRecorder
+	recorder *MockStateReaderMockRecorder
 }
 
-// MockStateHistoryReaderMockRecorder is the mock recorder for MockStateHistoryReader.
-type MockStateHistoryReaderMockRecorder struct {
-	mock *MockStateHistoryReader
+// MockStateReaderMockRecorder is the mock recorder for MockStateReader.
+type MockStateReaderMockRecorder struct {
+	mock *MockStateReader
 }
 
-// NewMockStateHistoryReader creates a new mock instance.
-func NewMockStateHistoryReader(ctrl *gomock.Controller) *MockStateHistoryReader {
-	mock := &MockStateHistoryReader{ctrl: ctrl}
-	mock.recorder = &MockStateHistoryReaderMockRecorder{mock}
+// NewMockStateReader creates a new mock instance.
+func NewMockStateReader(ctrl *gomock.Controller) *MockStateReader {
+	mock := &MockStateReader{ctrl: ctrl}
+	mock.recorder = &MockStateReaderMockRecorder{mock}
 	return mock
 }
 
 // EXPECT returns an object that allows the caller to indicate expected use.
-func (m *MockStateHistoryReader) EXPECT() *MockStateHistoryReaderMockRecorder {
+func (m *MockStateReader) EXPECT() *MockStateReaderMockRecorder {
 	return m.recorder
 }
 
 // Class mocks base method.
-func (m *MockStateHistoryReader) Class(arg0 *felt.Felt) (*core.DeclaredClass, error) {
+func (m *MockStateReader) Class(arg0 *felt.Felt) (*core.DeclaredClass, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Class", arg0)
 	ret0, _ := ret[0].(*core.DeclaredClass)
@@ -51,13 +51,13 @@ func (m *MockStateHistoryReader) Class(arg0 *felt.Felt) (*core.DeclaredClass, er
 }
 
 // Class indicates an expected call of Class.
-func (mr *MockStateHistoryReaderMockRecorder) Class(arg0 any) *gomock.Call {
+func (mr *MockStateReaderMockRecorder) Class(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Class", reflect.TypeOf((*MockStateHistoryReader)(nil).Class), arg0)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Class", reflect.TypeOf((*MockStateReader)(nil).Class), arg0)
 }
 
 // ClassTrie mocks base method.
-func (m *MockStateHistoryReader) ClassTrie() (*trie.Trie, error) {
+func (m *MockStateReader) ClassTrie() (*trie.Trie, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "ClassTrie")
 	ret0, _ := ret[0].(*trie.Trie)
@@ -66,13 +66,13 @@ func (m *MockStateHistoryReader) ClassTrie() (*trie.Trie, error) {
 }
 
 // ClassTrie indicates an expected call of ClassTrie.
-func (mr *MockStateHistoryReaderMockRecorder) ClassTrie() *gomock.Call {
+func (mr *MockStateReaderMockRecorder) ClassTrie() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClassTrie", reflect.TypeOf((*MockStateHistoryReader)(nil).ClassTrie))
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClassTrie", reflect.TypeOf((*MockStateReader)(nil).ClassTrie))
 }
 
 // ContractClassHash mocks base method.
-func (m *MockStateHistoryReader) ContractClassHash(arg0 *felt.Felt) (*felt.Felt, error) {
+func (m *MockStateReader) ContractClassHash(arg0 *felt.Felt) (*felt.Felt, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "ContractClassHash", arg0)
 	ret0, _ := ret[0].(*felt.Felt)
@@ -81,43 +81,13 @@ func (m *MockStateHistoryReader) ContractClassHash(arg0 *felt.Felt) (*felt.Felt,
 }
 
 // ContractClassHash indicates an expected call of ContractClassHash.
-func (mr *MockStateHistoryReaderMockRecorder) ContractClassHash(arg0 any) *gomock.Call {
+func (mr *MockStateReaderMockRecorder) ContractClassHash(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContractClassHash", reflect.TypeOf((*MockStateHistoryReader)(nil).ContractClassHash), arg0)
-}
-
-// ContractClassHashAt mocks base method.
-func (m *MockStateHistoryReader) ContractClassHashAt(arg0 *felt.Felt, arg1 uint64) (*felt.Felt, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ContractClassHashAt", arg0, arg1)
-	ret0, _ := ret[0].(*felt.Felt)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ContractClassHashAt indicates an expected call of ContractClassHashAt.
-func (mr *MockStateHistoryReaderMockRecorder) ContractClassHashAt(arg0, arg1 any) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContractClassHashAt", reflect.TypeOf((*MockStateHistoryReader)(nil).ContractClassHashAt), arg0, arg1)
-}
-
-// ContractIsAlreadyDeployedAt mocks base method.
-func (m *MockStateHistoryReader) ContractIsAlreadyDeployedAt(arg0 *felt.Felt, arg1 uint64) (bool, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ContractIsAlreadyDeployedAt", arg0, arg1)
-	ret0, _ := ret[0].(bool)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ContractIsAlreadyDeployedAt indicates an expected call of ContractIsAlreadyDeployedAt.
-func (mr *MockStateHistoryReaderMockRecorder) ContractIsAlreadyDeployedAt(arg0, arg1 any) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContractIsAlreadyDeployedAt", reflect.TypeOf((*MockStateHistoryReader)(nil).ContractIsAlreadyDeployedAt), arg0, arg1)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContractClassHash", reflect.TypeOf((*MockStateReader)(nil).ContractClassHash), arg0)
 }
 
 // ContractNonce mocks base method.
-func (m *MockStateHistoryReader) ContractNonce(arg0 *felt.Felt) (*felt.Felt, error) {
+func (m *MockStateReader) ContractNonce(arg0 *felt.Felt) (*felt.Felt, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "ContractNonce", arg0)
 	ret0, _ := ret[0].(*felt.Felt)
@@ -126,28 +96,13 @@ func (m *MockStateHistoryReader) ContractNonce(arg0 *felt.Felt) (*felt.Felt, err
 }
 
 // ContractNonce indicates an expected call of ContractNonce.
-func (mr *MockStateHistoryReaderMockRecorder) ContractNonce(arg0 any) *gomock.Call {
+func (mr *MockStateReaderMockRecorder) ContractNonce(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContractNonce", reflect.TypeOf((*MockStateHistoryReader)(nil).ContractNonce), arg0)
-}
-
-// ContractNonceAt mocks base method.
-func (m *MockStateHistoryReader) ContractNonceAt(arg0 *felt.Felt, arg1 uint64) (*felt.Felt, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ContractNonceAt", arg0, arg1)
-	ret0, _ := ret[0].(*felt.Felt)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ContractNonceAt indicates an expected call of ContractNonceAt.
-func (mr *MockStateHistoryReaderMockRecorder) ContractNonceAt(arg0, arg1 any) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContractNonceAt", reflect.TypeOf((*MockStateHistoryReader)(nil).ContractNonceAt), arg0, arg1)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContractNonce", reflect.TypeOf((*MockStateReader)(nil).ContractNonce), arg0)
 }
 
 // ContractStorage mocks base method.
-func (m *MockStateHistoryReader) ContractStorage(arg0, arg1 *felt.Felt) (*felt.Felt, error) {
+func (m *MockStateReader) ContractStorage(arg0, arg1 *felt.Felt) (*felt.Felt, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "ContractStorage", arg0, arg1)
 	ret0, _ := ret[0].(*felt.Felt)
@@ -156,28 +111,13 @@ func (m *MockStateHistoryReader) ContractStorage(arg0, arg1 *felt.Felt) (*felt.F
 }
 
 // ContractStorage indicates an expected call of ContractStorage.
-func (mr *MockStateHistoryReaderMockRecorder) ContractStorage(arg0, arg1 any) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContractStorage", reflect.TypeOf((*MockStateHistoryReader)(nil).ContractStorage), arg0, arg1)
-}
-
-// ContractStorageAt mocks base method.
-func (m *MockStateHistoryReader) ContractStorageAt(arg0, arg1 *felt.Felt, arg2 uint64) (*felt.Felt, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ContractStorageAt", arg0, arg1, arg2)
-	ret0, _ := ret[0].(*felt.Felt)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// ContractStorageAt indicates an expected call of ContractStorageAt.
-func (mr *MockStateHistoryReaderMockRecorder) ContractStorageAt(arg0, arg1, arg2 any) *gomock.Call {
+func (mr *MockStateReaderMockRecorder) ContractStorage(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContractStorageAt", reflect.TypeOf((*MockStateHistoryReader)(nil).ContractStorageAt), arg0, arg1, arg2)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContractStorage", reflect.TypeOf((*MockStateReader)(nil).ContractStorage), arg0, arg1)
 }
 
 // ContractStorageTrie mocks base method.
-func (m *MockStateHistoryReader) ContractStorageTrie(arg0 *felt.Felt) (*trie.Trie, error) {
+func (m *MockStateReader) ContractStorageTrie(arg0 *felt.Felt) (*trie.Trie, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "ContractStorageTrie", arg0)
 	ret0, _ := ret[0].(*trie.Trie)
@@ -186,13 +126,13 @@ func (m *MockStateHistoryReader) ContractStorageTrie(arg0 *felt.Felt) (*trie.Tri
 }
 
 // ContractStorageTrie indicates an expected call of ContractStorageTrie.
-func (mr *MockStateHistoryReaderMockRecorder) ContractStorageTrie(arg0 any) *gomock.Call {
+func (mr *MockStateReaderMockRecorder) ContractStorageTrie(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContractStorageTrie", reflect.TypeOf((*MockStateHistoryReader)(nil).ContractStorageTrie), arg0)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContractStorageTrie", reflect.TypeOf((*MockStateReader)(nil).ContractStorageTrie), arg0)
 }
 
 // ContractTrie mocks base method.
-func (m *MockStateHistoryReader) ContractTrie() (*trie.Trie, error) {
+func (m *MockStateReader) ContractTrie() (*trie.Trie, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "ContractTrie")
 	ret0, _ := ret[0].(*trie.Trie)
@@ -201,7 +141,7 @@ func (m *MockStateHistoryReader) ContractTrie() (*trie.Trie, error) {
 }
 
 // ContractTrie indicates an expected call of ContractTrie.
-func (mr *MockStateHistoryReaderMockRecorder) ContractTrie() *gomock.Call {
+func (mr *MockStateReaderMockRecorder) ContractTrie() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContractTrie", reflect.TypeOf((*MockStateHistoryReader)(nil).ContractTrie))
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContractTrie", reflect.TypeOf((*MockStateReader)(nil).ContractTrie))
 }
diff --git a/mocks/mock_synchronizer.go b/mocks/mock_synchronizer.go
index 13e8bd04e9..53cfac557d 100644
--- a/mocks/mock_synchronizer.go
+++ b/mocks/mock_synchronizer.go
@@ -12,6 +12,7 @@ package mocks
 import (
 	reflect "reflect"
 
+	blockchain "github.com/NethermindEth/juno/blockchain"
 	core "github.com/NethermindEth/juno/core"
 	sync "github.com/NethermindEth/juno/sync"
 	gomock "go.uber.org/mock/gomock"
@@ -21,7 +22,6 @@ import (
 type MockSyncReader struct {
 	ctrl     *gomock.Controller
 	recorder *MockSyncReaderMockRecorder
-	isgomock struct{}
 }
 
 // MockSyncReaderMockRecorder is the mock recorder for MockSyncReader.
@@ -85,11 +85,11 @@ func (mr *MockSyncReaderMockRecorder) PendingBlock() *gomock.Call {
 }
 
 // PendingState mocks base method.
-func (m *MockSyncReader) PendingState() (core.StateReader, func() error, error) {
+func (m *MockSyncReader) PendingState() (blockchain.StateReader, blockchain.StateCloser, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "PendingState")
-	ret0, _ := ret[0].(core.StateReader)
-	ret1, _ := ret[1].(func() error)
+	ret0, _ := ret[0].(blockchain.StateReader)
+	ret1, _ := ret[1].(blockchain.StateCloser)
 	ret2, _ := ret[2].(error)
 	return ret0, ret1, ret2
 }
diff --git a/mocks/mock_vm.go b/mocks/mock_vm.go
index 81ed7ca151..eba2af9cb4 100644
--- a/mocks/mock_vm.go
+++ b/mocks/mock_vm.go
@@ -23,7 +23,6 @@ import (
 type MockVM struct {
 	ctrl     *gomock.Controller
 	recorder *MockVMMockRecorder
-	isgomock struct{}
 }
 
 // MockVMMockRecorder is the mock recorder for MockVM.
@@ -44,31 +43,31 @@ func (m *MockVM) EXPECT() *MockVMMockRecorder {
 }
 
 // Call mocks base method.
-func (m *MockVM) Call(callInfo *vm.CallInfo, blockInfo *vm.BlockInfo, state core.StateReader, network *utils.Network, maxSteps uint64, sierraVersion string) (vm.CallResult, error) {
+func (m *MockVM) Call(arg0 *vm.CallInfo, arg1 *vm.BlockInfo, arg2 vm.StateReader, arg3 *utils.Network, arg4 uint64, arg5 string) ([]*felt.Felt, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "Call", callInfo, blockInfo, state, network, maxSteps, sierraVersion)
-	ret0, _ := ret[0].(vm.CallResult)
+	ret := m.ctrl.Call(m, "Call", arg0, arg1, arg2, arg3, arg4, arg5)
+	ret0, _ := ret[0].([]*felt.Felt)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // Call indicates an expected call of Call.
-func (mr *MockVMMockRecorder) Call(callInfo, blockInfo, state, network, maxSteps, sierraVersion any) *gomock.Call {
+func (mr *MockVMMockRecorder) Call(arg0, arg1, arg2, arg3, arg4, arg5 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Call", reflect.TypeOf((*MockVM)(nil).Call), callInfo, blockInfo, state, network, maxSteps, sierraVersion)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Call", reflect.TypeOf((*MockVM)(nil).Call), arg0, arg1, arg2, arg3, arg4, arg5)
 }
 
 // Execute mocks base method.
-func (m *MockVM) Execute(txns []core.Transaction, declaredClasses []core.Class, paidFeesOnL1 []*felt.Felt, blockInfo *vm.BlockInfo, state core.StateReader, network *utils.Network, skipChargeFee, skipValidate, errOnRevert bool) (vm.ExecutionResults, error) {
+func (m *MockVM) Execute(arg0 []core.Transaction, arg1 []core.Class, arg2 []*felt.Felt, arg3 *vm.BlockInfo, arg4 vm.StateReader, arg5 *utils.Network, arg6, arg7, arg8 bool) (vm.ExecutionResults, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "Execute", txns, declaredClasses, paidFeesOnL1, blockInfo, state, network, skipChargeFee, skipValidate, errOnRevert)
+	ret := m.ctrl.Call(m, "Execute", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
 	ret0, _ := ret[0].(vm.ExecutionResults)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // Execute indicates an expected call of Execute.
-func (mr *MockVMMockRecorder) Execute(txns, declaredClasses, paidFeesOnL1, blockInfo, state, network, skipChargeFee, skipValidate, errOnRevert any) *gomock.Call {
+func (mr *MockVMMockRecorder) Execute(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockVM)(nil).Execute), txns, declaredClasses, paidFeesOnL1, blockInfo, state, network, skipChargeFee, skipValidate, errOnRevert)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockVM)(nil).Execute), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
 }
diff --git a/node/throttled_vm.go b/node/throttled_vm.go
index 042cffb02f..b47738fa6b 100644
--- a/node/throttled_vm.go
+++ b/node/throttled_vm.go
@@ -19,7 +19,7 @@ func NewThrottledVM(res vm.VM, concurrenyBudget uint, maxQueueLen int32) *Thrott
 	}
 }
 
-func (tvm *ThrottledVM) Call(callInfo *vm.CallInfo, blockInfo *vm.BlockInfo, state core.StateReader,
+func (tvm *ThrottledVM) Call(callInfo *vm.CallInfo, blockInfo *vm.BlockInfo, state vm.StateReader,
 	network *utils.Network, maxSteps uint64, sierraVersion string,
 ) (vm.CallResult, error) {
 	ret := vm.CallResult{}
@@ -31,7 +31,7 @@ func (tvm *ThrottledVM) Call(callInfo *vm.CallInfo, blockInfo *vm.BlockInfo, sta
 }
 
 func (tvm *ThrottledVM) Execute(txns []core.Transaction, declaredClasses []core.Class, paidFeesOnL1 []*felt.Felt,
-	blockInfo *vm.BlockInfo, state core.StateReader, network *utils.Network, skipChargeFee, skipValidate, errOnRevert bool,
+	blockInfo *vm.BlockInfo, state vm.StateReader, network *utils.Network, skipChargeFee, skipValidate, errOnRevert bool,
 ) (vm.ExecutionResults, error) {
 	var executionResult vm.ExecutionResults
 	return executionResult, tvm.Do(func(vm *vm.VM) error {
diff --git a/rpc/v6/class_test.go b/rpc/v6/class_test.go
index 691f8873a8..af0e49915b 100644
--- a/rpc/v6/class_test.go
+++ b/rpc/v6/class_test.go
@@ -28,7 +28,7 @@ func TestClass(t *testing.T) {
 	t.Cleanup(mockCtrl.Finish)
 
 	mockReader := mocks.NewMockReader(mockCtrl)
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 
 	mockState.EXPECT().Class(gomock.Any()).DoAndReturn(func(classHash *felt.Felt) (*core.DeclaredClass, error) {
 		class, err := integGw.Class(context.Background(), classHash)
@@ -80,7 +80,7 @@ func TestClass(t *testing.T) {
 
 	t.Run("class hash not found error", func(t *testing.T) {
 		mockReader := mocks.NewMockReader(mockCtrl)
-		mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+		mockState := mocks.NewMockStateReader(mockCtrl)
 		handler := rpc.New(mockReader, nil, nil, "", n, utils.NewNopZapLogger())
 
 		mockReader.EXPECT().HeadState().Return(mockState, func() error {
@@ -103,7 +103,7 @@ func TestClassAt(t *testing.T) {
 	t.Cleanup(mockCtrl.Finish)
 
 	mockReader := mocks.NewMockReader(mockCtrl)
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 
 	cairo0ContractAddress, _ := new(felt.Felt).SetRandom()
 	cairo0ClassHash := utils.HexToFelt(t, "0x4631b6b3fa31e140524b7d21ba784cea223e618bffe60b5bbdca44a8b45be04")
@@ -180,7 +180,7 @@ func TestClassHashAt(t *testing.T) {
 		assert.Equal(t, rpccore.ErrBlockNotFound, rpcErr)
 	})
 
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 
 	t.Run("non-existent contract", func(t *testing.T) {
 		mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil)
diff --git a/rpc/v6/contract_test.go b/rpc/v6/contract_test.go
index 1a4cbb93b4..c99d52f669 100644
--- a/rpc/v6/contract_test.go
+++ b/rpc/v6/contract_test.go
@@ -48,7 +48,7 @@ func TestNonce(t *testing.T) {
 		assert.Equal(t, rpccore.ErrBlockNotFound, rpcErr)
 	})
 
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 
 	t.Run("non-existent contract", func(t *testing.T) {
 		mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil)
@@ -122,7 +122,7 @@ func TestStorageAt(t *testing.T) {
 		assert.Equal(t, rpccore.ErrBlockNotFound, rpcErr)
 	})
 
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 
 	t.Run("non-existent contract", func(t *testing.T) {
 		mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil)
diff --git a/rpc/v6/estimate_fee_test.go b/rpc/v6/estimate_fee_test.go
index 178c26186a..6b4bd17524 100644
--- a/rpc/v6/estimate_fee_test.go
+++ b/rpc/v6/estimate_fee_test.go
@@ -46,7 +46,7 @@ func TestEstimateMessageFee(t *testing.T) {
 		Timestamp:     456,
 		L1GasPriceETH: new(felt.Felt).SetUint64(42),
 	}
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 
 	mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil)
 	mockReader.EXPECT().HeadsHeader().Return(latestHeader, nil)
@@ -56,7 +56,7 @@ func TestEstimateMessageFee(t *testing.T) {
 		Header: latestHeader,
 	}, gomock.Any(), &utils.Mainnet, gomock.Any(), false, true).DoAndReturn(
 		func(txns []core.Transaction, declaredClasses []core.Class, paidFeesOnL1 []*felt.Felt, blockInfo *vm.BlockInfo,
-			state core.StateReader, network *utils.Network, skipChargeFee, skipValidate, errOnRevert bool,
+			state vm.StateReader, network *utils.Network, skipChargeFee, skipValidate, errOnRevert bool,
 		) (vm.ExecutionResults, error) {
 			require.Len(t, txns, 1)
 			assert.NotNil(t, txns[0].(*core.L1HandlerTransaction))
diff --git a/rpc/v6/handlers_test.go b/rpc/v6/handlers_test.go
index c948c73c85..a50a0ee4ce 100644
--- a/rpc/v6/handlers_test.go
+++ b/rpc/v6/handlers_test.go
@@ -43,7 +43,7 @@ func TestThrottledVMError(t *testing.T) {
 
 	throttledVM := node.NewThrottledVM(mockVM, 0, 0)
 	handler := rpc.New(mockReader, mockSyncReader, throttledVM, "", utils.Ptr(utils.Mainnet), nil)
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 
 	throttledErr := "VM throughput limit reached"
 	t.Run("call", func(t *testing.T) {
@@ -87,9 +87,9 @@ func TestThrottledVMError(t *testing.T) {
 		}
 
 		mockReader.EXPECT().BlockByHash(blockHash).Return(block, nil)
-		state := mocks.NewMockStateHistoryReader(mockCtrl)
+		state := mocks.NewMockStateReader(mockCtrl)
 		mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(state, nopCloser, nil)
-		headState := mocks.NewMockStateHistoryReader(mockCtrl)
+		headState := mocks.NewMockStateReader(mockCtrl)
 		headState.EXPECT().Class(declareTx.ClassHash).Return(declaredClass, nil)
 		mockSyncReader.EXPECT().PendingState().Return(headState, nopCloser, nil)
 		_, rpcErr := handler.TraceBlockTransactions(context.Background(), rpc.BlockID{Hash: blockHash})
diff --git a/rpc/v6/helpers.go b/rpc/v6/helpers.go
index 3de321f1a6..bf4761eda7 100644
--- a/rpc/v6/helpers.go
+++ b/rpc/v6/helpers.go
@@ -149,8 +149,8 @@ func feeUnit(txn core.Transaction) FeeUnit {
 	return feeUnit
 }
 
-func (h *Handler) stateByBlockID(id *BlockID) (core.StateReader, blockchain.StateCloser, *jsonrpc.Error) {
-	var reader core.StateReader
+func (h *Handler) stateByBlockID(id *BlockID) (blockchain.StateReader, blockchain.StateCloser, *jsonrpc.Error) {
+	var reader blockchain.StateReader
 	var closer blockchain.StateCloser
 	var err error
 	switch {
diff --git a/rpc/v6/simulation_test.go b/rpc/v6/simulation_test.go
index 3dfab407d6..ac87360e20 100644
--- a/rpc/v6/simulation_test.go
+++ b/rpc/v6/simulation_test.go
@@ -27,7 +27,7 @@ func TestSimulateTransactions(t *testing.T) {
 	mockVM := mocks.NewMockVM(mockCtrl)
 	handler := rpc.New(mockReader, nil, mockVM, "", n, utils.NewNopZapLogger())
 
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 	mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil).AnyTimes()
 	headsHeader := &core.Header{
 		SequencerAddress: n.BlockHashMetaInfo.FallBackSequencerAddress,
diff --git a/rpc/v6/trace.go b/rpc/v6/trace.go
index 68eb58167e..f8ad3c2120 100644
--- a/rpc/v6/trace.go
+++ b/rpc/v6/trace.go
@@ -214,7 +214,7 @@ func (h *Handler) traceBlockTransactions(ctx context.Context, block *core.Block,
 	defer h.callAndLogErr(closer, "Failed to close state in traceBlockTransactions")
 
 	var (
-		headState       core.StateReader
+		headState       blockchain.StateReader
 		headStateCloser blockchain.StateCloser
 	)
 	if isPending {
diff --git a/rpc/v6/trace_test.go b/rpc/v6/trace_test.go
index a37bf3ddfd..53ec9a082e 100644
--- a/rpc/v6/trace_test.go
+++ b/rpc/v6/trace_test.go
@@ -119,7 +119,7 @@ func TestTraceTransactionV0_6(t *testing.T) {
 		mockReader.EXPECT().BlockByHash(header.Hash).Return(block, nil)
 
 		mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(nil, nopCloser, nil)
-		headState := mocks.NewMockStateHistoryReader(mockCtrl)
+		headState := mocks.NewMockStateReader(mockCtrl)
 		headState.EXPECT().Class(tx.ClassHash).Return(declaredClass, nil)
 		mockReader.EXPECT().HeadState().Return(headState, nopCloser, nil)
 
@@ -179,7 +179,7 @@ func TestTraceTransactionV0_6(t *testing.T) {
 		}, nil)
 
 		mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(nil, nopCloser, nil)
-		headState := mocks.NewMockStateHistoryReader(mockCtrl)
+		headState := mocks.NewMockStateReader(mockCtrl)
 		headState.EXPECT().Class(tx.ClassHash).Return(declaredClass, nil)
 		mockSyncReader.EXPECT().PendingState().Return(headState, nopCloser, nil)
 
@@ -272,9 +272,9 @@ func TestTraceBlockTransactions(t *testing.T) {
 		}
 
 		mockReader.EXPECT().BlockByHash(blockHash).Return(block, nil)
-		state := mocks.NewMockStateHistoryReader(mockCtrl)
+		state := mocks.NewMockStateReader(mockCtrl)
 		mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(state, nopCloser, nil)
-		headState := mocks.NewMockStateHistoryReader(mockCtrl)
+		headState := mocks.NewMockStateReader(mockCtrl)
 		headState.EXPECT().Class(declareTx.ClassHash).Return(declaredClass, nil)
 		mockSyncReader.EXPECT().PendingState().Return(headState, nopCloser, nil)
 
@@ -346,7 +346,7 @@ func TestTraceBlockTransactions(t *testing.T) {
 		mockReader.EXPECT().BlockByHash(blockHash).Return(block, nil)
 
 		mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(nil, nopCloser, nil)
-		headState := mocks.NewMockStateHistoryReader(mockCtrl)
+		headState := mocks.NewMockStateReader(mockCtrl)
 		headState.EXPECT().Class(tx.ClassHash).Return(declaredClass, nil)
 		mockReader.EXPECT().HeadState().Return(headState, nopCloser, nil)
 
@@ -418,7 +418,7 @@ func TestCall(t *testing.T) {
 		assert.Equal(t, rpccore.ErrBlockNotFound, rpcErr)
 	})
 
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 
 	t.Run("call - unknown contract", func(t *testing.T) {
 		mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil)
diff --git a/rpc/v7/compiled_casm_test.go b/rpc/v7/compiled_casm_test.go
index 2d1baaa299..8c709c735e 100644
--- a/rpc/v7/compiled_casm_test.go
+++ b/rpc/v7/compiled_casm_test.go
@@ -37,7 +37,7 @@ func TestCompiledCasm(t *testing.T) {
 	t.Run("class doesn't exist", func(t *testing.T) {
 		classHash := utils.HexToFelt(t, "0x111")
 
-		mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+		mockState := mocks.NewMockStateReader(mockCtrl)
 		mockState.EXPECT().Class(classHash).Return(nil, db.ErrKeyNotFound)
 		rd.EXPECT().HeadState().Return(mockState, nopCloser, nil)
 
@@ -66,7 +66,7 @@ func TestCompiledCasm(t *testing.T) {
 		err = json.Unmarshal(program, &cairo0Definition)
 		require.NoError(t, err)
 
-		mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+		mockState := mocks.NewMockStateReader(mockCtrl)
 		mockState.EXPECT().Class(classHash).Return(&core.DeclaredClass{Class: class}, nil)
 		rd.EXPECT().HeadState().Return(mockState, nopCloser, nil)
 
diff --git a/rpc/v7/estimate_fee_test.go b/rpc/v7/estimate_fee_test.go
index 2b6236643d..ffc8473925 100644
--- a/rpc/v7/estimate_fee_test.go
+++ b/rpc/v7/estimate_fee_test.go
@@ -30,7 +30,7 @@ func TestEstimateFee(t *testing.T) {
 	log := utils.NewNopZapLogger()
 	handler := rpcv7.New(mockReader, nil, mockVM, "", n, log)
 
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 	mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil).AnyTimes()
 	mockReader.EXPECT().HeadsHeader().Return(&core.Header{}, nil).AnyTimes()
 
diff --git a/rpc/v7/handlers_test.go b/rpc/v7/handlers_test.go
index e8285b6014..84c9904043 100644
--- a/rpc/v7/handlers_test.go
+++ b/rpc/v7/handlers_test.go
@@ -43,7 +43,7 @@ func TestThrottledVMError(t *testing.T) {
 
 	throttledVM := node.NewThrottledVM(mockVM, 0, 0)
 	handler := rpcv7.New(mockReader, mockSyncReader, throttledVM, "", utils.Ptr(utils.Mainnet), nil)
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 
 	throttledErr := "VM throughput limit reached"
 	t.Run("call", func(t *testing.T) {
@@ -89,9 +89,9 @@ func TestThrottledVMError(t *testing.T) {
 		}
 
 		mockReader.EXPECT().BlockByHash(blockHash).Return(block, nil)
-		state := mocks.NewMockStateHistoryReader(mockCtrl)
+		state := mocks.NewMockStateReader(mockCtrl)
 		mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(state, nopCloser, nil)
-		headState := mocks.NewMockStateHistoryReader(mockCtrl)
+		headState := mocks.NewMockStateReader(mockCtrl)
 		headState.EXPECT().Class(declareTx.ClassHash).Return(declaredClass, nil)
 		mockSyncReader.EXPECT().PendingState().Return(headState, nopCloser, nil)
 		_, httpHeader, rpcErr := handler.TraceBlockTransactions(context.Background(), rpcv7.BlockID{Hash: blockHash})
diff --git a/rpc/v7/helpers.go b/rpc/v7/helpers.go
index 00c26d6637..b36a1de194 100644
--- a/rpc/v7/helpers.go
+++ b/rpc/v7/helpers.go
@@ -156,8 +156,8 @@ func feeUnit(txn core.Transaction) FeeUnit {
 	return feeUnit
 }
 
-func (h *Handler) stateByBlockID(id *BlockID) (core.StateReader, blockchain.StateCloser, *jsonrpc.Error) {
-	var reader core.StateReader
+func (h *Handler) stateByBlockID(id *BlockID) (blockchain.StateReader, blockchain.StateCloser, *jsonrpc.Error) {
+	var reader blockchain.StateReader
 	var closer blockchain.StateCloser
 	var err error
 	switch {
diff --git a/rpc/v7/simulation_test.go b/rpc/v7/simulation_test.go
index b925142f10..c31acde07e 100644
--- a/rpc/v7/simulation_test.go
+++ b/rpc/v7/simulation_test.go
@@ -28,7 +28,7 @@ func TestSimulateTransactions(t *testing.T) {
 	mockVM := mocks.NewMockVM(mockCtrl)
 	handler := rpcv7.New(mockReader, nil, mockVM, "", n, utils.NewNopZapLogger())
 
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 	mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil).AnyTimes()
 	headsHeader := &core.Header{
 		SequencerAddress: n.BlockHashMetaInfo.FallBackSequencerAddress,
diff --git a/rpc/v7/storage_test.go b/rpc/v7/storage_test.go
index 0da282b1df..79f6bed721 100644
--- a/rpc/v7/storage_test.go
+++ b/rpc/v7/storage_test.go
@@ -47,7 +47,7 @@ func TestStorageAt(t *testing.T) {
 		assert.Equal(t, rpccore.ErrBlockNotFound, rpcErr)
 	})
 
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 
 	t.Run("non-existent contract", func(t *testing.T) {
 		mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil)
diff --git a/rpc/v7/trace.go b/rpc/v7/trace.go
index 70d41c12b2..a863e0d246 100644
--- a/rpc/v7/trace.go
+++ b/rpc/v7/trace.go
@@ -271,7 +271,7 @@ func (h *Handler) traceBlockTransactions(ctx context.Context, block *core.Block)
 	defer h.callAndLogErr(closer, "Failed to close state in traceBlockTransactions")
 
 	var (
-		headState       core.StateReader
+		headState       blockchain.StateReader
 		headStateCloser blockchain.StateCloser
 	)
 	if isPending {
diff --git a/rpc/v7/trace_test.go b/rpc/v7/trace_test.go
index 7bbec4e2ac..cc49f04c8c 100644
--- a/rpc/v7/trace_test.go
+++ b/rpc/v7/trace_test.go
@@ -139,7 +139,7 @@ func TestTraceTransaction(t *testing.T) {
 		mockReader.EXPECT().BlockByHash(header.Hash).Return(block, nil)
 
 		mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(nil, nopCloser, nil)
-		headState := mocks.NewMockStateHistoryReader(mockCtrl)
+		headState := mocks.NewMockStateReader(mockCtrl)
 		headState.EXPECT().Class(tx.ClassHash).Return(declaredClass, nil)
 		mockReader.EXPECT().HeadState().Return(headState, nopCloser, nil)
 
@@ -236,7 +236,7 @@ func TestTraceTransaction(t *testing.T) {
 		}, nil)
 
 		mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(nil, nopCloser, nil)
-		headState := mocks.NewMockStateHistoryReader(mockCtrl)
+		headState := mocks.NewMockStateReader(mockCtrl)
 		headState.EXPECT().Class(tx.ClassHash).Return(declaredClass, nil)
 		mockSyncReader.EXPECT().PendingState().Return(headState, nopCloser, nil)
 
@@ -369,9 +369,9 @@ func TestTraceBlockTransactions(t *testing.T) {
 		}
 
 		mockReader.EXPECT().BlockByHash(blockHash).Return(block, nil)
-		state := mocks.NewMockStateHistoryReader(mockCtrl)
+		state := mocks.NewMockStateReader(mockCtrl)
 		mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(state, nopCloser, nil)
-		headState := mocks.NewMockStateHistoryReader(mockCtrl)
+		headState := mocks.NewMockStateReader(mockCtrl)
 		headState.EXPECT().Class(declareTx.ClassHash).Return(declaredClass, nil)
 		mockSyncReader.EXPECT().PendingState().Return(headState, nopCloser, nil)
 
@@ -451,7 +451,7 @@ func TestTraceBlockTransactions(t *testing.T) {
 		mockReader.EXPECT().BlockByHash(blockHash).Return(block, nil)
 
 		mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(nil, nopCloser, nil)
-		headState := mocks.NewMockStateHistoryReader(mockCtrl)
+		headState := mocks.NewMockStateReader(mockCtrl)
 		headState.EXPECT().Class(tx.ClassHash).Return(declaredClass, nil)
 		mockReader.EXPECT().HeadState().Return(headState, nopCloser, nil)
 
@@ -527,7 +527,7 @@ func TestCall(t *testing.T) {
 		assert.Equal(t, rpccore.ErrBlockNotFound, rpcErr)
 	})
 
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 
 	t.Run("call - unknown contract", func(t *testing.T) {
 		mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil)
diff --git a/rpc/v8/compiled_casm_test.go b/rpc/v8/compiled_casm_test.go
index 4f2f09143f..8265d89d32 100644
--- a/rpc/v8/compiled_casm_test.go
+++ b/rpc/v8/compiled_casm_test.go
@@ -37,7 +37,7 @@ func TestCompiledCasm(t *testing.T) {
 	t.Run("class doesn't exist", func(t *testing.T) {
 		classHash := utils.HexToFelt(t, "0x111")
 
-		mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+		mockState := mocks.NewMockStateReader(mockCtrl)
 		mockState.EXPECT().Class(classHash).Return(nil, db.ErrKeyNotFound)
 		rd.EXPECT().HeadState().Return(mockState, nopCloser, nil)
 
@@ -66,7 +66,7 @@ func TestCompiledCasm(t *testing.T) {
 		err = json.Unmarshal(program, &cairo0Definition)
 		require.NoError(t, err)
 
-		mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+		mockState := mocks.NewMockStateReader(mockCtrl)
 		mockState.EXPECT().Class(classHash).Return(&core.DeclaredClass{Class: class}, nil)
 		rd.EXPECT().HeadState().Return(mockState, nopCloser, nil)
 
diff --git a/rpc/v8/estimate_fee_test.go b/rpc/v8/estimate_fee_test.go
index b57b0dee7d..f13b4e18a7 100644
--- a/rpc/v8/estimate_fee_test.go
+++ b/rpc/v8/estimate_fee_test.go
@@ -30,7 +30,7 @@ func TestEstimateFee(t *testing.T) {
 	log := utils.NewNopZapLogger()
 	handler := rpc.New(mockReader, nil, mockVM, "", log)
 
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 	mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil).AnyTimes()
 	mockReader.EXPECT().HeadsHeader().Return(&core.Header{}, nil).AnyTimes()
 
diff --git a/rpc/v8/handlers_test.go b/rpc/v8/handlers_test.go
index 8ecd875cd9..46229ffbcd 100644
--- a/rpc/v8/handlers_test.go
+++ b/rpc/v8/handlers_test.go
@@ -43,7 +43,7 @@ func TestThrottledVMError(t *testing.T) {
 
 	throttledVM := node.NewThrottledVM(mockVM, 0, 0)
 	handler := rpcv8.New(mockReader, mockSyncReader, throttledVM, "", nil)
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 
 	throttledErr := "VM throughput limit reached"
 	t.Run("call", func(t *testing.T) {
@@ -89,9 +89,9 @@ func TestThrottledVMError(t *testing.T) {
 		}
 
 		mockReader.EXPECT().BlockByHash(blockHash).Return(block, nil)
-		state := mocks.NewMockStateHistoryReader(mockCtrl)
+		state := mocks.NewMockStateReader(mockCtrl)
 		mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(state, nopCloser, nil)
-		headState := mocks.NewMockStateHistoryReader(mockCtrl)
+		headState := mocks.NewMockStateReader(mockCtrl)
 		headState.EXPECT().Class(declareTx.ClassHash).Return(declaredClass, nil)
 		mockSyncReader.EXPECT().PendingState().Return(headState, nopCloser, nil)
 		_, httpHeader, rpcErr := handler.TraceBlockTransactions(context.Background(), rpcv8.BlockID{Hash: blockHash})
diff --git a/rpc/v8/helpers.go b/rpc/v8/helpers.go
index 0a07aeeaff..85b869b28c 100644
--- a/rpc/v8/helpers.go
+++ b/rpc/v8/helpers.go
@@ -134,8 +134,8 @@ func feeUnit(txn core.Transaction) FeeUnit {
 	return feeUnit
 }
 
-func (h *Handler) stateByBlockID(id *BlockID) (core.StateReader, blockchain.StateCloser, *jsonrpc.Error) {
-	var reader core.StateReader
+func (h *Handler) stateByBlockID(id *BlockID) (blockchain.StateReader, blockchain.StateCloser, *jsonrpc.Error) {
+	var reader blockchain.StateReader
 	var closer blockchain.StateCloser
 	var err error
 	switch {
diff --git a/rpc/v8/simulation_test.go b/rpc/v8/simulation_test.go
index c6d6bf5a5c..fc2b9d5e4b 100644
--- a/rpc/v8/simulation_test.go
+++ b/rpc/v8/simulation_test.go
@@ -34,7 +34,7 @@ func TestSimulateTransactions(t *testing.T) {
 			PriceInFri: &felt.Zero,
 		},
 	}
-	defaultMockBehavior := func(mockReader *mocks.MockReader, _ *mocks.MockVM, mockState *mocks.MockStateHistoryReader) {
+	defaultMockBehavior := func(mockReader *mocks.MockReader, _ *mocks.MockVM, mockState *mocks.MockStateReader) {
 		mockReader.EXPECT().Network().Return(n)
 		mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil)
 		mockReader.EXPECT().HeadsHeader().Return(headsHeader, nil)
@@ -43,14 +43,14 @@ func TestSimulateTransactions(t *testing.T) {
 		name            string
 		stepsUsed       uint64
 		err             *jsonrpc.Error
-		mockBehavior    func(*mocks.MockReader, *mocks.MockVM, *mocks.MockStateHistoryReader)
+		mockBehavior    func(*mocks.MockReader, *mocks.MockVM, *mocks.MockStateReader)
 		simulationFlags []rpc.SimulationFlag
 		simulatedTxs    []rpc.SimulatedTransaction
 	}{
 		{ //nolint:dupl
 			name:      "ok with zero values, skip fee",
 			stepsUsed: 123,
-			mockBehavior: func(mockReader *mocks.MockReader, mockVM *mocks.MockVM, mockState *mocks.MockStateHistoryReader) {
+			mockBehavior: func(mockReader *mocks.MockReader, mockVM *mocks.MockVM, mockState *mocks.MockStateReader) {
 				defaultMockBehavior(mockReader, mockVM, mockState)
 				mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &vm.BlockInfo{
 					Header: headsHeader,
@@ -69,7 +69,7 @@ func TestSimulateTransactions(t *testing.T) {
 		{ //nolint:dupl
 			name:      "ok with zero values, skip validate",
 			stepsUsed: 123,
-			mockBehavior: func(mockReader *mocks.MockReader, mockVM *mocks.MockVM, mockState *mocks.MockStateHistoryReader) {
+			mockBehavior: func(mockReader *mocks.MockReader, mockVM *mocks.MockVM, mockState *mocks.MockStateReader) {
 				defaultMockBehavior(mockReader, mockVM, mockState)
 				mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &vm.BlockInfo{
 					Header: headsHeader,
@@ -87,7 +87,7 @@ func TestSimulateTransactions(t *testing.T) {
 		},
 		{
 			name: "transaction execution error",
-			mockBehavior: func(mockReader *mocks.MockReader, mockVM *mocks.MockVM, mockState *mocks.MockStateHistoryReader) {
+			mockBehavior: func(mockReader *mocks.MockReader, mockVM *mocks.MockVM, mockState *mocks.MockStateReader) {
 				defaultMockBehavior(mockReader, mockVM, mockState)
 				mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &vm.BlockInfo{
 					Header: headsHeader,
@@ -105,7 +105,7 @@ func TestSimulateTransactions(t *testing.T) {
 		},
 		{
 			name: "inconsistent lengths error",
-			mockBehavior: func(mockReader *mocks.MockReader, mockVM *mocks.MockVM, mockState *mocks.MockStateHistoryReader) {
+			mockBehavior: func(mockReader *mocks.MockReader, mockVM *mocks.MockVM, mockState *mocks.MockStateReader) {
 				defaultMockBehavior(mockReader, mockVM, mockState)
 				mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &vm.BlockInfo{
 					Header: headsHeader,
@@ -133,7 +133,7 @@ func TestSimulateTransactions(t *testing.T) {
 
 			mockReader := mocks.NewMockReader(mockCtrl)
 			mockVM := mocks.NewMockVM(mockCtrl)
-			mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+			mockState := mocks.NewMockStateReader(mockCtrl)
 
 			test.mockBehavior(mockReader, mockVM, mockState)
 			handler := rpc.New(mockReader, nil, mockVM, "", utils.NewNopZapLogger())
diff --git a/rpc/v8/storage.go b/rpc/v8/storage.go
index b67f04c225..71fe08148d 100644
--- a/rpc/v8/storage.go
+++ b/rpc/v8/storage.go
@@ -3,6 +3,7 @@ package rpcv8
 import (
 	"errors"
 
+	"github.com/NethermindEth/juno/blockchain"
 	"github.com/NethermindEth/juno/core"
 	"github.com/NethermindEth/juno/core/felt"
 	"github.com/NethermindEth/juno/core/trie"
@@ -190,7 +191,7 @@ func getClassProof(tr *trie.Trie, classes []felt.Felt) ([]*HashToNode, error) {
 	return adaptProofNodes(classProof), nil
 }
 
-func getContractProof(tr *trie.Trie, state core.StateReader, contracts []felt.Felt) (*ContractProof, error) {
+func getContractProof(tr *trie.Trie, state blockchain.StateReader, contracts []felt.Felt) (*ContractProof, error) {
 	contractProof := trie.NewProofNodeSet()
 	contractLeavesData := make([]*LeafData, len(contracts))
 	for i, contract := range contracts {
@@ -229,7 +230,7 @@ func getContractProof(tr *trie.Trie, state core.StateReader, contracts []felt.Fe
 	}, nil
 }
 
-func getContractStorageProof(state core.StateReader, storageKeys []StorageKeys) ([][]*HashToNode, error) {
+func getContractStorageProof(state blockchain.StateReader, storageKeys []StorageKeys) ([][]*HashToNode, error) {
 	contractStorageRes := make([][]*HashToNode, len(storageKeys))
 	for i, storageKey := range storageKeys {
 		contractStorageTrie, err := state.ContractStorageTrie(storageKey.Contract)
diff --git a/rpc/v8/storage_test.go b/rpc/v8/storage_test.go
index 636af020a2..23f5789fb0 100644
--- a/rpc/v8/storage_test.go
+++ b/rpc/v8/storage_test.go
@@ -58,7 +58,7 @@ func TestStorageAt(t *testing.T) {
 		assert.Equal(t, rpccore.ErrBlockNotFound, rpcErr)
 	})
 
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 
 	t.Run("non-existent contract", func(t *testing.T) {
 		mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil)
@@ -145,7 +145,7 @@ func TestStorageProof(t *testing.T) {
 	trieRoot, _ := tempTrie.Root()
 
 	mockReader := mocks.NewMockReader(mockCtrl)
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 	mockReader.EXPECT().HeadState().Return(mockState, func() error { return nil }, nil).AnyTimes()
 	mockReader.EXPECT().Head().Return(&core.Block{Header: &core.Header{Hash: blkHash, Number: blockNumber}}, nil).AnyTimes()
 	mockState.EXPECT().ClassTrie().Return(tempTrie, nil).AnyTimes()
diff --git a/rpc/v8/subscriptions_test.go b/rpc/v8/subscriptions_test.go
index 5fb52dc100..a1998c9646 100644
--- a/rpc/v8/subscriptions_test.go
+++ b/rpc/v8/subscriptions_test.go
@@ -463,9 +463,11 @@ func (fs *fakeSyncer) HighestBlockHeader() *core.Header {
 	return nil
 }
 
-func (fs *fakeSyncer) Pending() (*sync.Pending, error)                       { return nil, nil }
-func (fs *fakeSyncer) PendingBlock() *core.Block                             { return nil }
-func (fs *fakeSyncer) PendingState() (core.StateReader, func() error, error) { return nil, nil, nil }
+func (fs *fakeSyncer) Pending() (*sync.Pending, error) { return nil, nil }
+func (fs *fakeSyncer) PendingBlock() *core.Block       { return nil }
+func (fs *fakeSyncer) PendingState() (blockchain.StateReader, blockchain.StateCloser, error) {
+	return nil, nil, nil
+}
 
 func TestSubscribeNewHeads(t *testing.T) {
 	log := utils.NewNopZapLogger()
diff --git a/rpc/v8/trace.go b/rpc/v8/trace.go
index 4456824270..cba0fe00bf 100644
--- a/rpc/v8/trace.go
+++ b/rpc/v8/trace.go
@@ -262,7 +262,7 @@ func (h *Handler) traceBlockTransactions(ctx context.Context, block *core.Block)
 	defer h.callAndLogErr(closer, "Failed to close state in traceBlockTransactions")
 
 	var (
-		headState       core.StateReader
+		headState       blockchain.StateReader
 		headStateCloser blockchain.StateCloser
 	)
 	if isPending {
diff --git a/rpc/v8/trace_test.go b/rpc/v8/trace_test.go
index 86797754e8..076f54f4ab 100644
--- a/rpc/v8/trace_test.go
+++ b/rpc/v8/trace_test.go
@@ -139,7 +139,7 @@ func TestTraceTransaction(t *testing.T) {
 		mockReader.EXPECT().BlockByHash(header.Hash).Return(block, nil)
 
 		mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(nil, nopCloser, nil)
-		headState := mocks.NewMockStateHistoryReader(mockCtrl)
+		headState := mocks.NewMockStateReader(mockCtrl)
 		headState.EXPECT().Class(tx.ClassHash).Return(declaredClass, nil)
 		mockReader.EXPECT().HeadState().Return(headState, nopCloser, nil)
 
@@ -240,7 +240,7 @@ func TestTraceTransaction(t *testing.T) {
 		}, nil)
 
 		mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(nil, nopCloser, nil)
-		headState := mocks.NewMockStateHistoryReader(mockCtrl)
+		headState := mocks.NewMockStateReader(mockCtrl)
 		headState.EXPECT().Class(tx.ClassHash).Return(declaredClass, nil)
 		mockSyncReader.EXPECT().PendingState().Return(headState, nopCloser, nil)
 
@@ -378,9 +378,9 @@ func TestTraceBlockTransactions(t *testing.T) {
 		}
 
 		mockReader.EXPECT().BlockByHash(blockHash).Return(block, nil)
-		state := mocks.NewMockStateHistoryReader(mockCtrl)
+		state := mocks.NewMockStateReader(mockCtrl)
 		mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(state, nopCloser, nil)
-		headState := mocks.NewMockStateHistoryReader(mockCtrl)
+		headState := mocks.NewMockStateReader(mockCtrl)
 		headState.EXPECT().Class(declareTx.ClassHash).Return(declaredClass, nil)
 		mockSyncReader.EXPECT().PendingState().Return(headState, nopCloser, nil)
 
@@ -462,7 +462,7 @@ func TestTraceBlockTransactions(t *testing.T) {
 		mockReader.EXPECT().BlockByHash(blockHash).Return(block, nil)
 
 		mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(nil, nopCloser, nil)
-		headState := mocks.NewMockStateHistoryReader(mockCtrl)
+		headState := mocks.NewMockStateReader(mockCtrl)
 		headState.EXPECT().Class(tx.ClassHash).Return(declaredClass, nil)
 		mockReader.EXPECT().HeadState().Return(headState, nopCloser, nil)
 
@@ -540,7 +540,7 @@ func TestCall(t *testing.T) {
 		assert.Equal(t, rpccore.ErrBlockNotFound, rpcErr)
 	})
 
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 
 	t.Run("call - unknown contract", func(t *testing.T) {
 		mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil)
diff --git a/sync/pending.go b/sync/pending.go
index 830dc6792f..faeefd407b 100644
--- a/sync/pending.go
+++ b/sync/pending.go
@@ -1,8 +1,10 @@
 package sync
 
 import (
+	"github.com/NethermindEth/juno/blockchain"
 	"github.com/NethermindEth/juno/core"
 	"github.com/NethermindEth/juno/core/felt"
+	"github.com/NethermindEth/juno/core/state"
 	"github.com/NethermindEth/juno/core/trie"
 )
 
@@ -15,10 +17,10 @@ type Pending struct {
 type PendingState struct {
 	stateDiff  *core.StateDiff
 	newClasses map[felt.Felt]core.Class
-	head       core.StateReader
+	head       blockchain.StateReader
 }
 
-func NewPendingState(stateDiff *core.StateDiff, newClasses map[felt.Felt]core.Class, head core.StateReader) *PendingState {
+func NewPendingState(stateDiff *core.StateDiff, newClasses map[felt.Felt]core.Class, head blockchain.StateReader) *PendingState {
 	return &PendingState{
 		stateDiff:  stateDiff,
 		newClasses: newClasses,
@@ -68,13 +70,13 @@ func (p *PendingState) Class(classHash *felt.Felt) (*core.DeclaredClass, error)
 }
 
 func (p *PendingState) ClassTrie() (*trie.Trie, error) {
-	return nil, core.ErrHistoricalTrieNotSupported
+	return nil, state.ErrHistoricalTrieNotSupported
 }
 
 func (p *PendingState) ContractTrie() (*trie.Trie, error) {
-	return nil, core.ErrHistoricalTrieNotSupported
+	return nil, state.ErrHistoricalTrieNotSupported
 }
 
 func (p *PendingState) ContractStorageTrie(addr *felt.Felt) (*trie.Trie, error) {
-	return nil, core.ErrHistoricalTrieNotSupported
+	return nil, state.ErrHistoricalTrieNotSupported
 }
diff --git a/sync/pending_test.go b/sync/pending_test.go
index d2cc63e73f..172d8e53a7 100644
--- a/sync/pending_test.go
+++ b/sync/pending_test.go
@@ -16,7 +16,7 @@ func TestPendingState(t *testing.T) {
 	mockCtrl := gomock.NewController(t)
 	t.Cleanup(mockCtrl.Finish)
 
-	mockState := mocks.NewMockStateHistoryReader(mockCtrl)
+	mockState := mocks.NewMockStateReader(mockCtrl)
 
 	deployedAddr, err := new(felt.Felt).SetRandom()
 	require.NoError(t, err)
diff --git a/sync/sync.go b/sync/sync.go
index 7cb995da6c..015b59e79d 100644
--- a/sync/sync.go
+++ b/sync/sync.go
@@ -75,7 +75,7 @@ type Reader interface {
 
 	Pending() (*Pending, error)
 	PendingBlock() *core.Block
-	PendingState() (core.StateReader, func() error, error)
+	PendingState() (blockchain.StateReader, blockchain.StateCloser, error)
 }
 
 // This is temporary and will be removed once the p2p synchronizer implements this interface.
@@ -109,7 +109,7 @@ func (n *NoopSynchronizer) Pending() (*Pending, error) {
 	return nil, errors.New("Pending() is not implemented")
 }
 
-func (n *NoopSynchronizer) PendingState() (core.StateReader, func() error, error) {
+func (n *NoopSynchronizer) PendingState() (blockchain.StateReader, blockchain.StateCloser, error) {
 	return nil, nil, errors.New("PendingState() not implemented")
 }
 
@@ -662,7 +662,7 @@ func (s *Synchronizer) PendingBlock() *core.Block {
 }
 
 // PendingState returns the state resulting from execution of the pending block
-func (s *Synchronizer) PendingState() (core.StateReader, func() error, error) {
+func (s *Synchronizer) PendingState() (blockchain.StateReader, blockchain.StateCloser, error) {
 	txn, err := s.db.NewTransaction(false)
 	if err != nil {
 		return nil, nil, err
diff --git a/vm/state_reader.go b/vm/state_reader.go
index 4ce85663ea..79b7792247 100644
--- a/vm/state_reader.go
+++ b/vm/state_reader.go
@@ -8,10 +8,18 @@ import (
 	"errors"
 	"unsafe"
 
+	"github.com/NethermindEth/juno/core"
 	"github.com/NethermindEth/juno/core/felt"
 	"github.com/NethermindEth/juno/db"
 )
 
+type StateReader interface {
+	ContractClassHash(addr *felt.Felt) (*felt.Felt, error)
+	ContractNonce(addr *felt.Felt) (*felt.Felt, error)
+	ContractStorage(addr, key *felt.Felt) (*felt.Felt, error)
+	Class(classHash *felt.Felt) (*core.DeclaredClass, error)
+}
+
 //export JunoFree
 func JunoFree(ptr unsafe.Pointer) {
 	C.free(ptr)
diff --git a/vm/vm.go b/vm/vm.go
index 658a3a0ec2..d93ef29b85 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -41,7 +41,7 @@ type VM interface {
 	Call(callInfo *CallInfo, blockInfo *BlockInfo, state core.StateReader, network *utils.Network,
 		maxSteps uint64, sierraVersion string) (CallResult, error)
 	Execute(txns []core.Transaction, declaredClasses []core.Class, paidFeesOnL1 []*felt.Felt, blockInfo *BlockInfo,
-		state core.StateReader, network *utils.Network, skipChargeFee, skipValidate, errOnRevert bool,
+		state StateReader, network *utils.Network, skipChargeFee, skipValidate, errOnRevert bool,
 	) (ExecutionResults, error)
 }
 
@@ -60,7 +60,7 @@ func New(concurrencyMode bool, log utils.SimpleLogger) VM {
 // callContext manages the context that a Call instance executes on
 type callContext struct {
 	// state that the call is running on
-	state core.StateReader
+	state StateReader
 	log   utils.SimpleLogger
 	// err field to be possibly populated in case of an error in execution
 	err string
@@ -212,7 +212,7 @@ func makeCBlockInfo(blockInfo *BlockInfo) C.BlockInfo {
 	return cBlockInfo
 }
 
-func (v *vm) Call(callInfo *CallInfo, blockInfo *BlockInfo, state core.StateReader,
+func (v *vm) Call(callInfo *CallInfo, blockInfo *BlockInfo, state StateReader,
 	network *utils.Network, maxSteps uint64, sierraVersion string,
 ) (CallResult, error) {
 	context := &callContext{
@@ -255,7 +255,7 @@ func (v *vm) Call(callInfo *CallInfo, blockInfo *BlockInfo, state core.StateRead
 
 // Execute executes a given transaction set and returns the gas spent per transaction
 func (v *vm) Execute(txns []core.Transaction, declaredClasses []core.Class, paidFeesOnL1 []*felt.Felt,
-	blockInfo *BlockInfo, state core.StateReader, network *utils.Network,
+	blockInfo *BlockInfo, state StateReader, network *utils.Network,
 	skipChargeFee, skipValidate, errOnRevert bool,
 ) (ExecutionResults, error) {
 	context := &callContext{

From e1380e2bb4a5d1a33e111e259f4706913d5d8295 Mon Sep 17 00:00:00 2001
From: weiihann <weihan774237@gmail.com>
Date: Tue, 18 Feb 2025 01:47:02 +0800
Subject: [PATCH 07/15] remove old contract

---
 core/contract.go            | 190 +-----------------------------------
 core/contract_test.go       | 157 +----------------------------
 core/state/contract.go      |  15 ---
 core/state/contract_test.go |  37 -------
 4 files changed, 3 insertions(+), 396 deletions(-)

diff --git a/core/contract.go b/core/contract.go
index 2af1fd8c4c..5e42d058e6 100644
--- a/core/contract.go
+++ b/core/contract.go
@@ -1,70 +1,11 @@
 package core
 
 import (
-	"errors"
-
 	"github.com/NethermindEth/juno/core/crypto"
 	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/core/trie"
-	"github.com/NethermindEth/juno/db"
-)
-
-// contract storage has fixed height at 251
-const ContractStorageTrieHeight = 251
-
-var (
-	ErrContractNotDeployed     = errors.New("contract not deployed")
-	ErrContractAlreadyDeployed = errors.New("contract already deployed")
 )
 
-// NewContractUpdater creates an updater for the contract instance at the given address.
-// Deploy should be called for contracts that were just deployed to the network.
-func NewContractUpdater(addr *felt.Felt, txn db.Transaction) (*ContractUpdater, error) {
-	contractDeployed, err := deployed(addr, txn)
-	if err != nil {
-		return nil, err
-	}
-
-	if !contractDeployed {
-		return nil, ErrContractNotDeployed
-	}
-
-	return &ContractUpdater{
-		Address: addr,
-		txn:     txn,
-	}, nil
-}
-
-// DeployContract sets up the database for a new contract.
-func DeployContract(addr, classHash *felt.Felt, txn db.Transaction) (*ContractUpdater, error) {
-	contractDeployed, err := deployed(addr, txn)
-	if err != nil {
-		return nil, err
-	}
-
-	if contractDeployed {
-		return nil, ErrContractAlreadyDeployed
-	}
-
-	err = setClassHash(txn, addr, classHash)
-	if err != nil {
-		return nil, err
-	}
-
-	c, err := NewContractUpdater(addr, txn)
-	if err != nil {
-		return nil, err
-	}
-
-	err = c.UpdateNonce(&felt.Zero)
-	if err != nil {
-		return nil, err
-	}
-
-	return c, nil
-}
-
-// ContractAddress computes the address of a Starknet contract.
+// Computes the address of a Starknet contract.
 func ContractAddress(callerAddress, classHash, salt *felt.Felt, constructorCallData []*felt.Felt) *felt.Felt {
 	prefix := new(felt.Felt).SetBytes([]byte("STARKNET_CONTRACT_ADDRESS"))
 	callDataHash := crypto.PedersenArray(constructorCallData...)
@@ -78,132 +19,3 @@ func ContractAddress(callerAddress, classHash, salt *felt.Felt, constructorCallD
 		callDataHash,
 	)
 }
-
-func deployed(addr *felt.Felt, txn db.Transaction) (bool, error) {
-	_, err := ContractClassHash(addr, txn)
-	if errors.Is(err, db.ErrKeyNotFound) {
-		return false, nil
-	}
-	if err != nil {
-		return false, err
-	}
-	return true, nil
-}
-
-// ContractUpdater is a helper to update an existing contract instance.
-type ContractUpdater struct {
-	// Address that this contract instance is deployed to
-	Address *felt.Felt
-	// txn to access the database
-	txn db.Transaction
-}
-
-// Purge eliminates the contract instance, deleting all associated data from storage
-// assumes storage is cleared in revert process
-func (c *ContractUpdater) Purge() error {
-	addrBytes := c.Address.Marshal()
-	buckets := []db.Bucket{db.ContractNonce, db.ContractClassHash}
-
-	for _, bucket := range buckets {
-		if err := c.txn.Delete(bucket.Key(addrBytes)); err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
-// ContractNonce returns the amount transactions sent from this contract.
-// Only account contracts can have a non-zero nonce.
-func ContractNonce(addr *felt.Felt, txn db.Transaction) (*felt.Felt, error) {
-	key := db.ContractNonce.Key(addr.Marshal())
-	var nonce *felt.Felt
-	if err := txn.Get(key, func(val []byte) error {
-		nonce = new(felt.Felt)
-		nonce.SetBytes(val)
-		return nil
-	}); err != nil {
-		return nil, err
-	}
-	return nonce, nil
-}
-
-// UpdateNonce updates the nonce value in the database.
-func (c *ContractUpdater) UpdateNonce(nonce *felt.Felt) error {
-	nonceKey := db.ContractNonce.Key(c.Address.Marshal())
-	return c.txn.Set(nonceKey, nonce.Marshal())
-}
-
-// ContractRoot returns the root of the contract storage.
-func ContractRoot(addr *felt.Felt, txn db.Transaction) (*felt.Felt, error) {
-	cStorage, err := storage(addr, txn)
-	if err != nil {
-		return nil, err
-	}
-	return cStorage.Root()
-}
-
-type OnValueChanged = func(location, oldValue *felt.Felt) error
-
-// UpdateStorage applies a change-set to the contract storage.
-func (c *ContractUpdater) UpdateStorage(diff map[felt.Felt]*felt.Felt, cb OnValueChanged) error {
-	cStorage, err := storage(c.Address, c.txn)
-	if err != nil {
-		return err
-	}
-	// apply the diff
-	for key, value := range diff {
-		oldValue, pErr := cStorage.Put(&key, value)
-		if pErr != nil {
-			return pErr
-		}
-
-		if oldValue != nil {
-			if err = cb(&key, oldValue); err != nil {
-				return err
-			}
-		}
-	}
-
-	return cStorage.Commit()
-}
-
-func ContractStorage(addr, key *felt.Felt, txn db.Transaction) (*felt.Felt, error) {
-	cStorage, err := storage(addr, txn)
-	if err != nil {
-		return nil, err
-	}
-	return cStorage.Get(key)
-}
-
-// ContractClassHash returns hash of the class that the contract at the given address instantiates.
-func ContractClassHash(addr *felt.Felt, txn db.Transaction) (*felt.Felt, error) {
-	key := db.ContractClassHash.Key(addr.Marshal())
-	var classHash *felt.Felt
-	if err := txn.Get(key, func(val []byte) error {
-		classHash = new(felt.Felt)
-		classHash.SetBytes(val)
-		return nil
-	}); err != nil {
-		return nil, err
-	}
-	return classHash, nil
-}
-
-func setClassHash(txn db.Transaction, addr, classHash *felt.Felt) error {
-	classHashKey := db.ContractClassHash.Key(addr.Marshal())
-	return txn.Set(classHashKey, classHash.Marshal())
-}
-
-// Replace replaces the class that the contract instantiates
-func (c *ContractUpdater) Replace(classHash *felt.Felt) error {
-	return setClassHash(c.txn, c.Address, classHash)
-}
-
-// storage returns the [core.Trie] that represents the
-// storage of the contract.
-func storage(addr *felt.Felt, txn db.Transaction) (*trie.Trie, error) {
-	addrBytes := addr.Marshal()
-	trieTxn := trie.NewStorage(txn, db.ContractStorage.Key(addrBytes))
-	return trie.NewTriePedersen(trieTxn, ContractStorageTrieHeight)
-}
diff --git a/core/contract_test.go b/core/contract_test.go
index 8ace83ba7e..37e85d0fea 100644
--- a/core/contract_test.go
+++ b/core/contract_test.go
@@ -1,20 +1,12 @@
-package core_test
+package core
 
 import (
 	"testing"
 
-	"github.com/NethermindEth/juno/core"
 	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/db/pebble"
 	"github.com/NethermindEth/juno/utils"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
 )
 
-var NoopOnValueChanged = func(location, oldValue *felt.Felt) error {
-	return nil
-}
-
 func TestContractAddress(t *testing.T) {
 	tests := []struct {
 		callerAddress       *felt.Felt
@@ -43,155 +35,10 @@ func TestContractAddress(t *testing.T) {
 
 	for _, tt := range tests {
 		t.Run("Address", func(t *testing.T) {
-			address := core.ContractAddress(tt.callerAddress, tt.classHash, tt.salt, tt.constructorCallData)
+			address := ContractAddress(tt.callerAddress, tt.classHash, tt.salt, tt.constructorCallData)
 			if !address.Equal(tt.want) {
 				t.Errorf("wrong address: got %s, want %s", address.String(), tt.want.String())
 			}
 		})
 	}
 }
-
-func TestNewContract(t *testing.T) {
-	testDB := pebble.NewMemTest(t)
-
-	txn, err := testDB.NewTransaction(true)
-	require.NoError(t, err)
-	t.Cleanup(func() {
-		require.NoError(t, txn.Discard())
-	})
-	addr := new(felt.Felt).SetUint64(234)
-	classHash := new(felt.Felt).SetBytes([]byte("class hash"))
-
-	t.Run("cannot create Contract instance if un-deployed", func(t *testing.T) {
-		_, err = core.NewContractUpdater(addr, txn)
-		require.EqualError(t, err, core.ErrContractNotDeployed.Error())
-	})
-
-	contract, err := core.DeployContract(addr, classHash, txn)
-	require.NoError(t, err)
-
-	t.Run("redeploy should fail", func(t *testing.T) {
-		_, err := core.DeployContract(addr, classHash, txn)
-		require.EqualError(t, err, core.ErrContractAlreadyDeployed.Error())
-	})
-
-	t.Run("a call to contract should fail with a committed txn", func(t *testing.T) {
-		assert.NoError(t, txn.Commit())
-		t.Run("ClassHash()", func(t *testing.T) {
-			_, err := core.ContractClassHash(addr, txn)
-			assert.Error(t, err)
-		})
-		t.Run("Root()", func(t *testing.T) {
-			_, err := core.ContractRoot(addr, txn)
-			assert.Error(t, err)
-		})
-		t.Run("Nonce()", func(t *testing.T) {
-			_, err := core.ContractNonce(addr, txn)
-			assert.Error(t, err)
-		})
-		t.Run("Storage()", func(t *testing.T) {
-			_, err := core.ContractStorage(addr, classHash, txn)
-			assert.Error(t, err)
-		})
-		t.Run("UpdateNonce()", func(t *testing.T) {
-			assert.Error(t, contract.UpdateNonce(&felt.Zero))
-		})
-		t.Run("UpdateStorage()", func(t *testing.T) {
-			assert.Error(t, contract.UpdateStorage(nil, NoopOnValueChanged))
-		})
-	})
-}
-
-func TestNonceAndClassHash(t *testing.T) {
-	testDB := pebble.NewMemTest(t)
-
-	txn, err := testDB.NewTransaction(true)
-	require.NoError(t, err)
-	addr := new(felt.Felt).SetUint64(44)
-	classHash := new(felt.Felt).SetUint64(37)
-
-	contract, err := core.DeployContract(addr, classHash, txn)
-	require.NoError(t, err)
-
-	t.Run("initial nonce should be 0", func(t *testing.T) {
-		got, err := core.ContractNonce(addr, txn)
-		require.NoError(t, err)
-		assert.Equal(t, new(felt.Felt), got)
-	})
-	t.Run("UpdateNonce()", func(t *testing.T) {
-		require.NoError(t, contract.UpdateNonce(classHash))
-
-		got, err := core.ContractNonce(addr, txn)
-		require.NoError(t, err)
-		assert.Equal(t, classHash, got)
-	})
-
-	t.Run("ClassHash()", func(t *testing.T) {
-		got, err := core.ContractClassHash(addr, txn)
-		require.NoError(t, err)
-		assert.Equal(t, classHash, got)
-	})
-
-	t.Run("Replace()", func(t *testing.T) {
-		replaceWith := utils.HexToFelt(t, "0xDEADBEEF")
-		require.NoError(t, contract.Replace(replaceWith))
-		got, err := core.ContractClassHash(addr, txn)
-		require.NoError(t, err)
-		assert.Equal(t, replaceWith, got)
-	})
-}
-
-func TestUpdateStorageAndStorage(t *testing.T) {
-	testDB := pebble.NewMemTest(t)
-
-	txn, err := testDB.NewTransaction(true)
-	require.NoError(t, err)
-	addr := new(felt.Felt).SetUint64(44)
-	classHash := new(felt.Felt).SetUint64(37)
-
-	contract, err := core.DeployContract(addr, classHash, txn)
-	require.NoError(t, err)
-
-	t.Run("apply storage diff", func(t *testing.T) {
-		oldRoot, err := core.ContractRoot(addr, txn)
-		require.NoError(t, err)
-
-		require.NoError(t, contract.UpdateStorage(map[felt.Felt]*felt.Felt{*addr: classHash}, NoopOnValueChanged))
-
-		gotValue, err := core.ContractStorage(addr, addr, txn)
-		require.NoError(t, err)
-		assert.Equal(t, classHash, gotValue)
-
-		newRoot, err := core.ContractRoot(addr, txn)
-		require.NoError(t, err)
-		assert.NotEqual(t, oldRoot, newRoot)
-	})
-
-	t.Run("delete key from storage with storage diff", func(t *testing.T) {
-		require.NoError(t, contract.UpdateStorage(map[felt.Felt]*felt.Felt{*addr: new(felt.Felt)}, NoopOnValueChanged))
-
-		val, err := core.ContractStorage(addr, addr, txn)
-		require.NoError(t, err)
-		require.Equal(t, &felt.Zero, val)
-
-		sRoot, err := core.ContractRoot(addr, txn)
-		require.NoError(t, err)
-		assert.Equal(t, new(felt.Felt), sRoot)
-	})
-}
-
-func TestPurge(t *testing.T) {
-	testDB := pebble.NewMemTest(t)
-
-	txn, err := testDB.NewTransaction(true)
-	require.NoError(t, err)
-	addr := new(felt.Felt).SetUint64(44)
-	classHash := new(felt.Felt).SetUint64(37)
-
-	contract, err := core.DeployContract(addr, classHash, txn)
-	require.NoError(t, err)
-
-	require.NoError(t, contract.Purge())
-	_, err = core.NewContractUpdater(addr, txn)
-	assert.ErrorIs(t, err, core.ErrContractNotDeployed)
-}
diff --git a/core/state/contract.go b/core/state/contract.go
index 848314d7a7..386ba13090 100644
--- a/core/state/contract.go
+++ b/core/state/contract.go
@@ -266,21 +266,6 @@ func getContract(addr *felt.Felt, txn db.Transaction) (*StateContract, error) {
 	return &contract, nil
 }
 
-// Computes the address of a Starknet contract.
-func ContractAddress(callerAddress, classHash, salt *felt.Felt, constructorCallData []*felt.Felt) *felt.Felt {
-	prefix := new(felt.Felt).SetBytes([]byte("STARKNET_CONTRACT_ADDRESS"))
-	callDataHash := crypto.PedersenArray(constructorCallData...)
-
-	// https://docs.starknet.io/architecture-and-concepts/smart-contracts/contract-address/
-	return crypto.PedersenArray(
-		prefix,
-		callerAddress,
-		salt,
-		classHash,
-		callDataHash,
-	)
-}
-
 func contractKey(addr *felt.Felt) []byte {
 	return db.Contract.Key(addr.Marshal())
 }
diff --git a/core/state/contract_test.go b/core/state/contract_test.go
index d118b2a1ce..a28c2d4d4c 100644
--- a/core/state/contract_test.go
+++ b/core/state/contract_test.go
@@ -5,7 +5,6 @@ import (
 
 	"github.com/NethermindEth/juno/core/felt"
 	"github.com/NethermindEth/juno/db/pebble"
-	"github.com/NethermindEth/juno/utils"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
@@ -35,42 +34,6 @@ func TestMarshalBinary(t *testing.T) {
 	assert.Nil(t, unmarshalled.StorageRoot)
 }
 
-func TestContractAddress(t *testing.T) {
-	tests := []struct {
-		callerAddress       *felt.Felt
-		classHash           *felt.Felt
-		salt                *felt.Felt
-		constructorCallData []*felt.Felt
-		want                *felt.Felt
-	}{
-		{
-			// https://alpha-mainnet.starknet.io/feeder_gateway/get_transaction?transactionHash=0x6486c6303dba2f364c684a2e9609211c5b8e417e767f37b527cda51e776e6f0
-			callerAddress: utils.HexToFelt(t, "0x0000000000000000000000000000000000000000"),
-			classHash: utils.HexToFelt(
-				t, "0x46f844ea1a3b3668f81d38b5c1bd55e816e0373802aefe732138628f0133486"),
-			salt: utils.HexToFelt(
-				t, "0x74dc2fe193daf1abd8241b63329c1123214842b96ad7fd003d25512598a956b"),
-			constructorCallData: []*felt.Felt{
-				utils.HexToFelt(t, "0x6d706cfbac9b8262d601c38251c5fbe0497c3a96cc91a92b08d91b61d9e70c4"),
-				utils.HexToFelt(t, "0x79dc0da7c54b95f10aa182ad0a46400db63156920adb65eca2654c0945a463"),
-				utils.HexToFelt(t, "0x2"),
-				utils.HexToFelt(t, "0x6658165b4984816ab189568637bedec5aa0a18305909c7f5726e4a16e3afef6"),
-				utils.HexToFelt(t, "0x6b648b36b074a91eee55730f5f5e075ec19c0a8f9ffb0903cefeee93b6ff328"),
-			},
-			want: utils.HexToFelt(t, "0x3ec215c6c9028ff671b46a2a9814970ea23ed3c4bcc3838c6d1dcbf395263c3"),
-		},
-	}
-
-	for _, tt := range tests {
-		t.Run("Address", func(t *testing.T) {
-			address := ContractAddress(tt.callerAddress, tt.classHash, tt.salt, tt.constructorCallData)
-			if !address.Equal(tt.want) {
-				t.Errorf("wrong address: got %s, want %s", address.String(), tt.want.String())
-			}
-		})
-	}
-}
-
 func TestNewContract(t *testing.T) {
 	testDB := pebble.NewMemTest(t)
 

From b7e7a1f45e521ad008483ff8001af5a37d4353c8 Mon Sep 17 00:00:00 2001
From: weiihann <weihan774237@gmail.com>
Date: Tue, 18 Feb 2025 13:42:11 +0800
Subject: [PATCH 08/15] integration done

---
 blockchain/state.go                        |   8 +-
 core/{trie => legacytrie}/bitarray.go      |   2 +-
 core/{trie => legacytrie}/bitarray_test.go |   2 +-
 core/{trie => legacytrie}/node.go          |   2 +-
 core/{trie => legacytrie}/storage.go       |   2 +-
 core/{trie => legacytrie}/trie.go          |   4 +-
 core/receipt.go                            |  17 +-
 core/state/history.go                      |   8 +-
 core/state/state.go                        |  12 +-
 core/state/state_test.go                   |   1 -
 core/transaction.go                        |  12 +-
 core/trie/node_test.go                     |  28 -
 core/trie/proof.go                         | 618 ---------------
 core/trie/proof_test.go                    | 827 ---------------------
 core/trie/storage_test.go                  | 108 ---
 core/trie/trie_pkg_test.go                 | 252 -------
 core/trie/trie_test.go                     | 456 ------------
 migration/migration.go                     |   2 +-
 migration/migration_pkg_test.go            |   2 +-
 mocks/mock_state.go                        |  14 +-
 rpc/v8/storage.go                          |  81 +-
 rpc/v8/storage_test.go                     |  74 +-
 sync/pending.go                            |   8 +-
 23 files changed, 120 insertions(+), 2420 deletions(-)
 rename core/{trie => legacytrie}/bitarray.go (99%)
 rename core/{trie => legacytrie}/bitarray_test.go (99%)
 rename core/{trie => legacytrie}/node.go (99%)
 rename core/{trie => legacytrie}/storage.go (99%)
 rename core/{trie => legacytrie}/trie.go (99%)
 delete mode 100644 core/trie/node_test.go
 delete mode 100644 core/trie/proof.go
 delete mode 100644 core/trie/proof_test.go
 delete mode 100644 core/trie/storage_test.go
 delete mode 100644 core/trie/trie_pkg_test.go
 delete mode 100644 core/trie/trie_test.go

diff --git a/blockchain/state.go b/blockchain/state.go
index 7b279c279c..bf506c842c 100644
--- a/blockchain/state.go
+++ b/blockchain/state.go
@@ -4,7 +4,7 @@ import (
 	"github.com/NethermindEth/juno/core"
 	"github.com/NethermindEth/juno/core/felt"
 	"github.com/NethermindEth/juno/core/state"
-	"github.com/NethermindEth/juno/core/trie"
+	"github.com/NethermindEth/juno/core/trie2"
 	"github.com/NethermindEth/juno/db"
 	"github.com/NethermindEth/juno/utils"
 )
@@ -34,9 +34,9 @@ type ClassReader interface {
 }
 
 type TrieProvider interface {
-	ClassTrie() (*trie.Trie, error)
-	ContractTrie() (*trie.Trie, error)
-	ContractStorageTrie(addr *felt.Felt) (*trie.Trie, error)
+	ClassTrie() (*trie2.Trie, error)
+	ContractTrie() (*trie2.Trie, error)
+	ContractStorageTrie(addr *felt.Felt) (*trie2.Trie, error)
 }
 
 // HeadState returns a StateReader that provides a stable view to the latest state
diff --git a/core/trie/bitarray.go b/core/legacytrie/bitarray.go
similarity index 99%
rename from core/trie/bitarray.go
rename to core/legacytrie/bitarray.go
index c44d24ba34..7594d7b6d2 100644
--- a/core/trie/bitarray.go
+++ b/core/legacytrie/bitarray.go
@@ -1,4 +1,4 @@
-package trie
+package legacytrie
 
 import (
 	"bytes"
diff --git a/core/trie/bitarray_test.go b/core/legacytrie/bitarray_test.go
similarity index 99%
rename from core/trie/bitarray_test.go
rename to core/legacytrie/bitarray_test.go
index e711a9ddd6..18a48ab064 100644
--- a/core/trie/bitarray_test.go
+++ b/core/legacytrie/bitarray_test.go
@@ -1,4 +1,4 @@
-package trie
+package legacytrie
 
 import (
 	"bytes"
diff --git a/core/trie/node.go b/core/legacytrie/node.go
similarity index 99%
rename from core/trie/node.go
rename to core/legacytrie/node.go
index 0ef2bfc44e..9a1e2f9d52 100644
--- a/core/trie/node.go
+++ b/core/legacytrie/node.go
@@ -1,4 +1,4 @@
-package trie
+package legacytrie
 
 import (
 	"bytes"
diff --git a/core/trie/storage.go b/core/legacytrie/storage.go
similarity index 99%
rename from core/trie/storage.go
rename to core/legacytrie/storage.go
index 1e16840834..abeed71c16 100644
--- a/core/trie/storage.go
+++ b/core/legacytrie/storage.go
@@ -1,4 +1,4 @@
-package trie
+package legacytrie
 
 import (
 	"bytes"
diff --git a/core/trie/trie.go b/core/legacytrie/trie.go
similarity index 99%
rename from core/trie/trie.go
rename to core/legacytrie/trie.go
index 8836632f93..3432850ab7 100644
--- a/core/trie/trie.go
+++ b/core/legacytrie/trie.go
@@ -1,5 +1,5 @@
 // Package trie implements a dense Merkle Patricia Trie. See the documentation on [Trie] for details.
-package trie
+package legacytrie
 
 import (
 	"errors"
@@ -14,8 +14,6 @@ import (
 	"github.com/NethermindEth/juno/utils"
 )
 
-const globalTrieHeight = 251 // TODO(weiihann): this is declared in core also, should be moved to a common place
-
 // Trie is a dense Merkle Patricia Trie (i.e., all internal nodes have two children).
 //
 // This implementation allows for a "flat" storage by keying nodes on their path rather than
diff --git a/core/receipt.go b/core/receipt.go
index 92f3e85f44..c4573c3482 100644
--- a/core/receipt.go
+++ b/core/receipt.go
@@ -6,7 +6,7 @@ import (
 
 	"github.com/NethermindEth/juno/core/crypto"
 	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/core/trie"
+	"github.com/NethermindEth/juno/core/trie2"
 )
 
 type GasConsumed struct {
@@ -67,7 +67,7 @@ func messagesSentHash(messages []*L2ToL1Message) *felt.Felt {
 func receiptCommitment(receipts []*TransactionReceipt) (*felt.Felt, error) {
 	return calculateCommitment(
 		receipts,
-		trie.RunOnTempTriePoseidon,
+		trie2.RunOnTempTriePoseidon,
 		func(receipt *TransactionReceipt) *felt.Felt {
 			return receipt.hash()
 		},
@@ -75,14 +75,14 @@ func receiptCommitment(receipts []*TransactionReceipt) (*felt.Felt, error) {
 }
 
 type (
-	onTempTrieFunc     func(uint8, func(*trie.Trie) error) error
+	onTempTrieFunc     func(uint8, func(*trie2.Trie) error) error
 	processFunc[T any] func(T) *felt.Felt
 )
 
 // General function for parallel processing of items and calculation of a commitment
 func calculateCommitment[T any](items []T, runOnTempTrie onTempTrieFunc, process processFunc[T]) (*felt.Felt, error) {
 	var commitment *felt.Felt
-	return commitment, runOnTempTrie(commitmentTrieHeight, func(trie *trie.Trie) error {
+	return commitment, runOnTempTrie(commitmentTrieHeight, func(trie *trie2.Trie) error {
 		numWorkers := min(runtime.GOMAXPROCS(0), len(items))
 		results := make([]*felt.Felt, len(items))
 		var wg sync.WaitGroup
@@ -107,16 +107,13 @@ func calculateCommitment[T any](items []T, runOnTempTrie onTempTrieFunc, process
 
 		for i, res := range results {
 			key := new(felt.Felt).SetUint64(uint64(i))
-			if _, err := trie.Put(key, res); err != nil {
+			if err := trie.Update(key, res); err != nil {
 				return err
 			}
 		}
 
-		root, err := trie.Root()
-		if err != nil {
-			return err
-		}
-		commitment = root
+		root := trie.Hash()
+		commitment = &root
 
 		return nil
 	})
diff --git a/core/state/history.go b/core/state/history.go
index e68225abae..dba5274c57 100644
--- a/core/state/history.go
+++ b/core/state/history.go
@@ -5,7 +5,7 @@ import (
 
 	"github.com/NethermindEth/juno/core"
 	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/core/trie"
+	"github.com/NethermindEth/juno/core/trie2"
 	"github.com/NethermindEth/juno/db"
 )
 
@@ -92,14 +92,14 @@ func (s *StateHistory) Class(classHash *felt.Felt) (*core.DeclaredClass, error)
 	return declaredClass, nil
 }
 
-func (s *StateHistory) ClassTrie() (*trie.Trie, error) {
+func (s *StateHistory) ClassTrie() (*trie2.Trie, error) {
 	return nil, ErrHistoricalTrieNotSupported
 }
 
-func (s *StateHistory) ContractTrie() (*trie.Trie, error) {
+func (s *StateHistory) ContractTrie() (*trie2.Trie, error) {
 	return nil, ErrHistoricalTrieNotSupported
 }
 
-func (s *StateHistory) ContractStorageTrie(addr *felt.Felt) (*trie.Trie, error) {
+func (s *StateHistory) ContractStorageTrie(addr *felt.Felt) (*trie2.Trie, error) {
 	return nil, ErrHistoricalTrieNotSupported
 }
diff --git a/core/state/state.go b/core/state/state.go
index 4b779137bb..60f9721a7a 100644
--- a/core/state/state.go
+++ b/core/state/state.go
@@ -10,7 +10,6 @@ import (
 	"github.com/NethermindEth/juno/core"
 	"github.com/NethermindEth/juno/core/crypto"
 	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/core/trie"
 	"github.com/NethermindEth/juno/core/trie2"
 	"github.com/NethermindEth/juno/db"
 )
@@ -115,15 +114,15 @@ func (s *State) Class(classHash *felt.Felt) (*core.DeclaredClass, error) {
 	return &class, nil
 }
 
-func (s *State) ClassTrie() (*trie.Trie, error) {
-	panic("not implemented")
+func (s *State) ClassTrie() (*trie2.Trie, error) {
+	return s.classTrie, nil
 }
 
-func (s *State) ContractTrie() (*trie.Trie, error) {
-	panic("not implemented")
+func (s *State) ContractTrie() (*trie2.Trie, error) {
+	return s.contractTrie, nil
 }
 
-func (s *State) ContractStorageTrie(addr *felt.Felt) (*trie.Trie, error) {
+func (s *State) ContractStorageTrie(addr *felt.Felt) (*trie2.Trie, error) {
 	panic("not implemented")
 }
 
@@ -134,7 +133,6 @@ func (s *State) Update(blockNum uint64, update *core.StateUpdate, declaredClasse
 		return err
 	}
 
-	// TODO(weiihann): try sorting the declaredClass by hashes in descending order
 	// Register the declared classes
 	for hash, class := range declaredClasses {
 		if err := s.putClass(&hash, class, blockNum); err != nil {
diff --git a/core/state/state_test.go b/core/state/state_test.go
index d3b832efbd..2e642d300e 100644
--- a/core/state/state_test.go
+++ b/core/state/state_test.go
@@ -260,7 +260,6 @@ func TestNonce(t *testing.T) {
 }
 
 func TestClass(t *testing.T) {
-	t.Skip("TODO(weiihann): remove this once integration is done")
 	txn, commit := setupState(t, nil, 0)
 	defer commit()
 
diff --git a/core/transaction.go b/core/transaction.go
index c65bc0d205..9ebb69d8dd 100644
--- a/core/transaction.go
+++ b/core/transaction.go
@@ -10,7 +10,7 @@ import (
 	"github.com/Masterminds/semver/v3"
 	"github.com/NethermindEth/juno/core/crypto"
 	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/core/trie"
+	"github.com/NethermindEth/juno/core/trie2"
 	"github.com/NethermindEth/juno/utils"
 	"github.com/bits-and-blooms/bloom/v3"
 	"github.com/ethereum/go-ethereum/common"
@@ -664,13 +664,13 @@ func transactionCommitmentPedersen(transactions []Transaction, protocolVersion s
 			return crypto.Pedersen(transaction.Hash(), signatureHash)
 		}
 	}
-	return calculateCommitment(transactions, trie.RunOnTempTriePedersen, hashFunc)
+	return calculateCommitment(transactions, trie2.RunOnTempTriePedersen, hashFunc)
 }
 
 // transactionCommitmentPoseidon0134 handles empty signatures compared to transactionCommitmentPoseidon0132:
 // empty signatures are interpreted as [] instead of [0]
 func transactionCommitmentPoseidon0134(transactions []Transaction) (*felt.Felt, error) {
-	return calculateCommitment(transactions, trie.RunOnTempTriePoseidon, func(transaction Transaction) *felt.Felt {
+	return calculateCommitment(transactions, trie2.RunOnTempTriePoseidon, func(transaction Transaction) *felt.Felt {
 		var digest crypto.PoseidonDigest
 		digest.Update(transaction.Hash())
 
@@ -684,7 +684,7 @@ func transactionCommitmentPoseidon0134(transactions []Transaction) (*felt.Felt,
 
 // transactionCommitmentPoseidon0132 is used to calculate tx commitment for 0.13.2 <= block.version < 0.13.4
 func transactionCommitmentPoseidon0132(transactions []Transaction) (*felt.Felt, error) {
-	return calculateCommitment(transactions, trie.RunOnTempTriePoseidon, func(transaction Transaction) *felt.Felt {
+	return calculateCommitment(transactions, trie2.RunOnTempTriePoseidon, func(transaction Transaction) *felt.Felt {
 		var digest crypto.PoseidonDigest
 		digest.Update(transaction.Hash())
 
@@ -718,7 +718,7 @@ func eventCommitmentPoseidon(receipts []*TransactionReceipt) (*felt.Felt, error)
 			})
 		}
 	}
-	return calculateCommitment(items, trie.RunOnTempTriePoseidon, func(item *eventWithTxHash) *felt.Felt {
+	return calculateCommitment(items, trie2.RunOnTempTriePoseidon, func(item *eventWithTxHash) *felt.Felt {
 		return crypto.PoseidonArray(
 			slices.Concat(
 				[]*felt.Felt{
@@ -746,7 +746,7 @@ func eventCommitmentPedersen(receipts []*TransactionReceipt) (*felt.Felt, error)
 	for _, receipt := range receipts {
 		events = append(events, receipt.Events...)
 	}
-	return calculateCommitment(events, trie.RunOnTempTriePedersen, func(event *Event) *felt.Felt {
+	return calculateCommitment(events, trie2.RunOnTempTriePedersen, func(event *Event) *felt.Felt {
 		return crypto.PedersenArray(
 			event.From,
 			crypto.PedersenArray(event.Keys...),
diff --git a/core/trie/node_test.go b/core/trie/node_test.go
deleted file mode 100644
index cc1bb06eda..0000000000
--- a/core/trie/node_test.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package trie_test
-
-import (
-	"encoding/hex"
-	"testing"
-
-	"github.com/NethermindEth/juno/core/crypto"
-	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/core/trie"
-	"github.com/NethermindEth/juno/utils"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-func TestNodeHash(t *testing.T) {
-	// https://github.com/eqlabs/pathfinder/blob/5e0f4423ed9e9385adbe8610643140e1a82eaef6/crates/pathfinder/src/state/merkle_node.rs#L350-L374
-	valueBytes, err := hex.DecodeString("1234ABCD")
-	require.NoError(t, err)
-
-	expected := utils.HexToFelt(t, "0x1d937094c09b5f8e26a662d21911871e3cbc6858d55cc49af9848ea6fed4e9")
-
-	node := trie.Node{
-		Value: new(felt.Felt).SetBytes(valueBytes),
-	}
-	path := trie.NewBitArray(6, 42)
-
-	assert.Equal(t, expected, node.Hash(&path, crypto.Pedersen), "TestTrieNode_Hash failed")
-}
diff --git a/core/trie/proof.go b/core/trie/proof.go
deleted file mode 100644
index c97b3eb311..0000000000
--- a/core/trie/proof.go
+++ /dev/null
@@ -1,618 +0,0 @@
-package trie
-
-import (
-	"errors"
-	"fmt"
-
-	"github.com/NethermindEth/juno/core/crypto"
-	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/utils"
-)
-
-type ProofNodeSet = utils.OrderedSet[felt.Felt, ProofNode]
-
-func NewProofNodeSet() *ProofNodeSet {
-	return utils.NewOrderedSet[felt.Felt, ProofNode]()
-}
-
-type ProofNode interface {
-	Hash(hash crypto.HashFn) *felt.Felt
-	Len() uint8
-	String() string
-}
-
-type Binary struct {
-	LeftHash  *felt.Felt
-	RightHash *felt.Felt
-}
-
-func (b *Binary) Hash(hash crypto.HashFn) *felt.Felt {
-	return hash(b.LeftHash, b.RightHash)
-}
-
-func (b *Binary) Len() uint8 {
-	return 1
-}
-
-func (b *Binary) String() string {
-	return fmt.Sprintf("Binary: %v:\n\tLeftHash: %v\n\tRightHash: %v\n", b.Hash(crypto.Pedersen), b.LeftHash, b.RightHash)
-}
-
-type Edge struct {
-	Child *felt.Felt // child hash
-	Path  *BitArray  // path from parent to child
-}
-
-func (e *Edge) Hash(hash crypto.HashFn) *felt.Felt {
-	var length [32]byte
-	length[31] = e.Path.len
-	pathFelt := e.Path.Felt()
-	lengthFelt := new(felt.Felt).SetBytes(length[:])
-	// TODO: no need to return reference, just return value to avoid heap allocation
-	return new(felt.Felt).Add(hash(e.Child, &pathFelt), lengthFelt)
-}
-
-func (e *Edge) Len() uint8 {
-	return e.Path.Len()
-}
-
-func (e *Edge) String() string {
-	return fmt.Sprintf("Edge: %v:\n\tChild: %v\n\tPath: %v\n", e.Hash(crypto.Pedersen), e.Child, e.Path)
-}
-
-// Prove generates a Merkle proof for a given key in the trie.
-// The result contains the proof nodes on the path from the root to the leaf.
-// The value is included in the proof if the key is present in the trie.
-// If the key is not present, the proof will contain the nodes on the path to the closest ancestor.
-func (t *Trie) Prove(key *felt.Felt, proof *ProofNodeSet) error {
-	k := t.FeltToKey(key)
-
-	nodesFromRoot, err := t.nodesFromRoot(&k)
-	if err != nil {
-		return err
-	}
-
-	var parentKey *BitArray
-
-	for i, sNode := range nodesFromRoot {
-		sNodeEdge, sNodeBinary, err := storageNodeToProofNode(t, parentKey, sNode)
-		if err != nil {
-			return err
-		}
-		isLeaf := sNode.key.len == t.height
-
-		if sNodeEdge != nil && !isLeaf { // Internal Edge
-			proof.Put(*sNodeEdge.Hash(t.hash), sNodeEdge)
-			proof.Put(*sNodeBinary.Hash(t.hash), sNodeBinary)
-		} else if sNodeEdge == nil && !isLeaf { // Internal Binary
-			proof.Put(*sNodeBinary.Hash(t.hash), sNodeBinary)
-		} else if sNodeEdge != nil && isLeaf { // Leaf Edge
-			proof.Put(*sNodeEdge.Hash(t.hash), sNodeEdge)
-		} else if sNodeEdge == nil && sNodeBinary == nil { // sNode is a binary leaf
-			break
-		}
-		parentKey = nodesFromRoot[i].key
-	}
-	return nil
-}
-
-// GetRangeProof generates a range proof for the given range of keys.
-// The proof contains the proof nodes on the path from the root to the closest ancestor of the left and right keys.
-func (t *Trie) GetRangeProof(leftKey, rightKey *felt.Felt, proofSet *ProofNodeSet) error {
-	err := t.Prove(leftKey, proofSet)
-	if err != nil {
-		return err
-	}
-
-	// If they are the same key, don't need to generate the proof again
-	if leftKey.Equal(rightKey) {
-		return nil
-	}
-
-	err = t.Prove(rightKey, proofSet)
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// VerifyProof verifies that a proof path is valid for a given key in a binary trie.
-// It walks through the proof nodes, verifying each step matches the expected path to reach the key.
-//
-// The verification process:
-// 1. Starts at the root hash and retrieves the corresponding proof node
-// 2. For each proof node:
-//   - Verifies the node's computed hash matches the expected hash
-//   - For Binary nodes:
-//     -- Uses the next unprocessed bit in the key to choose left/right path
-//     -- If key bit is 0, takes left path; if 1, takes right path
-//   - For Edge nodes:
-//     -- Verifies the compressed path matches the corresponding bits in the key
-//     -- Moves to the child node if paths match
-//
-// 3. Continues until all bits in the key are processed
-//
-// The proof is considered invalid if:
-//   - Any proof node is missing from the OrderedSet
-//   - Any node's computed hash doesn't match its expected hash
-//   - The path bits don't match the key bits
-//   - The proof ends before processing all key bits
-func VerifyProof(root, keyFelt *felt.Felt, proof *ProofNodeSet, hash crypto.HashFn) (*felt.Felt, error) {
-	keyBits := new(BitArray).SetFelt(globalTrieHeight, keyFelt)
-	expectedHash := root
-
-	var curPos uint8
-	for {
-		proofNode, ok := proof.Get(*expectedHash)
-		if !ok {
-			return nil, fmt.Errorf("proof node not found, expected hash: %s", expectedHash.String())
-		}
-
-		// Verify the hash matches
-		if !proofNode.Hash(hash).Equal(expectedHash) {
-			return nil, fmt.Errorf("proof node hash mismatch, expected hash: %s, got hash: %s", expectedHash.String(), proofNode.Hash(hash).String())
-		}
-
-		switch node := proofNode.(type) {
-		case *Binary: // Binary nodes represent left/right choices
-			if keyBits.Len() <= curPos {
-				return nil, fmt.Errorf("key length less than current position, key length: %d, current position: %d", keyBits.Len(), curPos)
-			}
-			// Determine the next node to traverse based on the next bit position
-			expectedHash = node.LeftHash
-			if keyBits.IsBitSet(curPos) {
-				expectedHash = node.RightHash
-			}
-			curPos++
-		case *Edge: // Edge nodes represent paths between binary nodes
-			if !verifyEdgePath(keyBits, node.Path, curPos) {
-				return &felt.Zero, nil
-			}
-
-			// Move to the immediate child node
-			curPos += node.Path.Len()
-			expectedHash = node.Child
-		}
-
-		// We've consumed all bits in our path
-		if curPos >= keyBits.Len() {
-			return expectedHash, nil
-		}
-	}
-}
-
-// VerifyRangeProof checks the validity of given key-value pairs and range proof against a provided root hash.
-// The key-value pairs should be consecutive (no gaps) and monotonically increasing.
-// The range proof contains two edge proofs: one for the first key and another for the last key.
-// Both edge proofs can be for existent or non-existent keys.
-// This function handles the following special cases:
-//
-//   - All elements proof: The proof can be nil if the range includes all leaves in the trie.
-//   - Single element proof: Both left and right edge proofs are identical, and the range contains only one element.
-//   - Zero element proof: A single edge proof suffices for verification. The proof is invalid if there are additional elements.
-//
-// The function returns a boolean indicating if there are more elements and an error if the range proof is invalid.
-//
-// TODO(weiihann): Given a binary leaf and a left-sibling first key, if the right sibling is removed, the proof would still be valid.
-// Conversely, given a binary leaf and a right-sibling last key, if the left sibling is removed, the proof would still be valid.
-// Range proof should not be valid for both of these cases, but currently is, which is an attack vector.
-// The problem probably lies in how we do root hash calculation.
-func VerifyRangeProof(root, first *felt.Felt, keys, values []*felt.Felt, proof *ProofNodeSet) (bool, error) { //nolint:funlen,gocyclo
-	// Ensure the number of keys and values are the same
-	if len(keys) != len(values) {
-		return false, fmt.Errorf("inconsistent length of proof data, keys: %d, values: %d", len(keys), len(values))
-	}
-
-	// Ensure all keys are monotonically increasing and values contain no deletions
-	for i := range keys {
-		if i < len(keys)-1 && keys[i].Cmp(keys[i+1]) > 0 {
-			return false, errors.New("keys are not monotonic increasing")
-		}
-
-		if values[i] == nil || values[i].Equal(&felt.Zero) {
-			return false, errors.New("range contains empty leaf")
-		}
-	}
-
-	// Special case: no edge proof provided; the given range contains all leaves in the trie
-	if proof == nil {
-		tr, err := buildTrie(globalTrieHeight, nil, nil, keys, values)
-		if err != nil {
-			return false, err
-		}
-
-		recomputedRoot, err := tr.Root()
-		if err != nil {
-			return false, err
-		}
-
-		if !recomputedRoot.Equal(root) {
-			return false, fmt.Errorf("root hash mismatch, expected: %s, got: %s", root.String(), recomputedRoot.String())
-		}
-
-		return false, nil // no more elements available
-	}
-
-	nodes := NewStorageNodeSet()
-	firstKey := new(BitArray).SetFelt(globalTrieHeight, first)
-
-	// Special case: there is a provided proof but no key-value pairs, make sure regenerated trie has no more values
-	// Empty range proof with more elements on the right is not accepted in this function.
-	// This is due to snap sync specification detail, where the responder must send an existing key (if any) if the requested range is empty.
-	if len(keys) == 0 {
-		rootKey, val, err := proofToPath(root, firstKey, proof, nodes)
-		if err != nil {
-			return false, err
-		}
-
-		if val != nil || hasRightElement(rootKey, firstKey, nodes) {
-			return false, errors.New("more entries available")
-		}
-
-		return false, nil
-	}
-
-	last := keys[len(keys)-1]
-	lastKey := new(BitArray).SetFelt(globalTrieHeight, last)
-
-	// Special case: there is only one element and two edge keys are the same
-	if len(keys) == 1 && firstKey.Equal(lastKey) {
-		rootKey, val, err := proofToPath(root, firstKey, proof, nodes)
-		if err != nil {
-			return false, err
-		}
-
-		elementKey := new(BitArray).SetFelt(globalTrieHeight, keys[0])
-		if !firstKey.Equal(elementKey) {
-			return false, errors.New("correct proof but invalid key")
-		}
-
-		if val == nil || !values[0].Equal(val) {
-			return false, errors.New("correct proof but invalid value")
-		}
-
-		return hasRightElement(rootKey, firstKey, nodes), nil
-	}
-
-	// In all other cases, we require two edge paths available.
-	// First, ensure that the last key is greater than the first key
-	if last.Cmp(first) <= 0 {
-		return false, errors.New("last key is less than first key")
-	}
-
-	rootKey, _, err := proofToPath(root, firstKey, proof, nodes)
-	if err != nil {
-		return false, err
-	}
-
-	lastRootKey, _, err := proofToPath(root, lastKey, proof, nodes)
-	if err != nil {
-		return false, err
-	}
-
-	if !rootKey.Equal(lastRootKey) {
-		return false, errors.New("first and last root keys do not match")
-	}
-
-	// Build the trie from the proof paths
-	tr, err := buildTrie(globalTrieHeight, rootKey, nodes.List(), keys, values)
-	if err != nil {
-		return false, err
-	}
-
-	// Verify that the recomputed root hash matches the provided root hash
-	recomputedRoot, err := tr.Root()
-	if err != nil {
-		return false, err
-	}
-
-	if !recomputedRoot.Equal(root) {
-		return false, fmt.Errorf("root hash mismatch, expected: %s, got: %s", root.String(), recomputedRoot.String())
-	}
-
-	return hasRightElement(rootKey, lastKey, nodes), nil
-}
-
-// isEdge checks if the storage node is an edge node.
-func isEdge(parentKey *BitArray, sNode StorageNode) bool {
-	sNodeLen := sNode.key.len
-	if parentKey == nil { // Root
-		return sNodeLen != 0
-	}
-	return sNodeLen-parentKey.len > 1
-}
-
-// storageNodeToProofNode converts a StorageNode to the ProofNode(s).
-// Juno's Trie has nodes that are Binary AND Edge, whereas the protocol requires nodes that are Binary XOR Edge.
-// We need to convert the former to the latter for proof generation.
-func storageNodeToProofNode(tri *Trie, parentKey *BitArray, sNode StorageNode) (*Edge, *Binary, error) {
-	var edge *Edge
-	if isEdge(parentKey, sNode) {
-		edgePath := path(sNode.key, parentKey)
-		edge = &Edge{
-			Path:  &edgePath,
-			Child: sNode.node.Value,
-		}
-	}
-	if sNode.key.len == tri.height { // Leaf
-		return edge, nil, nil
-	}
-	lNode, err := tri.GetNodeFromKey(sNode.node.Left)
-	if err != nil {
-		return nil, nil, err
-	}
-	rNode, err := tri.GetNodeFromKey(sNode.node.Right)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	rightHash := rNode.Value
-	if isEdge(sNode.key, StorageNode{node: rNode, key: sNode.node.Right}) {
-		edgePath := path(sNode.node.Right, sNode.key)
-		rEdge := &Edge{
-			Path:  &edgePath,
-			Child: rNode.Value,
-		}
-		rightHash = rEdge.Hash(tri.hash)
-	}
-	leftHash := lNode.Value
-	if isEdge(sNode.key, StorageNode{node: lNode, key: sNode.node.Left}) {
-		edgePath := path(sNode.node.Left, sNode.key)
-		lEdge := &Edge{
-			Path:  &edgePath,
-			Child: lNode.Value,
-		}
-		leftHash = lEdge.Hash(tri.hash)
-	}
-	binary := &Binary{
-		LeftHash:  leftHash,
-		RightHash: rightHash,
-	}
-
-	return edge, binary, nil
-}
-
-// proofToPath converts a Merkle proof to trie node path. All necessary nodes will be resolved and leave the remaining
-// as hashes. The given edge proof can be existent or non-existent.
-func proofToPath(root *felt.Felt, keyBits *BitArray, proof *ProofNodeSet, nodes *StorageNodeSet) (*BitArray, *felt.Felt, error) {
-	rootKey, val, err := buildPath(root, keyBits, 0, nil, proof, nodes)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	// Special case: non-existent key at the root
-	// We must include the root node in the node set.
-	// We will only get the following two cases:
-	// 1. The root node is an edge node only where path.len == key.len (single key trie)
-	// 2. The root node is an edge node + binary node (double key trie)
-	if nodes.Size() == 0 {
-		proofNode, ok := proof.Get(*root)
-		if !ok {
-			return nil, nil, fmt.Errorf("root proof node not found: %s", root)
-		}
-
-		edge, ok := proofNode.(*Edge)
-		if !ok {
-			return nil, nil, fmt.Errorf("expected edge node at root, got: %T", proofNode)
-		}
-
-		sn := NewPartialStorageNode(edge.Path, edge.Child)
-
-		// Handle leaf edge case (single key trie)
-		if edge.Path.Len() == keyBits.Len() {
-			if err := nodes.Put(*sn.key, sn); err != nil {
-				return nil, nil, fmt.Errorf("failed to store leaf edge: %w", err)
-			}
-			return sn.Key(), sn.Value(), nil
-		}
-
-		// Handle edge + binary case (double key trie)
-		child, ok := proof.Get(*edge.Child)
-		if !ok {
-			return nil, nil, fmt.Errorf("edge child not found: %s", edge.Child)
-		}
-
-		binary, ok := child.(*Binary)
-		if !ok {
-			return nil, nil, fmt.Errorf("expected binary node as child, got: %T", child)
-		}
-		sn.node.LeftHash = binary.LeftHash
-		sn.node.RightHash = binary.RightHash
-
-		if err := nodes.Put(*sn.key, sn); err != nil {
-			return nil, nil, fmt.Errorf("failed to store edge+binary: %w", err)
-		}
-		rootKey = sn.Key()
-	}
-
-	return rootKey, val, nil
-}
-
-// buildPath recursively builds the path for a given node hash, key, and current position.
-// It returns the current node's key and any leaf value found along this path.
-func buildPath(
-	nodeHash *felt.Felt,
-	key *BitArray,
-	curPos uint8,
-	curNode *StorageNode,
-	proof *ProofNodeSet,
-	nodes *StorageNodeSet,
-) (*BitArray, *felt.Felt, error) {
-	// We reached the leaf
-	if curPos == key.Len() {
-		leafKey := key.Copy()
-		leafNode := NewPartialStorageNode(&leafKey, nodeHash)
-		if err := nodes.Put(leafKey, leafNode); err != nil {
-			return nil, nil, err
-		}
-		return leafNode.Key(), leafNode.Value(), nil
-	}
-
-	proofNode, ok := proof.Get(*nodeHash)
-	if !ok { // non-existent proof node
-		return emptyBitArray, nil, nil
-	}
-
-	switch pn := proofNode.(type) {
-	case *Binary:
-		return handleBinaryNode(pn, nodeHash, key, curPos, curNode, proof, nodes)
-	case *Edge:
-		return handleEdgeNode(pn, key, curPos, proof, nodes)
-	}
-
-	return nil, nil, nil
-}
-
-// handleBinaryNode processes a binary node in the proof path by creating/updating a storage node,
-// setting its left/right hashes, and recursively building the path for the appropriate child direction.
-// It returns the current node's key and any leaf value found along this path.
-func handleBinaryNode(
-	binary *Binary,
-	nodeHash *felt.Felt,
-	key *BitArray,
-	curPos uint8,
-	curNode *StorageNode,
-	proof *ProofNodeSet,
-	nodes *StorageNodeSet,
-) (*BitArray, *felt.Felt, error) {
-	// If curNode is nil, it means that this current binary node is the root node.
-	// Or, it's an internal binary node and the parent is also a binary node.
-	// A standalone binary proof node always corresponds to a single storage node.
-	// If curNode is not nil, it means that the parent node is an edge node.
-	// In this case, the key of the storage node is based on the parent edge node.
-	if curNode == nil {
-		curNode = NewPartialStorageNode(new(BitArray).MSBs(key, curPos), nodeHash)
-	}
-	curNode.node.LeftHash = binary.LeftHash
-	curNode.node.RightHash = binary.RightHash
-
-	// Calculate next position and determine to take left or right path
-	nextPos := curPos + 1
-	isRightPath := key.IsBitSet(curPos)
-	nextHash := binary.LeftHash
-	if isRightPath {
-		nextHash = binary.RightHash
-	}
-
-	childKey, val, err := buildPath(nextHash, key, nextPos, nil, proof, nodes)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	// Set child reference
-	if isRightPath {
-		curNode.node.Right = childKey
-	} else {
-		curNode.node.Left = childKey
-	}
-
-	if err := nodes.Put(*curNode.key, curNode); err != nil {
-		return nil, nil, fmt.Errorf("failed to store binary node: %w", err)
-	}
-
-	return curNode.Key(), val, nil
-}
-
-// handleEdgeNode processes an edge node in the proof path by verifying the edge path matches
-// the key path and either creating a leaf node or continuing to traverse the trie. It returns
-// the current node's key and any leaf value found along this path.
-func handleEdgeNode(
-	edge *Edge,
-	key *BitArray,
-	curPos uint8,
-	proof *ProofNodeSet,
-	nodes *StorageNodeSet,
-) (*BitArray, *felt.Felt, error) {
-	// Verify the edge path matches the key path
-	if !verifyEdgePath(key, edge.Path, curPos) {
-		return emptyBitArray, nil, nil
-	}
-
-	// The next node position is the end of the edge path
-	nextPos := curPos + edge.Path.Len()
-	curNode := NewPartialStorageNode(new(BitArray).MSBs(key, nextPos), edge.Child)
-
-	// This is an edge leaf, stop traversing the trie
-	if nextPos == key.Len() {
-		if err := nodes.Put(*curNode.key, curNode); err != nil {
-			return nil, nil, fmt.Errorf("failed to store edge leaf: %w", err)
-		}
-		return curNode.Key(), curNode.Value(), nil
-	}
-
-	_, val, err := buildPath(edge.Child, key, nextPos, curNode, proof, nodes)
-	if err != nil {
-		return nil, nil, fmt.Errorf("failed to build child path: %w", err)
-	}
-
-	if err := nodes.Put(*curNode.key, curNode); err != nil {
-		return nil, nil, fmt.Errorf("failed to store internal edge: %w", err)
-	}
-
-	return curNode.Key(), val, nil
-}
-
-// verifyEdgePath checks if the edge path matches the key path at the current position.
-func verifyEdgePath(key, edgePath *BitArray, curPos uint8) bool {
-	return new(BitArray).LSBs(key, curPos).EqualMSBs(edgePath)
-}
-
-// buildTrie builds a trie from a list of storage nodes and a list of keys and values.
-func buildTrie(height uint8, rootKey *BitArray, nodes []*StorageNode, keys, values []*felt.Felt) (*Trie, error) {
-	tr, err := NewTriePedersen(newMemStorage(), height)
-	if err != nil {
-		return nil, err
-	}
-
-	tr.setRootKey(rootKey)
-
-	// Nodes are inserted in reverse order because the leaf nodes are placed at the front of the list.
-	// We would want to insert root node first so the root key is set first.
-	for i := len(nodes) - 1; i >= 0; i-- {
-		if err := tr.PutInner(nodes[i].key, nodes[i].node); err != nil {
-			return nil, err
-		}
-	}
-
-	for index, key := range keys {
-		_, err = tr.PutWithProof(key, values[index], nodes)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	return tr, nil
-}
-
-// hasRightElement checks if there is a right sibling for the given key in the trie.
-// This function assumes that the entire path has been resolved.
-func hasRightElement(rootKey, key *BitArray, nodes *StorageNodeSet) bool {
-	cur := rootKey
-	for cur != nil && !cur.Equal(emptyBitArray) {
-		sn, ok := nodes.Get(*cur)
-		if !ok {
-			return false
-		}
-
-		// We resolved the entire path, no more elements
-		if key.Equal(cur) {
-			return false
-		}
-
-		// If we're taking a left path and there's a right sibling,
-		// then there are elements with larger values
-		isLeft := !key.IsBitSet(cur.Len())
-		if isLeft && sn.node.RightHash != nil {
-			return true
-		}
-
-		// Move to next node based on the path
-		cur = sn.node.Right
-		if isLeft {
-			cur = sn.node.Left
-		}
-	}
-
-	return false
-}
diff --git a/core/trie/proof_test.go b/core/trie/proof_test.go
deleted file mode 100644
index 5a43932042..0000000000
--- a/core/trie/proof_test.go
+++ /dev/null
@@ -1,827 +0,0 @@
-package trie_test
-
-import (
-	"math/rand"
-	"sort"
-	"testing"
-
-	"github.com/NethermindEth/juno/core/crypto"
-	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/core/trie"
-	"github.com/NethermindEth/juno/db/pebble"
-	"github.com/NethermindEth/juno/utils"
-	"github.com/stretchr/testify/require"
-)
-
-func TestProve(t *testing.T) {
-	t.Parallel()
-
-	n := 1000
-	tempTrie, records := nonRandomTrie(t, n)
-
-	for _, record := range records {
-		proofSet := trie.NewProofNodeSet()
-		err := tempTrie.Prove(record.key, proofSet)
-		require.NoError(t, err)
-
-		root, err := tempTrie.Root()
-		require.NoError(t, err)
-
-		val, err := trie.VerifyProof(root, record.key, proofSet, crypto.Pedersen)
-		if err != nil {
-			t.Fatalf("failed for key %s", record.key.String())
-		}
-		require.Equal(t, record.value, val)
-	}
-}
-
-func TestProveNonExistent(t *testing.T) {
-	t.Parallel()
-
-	n := 1000
-	tempTrie, _ := nonRandomTrie(t, n)
-
-	for i := 1; i < n+1; i++ {
-		keyFelt := new(felt.Felt).SetUint64(uint64(i + n))
-
-		proofSet := trie.NewProofNodeSet()
-		err := tempTrie.Prove(keyFelt, proofSet)
-		require.NoError(t, err)
-
-		root, err := tempTrie.Root()
-		require.NoError(t, err)
-
-		val, err := trie.VerifyProof(root, keyFelt, proofSet, crypto.Pedersen)
-		if err != nil {
-			t.Fatalf("failed for key %s", keyFelt.String())
-		}
-		require.Equal(t, &felt.Zero, val)
-	}
-}
-
-func TestProveRandom(t *testing.T) {
-	t.Parallel()
-	tempTrie, records := randomTrie(t, 1000)
-
-	for _, record := range records {
-		proofSet := trie.NewProofNodeSet()
-		err := tempTrie.Prove(record.key, proofSet)
-		require.NoError(t, err)
-
-		root, err := tempTrie.Root()
-		require.NoError(t, err)
-
-		val, err := trie.VerifyProof(root, record.key, proofSet, crypto.Pedersen)
-		require.NoError(t, err)
-		require.Equal(t, record.value, val)
-	}
-}
-
-func TestProveCustom(t *testing.T) {
-	t.Parallel()
-
-	tests := []testTrie{
-		{
-			name:    "simple binary",
-			buildFn: buildSimpleTrie,
-			testKeys: []testKey{
-				{
-					name:     "prove existing key",
-					key:      new(felt.Felt).SetUint64(1),
-					expected: new(felt.Felt).SetUint64(3),
-				},
-			},
-		},
-		{
-			name:    "simple double binary",
-			buildFn: buildSimpleDoubleBinaryTrie,
-			testKeys: []testKey{
-				{
-					name:     "prove existing key 0",
-					key:      new(felt.Felt).SetUint64(0),
-					expected: new(felt.Felt).SetUint64(2),
-				},
-				{
-					name:     "prove existing key 3",
-					key:      new(felt.Felt).SetUint64(3),
-					expected: new(felt.Felt).SetUint64(5),
-				},
-				{
-					name:     "prove non-existent key 2",
-					key:      new(felt.Felt).SetUint64(2),
-					expected: new(felt.Felt).SetUint64(0),
-				},
-				{
-					name:     "prove non-existent key 123",
-					key:      new(felt.Felt).SetUint64(123),
-					expected: new(felt.Felt).SetUint64(0),
-				},
-			},
-		},
-		{
-			name:    "simple binary root",
-			buildFn: buildSimpleBinaryRootTrie,
-			testKeys: []testKey{
-				{
-					name:     "prove existing key",
-					key:      new(felt.Felt).SetUint64(0),
-					expected: utils.HexToFelt(t, "0xcc"),
-				},
-			},
-		},
-		{
-			name: "left-right edge",
-			buildFn: func(t *testing.T) (*trie.Trie, []*keyValue) {
-				memdb := pebble.NewMemTest(t)
-				txn, err := memdb.NewTransaction(true)
-				require.NoError(t, err)
-
-				tr, err := trie.NewTriePedersen(trie.NewStorage(txn, []byte{1}), 251)
-				require.NoError(t, err)
-
-				records := []*keyValue{
-					{key: utils.HexToFelt(t, "0xff"), value: utils.HexToFelt(t, "0xaa")},
-				}
-
-				for _, record := range records {
-					_, err = tr.Put(record.key, record.value)
-					require.NoError(t, err)
-				}
-				require.NoError(t, tr.Commit())
-				return tr, records
-			},
-			testKeys: []testKey{
-				{
-					name:     "prove existing key",
-					key:      utils.HexToFelt(t, "0xff"),
-					expected: utils.HexToFelt(t, "0xaa"),
-				},
-			},
-		},
-		{
-			name:    "three key trie",
-			buildFn: build3KeyTrie,
-			testKeys: []testKey{
-				{
-					name:     "prove existing key",
-					key:      new(felt.Felt).SetUint64(2),
-					expected: new(felt.Felt).SetUint64(6),
-				},
-			},
-		},
-	}
-
-	for _, test := range tests {
-		t.Run(test.name, func(t *testing.T) {
-			t.Parallel()
-
-			tr, _ := test.buildFn(t)
-
-			for _, tc := range test.testKeys {
-				t.Run(tc.name, func(t *testing.T) {
-					proofSet := trie.NewProofNodeSet()
-					err := tr.Prove(tc.key, proofSet)
-					require.NoError(t, err)
-
-					root, err := tr.Root()
-					require.NoError(t, err)
-
-					val, err := trie.VerifyProof(root, tc.key, proofSet, crypto.Pedersen)
-					require.NoError(t, err)
-					require.Equal(t, tc.expected, val)
-				})
-			}
-		})
-	}
-}
-
-// TestRangeProof tests normal range proof with both edge proofs
-func TestRangeProof(t *testing.T) {
-	t.Parallel()
-
-	n := 500
-	tr, records := randomTrie(t, n)
-	root, err := tr.Root()
-	require.NoError(t, err)
-
-	for range 100 {
-		start := rand.Intn(n)
-		end := rand.Intn(n-start) + start + 1
-
-		proof := trie.NewProofNodeSet()
-		err := tr.GetRangeProof(records[start].key, records[end-1].key, proof)
-		require.NoError(t, err)
-
-		keys := []*felt.Felt{}
-		values := []*felt.Felt{}
-		for i := start; i < end; i++ {
-			keys = append(keys, records[i].key)
-			values = append(values, records[i].value)
-		}
-
-		_, err = trie.VerifyRangeProof(root, records[start].key, keys, values, proof)
-		require.NoError(t, err)
-	}
-}
-
-// TestRangeProofWithNonExistentProof tests normal range proof with non-existent proofs
-func TestRangeProofWithNonExistentProof(t *testing.T) {
-	t.Parallel()
-
-	n := 500
-	tr, records := randomTrie(t, n)
-	root, err := tr.Root()
-	require.NoError(t, err)
-
-	for range 100 {
-		start := rand.Intn(n)
-		end := rand.Intn(n-start) + start + 1
-
-		first := decrementFelt(records[start].key)
-		if start != 0 && first.Equal(records[start-1].key) {
-			continue
-		}
-
-		proof := trie.NewProofNodeSet()
-		err := tr.GetRangeProof(first, records[end-1].key, proof)
-		require.NoError(t, err)
-
-		keys := make([]*felt.Felt, end-start)
-		values := make([]*felt.Felt, end-start)
-		for i := start; i < end; i++ {
-			keys[i-start] = records[i].key
-			values[i-start] = records[i].value
-		}
-
-		_, err = trie.VerifyRangeProof(root, first, keys, values, proof)
-		require.NoError(t, err)
-	}
-}
-
-// TestRangeProofWithInvalidNonExistentProof tests range proof with invalid non-existent proofs.
-// One scenario is when there is a gap between the first element and the left edge proof.
-func TestRangeProofWithInvalidNonExistentProof(t *testing.T) {
-	t.Parallel()
-
-	n := 500
-	tr, records := randomTrie(t, n)
-	root, err := tr.Root()
-	require.NoError(t, err)
-
-	start, end := 100, 200
-	first := decrementFelt(records[start].key)
-
-	proof := trie.NewProofNodeSet()
-	err = tr.GetRangeProof(first, records[end-1].key, proof)
-	require.NoError(t, err)
-
-	start = 105 // Gap created
-	keys := make([]*felt.Felt, end-start)
-	values := make([]*felt.Felt, end-start)
-	for i := start; i < end; i++ {
-		keys[i-start] = records[i].key
-		values[i-start] = records[i].value
-	}
-
-	_, err = trie.VerifyRangeProof(root, first, keys, values, proof)
-	require.Error(t, err)
-}
-
-func TestOneElementRangeProof(t *testing.T) {
-	t.Parallel()
-
-	n := 1000
-	tr, records := randomTrie(t, n)
-	root, err := tr.Root()
-	require.NoError(t, err)
-
-	t.Run("both edge proofs with the same key", func(t *testing.T) {
-		t.Parallel()
-
-		start := 100
-		proof := trie.NewProofNodeSet()
-		err = tr.GetRangeProof(records[start].key, records[start].key, proof)
-		require.NoError(t, err)
-
-		_, err = trie.VerifyRangeProof(root, records[start].key, []*felt.Felt{records[start].key}, []*felt.Felt{records[start].value}, proof)
-		require.NoError(t, err)
-	})
-
-	t.Run("left non-existent edge proof", func(t *testing.T) {
-		t.Parallel()
-
-		start := 100
-		proof := trie.NewProofNodeSet()
-		err = tr.GetRangeProof(decrementFelt(records[start].key), records[start].key, proof)
-		require.NoError(t, err)
-
-		_, err = trie.VerifyRangeProof(root, decrementFelt(records[start].key), []*felt.Felt{records[start].key}, []*felt.Felt{records[start].value}, proof)
-		require.NoError(t, err)
-	})
-
-	t.Run("right non-existent edge proof", func(t *testing.T) {
-		t.Parallel()
-
-		end := 100
-		proof := trie.NewProofNodeSet()
-		err = tr.GetRangeProof(records[end].key, incrementFelt(records[end].key), proof)
-		require.NoError(t, err)
-
-		_, err = trie.VerifyRangeProof(root, records[end].key, []*felt.Felt{records[end].key}, []*felt.Felt{records[end].value}, proof)
-		require.NoError(t, err)
-	})
-
-	t.Run("both non-existent edge proofs", func(t *testing.T) {
-		t.Parallel()
-
-		start := 100
-		first, last := decrementFelt(records[start].key), incrementFelt(records[start].key)
-		proof := trie.NewProofNodeSet()
-		err = tr.GetRangeProof(first, last, proof)
-		require.NoError(t, err)
-
-		_, err = trie.VerifyRangeProof(root, first, []*felt.Felt{records[start].key}, []*felt.Felt{records[start].value}, proof)
-		require.NoError(t, err)
-	})
-
-	t.Run("1 key trie", func(t *testing.T) {
-		t.Parallel()
-
-		tr, records := build1KeyTrie(t)
-		root, err := tr.Root()
-		require.NoError(t, err)
-
-		proof := trie.NewProofNodeSet()
-		err = tr.GetRangeProof(&felt.Zero, records[0].key, proof)
-		require.NoError(t, err)
-
-		_, err = trie.VerifyRangeProof(root, records[0].key, []*felt.Felt{records[0].key}, []*felt.Felt{records[0].value}, proof)
-		require.NoError(t, err)
-	})
-}
-
-// TestAllElementsRangeProof tests the range proof with all elements and nil proof.
-func TestAllElementsRangeProof(t *testing.T) {
-	t.Parallel()
-
-	n := 1000
-	tr, records := randomTrie(t, n)
-	root, err := tr.Root()
-	require.NoError(t, err)
-
-	keys := make([]*felt.Felt, n)
-	values := make([]*felt.Felt, n)
-	for i, record := range records {
-		keys[i] = record.key
-		values[i] = record.value
-	}
-
-	_, err = trie.VerifyRangeProof(root, nil, keys, values, nil)
-	require.NoError(t, err)
-
-	// Should also work with proof
-	proof := trie.NewProofNodeSet()
-	err = tr.GetRangeProof(records[0].key, records[n-1].key, proof)
-	require.NoError(t, err)
-
-	_, err = trie.VerifyRangeProof(root, keys[0], keys, values, proof)
-	require.NoError(t, err)
-}
-
-// TestSingleSideRangeProof tests the range proof starting with zero.
-func TestSingleSideRangeProof(t *testing.T) {
-	t.Parallel()
-
-	tr, records := randomTrie(t, 1000)
-	root, err := tr.Root()
-	require.NoError(t, err)
-
-	for i := 0; i < len(records); i += 100 {
-		proof := trie.NewProofNodeSet()
-		err := tr.GetRangeProof(&felt.Zero, records[i].key, proof)
-		require.NoError(t, err)
-
-		keys := make([]*felt.Felt, i+1)
-		values := make([]*felt.Felt, i+1)
-		for j := range i + 1 {
-			keys[j] = records[j].key
-			values[j] = records[j].value
-		}
-
-		_, err = trie.VerifyRangeProof(root, &felt.Zero, keys, values, proof)
-		require.NoError(t, err)
-	}
-}
-
-func TestGappedRangeProof(t *testing.T) {
-	t.Parallel()
-	t.Skip("gapped keys will sometimes succeed, the current proof format is not able to handle this")
-
-	tr, records := nonRandomTrie(t, 5)
-	root, err := tr.Root()
-	require.NoError(t, err)
-
-	first, last := 1, 4
-	proof := trie.NewProofNodeSet()
-	err = tr.GetRangeProof(records[first].key, records[last].key, proof)
-	require.NoError(t, err)
-
-	keys := []*felt.Felt{}
-	values := []*felt.Felt{}
-	for i := first; i <= last; i++ {
-		if i == (first+last)/2 {
-			continue
-		}
-
-		keys = append(keys, records[i].key)
-		values = append(values, records[i].value)
-	}
-
-	_, err = trie.VerifyRangeProof(root, records[first].key, keys, values, proof)
-	require.Error(t, err)
-}
-
-func TestEmptyRangeProof(t *testing.T) {
-	t.Parallel()
-
-	tr, records := randomTrie(t, 1000)
-	root, err := tr.Root()
-	require.NoError(t, err)
-
-	cases := []struct {
-		pos int
-		err bool
-	}{
-		{len(records) - 1, false},
-		{500, true},
-	}
-
-	for _, c := range cases {
-		proof := trie.NewProofNodeSet()
-		first := incrementFelt(records[c.pos].key)
-		err = tr.GetRangeProof(first, first, proof)
-		require.NoError(t, err)
-
-		_, err := trie.VerifyRangeProof(root, first, nil, nil, proof)
-		if c.err {
-			require.Error(t, err)
-		} else {
-			require.NoError(t, err)
-		}
-	}
-}
-
-func TestHasRightElement(t *testing.T) {
-	t.Parallel()
-
-	tr, records := randomTrie(t, 500)
-	root, err := tr.Root()
-	require.NoError(t, err)
-
-	cases := []struct {
-		start   int
-		end     int
-		hasMore bool
-	}{
-		{-1, 1, true},                           // single element with non-existent left proof
-		{0, 1, true},                            // single element with existent left proof
-		{0, 100, true},                          // start to middle
-		{50, 100, true},                         // middle only
-		{50, len(records), false},               // middle to end
-		{len(records) - 1, len(records), false}, // Single last element with two existent proofs(point to same key)
-		{0, len(records), false},                // The whole set with existent left proof
-		{-1, len(records), false},               // The whole set with non-existent left proof
-	}
-
-	for _, c := range cases {
-		var (
-			first *felt.Felt
-			start = c.start
-			end   = c.end
-			proof = trie.NewProofNodeSet()
-		)
-		if start == -1 {
-			first = &felt.Zero
-			start = 0
-		} else {
-			first = records[start].key
-		}
-
-		err := tr.GetRangeProof(first, records[end-1].key, proof)
-		require.NoError(t, err)
-
-		keys := []*felt.Felt{}
-		values := []*felt.Felt{}
-		for i := start; i < end; i++ {
-			keys = append(keys, records[i].key)
-			values = append(values, records[i].value)
-		}
-
-		hasMore, err := trie.VerifyRangeProof(root, first, keys, values, proof)
-		require.NoError(t, err)
-		require.Equal(t, c.hasMore, hasMore)
-	}
-}
-
-// TestBadRangeProof generates random bad proof scenarios and verifies that the proof is invalid.
-func TestBadRangeProof(t *testing.T) {
-	t.Parallel()
-
-	tr, records := randomTrie(t, 1000)
-	root, err := tr.Root()
-	require.NoError(t, err)
-
-	for range 100 {
-		start := rand.Intn(len(records))
-		end := rand.Intn(len(records)-start) + start + 1
-
-		proof := trie.NewProofNodeSet()
-		err := tr.GetRangeProof(records[start].key, records[end-1].key, proof)
-		require.NoError(t, err)
-
-		keys := []*felt.Felt{}
-		values := []*felt.Felt{}
-		for j := start; j < end; j++ {
-			keys = append(keys, records[j].key)
-			values = append(values, records[j].value)
-		}
-
-		first := keys[0]
-		testCase := rand.Intn(5)
-
-		index := rand.Intn(end - start)
-		switch testCase {
-		case 0: // modified key
-			keys[index] = new(felt.Felt).SetUint64(rand.Uint64())
-		case 1: // modified value
-			values[index] = new(felt.Felt).SetUint64(rand.Uint64())
-		case 2: // out of order
-			index2 := rand.Intn(end - start)
-			if index2 == index {
-				continue
-			}
-			keys[index], keys[index2] = keys[index2], keys[index]
-			values[index], values[index2] = values[index2], values[index]
-		case 3: // set random key to empty
-			keys[index] = &felt.Zero
-		case 4: // set random value to empty
-			values[index] = &felt.Zero
-			// TODO(weiihann): gapped proof will fail sometimes
-			// case 5: // gapped
-			// 	if end-start < 100 || index == 0 || index == end-start-1 {
-			// 		continue
-			// 	}
-			// 	keys = append(keys[:index], keys[index+1:]...)
-			// 	values = append(values[:index], values[index+1:]...)
-		}
-		_, err = trie.VerifyRangeProof(root, first, keys, values, proof)
-		if err == nil {
-			t.Fatalf("expected error for test case %d, index %d, start %d, end %d", testCase, index, start, end)
-		}
-	}
-}
-
-func BenchmarkProve(b *testing.B) {
-	tr, records := randomTrie(b, 1000)
-	b.ResetTimer()
-	for i := range b.N {
-		proof := trie.NewProofNodeSet()
-		key := records[i%len(records)].key
-		if err := tr.Prove(key, proof); err != nil {
-			b.Fatal(err)
-		}
-	}
-}
-
-func BenchmarkVerifyProof(b *testing.B) {
-	tr, records := randomTrie(b, 1000)
-	root, err := tr.Root()
-	require.NoError(b, err)
-
-	proofs := make([]*trie.ProofNodeSet, 0, len(records))
-	for _, record := range records {
-		proof := trie.NewProofNodeSet()
-		if err := tr.Prove(record.key, proof); err != nil {
-			b.Fatal(err)
-		}
-		proofs = append(proofs, proof)
-	}
-
-	b.ResetTimer()
-	for i := range b.N {
-		index := i % len(records)
-		if _, err := trie.VerifyProof(root, records[index].key, proofs[index], crypto.Pedersen); err != nil {
-			b.Fatal(err)
-		}
-	}
-}
-
-func BenchmarkVerifyRangeProof(b *testing.B) {
-	tr, records := randomTrie(b, 1000)
-	root, err := tr.Root()
-	require.NoError(b, err)
-
-	start := 2
-	end := start + 500
-
-	proof := trie.NewProofNodeSet()
-	err = tr.GetRangeProof(records[start].key, records[end-1].key, proof)
-	require.NoError(b, err)
-
-	keys := make([]*felt.Felt, end-start)
-	values := make([]*felt.Felt, end-start)
-	for i := start; i < end; i++ {
-		keys[i-start] = records[i].key
-		values[i-start] = records[i].value
-	}
-
-	b.ResetTimer()
-	for range b.N {
-		_, err := trie.VerifyRangeProof(root, keys[0], keys, values, proof)
-		require.NoError(b, err)
-	}
-}
-
-func buildTrie(t *testing.T, records []*keyValue) *trie.Trie {
-	if len(records) == 0 {
-		t.Fatal("records must have at least one element")
-	}
-
-	memdb := pebble.NewMemTest(t)
-	txn, err := memdb.NewTransaction(true)
-	require.NoError(t, err)
-
-	tempTrie, err := trie.NewTriePedersen(trie.NewStorage(txn, []byte{0}), 251)
-	require.NoError(t, err)
-
-	for _, record := range records {
-		_, err = tempTrie.Put(record.key, record.value)
-		require.NoError(t, err)
-	}
-
-	require.NoError(t, tempTrie.Commit())
-
-	return tempTrie
-}
-
-func build1KeyTrie(t *testing.T) (*trie.Trie, []*keyValue) {
-	return nonRandomTrie(t, 1)
-}
-
-func buildSimpleTrie(t *testing.T) (*trie.Trie, []*keyValue) {
-	//   (250, 0, x1)		edge
-	//        |
-	//     (0,0,x1)			binary
-	//      /    \
-	//     (2)  (3)
-	records := []*keyValue{
-		{key: new(felt.Felt).SetUint64(0), value: new(felt.Felt).SetUint64(2)},
-		{key: new(felt.Felt).SetUint64(1), value: new(felt.Felt).SetUint64(3)},
-	}
-
-	return buildTrie(t, records), records
-}
-
-func buildSimpleBinaryRootTrie(t *testing.T) (*trie.Trie, []*keyValue) {
-	// PF
-	//           (0, 0, x)
-	//    /                    \
-	// (250, 0, cc)     (250, 11111.., dd)
-	//    |                     |
-	//   (cc)                  (dd)
-
-	//	JUNO
-	//           (0, 0, x)
-	//    /                    \
-	// (251, 0, cc)     (251, 11111.., dd)
-	records := []*keyValue{
-		{key: new(felt.Felt).SetUint64(0), value: utils.HexToFelt(t, "0xcc")},
-		{key: utils.HexToFelt(t, "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), value: utils.HexToFelt(t, "0xdd")},
-	}
-	return buildTrie(t, records), records
-}
-
-//nolint:dupl
-func buildSimpleDoubleBinaryTrie(t *testing.T) (*trie.Trie, []*keyValue) {
-	//           (249,0,x3)         // Edge
-	//               |
-	//           (0, 0, x3)         // Binary
-	//         /            \
-	//     (0,0,x1) // B  (1, 1, 5) // Edge leaf
-	//      /    \             |
-	//     (2)  (3)           (5)
-	records := []*keyValue{
-		{key: new(felt.Felt).SetUint64(0), value: new(felt.Felt).SetUint64(2)},
-		{key: new(felt.Felt).SetUint64(1), value: new(felt.Felt).SetUint64(3)},
-		{key: new(felt.Felt).SetUint64(3), value: new(felt.Felt).SetUint64(5)},
-	}
-	return buildTrie(t, records), records
-}
-
-//nolint:dupl
-func build3KeyTrie(t *testing.T) (*trie.Trie, []*keyValue) {
-	// 			Starknet
-	//			--------
-	//
-	//			Edge
-	//			|
-	//			Binary with len 249				 parent
-	//		 /				\
-	//	Binary (250)	Edge with len 250
-	//	/	\				/
-	// 0x4	0x5			0x6						 child
-
-	//			 Juno
-	//			 ----
-	//
-	//		Node (path 249)
-	//		/			\
-	//  Node (binary)	 \
-	//	/	\			 /
-	// 0x4	0x5		   0x6
-	records := []*keyValue{
-		{key: new(felt.Felt).SetUint64(0), value: new(felt.Felt).SetUint64(4)},
-		{key: new(felt.Felt).SetUint64(1), value: new(felt.Felt).SetUint64(5)},
-		{key: new(felt.Felt).SetUint64(2), value: new(felt.Felt).SetUint64(6)},
-	}
-
-	return buildTrie(t, records), records
-}
-
-func nonRandomTrie(t *testing.T, numKeys int) (*trie.Trie, []*keyValue) {
-	memdb := pebble.NewMemTest(t)
-	txn, err := memdb.NewTransaction(true)
-	require.NoError(t, err)
-
-	tempTrie, err := trie.NewTriePedersen(trie.NewStorage(txn, []byte{0}), 251)
-	require.NoError(t, err)
-
-	records := make([]*keyValue, numKeys)
-	for i := 1; i < numKeys+1; i++ {
-		key := new(felt.Felt).SetUint64(uint64(i))
-		records[i-1] = &keyValue{key: key, value: key}
-		_, err := tempTrie.Put(key, key)
-		require.NoError(t, err)
-	}
-
-	sort.Slice(records, func(i, j int) bool {
-		return records[i].key.Cmp(records[j].key) < 0
-	})
-
-	require.NoError(t, tempTrie.Commit())
-
-	return tempTrie, records
-}
-
-func randomTrie(t testing.TB, n int) (*trie.Trie, []*keyValue) {
-	rrand := rand.New(rand.NewSource(3))
-
-	memdb := pebble.NewMemTest(t)
-	txn, err := memdb.NewTransaction(true)
-	require.NoError(t, err)
-
-	tempTrie, err := trie.NewTriePedersen(trie.NewStorage(txn, []byte{0}), 251)
-	require.NoError(t, err)
-
-	records := make([]*keyValue, n)
-	for i := range n {
-		key := new(felt.Felt).SetUint64(uint64(rrand.Uint32() + 1))
-		records[i] = &keyValue{key: key, value: key}
-		_, err := tempTrie.Put(key, key)
-		require.NoError(t, err)
-	}
-
-	require.NoError(t, tempTrie.Commit())
-
-	// Sort records by key
-	sort.Slice(records, func(i, j int) bool {
-		return records[i].key.Cmp(records[j].key) < 0
-	})
-
-	return tempTrie, records
-}
-
-func decrementFelt(f *felt.Felt) *felt.Felt {
-	return new(felt.Felt).Sub(f, new(felt.Felt).SetUint64(1))
-}
-
-func incrementFelt(f *felt.Felt) *felt.Felt {
-	return new(felt.Felt).Add(f, new(felt.Felt).SetUint64(1))
-}
-
-type testKey struct {
-	name     string
-	key      *felt.Felt
-	expected *felt.Felt
-}
-
-type testTrie struct {
-	name     string
-	buildFn  func(*testing.T) (*trie.Trie, []*keyValue)
-	testKeys []testKey
-}
-
-type keyValue struct {
-	key   *felt.Felt
-	value *felt.Felt
-}
diff --git a/core/trie/storage_test.go b/core/trie/storage_test.go
deleted file mode 100644
index 21302f1308..0000000000
--- a/core/trie/storage_test.go
+++ /dev/null
@@ -1,108 +0,0 @@
-package trie_test
-
-import (
-	"errors"
-	"testing"
-
-	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/core/trie"
-	"github.com/NethermindEth/juno/db"
-	"github.com/NethermindEth/juno/db/pebble"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-func TestStorage(t *testing.T) {
-	testDB := pebble.NewMemTest(t)
-	prefix := []byte{37, 44}
-	key := trie.NewBitArray(44, 0)
-
-	value, err := new(felt.Felt).SetRandom()
-	require.NoError(t, err)
-
-	node := &trie.Node{
-		Value: value,
-	}
-
-	t.Run("put a node", func(t *testing.T) {
-		require.NoError(t, testDB.Update(func(txn db.Transaction) error {
-			tTxn := trie.NewStorage(txn, prefix)
-			return tTxn.Put(&key, node)
-		}))
-	})
-
-	t.Run("get a node", func(t *testing.T) {
-		require.NoError(t, testDB.View(func(txn db.Transaction) error {
-			tTxn := trie.NewStorage(txn, prefix)
-			var got *trie.Node
-			got, err = tTxn.Get(&key)
-			require.NoError(t, err)
-			assert.Equal(t, node, got)
-			return err
-		}))
-	})
-
-	t.Run("roll back on error", func(t *testing.T) {
-		// Successfully delete a node and return an error to force a roll back.
-		require.Error(t, testDB.Update(func(txn db.Transaction) error {
-			tTxn := trie.NewStorage(txn, prefix)
-			err = tTxn.Delete(&key)
-			require.NoError(t, err)
-			return errors.New("should rollback")
-		}))
-
-		// If the transaction was properly rolled back, the node that we
-		// "deleted" should still exist in the db.
-		require.NoError(t, testDB.View(func(txn db.Transaction) error {
-			tTxn := trie.NewStorage(txn, prefix)
-			var got *trie.Node
-			got, err = tTxn.Get(&key)
-			assert.Equal(t, node, got)
-			return err
-		}))
-	})
-
-	t.Run("delete a node", func(t *testing.T) {
-		// Delete a node.
-		require.NoError(t, testDB.Update(func(txn db.Transaction) error {
-			tTxn := trie.NewStorage(txn, prefix)
-			return tTxn.Delete(&key)
-		}))
-
-		// Node should no longer exist in the database.
-		require.EqualError(t, testDB.View(func(txn db.Transaction) error {
-			tTxn := trie.NewStorage(txn, prefix)
-			_, err = tTxn.Get(&key)
-			return err
-		}), db.ErrKeyNotFound.Error())
-	})
-
-	rootKey := trie.NewBitArray(8, 2)
-
-	t.Run("put root key", func(t *testing.T) {
-		require.NoError(t, testDB.Update(func(txn db.Transaction) error {
-			tTxn := trie.NewStorage(txn, prefix)
-			return tTxn.PutRootKey(&rootKey)
-		}))
-	})
-
-	t.Run("read root key", func(t *testing.T) {
-		require.NoError(t, testDB.View(func(txn db.Transaction) error {
-			tTxn := trie.NewStorage(txn, prefix)
-			gotRootKey, err := tTxn.RootKey()
-			require.NoError(t, err)
-			assert.Equal(t, &rootKey, gotRootKey)
-			return nil
-		}))
-	})
-
-	t.Run("delete root key", func(t *testing.T) {
-		require.NoError(t, testDB.Update(func(txn db.Transaction) error {
-			tTxn := trie.NewStorage(txn, prefix)
-			require.NoError(t, tTxn.DeleteRootKey())
-			_, err := tTxn.RootKey()
-			require.ErrorIs(t, err, db.ErrKeyNotFound)
-			return nil
-		}))
-	})
-}
diff --git a/core/trie/trie_pkg_test.go b/core/trie/trie_pkg_test.go
deleted file mode 100644
index d9d13b1e4c..0000000000
--- a/core/trie/trie_pkg_test.go
+++ /dev/null
@@ -1,252 +0,0 @@
-package trie
-
-import (
-	"strconv"
-	"testing"
-
-	"github.com/NethermindEth/juno/core/felt"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-func TestTrieKeys(t *testing.T) {
-	t.Run("put to empty trie", func(t *testing.T) {
-		tempTrie, err := NewTriePedersen(newMemStorage(), 251)
-		require.NoError(t, err)
-		keyNum, err := strconv.ParseUint("1101", 2, 64)
-		require.NoError(t, err)
-
-		key := new(felt.Felt).SetUint64(keyNum)
-		val := new(felt.Felt).SetUint64(11)
-
-		_, err = tempTrie.Put(key, val)
-		require.NoError(t, err)
-
-		value, err := tempTrie.Get(key)
-		require.NoError(t, err)
-
-		assert.Equal(t, val, value, "key-val not match")
-		assert.Equal(t, tempTrie.FeltToKey(key), *tempTrie.rootKey, "root key not match single node's key")
-	})
-
-	t.Run("put a left then a right node", func(t *testing.T) {
-		tempTrie, err := NewTriePedersen(newMemStorage(), 251)
-		require.NoError(t, err)
-		// First put a left node
-		leftKeyNum, err := strconv.ParseUint("10001", 2, 64)
-		require.NoError(t, err)
-
-		leftKey := new(felt.Felt).SetUint64(leftKeyNum)
-		leftVal := new(felt.Felt).SetUint64(12)
-
-		_, err = tempTrie.Put(leftKey, leftVal)
-		require.NoError(t, err)
-
-		// Then put a right node
-		rightKeyNum, err := strconv.ParseUint("10011", 2, 64)
-		require.NoError(t, err)
-
-		rightKey := new(felt.Felt).SetUint64(rightKeyNum)
-		rightVal := new(felt.Felt).SetUint64(22)
-
-		_, err = tempTrie.Put(rightKey, rightVal)
-		require.NoError(t, err)
-
-		// Check parent and its left right children
-		l := tempTrie.FeltToKey(leftKey)
-		r := tempTrie.FeltToKey(rightKey)
-		var commonKey BitArray
-		commonKey.CommonMSBs(&l, &r)
-
-		// Common key should be 0b100, length 251-2;
-		// expectKey := NewKey(251-2, []byte{0x4})
-		expectKey := NewBitArray(249, 4)
-
-		assert.Equal(t, expectKey, commonKey)
-
-		// Current rootKey should be the common key
-		assert.Equal(t, &expectKey, tempTrie.rootKey)
-
-		parentNode, err := tempTrie.storage.Get(&commonKey)
-		require.NoError(t, err)
-
-		assert.Equal(t, tempTrie.FeltToKey(leftKey), *parentNode.Left)
-		assert.Equal(t, tempTrie.FeltToKey(rightKey), *parentNode.Right)
-	})
-
-	t.Run("put a right node then a left node", func(t *testing.T) {
-		tempTrie, err := NewTriePedersen(newMemStorage(), 251)
-		require.NoError(t, err)
-		// First put a right node
-		rightKeyNum, err := strconv.ParseUint("10011", 2, 64)
-		require.NoError(t, err)
-
-		rightKey := new(felt.Felt).SetUint64(rightKeyNum)
-		rightVal := new(felt.Felt).SetUint64(22)
-		_, err = tempTrie.Put(rightKey, rightVal)
-		require.NoError(t, err)
-
-		// Then put a left node
-		leftKeyNum, err := strconv.ParseUint("10001", 2, 64)
-		require.NoError(t, err)
-
-		leftKey := new(felt.Felt).SetUint64(leftKeyNum)
-		leftVal := new(felt.Felt).SetUint64(12)
-
-		_, err = tempTrie.Put(leftKey, leftVal)
-		require.NoError(t, err)
-
-		// Check parent and its left right children
-		l := tempTrie.FeltToKey(leftKey)
-		r := tempTrie.FeltToKey(rightKey)
-		var commonKey BitArray
-		commonKey.CommonMSBs(&l, &r)
-
-		expectKey := NewBitArray(249, 4)
-
-		assert.Equal(t, &expectKey, &commonKey)
-
-		parentNode, err := tempTrie.storage.Get(&commonKey)
-		require.NoError(t, err)
-
-		assert.Equal(t, tempTrie.FeltToKey(leftKey), *parentNode.Left)
-		assert.Equal(t, tempTrie.FeltToKey(rightKey), *parentNode.Right)
-	})
-
-	t.Run("Add new key to different branches", func(t *testing.T) {
-		tempTrie, err := NewTriePedersen(newMemStorage(), 251)
-		require.NoError(t, err)
-		// left branch
-		leftKey := new(felt.Felt).SetUint64(0b100)
-		leftVal := new(felt.Felt).SetUint64(12)
-
-		// right branch
-		rightKeyNum, err := strconv.ParseUint("111", 2, 64)
-		require.NoError(t, err)
-
-		rightKey := new(felt.Felt).SetUint64(rightKeyNum)
-		rightVal := new(felt.Felt).SetUint64(22)
-
-		// Build a basic trie
-		_, err = tempTrie.Put(leftKey, leftVal)
-		require.NoError(t, err)
-
-		_, err = tempTrie.Put(rightKey, rightVal)
-		require.NoError(t, err)
-
-		newVal := new(felt.Felt).SetUint64(12)
-		t.Run("Add to left branch", func(t *testing.T) {
-			newKey := new(felt.Felt).SetUint64(0b101)
-			_, err = tempTrie.Put(newKey, newVal)
-			require.NoError(t, err)
-			commonKey := NewBitArray(250, 2)
-			parentNode, pErr := tempTrie.storage.Get(&commonKey)
-			require.NoError(t, pErr)
-			assert.Equal(t, tempTrie.FeltToKey(leftKey), *parentNode.Left)
-			assert.Equal(t, tempTrie.FeltToKey(newKey), *parentNode.Right)
-		})
-		t.Run("Add to right branch", func(t *testing.T) {
-			newKey := new(felt.Felt).SetUint64(0b110)
-			_, err = tempTrie.Put(newKey, newVal)
-			require.NoError(t, err)
-			commonKey := NewBitArray(250, 3)
-			parentNode, pErr := tempTrie.storage.Get(&commonKey)
-			require.NoError(t, pErr)
-			assert.Equal(t, tempTrie.FeltToKey(newKey), *parentNode.Left)
-			assert.Equal(t, tempTrie.FeltToKey(rightKey), *parentNode.Right)
-		})
-		t.Run("Add new node as parent sibling", func(t *testing.T) {
-			newKeyNum, err := strconv.ParseUint("000", 2, 64)
-			require.NoError(t, err)
-
-			newKey := new(felt.Felt).SetUint64(newKeyNum)
-			newVal := new(felt.Felt).SetUint64(12)
-
-			_, err = tempTrie.Put(newKey, newVal)
-			require.NoError(t, err)
-
-			commonKey := NewBitArray(248, 0)
-			parentNode, err := tempTrie.storage.Get(&commonKey)
-			require.NoError(t, err)
-
-			assert.Equal(t, tempTrie.FeltToKey(newKey), *parentNode.Left)
-
-			expectRightKey := NewBitArray(249, 1)
-
-			assert.Equal(t, &expectRightKey, parentNode.Right)
-		})
-	})
-}
-
-func TestTrieKeysAfterDeleteSubtree(t *testing.T) {
-	// Left branch's left child
-	leftLeftKeyNum, err := strconv.ParseUint("100", 2, 64)
-	require.NoError(t, err)
-
-	leftLeftKey := new(felt.Felt).SetUint64(leftLeftKeyNum)
-	leftLeftVal := new(felt.Felt).SetUint64(11)
-
-	// Left branch's right child
-	leftRightKeyNum, err := strconv.ParseUint("101", 2, 64)
-	require.NoError(t, err)
-
-	leftRightKey := new(felt.Felt).SetUint64(leftRightKeyNum)
-	leftRightVal := new(felt.Felt).SetUint64(22)
-
-	// Right branch's node
-	rightKeyNum, err := strconv.ParseUint("111", 2, 64)
-	require.NoError(t, err)
-
-	rightKey := new(felt.Felt).SetUint64(rightKeyNum)
-	rightVal := new(felt.Felt).SetUint64(33)
-
-	// Zero value
-	zeroVal := new(felt.Felt).SetUint64(0)
-
-	tests := [...]struct {
-		name       string
-		deleteKey  *felt.Felt
-		expectLeft *felt.Felt
-	}{
-		{
-			name:       "delete the left branch's left child",
-			deleteKey:  leftLeftKey,
-			expectLeft: leftRightKey,
-		},
-		{
-			name:       "delete the left branch's right child",
-			deleteKey:  leftRightKey,
-			expectLeft: leftLeftKey,
-		},
-	}
-
-	for _, test := range tests {
-		t.Run(test.name, func(t *testing.T) {
-			tempTrie, err := NewTriePedersen(newMemStorage(), 251)
-			require.NoError(t, err)
-			// Build a basic trie
-			_, err = tempTrie.Put(leftLeftKey, leftLeftVal)
-			require.NoError(t, err)
-
-			_, err = tempTrie.Put(leftRightKey, leftRightVal)
-			require.NoError(t, err)
-
-			_, err = tempTrie.Put(rightKey, rightVal)
-			require.NoError(t, err)
-
-			// Delete the node on left sub branch
-			_, err = tempTrie.Put(test.deleteKey, zeroVal)
-			require.NoError(t, err)
-
-			newRootKey := NewBitArray(249, 1)
-
-			assert.Equal(t, &newRootKey, tempTrie.rootKey)
-
-			rootNode, err := tempTrie.storage.Get(&newRootKey)
-			require.NoError(t, err)
-
-			assert.Equal(t, tempTrie.FeltToKey(rightKey), *rootNode.Right)
-			assert.Equal(t, tempTrie.FeltToKey(test.expectLeft), *rootNode.Left)
-		})
-	}
-}
diff --git a/core/trie/trie_test.go b/core/trie/trie_test.go
deleted file mode 100644
index c1233f9efe..0000000000
--- a/core/trie/trie_test.go
+++ /dev/null
@@ -1,456 +0,0 @@
-package trie_test
-
-import (
-	"strconv"
-	"testing"
-
-	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/core/trie"
-	"github.com/NethermindEth/juno/db"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-// Todo: Refactor:
-//
-//   - [*] Test names should not have "_"
-//   - [*] Table test are being used incorrectly: they should be separated into subsets, see node_test.go
-//   - [*] Functions such as Path and findCommonKey don't need to be public. Thus,
-//     they don't need to be tested explicitly.
-//   - [*] There are warning which ignore returned errors, returned errors should not be ignored.
-//   - [ ] Add more test cases with different heights
-//   - [*] Add more complicated Put and Delete scenarios
-func TestTriePut(t *testing.T) {
-	t.Run("put zero to empty trie", func(t *testing.T) {
-		require.NoError(t, trie.RunOnTempTriePedersen(251, func(tempTrie *trie.Trie) error {
-			key := new(felt.Felt).SetUint64(1)
-			zeroVal := new(felt.Felt).SetUint64(0)
-
-			oldVal, err := tempTrie.Put(key, zeroVal)
-			require.NoError(t, err)
-
-			assert.Nil(t, oldVal)
-
-			return nil
-		}))
-	})
-
-	t.Run("put zero value", func(t *testing.T) {
-		require.NoError(t, trie.RunOnTempTriePedersen(251, func(tempTrie *trie.Trie) error {
-			keyNum, err := strconv.ParseUint("1101", 2, 64)
-			require.NoError(t, err)
-
-			key := new(felt.Felt).SetUint64(keyNum)
-			zeroVal := new(felt.Felt).SetUint64(0)
-
-			_, err = tempTrie.Put(key, zeroVal)
-			require.NoError(t, err)
-
-			value, err := tempTrie.Get(key)
-			assert.NoError(t, err)
-			assert.Equal(t, &felt.Zero, value)
-			// Trie's root should be nil
-			assert.Nil(t, tempTrie.RootKey())
-
-			return nil
-		}))
-	})
-
-	t.Run("put to replace an existed value", func(t *testing.T) {
-		require.NoError(t, trie.RunOnTempTriePedersen(251, func(tempTrie *trie.Trie) error {
-			keyNum, err := strconv.ParseUint("1101", 2, 64)
-			require.NoError(t, err)
-
-			key := new(felt.Felt).SetUint64(keyNum)
-			val := new(felt.Felt).SetUint64(1)
-
-			_, err = tempTrie.Put(key, val)
-			require.NoError(t, err)
-
-			newVal := new(felt.Felt).SetUint64(2)
-
-			_, err = tempTrie.Put(key, newVal)
-			require.NoError(t, err, "update a new value at an exist key")
-
-			value, err := tempTrie.Get(key)
-			require.NoError(t, err)
-
-			assert.Equal(t, newVal, value)
-
-			return nil
-		}))
-	})
-}
-
-func TestTrieDeleteBasic(t *testing.T) {
-	// left branch
-	leftKeyNum, err := strconv.ParseUint("100", 2, 64)
-	require.NoError(t, err)
-
-	leftKey := new(felt.Felt).SetUint64(leftKeyNum)
-	leftVal := new(felt.Felt).SetUint64(12)
-
-	// right branch
-	rightKeyNum, err := strconv.ParseUint("111", 2, 64)
-	require.NoError(t, err)
-
-	rightKey := new(felt.Felt).SetUint64(rightKeyNum)
-	rightVal := new(felt.Felt).SetUint64(22)
-
-	// Zero value
-	zeroVal := new(felt.Felt).SetUint64(0)
-
-	tests := [...]struct {
-		name          string
-		deleteKeys    []*felt.Felt
-		expectRootKey *felt.Felt
-	}{
-		{
-			name:          "delete left child",
-			deleteKeys:    []*felt.Felt{leftKey},
-			expectRootKey: rightKey,
-		},
-		{
-			name:          "delete right child",
-			deleteKeys:    []*felt.Felt{rightKey},
-			expectRootKey: leftKey,
-		},
-		{
-			name:          "delete both children",
-			deleteKeys:    []*felt.Felt{leftKey, rightKey},
-			expectRootKey: (*felt.Felt)(nil),
-		},
-	}
-
-	for _, test := range tests {
-		t.Run(test.name, func(t *testing.T) {
-			require.NoError(t, trie.RunOnTempTriePedersen(251, func(tempTrie *trie.Trie) error {
-				// Build a basic trie
-				_, err := tempTrie.Put(leftKey, leftVal)
-				require.NoError(t, err)
-
-				_, err = tempTrie.Put(rightKey, rightVal)
-				require.NoError(t, err)
-
-				for _, key := range test.deleteKeys {
-					_, err := tempTrie.Put(key, zeroVal)
-					require.NoError(t, err)
-
-					val, err := tempTrie.Get(key)
-
-					assert.NoError(t, err, "shouldnt return an error when access a deleted key")
-					assert.Equal(t, &felt.Zero, val, "should return zero value when access a deleted key")
-				}
-
-				// Check the final rootKey
-
-				if test.expectRootKey != nil {
-					assert.Equal(t, *test.expectRootKey, tempTrie.RootKey().Felt())
-				} else {
-					assert.Nil(t, tempTrie.RootKey())
-				}
-
-				return nil
-			}))
-		})
-	}
-}
-
-func TestPutZero(t *testing.T) {
-	require.NoError(t, trie.RunOnTempTriePedersen(251, func(tempTrie *trie.Trie) error {
-		emptyRoot, err := tempTrie.Root()
-		require.NoError(t, err)
-		var roots []*felt.Felt
-		var keys []*felt.Felt
-
-		// put random 64 keys and record roots
-		for range 64 {
-			key, value := new(felt.Felt), new(felt.Felt)
-
-			_, err = key.SetRandom()
-			require.NoError(t, err)
-
-			t.Logf("key: %s", key.String())
-
-			_, err = value.SetRandom()
-			require.NoError(t, err)
-
-			t.Logf("value: %s", value.String())
-
-			_, err = tempTrie.Put(key, value)
-			require.NoError(t, err)
-
-			keys = append(keys, key)
-
-			var root *felt.Felt
-			root, err = tempTrie.Root()
-			require.NoError(t, err)
-
-			roots = append(roots, root)
-		}
-
-		t.Run("adding a zero value to a non-existent key should not change Trie", func(t *testing.T) {
-			var key, root *felt.Felt
-			key, err = new(felt.Felt).SetRandom()
-			require.NoError(t, err)
-
-			_, err = tempTrie.Put(key, new(felt.Felt))
-			require.NoError(t, err)
-
-			root, err = tempTrie.Root()
-			require.NoError(t, err)
-
-			assert.Equal(t, true, root.Equal(roots[len(roots)-1]))
-		})
-
-		t.Run("remove keys one by one, check roots", func(t *testing.T) {
-			var gotRoot *felt.Felt
-			// put zero in reverse order and check roots still match
-			for i := range 64 {
-				root := roots[len(roots)-1-i]
-
-				gotRoot, err = tempTrie.Root()
-				require.NoError(t, err)
-
-				assert.Equal(t, root, gotRoot)
-
-				key := keys[len(keys)-1-i]
-				_, err = tempTrie.Put(key, new(felt.Felt))
-				require.NoError(t, err)
-			}
-		})
-
-		t.Run("empty roots should match", func(t *testing.T) {
-			actualEmptyRoot, err := tempTrie.Root()
-			require.NoError(t, err)
-
-			assert.Equal(t, true, actualEmptyRoot.Equal(emptyRoot))
-		})
-		return nil
-	}))
-}
-
-func TestTrie(t *testing.T) {
-	require.NoError(t, trie.RunOnTempTriePedersen(251, func(tempTrie *trie.Trie) error {
-		emptyRoot, err := tempTrie.Root()
-		require.NoError(t, err)
-		var roots []*felt.Felt
-		var keys []*felt.Felt
-
-		// put random 64 keys and record roots
-		for range 64 {
-			key, value := new(felt.Felt), new(felt.Felt)
-
-			_, err = key.SetRandom()
-			require.NoError(t, err)
-
-			_, err = value.SetRandom()
-			require.NoError(t, err)
-
-			_, err = tempTrie.Put(key, value)
-			require.NoError(t, err)
-
-			keys = append(keys, key)
-
-			var root *felt.Felt
-			root, err = tempTrie.Root()
-			require.NoError(t, err)
-
-			roots = append(roots, root)
-		}
-
-		t.Run("adding a zero value to a non-existent key should not change Trie", func(t *testing.T) {
-			var key, root *felt.Felt
-			key, err = new(felt.Felt).SetRandom()
-			require.NoError(t, err)
-
-			_, err = tempTrie.Put(key, new(felt.Felt))
-			require.NoError(t, err)
-
-			root, err = tempTrie.Root()
-			require.NoError(t, err)
-
-			assert.Equal(t, true, root.Equal(roots[len(roots)-1]))
-		})
-
-		t.Run("remove keys one by one, check roots", func(t *testing.T) {
-			var gotRoot *felt.Felt
-			// put zero in reverse order and check roots still match
-			for i := range 64 {
-				root := roots[len(roots)-1-i]
-
-				gotRoot, err = tempTrie.Root()
-				require.NoError(t, err)
-
-				assert.Equal(t, root, gotRoot)
-
-				key := keys[len(keys)-1-i]
-				_, err = tempTrie.Put(key, new(felt.Felt))
-				require.NoError(t, err)
-			}
-		})
-
-		t.Run("empty roots should match", func(t *testing.T) {
-			actualEmptyRoot, err := tempTrie.Root()
-			require.NoError(t, err)
-
-			assert.Equal(t, true, actualEmptyRoot.Equal(emptyRoot))
-		})
-		return nil
-	}))
-}
-
-func TestOldData(t *testing.T) {
-	require.NoError(t, trie.RunOnTempTriePedersen(251, func(tempTrie *trie.Trie) error {
-		key := new(felt.Felt).SetUint64(12)
-		old := new(felt.Felt)
-
-		t.Run("put zero to empty key, expect no change", func(t *testing.T) {
-			was, err := tempTrie.Put(key, old)
-			require.NoError(t, err)
-			assert.Nil(t, was) // no change
-		})
-
-		t.Run("put non-zero to empty key, expect zero", func(t *testing.T) {
-			was, err := tempTrie.Put(key, old)
-			require.NoError(t, err)
-			assert.Nil(t, was) // no change
-
-			newVal := new(felt.Felt).SetUint64(1)
-			was, err = tempTrie.Put(key, newVal)
-			require.NoError(t, err)
-
-			assert.Equal(t, old, was)
-			old.Set(newVal)
-		})
-
-		t.Run("change value of a key, expect old value", func(t *testing.T) {
-			newVal := new(felt.Felt).SetUint64(2)
-			was, err := tempTrie.Put(key, newVal)
-			require.NoError(t, err)
-
-			assert.Equal(t, old, was)
-			old.Set(newVal)
-		})
-
-		t.Run("delete key, expect old value", func(t *testing.T) {
-			// put zero value to delete current key
-			was, err := tempTrie.Put(key, &felt.Zero)
-			require.NoError(t, err)
-
-			assert.Equal(t, old, was)
-		})
-
-		t.Run("delete non-existent key, expect no change", func(t *testing.T) {
-			// put zero again to check old data
-			was, err := tempTrie.Put(key, new(felt.Felt))
-			require.NoError(t, err)
-
-			// there should no old data to return
-			assert.Nil(t, was)
-		})
-
-		return nil
-	}))
-}
-
-func TestMaxTrieHeight(t *testing.T) {
-	t.Run("create trie with invalid height", func(t *testing.T) {
-		assert.Error(t, trie.RunOnTempTriePedersen(felt.Bits+1, func(_ *trie.Trie) error {
-			return nil
-		}))
-	})
-
-	t.Run("insert invalid key", func(t *testing.T) {
-		require.NoError(t, trie.RunOnTempTriePedersen(uint8(felt.Bits), func(tt *trie.Trie) error {
-			badKey := new(felt.Felt).Sub(&felt.Zero, new(felt.Felt).SetUint64(1))
-			_, err := tt.Put(badKey, new(felt.Felt))
-			assert.Error(t, err)
-			return nil
-		}))
-	})
-}
-
-func TestRootKeyAlwaysUpdatedOnCommit(t *testing.T) {
-	// Not doing what this test requires--always updating the root key on commit--
-	// leads to some tricky errors. For example:
-	//
-	//  1. A trie is created and performs the following operations:
-	//     a. Put leaf
-	//     b. Commit
-	//     c. Delete leaf
-	//     d. Commit
-	//  2. A second trie is created with the same db transaction and immediately
-	//     calls [trie.Root].
-	//
-	// If the root key is not updated in the db transaction at step 1d,
-	// the second trie will initialise its root key to the wrong value
-	// (to the value the root key had at step 1b).
-
-	// We simulate the situation described above.
-
-	height := uint8(251)
-
-	// The database transaction we will use to create both tries.
-	txn := db.NewMemTransaction()
-	tTxn := trie.NewStorage(txn, []byte{1, 2, 3})
-
-	// Step 1: Create first trie
-	tempTrie, err := trie.NewTriePedersen(tTxn, height)
-	require.NoError(t, err)
-
-	// Step 1a: Put
-	key := new(felt.Felt).SetUint64(1)
-	_, err = tempTrie.Put(key, new(felt.Felt).SetUint64(1))
-	require.NoError(t, err)
-
-	// Step 1b: Commit
-	require.NoError(t, tempTrie.Commit())
-
-	// Step 1c: Delete
-	_, err = tempTrie.Put(key, new(felt.Felt)) // Inserting zero felt is a deletion.
-	require.NoError(t, err)
-
-	want := new(felt.Felt)
-
-	// Step 1d: Commit
-	got, err := tempTrie.Root()
-	require.NoError(t, err)
-	// Ensure root value matches expectation.
-	assert.Equal(t, want, got)
-
-	// Step 2: Different trie created with the same db transaction and calls [trie.Root].
-	tTxn = trie.NewStorage(txn, []byte{1, 2, 3})
-	secondTrie, err := trie.NewTriePedersen(tTxn, height)
-	require.NoError(t, err)
-	got, err = secondTrie.Root()
-	require.NoError(t, err)
-	// Ensure root value is the same as the first trie.
-	assert.Equal(t, want, got)
-}
-
-var benchTriePutR *felt.Felt
-
-func BenchmarkTriePut(b *testing.B) {
-	keys := make([]*felt.Felt, 0, b.N)
-	for range b.N {
-		rnd, err := new(felt.Felt).SetRandom()
-		require.NoError(b, err)
-		keys = append(keys, rnd)
-	}
-
-	one := new(felt.Felt).SetUint64(1)
-	require.NoError(b, trie.RunOnTempTriePedersen(251, func(t *trie.Trie) error {
-		var f *felt.Felt
-		var err error
-		b.ResetTimer()
-		for i := range b.N {
-			f, err = t.Put(keys[i], one)
-			if err != nil {
-				return err
-			}
-		}
-		benchTriePutR = f
-		return t.Commit()
-	}))
-}
diff --git a/migration/migration.go b/migration/migration.go
index d4366c7adc..6d3ace9adb 100644
--- a/migration/migration.go
+++ b/migration/migration.go
@@ -15,7 +15,7 @@ import (
 	"github.com/NethermindEth/juno/blockchain"
 	"github.com/NethermindEth/juno/core"
 	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/core/trie"
+	trie "github.com/NethermindEth/juno/core/legacytrie"
 	"github.com/NethermindEth/juno/db"
 	"github.com/NethermindEth/juno/encoder"
 	"github.com/NethermindEth/juno/starknet"
diff --git a/migration/migration_pkg_test.go b/migration/migration_pkg_test.go
index 008e8b1356..5594ba5c62 100644
--- a/migration/migration_pkg_test.go
+++ b/migration/migration_pkg_test.go
@@ -13,7 +13,7 @@ import (
 	"github.com/NethermindEth/juno/clients/feeder"
 	"github.com/NethermindEth/juno/core"
 	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/core/trie"
+	trie "github.com/NethermindEth/juno/core/legacytrie"
 	"github.com/NethermindEth/juno/db"
 	"github.com/NethermindEth/juno/db/pebble"
 	"github.com/NethermindEth/juno/encoder"
diff --git a/mocks/mock_state.go b/mocks/mock_state.go
index fd94ff4391..6b426504a9 100644
--- a/mocks/mock_state.go
+++ b/mocks/mock_state.go
@@ -14,7 +14,7 @@ import (
 
 	core "github.com/NethermindEth/juno/core"
 	felt "github.com/NethermindEth/juno/core/felt"
-	trie "github.com/NethermindEth/juno/core/trie"
+	trie2 "github.com/NethermindEth/juno/core/trie2"
 	gomock "go.uber.org/mock/gomock"
 )
 
@@ -57,10 +57,10 @@ func (mr *MockStateReaderMockRecorder) Class(arg0 any) *gomock.Call {
 }
 
 // ClassTrie mocks base method.
-func (m *MockStateReader) ClassTrie() (*trie.Trie, error) {
+func (m *MockStateReader) ClassTrie() (*trie2.Trie, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "ClassTrie")
-	ret0, _ := ret[0].(*trie.Trie)
+	ret0, _ := ret[0].(*trie2.Trie)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
@@ -117,10 +117,10 @@ func (mr *MockStateReaderMockRecorder) ContractStorage(arg0, arg1 any) *gomock.C
 }
 
 // ContractStorageTrie mocks base method.
-func (m *MockStateReader) ContractStorageTrie(arg0 *felt.Felt) (*trie.Trie, error) {
+func (m *MockStateReader) ContractStorageTrie(arg0 *felt.Felt) (*trie2.Trie, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "ContractStorageTrie", arg0)
-	ret0, _ := ret[0].(*trie.Trie)
+	ret0, _ := ret[0].(*trie2.Trie)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
@@ -132,10 +132,10 @@ func (mr *MockStateReaderMockRecorder) ContractStorageTrie(arg0 any) *gomock.Cal
 }
 
 // ContractTrie mocks base method.
-func (m *MockStateReader) ContractTrie() (*trie.Trie, error) {
+func (m *MockStateReader) ContractTrie() (*trie2.Trie, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "ContractTrie")
-	ret0, _ := ret[0].(*trie.Trie)
+	ret0, _ := ret[0].(*trie2.Trie)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
diff --git a/rpc/v8/storage.go b/rpc/v8/storage.go
index 71fe08148d..63fc09d6d2 100644
--- a/rpc/v8/storage.go
+++ b/rpc/v8/storage.go
@@ -2,11 +2,12 @@ package rpcv8
 
 import (
 	"errors"
+	"fmt"
 
 	"github.com/NethermindEth/juno/blockchain"
 	"github.com/NethermindEth/juno/core"
 	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/core/trie"
+	"github.com/NethermindEth/juno/core/trie2"
 	"github.com/NethermindEth/juno/db"
 	"github.com/NethermindEth/juno/jsonrpc"
 	"github.com/NethermindEth/juno/rpc/rpccore"
@@ -112,23 +113,16 @@ func (h *Handler) StorageProof(id BlockID,
 		return nil, rpccore.ErrInternal.CloneWithData(err)
 	}
 
-	contractTreeRoot, err := contractTrie.Root()
-	if err != nil {
-		return nil, rpccore.ErrInternal.CloneWithData(err)
-	}
-
-	classTreeRoot, err := classTrie.Root()
-	if err != nil {
-		return nil, rpccore.ErrInternal.CloneWithData(err)
-	}
+	contractTrieRoot := contractTrie.Hash()
+	classTrieRoot := classTrie.Hash()
 
 	return &StorageProofResult{
 		ClassesProof:           classProof,
 		ContractsProof:         contractProof,
 		ContractsStorageProofs: contractStorageProof,
 		GlobalRoots: &GlobalRoots{
-			ContractsTreeRoot: contractTreeRoot,
-			ClassesTreeRoot:   classTreeRoot,
+			ContractsTreeRoot: &contractTrieRoot,
+			ClassesTreeRoot:   &classTrieRoot,
 			BlockHash:         head.Hash,
 		},
 	}, nil
@@ -180,8 +174,8 @@ func headOnly(id BlockID, head *core.Block) bool {
 	}
 }
 
-func getClassProof(tr *trie.Trie, classes []felt.Felt) ([]*HashToNode, error) {
-	classProof := trie.NewProofNodeSet()
+func getClassProof(tr *trie2.Trie, classes []felt.Felt) ([]*HashToNode, error) {
+	classProof := trie2.NewProofNodeSet()
 	for _, class := range classes {
 		if err := tr.Prove(&class, classProof); err != nil {
 			return nil, err
@@ -191,19 +185,15 @@ func getClassProof(tr *trie.Trie, classes []felt.Felt) ([]*HashToNode, error) {
 	return adaptProofNodes(classProof), nil
 }
 
-func getContractProof(tr *trie.Trie, state blockchain.StateReader, contracts []felt.Felt) (*ContractProof, error) {
-	contractProof := trie.NewProofNodeSet()
+func getContractProof(tr *trie2.Trie, state blockchain.StateReader, contracts []felt.Felt) (*ContractProof, error) {
+	contractProof := trie2.NewProofNodeSet()
 	contractLeavesData := make([]*LeafData, len(contracts))
 	for i, contract := range contracts {
 		if err := tr.Prove(&contract, contractProof); err != nil {
 			return nil, err
 		}
 
-		root, err := tr.Root()
-		if err != nil {
-			return nil, err
-		}
-
+		root := tr.Hash()
 		nonce, err := state.ContractNonce(&contract)
 		if err != nil {
 			if errors.Is(err, db.ErrKeyNotFound) { // contract does not exist, skip getting leaf data
@@ -220,7 +210,7 @@ func getContractProof(tr *trie.Trie, state blockchain.StateReader, contracts []f
 		contractLeavesData[i] = &LeafData{
 			Nonce:       nonce,
 			ClassHash:   classHash,
-			StorageRoot: root,
+			StorageRoot: &root,
 		}
 	}
 
@@ -238,7 +228,7 @@ func getContractStorageProof(state blockchain.StateReader, storageKeys []Storage
 			return nil, err
 		}
 
-		contractStorageProof := trie.NewProofNodeSet()
+		contractStorageProof := trie2.NewProofNodeSet()
 		for _, key := range storageKey.Keys {
 			if err := contractStorageTrie.Prove(&key, contractStorageProof); err != nil {
 				return nil, err
@@ -251,24 +241,24 @@ func getContractStorageProof(state blockchain.StateReader, storageKeys []Storage
 	return contractStorageRes, nil
 }
 
-func adaptProofNodes(proof *trie.ProofNodeSet) []*HashToNode {
+func adaptProofNodes(proof *trie2.ProofNodeSet) []*HashToNode {
 	nodes := make([]*HashToNode, proof.Size())
 	nodeList := proof.List()
 	for i, hash := range proof.Keys() {
 		var node Node
 
 		switch n := nodeList[i].(type) {
-		case *trie.Binary:
+		case *trie2.BinaryNode:
 			node = &BinaryNode{
-				Left:  n.LeftHash,
-				Right: n.RightHash,
+				Left:  nodeFelt(n.Children[0]),
+				Right: nodeFelt(n.Children[1]),
 			}
-		case *trie.Edge:
-			path := n.Path.Felt()
+		case *trie2.EdgeNode:
+			pathFelt := n.Path.Felt()
 			node = &EdgeNode{
-				Path:   path.String(),
+				Path:   pathFelt.String(),
 				Length: int(n.Path.Len()),
-				Child:  n.Child,
+				Child:  nodeFelt(n.Child),
 			}
 		}
 
@@ -281,13 +271,24 @@ func adaptProofNodes(proof *trie.ProofNodeSet) []*HashToNode {
 	return nodes
 }
 
+func nodeFelt(n trie2.Node) *felt.Felt {
+	switch n := n.(type) {
+	case *trie2.HashNode:
+		return &n.Felt
+	case *trie2.ValueNode:
+		return &n.Felt
+	default:
+		panic(fmt.Sprintf("unknown node type: %T", n))
+	}
+}
+
 type StorageKeys struct {
 	Contract *felt.Felt  `json:"contract_address"`
 	Keys     []felt.Felt `json:"storage_keys"`
 }
 
 type Node interface {
-	AsProofNode() trie.ProofNode
+	TrieNode() trie2.Node
 }
 
 type BinaryNode struct {
@@ -301,20 +302,20 @@ type EdgeNode struct {
 	Child  *felt.Felt `json:"child"`
 }
 
-func (e *EdgeNode) AsProofNode() trie.ProofNode {
+func (e *EdgeNode) TrieNode() trie2.Node {
 	f, _ := new(felt.Felt).SetString(e.Path)
 	pbs := f.Bytes()
 
-	return &trie.Edge{
-		Path:  new(trie.BitArray).SetBytes(uint8(e.Length), pbs[:]),
-		Child: e.Child,
+	return &trie2.EdgeNode{
+		Path:  new(trie2.Path).SetBytes(uint8(e.Length), pbs[:]),
+		Child: &trie2.HashNode{Felt: *e.Child}, // TODO(weiihann): this could be a value node too
 	}
 }
 
-func (b *BinaryNode) AsProofNode() trie.ProofNode {
-	return &trie.Binary{
-		LeftHash:  b.Left,
-		RightHash: b.Right,
+func (b *BinaryNode) TrieNode() trie2.Node {
+	return &trie2.BinaryNode{
+		// TODO(weiihann): this could be a value node too
+		Children: [2]trie2.Node{&trie2.HashNode{Felt: *b.Left}, &trie2.HashNode{Felt: *b.Right}},
 	}
 }
 
diff --git a/rpc/v8/storage_test.go b/rpc/v8/storage_test.go
index 23f5789fb0..98ac5e60b9 100644
--- a/rpc/v8/storage_test.go
+++ b/rpc/v8/storage_test.go
@@ -11,7 +11,7 @@ import (
 	"github.com/NethermindEth/juno/core"
 	"github.com/NethermindEth/juno/core/crypto"
 	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/core/trie"
+	"github.com/NethermindEth/juno/core/trie2"
 	"github.com/NethermindEth/juno/db"
 	"github.com/NethermindEth/juno/db/pebble"
 	"github.com/NethermindEth/juno/jsonrpc"
@@ -138,11 +138,18 @@ func TestStorageProof(t *testing.T) {
 		blockNumber = uint64(1313)
 	)
 
-	tempTrie := emptyTrie(t)
-	_, _ = tempTrie.Put(key, value)
-	_, _ = tempTrie.Put(key2, value2)
-	_ = tempTrie.Commit()
-	trieRoot, _ := tempTrie.Root()
+	testDB := pebble.NewMemTest(t)
+	txn, err := testDB.NewTransaction(true)
+	require.NoError(t, err)
+	tempTrie, err := trie2.New(trie2.TrieID(), 251, crypto.Pedersen, txn)
+	require.NoError(t, err)
+	_ = tempTrie.Update(key, value)
+	_ = tempTrie.Update(key2, value2)
+	_, _ = tempTrie.Commit()
+	trieRoot := tempTrie.Hash()
+
+	tempTrie, err = trie2.New(trie2.TrieID(), 251, crypto.Pedersen, txn)
+	require.NoError(t, err)
 
 	mockReader := mocks.NewMockReader(mockCtrl)
 	mockState := mocks.NewMockStateReader(mockCtrl)
@@ -220,14 +227,14 @@ func TestStorageProof(t *testing.T) {
 		require.Nil(t, rpcErr)
 		require.NotNil(t, proof)
 		arityTest(t, proof, 3, 0, 0, 0)
-		verifyIf(t, trieRoot, noSuchKey, nil, proof.ClassesProof, tempTrie.HashFn())
+		verifyIf(t, &trieRoot, noSuchKey, nil, proof.ClassesProof, tempTrie.HashFn())
 	})
 	t.Run("class trie hash exists in a trie", func(t *testing.T) {
 		proof, rpcErr := handler.StorageProof(blockLatest, []felt.Felt{*key}, nil, nil)
 		require.Nil(t, rpcErr)
 		require.NotNil(t, proof)
 		arityTest(t, proof, 3, 0, 0, 0)
-		verifyIf(t, trieRoot, key, value, proof.ClassesProof, tempTrie.HashFn())
+		verifyIf(t, &trieRoot, key, value, proof.ClassesProof, tempTrie.HashFn())
 	})
 	t.Run("only unique proof nodes are returned", func(t *testing.T) {
 		proof, rpcErr := handler.StorageProof(blockLatest, []felt.Felt{*key, *key2}, nil, nil)
@@ -235,13 +242,13 @@ func TestStorageProof(t *testing.T) {
 		require.NotNil(t, proof)
 
 		rootNodes := utils.Filter(proof.ClassesProof, func(h *rpc.HashToNode) bool {
-			return h.Hash.Equal(trieRoot)
+			return h.Hash.Equal(&trieRoot)
 		})
 		require.Len(t, rootNodes, 1)
 
 		// verify we can still prove any of the keys in query
-		verifyIf(t, trieRoot, key, value, proof.ClassesProof, tempTrie.HashFn())
-		verifyIf(t, trieRoot, key2, value2, proof.ClassesProof, tempTrie.HashFn())
+		verifyIf(t, &trieRoot, key, value, proof.ClassesProof, tempTrie.HashFn())
+		verifyIf(t, &trieRoot, key2, value2, proof.ClassesProof, tempTrie.HashFn())
 	})
 	t.Run("storage trie address does not exist in a trie", func(t *testing.T) {
 		mockState.EXPECT().ContractNonce(noSuchKey).Return(nil, db.ErrKeyNotFound).Times(1)
@@ -253,7 +260,7 @@ func TestStorageProof(t *testing.T) {
 		arityTest(t, proof, 0, 3, 1, 0)
 		require.Nil(t, proof.ContractsProof.LeavesData[0])
 
-		verifyIf(t, trieRoot, noSuchKey, nil, proof.ContractsProof.Nodes, tempTrie.HashFn())
+		verifyIf(t, &trieRoot, noSuchKey, nil, proof.ContractsProof.Nodes, tempTrie.HashFn())
 	})
 	t.Run("storage trie address exists in a trie", func(t *testing.T) {
 		nonce := new(felt.Felt).SetUint64(121)
@@ -271,11 +278,13 @@ func TestStorageProof(t *testing.T) {
 		require.Equal(t, nonce, ld.Nonce)
 		require.Equal(t, classHasah, ld.ClassHash)
 
-		verifyIf(t, trieRoot, key, value, proof.ContractsProof.Nodes, tempTrie.HashFn())
+		verifyIf(t, &trieRoot, key, value, proof.ContractsProof.Nodes, tempTrie.HashFn())
 	})
 	t.Run("contract storage trie address does not exist in a trie", func(t *testing.T) {
 		contract := utils.HexToFelt(t, "0xdead")
-		mockState.EXPECT().ContractStorageTrie(contract).Return(emptyTrie(t), nil).Times(1)
+		emptyTrie, err := trie2.NewEmptyPedersen()
+		require.NoError(t, err)
+		mockState.EXPECT().ContractStorageTrie(contract).Return(emptyTrie, nil).Times(1)
 
 		storageKeys := []rpc.StorageKeys{{Contract: contract, Keys: []felt.Felt{*key}}}
 		proof, rpcErr := handler.StorageProof(blockLatest, nil, nil, storageKeys)
@@ -296,7 +305,7 @@ func TestStorageProof(t *testing.T) {
 		arityTest(t, proof, 0, 0, 0, 1)
 		require.Len(t, proof.ContractsStorageProofs[0], 3)
 
-		verifyIf(t, trieRoot, noSuchKey, nil, proof.ContractsStorageProofs[0], tempTrie.HashFn())
+		verifyIf(t, &trieRoot, noSuchKey, nil, proof.ContractsStorageProofs[0], tempTrie.HashFn())
 	})
 	//nolint:dupl
 	t.Run("contract storage trie address/key exists in a trie", func(t *testing.T) {
@@ -310,7 +319,7 @@ func TestStorageProof(t *testing.T) {
 		arityTest(t, proof, 0, 0, 0, 1)
 		require.Len(t, proof.ContractsStorageProofs[0], 3)
 
-		verifyIf(t, trieRoot, key, value, proof.ContractsStorageProofs[0], tempTrie.HashFn())
+		verifyIf(t, &trieRoot, key, value, proof.ContractsStorageProofs[0], tempTrie.HashFn())
 	})
 	t.Run("class & storage tries proofs requested", func(t *testing.T) {
 		nonce := new(felt.Felt).SetUint64(121)
@@ -587,16 +596,13 @@ func TestStorageProof_StorageRoots(t *testing.T) {
 		contractTrie, err := reader.ContractTrie()
 		assert.NoError(t, err)
 
-		clsRoot, err := classTrie.Root()
-		assert.NoError(t, err)
+		clsRoot := classTrie.Hash()
+		stgRoot := contractTrie.Hash()
 
-		stgRoot, err := contractTrie.Root()
-		assert.NoError(t, err)
+		assert.Equal(t, expectedClsRoot, &clsRoot, clsRoot.String())
+		assert.Equal(t, expectedStgRoot, &stgRoot, stgRoot.String())
 
-		assert.Equal(t, expectedClsRoot, clsRoot, clsRoot.String())
-		assert.Equal(t, expectedStgRoot, stgRoot, stgRoot.String())
-
-		verifyGlobalStateRoot(t, expectedGlobalRoot, clsRoot, stgRoot)
+		verifyGlobalStateRoot(t, expectedGlobalRoot, &clsRoot, &stgRoot)
 	})
 
 	t.Run("check requested contract and storage slot exists", func(t *testing.T) {
@@ -609,7 +615,7 @@ func TestStorageProof_StorageRoots(t *testing.T) {
 
 		leaf, err := contractTrie.Get(expectedContractAddress)
 		assert.NoError(t, err)
-		assert.Equal(t, leaf, expectedContractLeaf, leaf.String())
+		assert.Equal(t, &leaf, expectedContractLeaf, leaf.String())
 
 		clsHash, err := stateReader.ContractClassHash(expectedContractAddress)
 		assert.NoError(t, err)
@@ -705,29 +711,19 @@ func verifyIf(
 ) {
 	t.Helper()
 
-	proofSet := trie.NewProofNodeSet()
+	proofSet := trie2.NewProofNodeSet()
 	for _, hn := range proof {
-		proofSet.Put(*hn.Hash, hn.Node.AsProofNode())
+		proofSet.Put(*hn.Hash, hn.Node.TrieNode())
 	}
 
-	leaf, err := trie.VerifyProof(root, key, proofSet, hashF)
+	leaf, err := trie2.VerifyProof(root, key, proofSet, hashF)
 	require.NoError(t, err)
 
 	// non-membership test
 	if value == nil {
 		value = felt.Zero.Clone()
 	}
-	require.Equal(t, leaf, value)
-}
-
-func emptyTrie(t *testing.T) *trie.Trie {
-	memdb := pebble.NewMemTest(t)
-	txn, err := memdb.NewTransaction(true)
-	require.NoError(t, err)
-
-	tempTrie, err := trie.NewTriePedersen(trie.NewStorage(txn, []byte{0}), 251)
-	require.NoError(t, err)
-	return tempTrie
+	require.Equal(t, &leaf, value)
 }
 
 func verifyGlobalStateRoot(t *testing.T, globalStateRoot, classRoot, storageRoot *felt.Felt) {
diff --git a/sync/pending.go b/sync/pending.go
index faeefd407b..c7d10cec01 100644
--- a/sync/pending.go
+++ b/sync/pending.go
@@ -5,7 +5,7 @@ import (
 	"github.com/NethermindEth/juno/core"
 	"github.com/NethermindEth/juno/core/felt"
 	"github.com/NethermindEth/juno/core/state"
-	"github.com/NethermindEth/juno/core/trie"
+	"github.com/NethermindEth/juno/core/trie2"
 )
 
 type Pending struct {
@@ -69,14 +69,14 @@ func (p *PendingState) Class(classHash *felt.Felt) (*core.DeclaredClass, error)
 	return p.head.Class(classHash)
 }
 
-func (p *PendingState) ClassTrie() (*trie.Trie, error) {
+func (p *PendingState) ClassTrie() (*trie2.Trie, error) {
 	return nil, state.ErrHistoricalTrieNotSupported
 }
 
-func (p *PendingState) ContractTrie() (*trie.Trie, error) {
+func (p *PendingState) ContractTrie() (*trie2.Trie, error) {
 	return nil, state.ErrHistoricalTrieNotSupported
 }
 
-func (p *PendingState) ContractStorageTrie(addr *felt.Felt) (*trie.Trie, error) {
+func (p *PendingState) ContractStorageTrie(addr *felt.Felt) (*trie2.Trie, error) {
 	return nil, state.ErrHistoricalTrieNotSupported
 }

From 9139001131a65ba6f9ddb67f7726e4711707ff68 Mon Sep 17 00:00:00 2001
From: weiihann <weihan774237@gmail.com>
Date: Wed, 19 Feb 2025 00:59:35 +0800
Subject: [PATCH 09/15] test fixes

---
 blockchain/blockchain_test.go |  1 -
 core/state/contract.go        | 24 +++++++++++-
 core/state/state.go           | 74 +++++++++++++++++++++++++++++------
 core/state/state_test.go      |  1 -
 4 files changed, 84 insertions(+), 16 deletions(-)

diff --git a/blockchain/blockchain_test.go b/blockchain/blockchain_test.go
index 1191dfa76f..32ad821a83 100644
--- a/blockchain/blockchain_test.go
+++ b/blockchain/blockchain_test.go
@@ -654,7 +654,6 @@ func TestRevert(t *testing.T) {
 	require.NoError(t, chain.RevertHead())
 
 	t.Run("empty blockchain should mean empty db", func(t *testing.T) {
-		t.Skip("TODO(weiihann):still has some leftover data in the db, resolve this")
 		require.NoError(t, testdb.View(func(txn db.Transaction) error {
 			it, err := txn.NewIterator(nil, false)
 			if err != nil {
diff --git a/core/state/contract.go b/core/state/contract.go
index 386ba13090..e1d8f76848 100644
--- a/core/state/contract.go
+++ b/core/state/contract.go
@@ -148,7 +148,7 @@ func (s *StateContract) Commit(txn db.Transaction, storeHistory bool, blockNum u
 
 	keys := maps.Keys(s.dirtyStorage)
 	slices.SortFunc(keys, func(a, b felt.Felt) int {
-		return a.Cmp(&b)
+		return b.Cmp(&a)
 	})
 
 	// Commit storage changes to the associated storage trie
@@ -209,6 +209,28 @@ func (s *StateContract) delete(txn db.Transaction) error {
 	return txn.Delete(key)
 }
 
+func (s *StateContract) deleteStorageTrie(txn db.Transaction) error {
+	tr, err := s.getTrie(txn)
+	if err != nil {
+		return err
+	}
+
+	it, err := tr.NodeIterator()
+	if err != nil {
+		return err
+	}
+	defer it.Close()
+
+	for it.First(); it.Valid(); it.Next() {
+		key := it.Key()
+		if err := txn.Delete(key); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
 // Flush the contract to the database
 func (s *StateContract) flush(txn db.Transaction) error {
 	key := contractKey(s.Address)
diff --git a/core/state/state.go b/core/state/state.go
index 60f9721a7a..0f33498788 100644
--- a/core/state/state.go
+++ b/core/state/state.go
@@ -102,6 +102,7 @@ func (s *State) ContractDeployedAt(addr felt.Felt, blockNum uint64) (bool, error
 	return contract.DeployHeight <= blockNum, nil
 }
 
+// Returns the class of a contract.
 func (s *State) Class(classHash *felt.Felt) (*core.DeclaredClass, error) {
 	classKey := classKey(classHash)
 
@@ -114,16 +115,24 @@ func (s *State) Class(classHash *felt.Felt) (*core.DeclaredClass, error) {
 	return &class, nil
 }
 
+// Returns the class trie.
 func (s *State) ClassTrie() (*trie2.Trie, error) {
 	return s.classTrie, nil
 }
 
+// Returns the contract trie.
 func (s *State) ContractTrie() (*trie2.Trie, error) {
 	return s.contractTrie, nil
 }
 
+// TODO: add tests for this
 func (s *State) ContractStorageTrie(addr *felt.Felt) (*trie2.Trie, error) {
-	panic("not implemented")
+	contract, err := s.getContract(*addr)
+	if err != nil {
+		return nil, err
+	}
+
+	return contract.getTrie(s.txn)
 }
 
 // Applies a state update to a given state. If any error is encountered, state is not updated.
@@ -174,22 +183,23 @@ func (s *State) Update(blockNum uint64, update *core.StateUpdate, declaredClasse
 	return nil
 }
 
+// Reverts a state update to a given state at a given block number.
 func (s *State) Revert(blockNum uint64, update *core.StateUpdate) error {
 	// Ensure the current root is the same as the new root
 	if err := s.verifyRoot(update.NewRoot); err != nil {
 		return err
 	}
 
-	if err := s.removeDeclaredClasses(blockNum, update.StateDiff.DeclaredV0Classes, update.StateDiff.DeclaredV1Classes); err != nil {
-		return fmt.Errorf("remove declared classes: %v", err)
-	}
-
 	reverseDiff, err := s.GetReverseStateDiff(blockNum, update.StateDiff)
 	if err != nil {
 		return fmt.Errorf("get reverse state diff: %v", err)
 	}
 
-	if err := s.deleteHistory(blockNum, reverseDiff); err != nil {
+	if err := s.removeDeclaredClasses(blockNum, update.StateDiff.DeclaredV0Classes, update.StateDiff.DeclaredV1Classes); err != nil {
+		return fmt.Errorf("remove declared classes: %v", err)
+	}
+
+	if err := s.deleteHistory(blockNum, update.StateDiff); err != nil {
 		return fmt.Errorf("delete history: %v", err)
 	}
 
@@ -216,21 +226,31 @@ func (s *State) Revert(blockNum uint64, update *core.StateUpdate) error {
 
 func (s *State) Commit(storeHistory bool, blockNum uint64) (*felt.Felt, error) {
 	keys := slices.SortedStableFunc(maps.Keys(s.dirtyContracts), func(a, b felt.Felt) int {
-		return a.Cmp(&b) // ascending
+		// Sort in descending order of the number of storage changes
+		// so that we start with the heaviest update first
+		contractA, contractB := s.dirtyContracts[a], s.dirtyContracts[b]
+
+		// Handle nil cases first
+		switch {
+		case contractA == nil && contractB == nil:
+			return 0
+		case contractA == nil:
+			return 1 // Move nil contracts to end
+		case contractB == nil:
+			return -1 // Keep non-nil contracts first
+		}
+
+		return len(contractB.dirtyStorage) - len(contractA.dirtyStorage)
 	})
+
 	for _, addr := range keys {
 		contract := s.dirtyContracts[addr]
 
 		// Contract is marked as deleted
 		if contract == nil {
-			if err := s.contractTrie.Update(&addr, &felt.Zero); err != nil {
+			if err := s.deleteContract(addr); err != nil {
 				return nil, err
 			}
-
-			if err := s.txn.Delete(contractKey(&addr)); err != nil {
-				return nil, err
-			}
-
 			continue
 		}
 
@@ -375,6 +395,34 @@ func (s *State) deleteHistory(blockNum uint64, diff *core.StateDiff) error {
 		}
 	}
 
+	for addr := range diff.DeployedContracts {
+		if err := s.txn.Delete(contractHistoryNonceKey(&addr, blockNum)); err != nil {
+			return err
+		}
+		if err := s.txn.Delete(contractHistoryClassHashKey(&addr, blockNum)); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (s *State) deleteContract(addr felt.Felt) error {
+	if err := s.contractTrie.Update(&addr, &felt.Zero); err != nil {
+		return err
+	}
+
+	if err := s.txn.Delete(contractKey(&addr)); err != nil {
+		return err
+	}
+
+	// Create a temporary contract with zero values so that we can delete the storage trie
+	tempContract := NewStateContract(&addr, &felt.Zero, &felt.Zero, 0)
+	err := tempContract.deleteStorageTrie(s.txn)
+	if err != nil {
+		return err
+	}
+
 	return nil
 }
 
diff --git a/core/state/state_test.go b/core/state/state_test.go
index 2e642d300e..18f5705b84 100644
--- a/core/state/state_test.go
+++ b/core/state/state_test.go
@@ -655,7 +655,6 @@ func TestRevert(t *testing.T) {
 	})
 
 	t.Run("db should be empty after block0 revert", func(t *testing.T) {
-		t.Skip("TODO(weiihann):still has some leftover data in the db, resolve this")
 		txn, commit := setupState(t, stateUpdates, 1)
 		defer commit()
 

From af0f84de5fc980c6b93ca224229506a4135af6b1 Mon Sep 17 00:00:00 2001
From: weiihann <weihan774237@gmail.com>
Date: Wed, 19 Feb 2025 01:50:48 +0800
Subject: [PATCH 10/15] commit contracts concurrently

---
 core/state/state.go        | 62 ++++++++++++++++++++++++--------------
 db/buffered_transaction.go | 23 ++++++++++++--
 2 files changed, 60 insertions(+), 25 deletions(-)

diff --git a/core/state/state.go b/core/state/state.go
index 0f33498788..35a2859ad7 100644
--- a/core/state/state.go
+++ b/core/state/state.go
@@ -5,6 +5,7 @@ import (
 	"errors"
 	"fmt"
 	"maps"
+	"runtime"
 	"slices"
 
 	"github.com/NethermindEth/juno/core"
@@ -12,6 +13,7 @@ import (
 	"github.com/NethermindEth/juno/core/felt"
 	"github.com/NethermindEth/juno/core/trie2"
 	"github.com/NethermindEth/juno/db"
+	"github.com/sourcegraph/conc/pool"
 )
 
 const (
@@ -243,25 +245,43 @@ func (s *State) Commit(storeHistory bool, blockNum uint64) (*felt.Felt, error) {
 		return len(contractB.dirtyStorage) - len(contractA.dirtyStorage)
 	})
 
-	for _, addr := range keys {
+	// Commit contracts in parallel in a buffered transaction
+	p := pool.New().WithMaxGoroutines(runtime.GOMAXPROCS(0)).WithErrors()
+	bufTxn := db.NewBufferedTransaction(s.txn)
+	comms := make([]*felt.Felt, len(keys))
+	for i, addr := range keys {
 		contract := s.dirtyContracts[addr]
 
-		// Contract is marked as deleted
-		if contract == nil {
-			if err := s.deleteContract(addr); err != nil {
-				return nil, err
+		p.Go(func() error {
+			// Contract is marked as deleted
+			if contract == nil {
+				if err := s.deleteContract(bufTxn, addr); err != nil {
+					return err
+				}
+				comms[i] = &felt.Zero
+				return nil
 			}
-			continue
-		}
 
-		// Otherwise, commit the contract changes and update the contract trie
-		err := contract.Commit(s.txn, storeHistory, blockNum)
-		if err != nil {
-			return nil, err
-		}
+			// Otherwise, commit the contract changes
+			if err := contract.Commit(bufTxn, storeHistory, blockNum); err != nil {
+				return err
+			}
+			comms[i] = contract.Commitment()
+			return nil
+		})
+	}
 
-		ctComm := contract.Commitment()
-		if err := s.contractTrie.Update(contract.Address, ctComm); err != nil {
+	if err := p.Wait(); err != nil {
+		return nil, err
+	}
+
+	if err := bufTxn.Flush(); err != nil {
+		return nil, err
+	}
+
+	// Update the contract trie with the new commitments
+	for i, addr := range keys {
+		if err := s.contractTrie.Update(&addr, comms[i]); err != nil {
 			return nil, err
 		}
 
@@ -269,7 +289,8 @@ func (s *State) Commit(storeHistory bool, blockNum uint64) (*felt.Felt, error) {
 		// Updating contracts with reverse diff will eventually lead to the deletion of noClassContract's storage key from db. Thus,
 		// we can use the lack of key's existence as reason for purging noClassContracts.
 		for nAddr := range noClassContracts {
-			if contract.Address.Equal(&nAddr) {
+			if addr.Equal(&nAddr) {
+				contract := s.dirtyContracts[addr]
 				root, err := contract.GetStorageRoot(s.txn)
 				if err != nil {
 					return nil, err
@@ -297,6 +318,7 @@ func (s *State) Commit(storeHistory bool, blockNum uint64) (*felt.Felt, error) {
 	if err != nil {
 		return nil, err
 	}
+
 	return stateCommitment(&contractRoot, &classRoot), nil
 }
 
@@ -407,18 +429,14 @@ func (s *State) deleteHistory(blockNum uint64, diff *core.StateDiff) error {
 	return nil
 }
 
-func (s *State) deleteContract(addr felt.Felt) error {
-	if err := s.contractTrie.Update(&addr, &felt.Zero); err != nil {
-		return err
-	}
-
-	if err := s.txn.Delete(contractKey(&addr)); err != nil {
+func (s *State) deleteContract(txn db.Transaction, addr felt.Felt) error {
+	if err := txn.Delete(contractKey(&addr)); err != nil {
 		return err
 	}
 
 	// Create a temporary contract with zero values so that we can delete the storage trie
 	tempContract := NewStateContract(&addr, &felt.Zero, &felt.Zero, 0)
-	err := tempContract.deleteStorageTrie(s.txn)
+	err := tempContract.deleteStorageTrie(txn)
 	if err != nil {
 		return err
 	}
diff --git a/db/buffered_transaction.go b/db/buffered_transaction.go
index b19ba1ab0e..66b60c9a9e 100644
--- a/db/buffered_transaction.go
+++ b/db/buffered_transaction.go
@@ -1,11 +1,12 @@
 package db
 
 import (
-	"errors"
+	"sync"
 )
 
 // BufferedTransaction buffers the updates in the memory to be later flushed to the underlying Transaction
 type BufferedTransaction struct {
+	mu      sync.RWMutex
 	updates map[string][]byte
 	txn     Transaction
 }
@@ -34,6 +35,9 @@ func (t *BufferedTransaction) Commit() error {
 
 // Set : see db.Transaction.Set
 func (t *BufferedTransaction) Set(key, val []byte) error {
+	t.mu.Lock()
+	defer t.mu.Unlock()
+
 	valueCopy := make([]byte, 0, len(val))
 	t.updates[string(key)] = append(valueCopy, val...)
 	return nil
@@ -41,12 +45,18 @@ func (t *BufferedTransaction) Set(key, val []byte) error {
 
 // Delete : see db.Transaction.Delete
 func (t *BufferedTransaction) Delete(key []byte) error {
+	t.mu.Lock()
+	defer t.mu.Unlock()
+
 	t.updates[string(key)] = nil
 	return nil
 }
 
 // Get : see db.Transaction.Get
 func (t *BufferedTransaction) Get(key []byte, cb func([]byte) error) error {
+	t.mu.RLock()
+	defer t.mu.RUnlock()
+
 	if value, found := t.updates[string(key)]; found {
 		if value == nil {
 			return ErrKeyNotFound
@@ -57,7 +67,11 @@ func (t *BufferedTransaction) Get(key []byte, cb func([]byte) error) error {
 }
 
 // Flush applies the pending changes to the underlying Transaction
+// The underlying updates will be cleared after the flush
 func (t *BufferedTransaction) Flush() error {
+	t.mu.Lock()
+	defer t.mu.Unlock()
+
 	for key, value := range t.updates {
 		keyBytes := []byte(key)
 		if value == nil {
@@ -70,6 +84,9 @@ func (t *BufferedTransaction) Flush() error {
 			}
 		}
 	}
+
+	t.updates = make(map[string][]byte)
+
 	return nil
 }
 
@@ -79,6 +96,6 @@ func (t *BufferedTransaction) Impl() any {
 }
 
 // NewIterator : see db.Transaction.NewIterator
-func (t *BufferedTransaction) NewIterator(_ []byte, _ bool) (Iterator, error) {
-	return nil, errors.New("buffered transactions dont support iterators")
+func (t *BufferedTransaction) NewIterator(lowerBound []byte, withUpperBound bool) (Iterator, error) {
+	return t.txn.NewIterator(lowerBound, withUpperBound)
 }

From 601589444c047f923590d0f50a37814aaa0037b2 Mon Sep 17 00:00:00 2001
From: weiihann <weihan774237@gmail.com>
Date: Wed, 19 Feb 2025 02:10:44 +0800
Subject: [PATCH 11/15] chore

---
 core/state/state.go | 35 ++++++++++++++++++-----------------
 1 file changed, 18 insertions(+), 17 deletions(-)

diff --git a/core/state/state.go b/core/state/state.go
index 35a2859ad7..35faef97d1 100644
--- a/core/state/state.go
+++ b/core/state/state.go
@@ -227,23 +227,9 @@ func (s *State) Revert(blockNum uint64, update *core.StateUpdate) error {
 }
 
 func (s *State) Commit(storeHistory bool, blockNum uint64) (*felt.Felt, error) {
-	keys := slices.SortedStableFunc(maps.Keys(s.dirtyContracts), func(a, b felt.Felt) int {
-		// Sort in descending order of the number of storage changes
-		// so that we start with the heaviest update first
-		contractA, contractB := s.dirtyContracts[a], s.dirtyContracts[b]
-
-		// Handle nil cases first
-		switch {
-		case contractA == nil && contractB == nil:
-			return 0
-		case contractA == nil:
-			return 1 // Move nil contracts to end
-		case contractB == nil:
-			return -1 // Keep non-nil contracts first
-		}
-
-		return len(contractB.dirtyStorage) - len(contractA.dirtyStorage)
-	})
+	// Sort in descending order of the number of storage changes
+	// so that we start with the heaviest update first
+	keys := slices.SortedStableFunc(maps.Keys(s.dirtyContracts), s.compareContracts)
 
 	// Commit contracts in parallel in a buffered transaction
 	p := pool.New().WithMaxGoroutines(runtime.GOMAXPROCS(0)).WithErrors()
@@ -655,3 +641,18 @@ func stateCommitment(contractRoot, classRoot *felt.Felt) *felt.Felt {
 func classKey(classHash *felt.Felt) []byte {
 	return db.Class.Key(classHash.Marshal())
 }
+
+func (s *State) compareContracts(a, b felt.Felt) int {
+	contractA, contractB := s.dirtyContracts[a], s.dirtyContracts[b]
+
+	switch {
+	case contractA == nil && contractB == nil:
+		return 0
+	case contractA == nil:
+		return 1 // Move nil contracts to end
+	case contractB == nil:
+		return -1 // Keep non-nil contracts first
+	}
+
+	return len(contractB.dirtyStorage) - len(contractA.dirtyStorage)
+}

From a6c7cd113b9f9cc29a1683f22ae797a3aa9e57c3 Mon Sep 17 00:00:00 2001
From: weiihann <weihan774237@gmail.com>
Date: Thu, 20 Feb 2025 10:08:27 +0800
Subject: [PATCH 12/15] update bucket

---
 cmd/juno/dbcmd.go    |  2 +-
 db/buckets.go        | 10 +++++-----
 db/buckets_enumer.go | 40 ++++++++++++++++++++++++++++++++++++----
 3 files changed, 42 insertions(+), 10 deletions(-)

diff --git a/cmd/juno/dbcmd.go b/cmd/juno/dbcmd.go
index 3cf32f438e..43bef33134 100644
--- a/cmd/juno/dbcmd.go
+++ b/cmd/juno/dbcmd.go
@@ -215,7 +215,7 @@ func dbSize(cmd *cobra.Command, args []string) error {
 		totalSize += bucketItem.Size
 		totalCount += bucketItem.Count
 
-		if utils.AnyOf(b, db.StateTrie, db.ContractStorage, db.Class, db.ContractNonce, db.ContractDeploymentHeight) {
+		if utils.AnyOf(b, db.ContractTrieContract, db.ContractTrieStorage, db.ClassTrie) {
 			withoutHistorySize += bucketItem.Size
 			withHistorySize += bucketItem.Size
 
diff --git a/db/buckets.go b/db/buckets.go
index 0b58c12d72..4cd02fc969 100644
--- a/db/buckets.go
+++ b/db/buckets.go
@@ -9,12 +9,12 @@ type Bucket byte
 // keys like Bolt or MDBX does. We use a global prefix list as a poor
 // man's bucket alternative.
 const (
-	StateTrie         Bucket = iota // state metadata (e.g., the state root)
+	StateTrie         Bucket = iota // LEGACY state metadata (e.g., the state root)
 	Peer                            // maps peer ID to peer multiaddresses
-	ContractClassHash               // maps contract addresses and class hashes
-	ContractStorage                 // contract storages
+	ContractClassHash               // LEGACY maps contract addresses and class hashes
+	ContractStorage                 // LEGACY contract storages
 	Class                           // maps class hashes to classes
-	ContractNonce                   // contract nonce
+	ContractNonce                   // LEGACY contract nonce
 	ChainHeight                     // Latest height of the blockchain
 	BlockHeaderNumbersByHash
 	BlockHeadersByNumber
@@ -26,7 +26,7 @@ const (
 	ContractStorageHistory   // [ContractStorageHistory] + ContractAddr + StorageLocation + BlockHeight -> StorageValue
 	ContractNonceHistory     // [ContractNonceHistory] + ContractAddr + BlockHeight -> ContractNonce
 	ContractClassHashHistory // [ContractClassHashHistory] + ContractAddr + BlockHeight -> ContractClassHash
-	ContractDeploymentHeight
+	ContractDeploymentHeight // LEGACY
 	L1Height
 	SchemaVersion
 	Unused // Previously used for storing Pending Block
diff --git a/db/buckets_enumer.go b/db/buckets_enumer.go
index 2e99c9258c..49ef0f0f7d 100644
--- a/db/buckets_enumer.go
+++ b/db/buckets_enumer.go
@@ -7,11 +7,11 @@ import (
 	"strings"
 )
 
-const _BucketName = "StateTriePeerContractClassHashContractStorageClassContractNonceChainHeightBlockHeaderNumbersByHashBlockHeadersByNumberTransactionBlockNumbersAndIndicesByHashTransactionsByBlockNumberAndIndexReceiptsByBlockNumberAndIndexStateUpdatesByBlockNumberClassesTrieContractStorageHistoryContractNonceHistoryContractClassHashHistoryContractDeploymentHeightL1HeightSchemaVersionUnusedBlockCommitmentsTemporarySchemaIntermediateStateL1HandlerTxnHashByMsgHash"
+const _BucketName = "StateTriePeerContractClassHashContractStorageClassContractNonceChainHeightBlockHeaderNumbersByHashBlockHeadersByNumberTransactionBlockNumbersAndIndicesByHashTransactionsByBlockNumberAndIndexReceiptsByBlockNumberAndIndexStateUpdatesByBlockNumberClassesTrieContractStorageHistoryContractNonceHistoryContractClassHashHistoryContractDeploymentHeightL1HeightSchemaVersionUnusedBlockCommitmentsTemporarySchemaIntermediateStateL1HandlerTxnHashByMsgHashMempoolHeadMempoolTailMempoolLengthMempoolNodeClassTrieContractTrieContractContractTrieStorageContract"
 
-var _BucketIndex = [...]uint16{0, 9, 13, 30, 45, 50, 63, 74, 98, 118, 157, 190, 219, 244, 255, 277, 297, 321, 345, 353, 366, 372, 388, 397, 420, 445}
+var _BucketIndex = [...]uint16{0, 9, 13, 30, 45, 50, 63, 74, 98, 118, 157, 190, 219, 244, 255, 277, 297, 321, 345, 353, 366, 372, 388, 397, 420, 445, 456, 467, 480, 491, 500, 520, 539, 547}
 
-const _BucketLowerName = "statetriepeercontractclasshashcontractstorageclasscontractnoncechainheightblockheadernumbersbyhashblockheadersbynumbertransactionblocknumbersandindicesbyhashtransactionsbyblocknumberandindexreceiptsbyblocknumberandindexstateupdatesbyblocknumberclassestriecontractstoragehistorycontractnoncehistorycontractclasshashhistorycontractdeploymentheightl1heightschemaversionunusedblockcommitmentstemporaryschemaintermediatestatel1handlertxnhashbymsghash"
+const _BucketLowerName = "statetriepeercontractclasshashcontractstorageclasscontractnoncechainheightblockheadernumbersbyhashblockheadersbynumbertransactionblocknumbersandindicesbyhashtransactionsbyblocknumberandindexreceiptsbyblocknumberandindexstateupdatesbyblocknumberclassestriecontractstoragehistorycontractnoncehistorycontractclasshashhistorycontractdeploymentheightl1heightschemaversionunusedblockcommitmentstemporaryschemaintermediatestatel1handlertxnhashbymsghashmempoolheadmempooltailmempoollengthmempoolnodeclasstriecontracttriecontractcontracttriestoragecontract"
 
 func (i Bucket) String() string {
 	if i >= Bucket(len(_BucketIndex)-1) {
@@ -49,9 +49,17 @@ func _BucketNoOp() {
 	_ = x[Temporary-(22)]
 	_ = x[SchemaIntermediateState-(23)]
 	_ = x[L1HandlerTxnHashByMsgHash-(24)]
+	_ = x[MempoolHead-(25)]
+	_ = x[MempoolTail-(26)]
+	_ = x[MempoolLength-(27)]
+	_ = x[MempoolNode-(28)]
+	_ = x[ClassTrie-(29)]
+	_ = x[ContractTrieContract-(30)]
+	_ = x[ContractTrieStorage-(31)]
+	_ = x[Contract-(32)]
 }
 
-var _BucketValues = []Bucket{StateTrie, Peer, ContractClassHash, ContractStorage, Class, ContractNonce, ChainHeight, BlockHeaderNumbersByHash, BlockHeadersByNumber, TransactionBlockNumbersAndIndicesByHash, TransactionsByBlockNumberAndIndex, ReceiptsByBlockNumberAndIndex, StateUpdatesByBlockNumber, ClassesTrie, ContractStorageHistory, ContractNonceHistory, ContractClassHashHistory, ContractDeploymentHeight, L1Height, SchemaVersion, Unused, BlockCommitments, Temporary, SchemaIntermediateState, L1HandlerTxnHashByMsgHash}
+var _BucketValues = []Bucket{StateTrie, Peer, ContractClassHash, ContractStorage, Class, ContractNonce, ChainHeight, BlockHeaderNumbersByHash, BlockHeadersByNumber, TransactionBlockNumbersAndIndicesByHash, TransactionsByBlockNumberAndIndex, ReceiptsByBlockNumberAndIndex, StateUpdatesByBlockNumber, ClassesTrie, ContractStorageHistory, ContractNonceHistory, ContractClassHashHistory, ContractDeploymentHeight, L1Height, SchemaVersion, Unused, BlockCommitments, Temporary, SchemaIntermediateState, L1HandlerTxnHashByMsgHash, MempoolHead, MempoolTail, MempoolLength, MempoolNode, ClassTrie, ContractTrieContract, ContractTrieStorage, Contract}
 
 var _BucketNameToValueMap = map[string]Bucket{
 	_BucketName[0:9]:          StateTrie,
@@ -104,6 +112,22 @@ var _BucketNameToValueMap = map[string]Bucket{
 	_BucketLowerName[397:420]: SchemaIntermediateState,
 	_BucketName[420:445]:      L1HandlerTxnHashByMsgHash,
 	_BucketLowerName[420:445]: L1HandlerTxnHashByMsgHash,
+	_BucketName[445:456]:      MempoolHead,
+	_BucketLowerName[445:456]: MempoolHead,
+	_BucketName[456:467]:      MempoolTail,
+	_BucketLowerName[456:467]: MempoolTail,
+	_BucketName[467:480]:      MempoolLength,
+	_BucketLowerName[467:480]: MempoolLength,
+	_BucketName[480:491]:      MempoolNode,
+	_BucketLowerName[480:491]: MempoolNode,
+	_BucketName[491:500]:      ClassTrie,
+	_BucketLowerName[491:500]: ClassTrie,
+	_BucketName[500:520]:      ContractTrieContract,
+	_BucketLowerName[500:520]: ContractTrieContract,
+	_BucketName[520:539]:      ContractTrieStorage,
+	_BucketLowerName[520:539]: ContractTrieStorage,
+	_BucketName[539:547]:      Contract,
+	_BucketLowerName[539:547]: Contract,
 }
 
 var _BucketNames = []string{
@@ -132,6 +156,14 @@ var _BucketNames = []string{
 	_BucketName[388:397],
 	_BucketName[397:420],
 	_BucketName[420:445],
+	_BucketName[445:456],
+	_BucketName[456:467],
+	_BucketName[467:480],
+	_BucketName[480:491],
+	_BucketName[491:500],
+	_BucketName[500:520],
+	_BucketName[520:539],
+	_BucketName[539:547],
 }
 
 // BucketString retrieves an enum value from the enum constants string name.

From d0ef5093b5818e07c0c9f70244617eacd0c57dad Mon Sep 17 00:00:00 2001
From: weiihann <weihan774237@gmail.com>
Date: Tue, 25 Feb 2025 14:08:36 +0800
Subject: [PATCH 13/15] fix(state,rpc,vm): rebase and trie id

---
 core/state/contract.go | 2 +-
 core/state/state.go    | 4 ++--
 go.mod                 | 2 +-
 mocks/mock_vm.go       | 4 ++--
 rpc/v8/storage_test.go | 4 ++--
 vm/vm.go               | 2 +-
 6 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/core/state/contract.go b/core/state/contract.go
index e1d8f76848..ce029bd65d 100644
--- a/core/state/contract.go
+++ b/core/state/contract.go
@@ -247,7 +247,7 @@ func (s *StateContract) getTrie(txn db.Transaction) (*trie2.Trie, error) {
 		return s.tr, nil
 	}
 
-	tr, err := trie2.New(trie2.ContractTrieID(*s.Address), ContractStorageTrieHeight, crypto.Pedersen, txn)
+	tr, err := trie2.New(trie2.NewContractStorageTrieID(*s.Address), ContractStorageTrieHeight, crypto.Pedersen, txn)
 	if err != nil {
 		return nil, err
 	}
diff --git a/core/state/state.go b/core/state/state.go
index 35faef97d1..f070be9481 100644
--- a/core/state/state.go
+++ b/core/state/state.go
@@ -43,12 +43,12 @@ type State struct {
 }
 
 func New(txn db.Transaction) (*State, error) {
-	contractTrie, err := trie2.New(trie2.ContractTrieID(felt.Zero), ContractTrieHeight, crypto.Pedersen, txn)
+	contractTrie, err := trie2.New(trie2.NewContractTrieID(), ContractTrieHeight, crypto.Pedersen, txn)
 	if err != nil {
 		return nil, err
 	}
 
-	classTrie, err := trie2.New(trie2.ClassTrieID(), ClassTrieHeight, crypto.Poseidon, txn)
+	classTrie, err := trie2.New(trie2.NewClassTrieID(), ClassTrieHeight, crypto.Poseidon, txn)
 	if err != nil {
 		return nil, err
 	}
diff --git a/go.mod b/go.mod
index 9fb3e67dca..bfdbf84e0e 100644
--- a/go.mod
+++ b/go.mod
@@ -34,6 +34,7 @@ require (
 	go.uber.org/mock v0.5.0
 	go.uber.org/zap v1.27.0
 	golang.org/x/crypto v0.34.0
+	golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa
 	golang.org/x/sync v0.11.0
 	google.golang.org/grpc v1.70.0
 	google.golang.org/protobuf v1.36.5
@@ -194,7 +195,6 @@ require (
 	go.uber.org/dig v1.18.0 // indirect
 	go.uber.org/fx v1.23.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
-	golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect
 	golang.org/x/mod v0.23.0 // indirect
 	golang.org/x/net v0.35.0 // indirect
 	golang.org/x/sys v0.30.0 // indirect
diff --git a/mocks/mock_vm.go b/mocks/mock_vm.go
index eba2af9cb4..94de1f61af 100644
--- a/mocks/mock_vm.go
+++ b/mocks/mock_vm.go
@@ -43,10 +43,10 @@ func (m *MockVM) EXPECT() *MockVMMockRecorder {
 }
 
 // Call mocks base method.
-func (m *MockVM) Call(arg0 *vm.CallInfo, arg1 *vm.BlockInfo, arg2 vm.StateReader, arg3 *utils.Network, arg4 uint64, arg5 string) ([]*felt.Felt, error) {
+func (m *MockVM) Call(arg0 *vm.CallInfo, arg1 *vm.BlockInfo, arg2 vm.StateReader, arg3 *utils.Network, arg4 uint64, arg5 string) (vm.CallResult, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Call", arg0, arg1, arg2, arg3, arg4, arg5)
-	ret0, _ := ret[0].([]*felt.Felt)
+	ret0, _ := ret[0].(vm.CallResult)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
diff --git a/rpc/v8/storage_test.go b/rpc/v8/storage_test.go
index 98ac5e60b9..6f81f2f828 100644
--- a/rpc/v8/storage_test.go
+++ b/rpc/v8/storage_test.go
@@ -141,14 +141,14 @@ func TestStorageProof(t *testing.T) {
 	testDB := pebble.NewMemTest(t)
 	txn, err := testDB.NewTransaction(true)
 	require.NoError(t, err)
-	tempTrie, err := trie2.New(trie2.TrieID(), 251, crypto.Pedersen, txn)
+	tempTrie, err := trie2.New(trie2.NewEmptyTrieID(), 251, crypto.Pedersen, txn)
 	require.NoError(t, err)
 	_ = tempTrie.Update(key, value)
 	_ = tempTrie.Update(key2, value2)
 	_, _ = tempTrie.Commit()
 	trieRoot := tempTrie.Hash()
 
-	tempTrie, err = trie2.New(trie2.TrieID(), 251, crypto.Pedersen, txn)
+	tempTrie, err = trie2.New(trie2.NewEmptyTrieID(), 251, crypto.Pedersen, txn)
 	require.NoError(t, err)
 
 	mockReader := mocks.NewMockReader(mockCtrl)
diff --git a/vm/vm.go b/vm/vm.go
index d93ef29b85..01fde07241 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -38,7 +38,7 @@ type CallResult struct {
 
 //go:generate mockgen -destination=../mocks/mock_vm.go -package=mocks github.com/NethermindEth/juno/vm VM
 type VM interface {
-	Call(callInfo *CallInfo, blockInfo *BlockInfo, state core.StateReader, network *utils.Network,
+	Call(callInfo *CallInfo, blockInfo *BlockInfo, state StateReader, network *utils.Network,
 		maxSteps uint64, sierraVersion string) (CallResult, error)
 	Execute(txns []core.Transaction, declaredClasses []core.Class, paidFeesOnL1 []*felt.Felt, blockInfo *BlockInfo,
 		state StateReader, network *utils.Network, skipChargeFee, skipValidate, errOnRevert bool,

From 6851f542c14d114b453b538415e5d4683a54f014 Mon Sep 17 00:00:00 2001
From: weiihann <weihan774237@gmail.com>
Date: Thu, 27 Feb 2025 10:26:45 +0800
Subject: [PATCH 14/15] fix bucket

---
 core/state/contract.go | 2 ++
 db/buckets.go          | 1 +
 2 files changed, 3 insertions(+)

diff --git a/core/state/contract.go b/core/state/contract.go
index ce029bd65d..d99682e825 100644
--- a/core/state/contract.go
+++ b/core/state/contract.go
@@ -215,6 +215,8 @@ func (s *StateContract) deleteStorageTrie(txn db.Transaction) error {
 		return err
 	}
 
+	// TODO: Instead of using node iterator and delete each node one by one,
+	// use the underlying DeleteRange from PebbleDB.
 	it, err := tr.NodeIterator()
 	if err != nil {
 		return err
diff --git a/db/buckets.go b/db/buckets.go
index 4cd02fc969..3096a8c92b 100644
--- a/db/buckets.go
+++ b/db/buckets.go
@@ -41,6 +41,7 @@ const (
 	ClassTrie            // ClassTrie + nodetype + path + pathlength -> Trie Node
 	ContractTrieContract // ContractTrieContract + nodetype + path + pathlength -> Trie Node
 	ContractTrieStorage  // ContractTrieStorage + nodetype + path + pathlength -> Trie Node
+	Contract             // Contract + ContractAddr -> Contract
 )
 
 // Key flattens a prefix and series of byte arrays into a single []byte.

From 538f3e1756a1c681c229acefebe1ded2fe55628a Mon Sep 17 00:00:00 2001
From: weiihann <weihan774237@gmail.com>
Date: Thu, 27 Feb 2025 19:01:47 +0800
Subject: [PATCH 15/15] refactor(state): delete history

---
 core/history.go          | 134 ---------------------------------------
 core/history_pkg_test.go | 104 ------------------------------
 2 files changed, 238 deletions(-)
 delete mode 100644 core/history.go
 delete mode 100644 core/history_pkg_test.go

diff --git a/core/history.go b/core/history.go
deleted file mode 100644
index 62656e5a97..0000000000
--- a/core/history.go
+++ /dev/null
@@ -1,134 +0,0 @@
-package core
-
-import (
-	"bytes"
-	"encoding/binary"
-	"errors"
-
-	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/db"
-	"github.com/NethermindEth/juno/utils"
-)
-
-var ErrCheckHeadState = errors.New("check head state")
-
-type history struct {
-	txn db.Transaction
-}
-
-func logDBKey(key []byte, height uint64) []byte {
-	return binary.BigEndian.AppendUint64(key, height)
-}
-
-func (h *history) logOldValue(key, value []byte, height uint64) error {
-	return h.txn.Set(logDBKey(key, height), value)
-}
-
-func (h *history) deleteLog(key []byte, height uint64) error {
-	return h.txn.Delete(logDBKey(key, height))
-}
-
-func (h *history) valueAt(key []byte, height uint64) ([]byte, error) {
-	it, err := h.txn.NewIterator(nil, false)
-	if err != nil {
-		return nil, err
-	}
-
-	for it.Seek(logDBKey(key, height)); it.Valid(); it.Next() {
-		seekedKey := it.Key()
-		// seekedKey size should be `len(key) + sizeof(uint64)` and seekedKey should match key prefix
-		if len(seekedKey) != len(key)+8 || !bytes.HasPrefix(seekedKey, key) {
-			break
-		}
-
-		seekedHeight := binary.BigEndian.Uint64(seekedKey[len(key):])
-		if seekedHeight < height {
-			// last change happened before the height we are looking for
-			// check head state
-			break
-		} else if seekedHeight == height {
-			// a log exists for the height we are looking for, so the old value in this log entry is not useful.
-			// advance the iterator and see we can use the next entry. If not, ErrCheckHeadState will be returned
-			continue
-		}
-
-		val, itErr := it.Value()
-		if err = utils.RunAndWrapOnError(it.Close, itErr); err != nil {
-			return nil, err
-		}
-		// seekedHeight > height
-		return val, nil
-	}
-
-	return nil, utils.RunAndWrapOnError(it.Close, ErrCheckHeadState)
-}
-
-func storageLogKey(contractAddress, storageLocation *felt.Felt) []byte {
-	return db.ContractStorageHistory.Key(contractAddress.Marshal(), storageLocation.Marshal())
-}
-
-// LogContractStorage logs the old value of a storage location for the given contract which changed on height `height`
-func (h *history) LogContractStorage(contractAddress, storageLocation, oldValue *felt.Felt, height uint64) error {
-	key := storageLogKey(contractAddress, storageLocation)
-	return h.logOldValue(key, oldValue.Marshal(), height)
-}
-
-// DeleteContractStorageLog deletes the log at the given height
-func (h *history) DeleteContractStorageLog(contractAddress, storageLocation *felt.Felt, height uint64) error {
-	return h.deleteLog(storageLogKey(contractAddress, storageLocation), height)
-}
-
-// ContractStorageAt returns the value of a storage location of the given contract at the height `height`
-func (h *history) ContractStorageAt(contractAddress, storageLocation *felt.Felt, height uint64) (*felt.Felt, error) {
-	key := storageLogKey(contractAddress, storageLocation)
-	value, err := h.valueAt(key, height)
-	if err != nil {
-		return nil, err
-	}
-
-	return new(felt.Felt).SetBytes(value), nil
-}
-
-func nonceLogKey(contractAddress *felt.Felt) []byte {
-	return db.ContractNonceHistory.Key(contractAddress.Marshal())
-}
-
-func (h *history) LogContractNonce(contractAddress, oldValue *felt.Felt, height uint64) error {
-	return h.logOldValue(nonceLogKey(contractAddress), oldValue.Marshal(), height)
-}
-
-func (h *history) DeleteContractNonceLog(contractAddress *felt.Felt, height uint64) error {
-	return h.deleteLog(nonceLogKey(contractAddress), height)
-}
-
-func (h *history) ContractNonceAt(contractAddress *felt.Felt, height uint64) (*felt.Felt, error) {
-	key := nonceLogKey(contractAddress)
-	value, err := h.valueAt(key, height)
-	if err != nil {
-		return nil, err
-	}
-
-	return new(felt.Felt).SetBytes(value), nil
-}
-
-func classHashLogKey(contractAddress *felt.Felt) []byte {
-	return db.ContractClassHashHistory.Key(contractAddress.Marshal())
-}
-
-func (h *history) LogContractClassHash(contractAddress, oldValue *felt.Felt, height uint64) error {
-	return h.logOldValue(classHashLogKey(contractAddress), oldValue.Marshal(), height)
-}
-
-func (h *history) DeleteContractClassHashLog(contractAddress *felt.Felt, height uint64) error {
-	return h.deleteLog(classHashLogKey(contractAddress), height)
-}
-
-func (h *history) ContractClassHashAt(contractAddress *felt.Felt, height uint64) (*felt.Felt, error) {
-	key := classHashLogKey(contractAddress)
-	value, err := h.valueAt(key, height)
-	if err != nil {
-		return nil, err
-	}
-
-	return new(felt.Felt).SetBytes(value), nil
-}
diff --git a/core/history_pkg_test.go b/core/history_pkg_test.go
deleted file mode 100644
index b883f4c0ed..0000000000
--- a/core/history_pkg_test.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package core
-
-import (
-	"testing"
-
-	"github.com/NethermindEth/juno/core/felt"
-	"github.com/NethermindEth/juno/db/pebble"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-func TestHistory(t *testing.T) {
-	testDB := pebble.NewMemTest(t)
-	txn, err := testDB.NewTransaction(true)
-	require.NoError(t, err)
-	t.Cleanup(func() {
-		require.NoError(t, txn.Discard())
-	})
-
-	history := &history{txn: txn}
-	contractAddress := new(felt.Felt).SetUint64(123)
-
-	for desc, test := range map[string]struct {
-		logger  func(location, oldValue *felt.Felt, height uint64) error
-		getter  func(location *felt.Felt, height uint64) (*felt.Felt, error)
-		deleter func(location *felt.Felt, height uint64) error
-	}{
-		"contract storage": {
-			logger: func(location, oldValue *felt.Felt, height uint64) error {
-				return history.LogContractStorage(contractAddress, location, oldValue, height)
-			},
-			getter: func(location *felt.Felt, height uint64) (*felt.Felt, error) {
-				return history.ContractStorageAt(contractAddress, location, height)
-			},
-			deleter: func(location *felt.Felt, height uint64) error {
-				return history.DeleteContractStorageLog(contractAddress, location, height)
-			},
-		},
-		"contract nonce": {
-			logger:  history.LogContractNonce,
-			getter:  history.ContractNonceAt,
-			deleter: history.DeleteContractNonceLog,
-		},
-		"contract class hash": {
-			logger:  history.LogContractClassHash,
-			getter:  history.ContractClassHashAt,
-			deleter: history.DeleteContractClassHashLog,
-		},
-	} {
-		location := new(felt.Felt).SetUint64(456)
-
-		t.Run(desc, func(t *testing.T) {
-			t.Run("no history", func(t *testing.T) {
-				_, err := test.getter(location, 1)
-				assert.ErrorIs(t, err, ErrCheckHeadState)
-			})
-
-			value := new(felt.Felt).SetUint64(789)
-
-			t.Run("log value changed at height 5 and 10", func(t *testing.T) {
-				assert.NoError(t, test.logger(location, &felt.Zero, 5))
-				assert.NoError(t, test.logger(location, value, 10))
-			})
-
-			t.Run("get value before height 5", func(t *testing.T) {
-				oldValue, err := test.getter(location, 1)
-				require.NoError(t, err)
-				assert.Equal(t, &felt.Zero, oldValue)
-			})
-
-			t.Run("get value between height 5-10 ", func(t *testing.T) {
-				oldValue, err := test.getter(location, 7)
-				require.NoError(t, err)
-				assert.Equal(t, value, oldValue)
-			})
-
-			t.Run("get value on height that change happened ", func(t *testing.T) {
-				oldValue, err := test.getter(location, 5)
-				require.NoError(t, err)
-				assert.Equal(t, value, oldValue)
-
-				_, err = test.getter(location, 10)
-				assert.ErrorIs(t, err, ErrCheckHeadState)
-			})
-
-			t.Run("get value after height 10 ", func(t *testing.T) {
-				_, err := test.getter(location, 13)
-				assert.ErrorIs(t, err, ErrCheckHeadState)
-			})
-
-			t.Run("get a random location ", func(t *testing.T) {
-				_, err := test.getter(new(felt.Felt).SetUint64(37), 13)
-				assert.ErrorIs(t, err, ErrCheckHeadState)
-			})
-
-			require.NoError(t, test.deleter(location, 10))
-
-			t.Run("get after delete", func(t *testing.T) {
-				_, err := test.getter(location, 7)
-				assert.ErrorIs(t, err, ErrCheckHeadState)
-			})
-		})
-	}
-}