Repository: NethermindEth/juno
Pull request #226 (2022-06-19 00:48:28)

Refactor Database
## Changes:
- Refactoring the database implementation

## Types of changes

What types of changes does your code introduce?
_Put an `x` in the boxes that apply_

- [x] Breaking change (fix or feature that would cause existing functionality to not work as expected)

## Testing
**Requires testing**

- [x] Yes
- [ ] No

**In case you checked yes, did you write tests??**

- [x] Yes
- [ ] No


codecov[bot]: # [Codecov](https://codecov.io/gh/NethermindEth/juno/pull/226?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth) Report
> Merging [#226](https://codecov.io/gh/NethermindEth/juno/pull/226?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth) (3b5ed3b) into [main](https://codecov.io/gh/NethermindEth/juno/commit/d88ff203700a6deff1a86dbc997f093b95a312b5?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth) (d88ff20) will **not change** coverage.
> The diff coverage is `100.00%`.

```diff
@@            Coverage Diff            @@
##              main      #226   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           66        65    -1     
  Lines         5899      5805   -94     
=========================================
- Hits          5899      5805   -94     
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `100.00% <100.00%> (ø)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/NethermindEth/juno/pull/226?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth) | Coverage Δ | |
|---|---|---|
| [internal/services/service.go](https://codecov.io/gh/NethermindEth/juno/pull/226/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth#diff-aW50ZXJuYWwvc2VydmljZXMvc2VydmljZS5nbw==) | `100.00% <ø> (ø)` | |
| [internal/db/abi/manager.go](https://codecov.io/gh/NethermindEth/juno/pull/226/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth#diff-aW50ZXJuYWwvZGIvYWJpL21hbmFnZXIuZ28=) | `100.00% <100.00%> (ø)` | |
| [internal/db/block/manager.go](https://codecov.io/gh/NethermindEth/juno/pull/226/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth#diff-aW50ZXJuYWwvZGIvYmxvY2svbWFuYWdlci5nbw==) | `100.00% <100.00%> (ø)` | |
| [internal/db/block\_specific.go](https://codecov.io/gh/NethermindEth/juno/pull/226/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth#diff-aW50ZXJuYWwvZGIvYmxvY2tfc3BlY2lmaWMuZ28=) | `100.00% <100.00%> (ø)` | |
| [internal/db/kv\_storer.go](https://codecov.io/gh/NethermindEth/juno/pull/226/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth#diff-aW50ZXJuYWwvZGIva3Zfc3RvcmVyLmdv) | `100.00% <100.00%> (ø)` | |
| [internal/db/mdbx.go](https://codecov.io/gh/NethermindEth/juno/pull/226/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth#diff-aW50ZXJuYWwvZGIvbWRieC5nbw==) | `100.00% <100.00%> (ø)` | |
| [internal/db/mdbx\_env.go](https://codecov.io/gh/NethermindEth/juno/pull/226/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth#diff-aW50ZXJuYWwvZGIvbWRieF9lbnYuZ28=) | `100.00% <100.00%> (ø)` | |
| [internal/db/state/state.go](https://codecov.io/gh/NethermindEth/juno/pull/226/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth#diff-aW50ZXJuYWwvZGIvc3RhdGUvc3RhdGUuZ28=) | `100.00% <100.00%> (ø)` | |
| [internal/db/transaction/manager.go](https://codecov.io/gh/NethermindEth/juno/pull/226/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth#diff-aW50ZXJuYWwvZGIvdHJhbnNhY3Rpb24vbWFuYWdlci5nbw==) | `100.00% <100.00%> (ø)` | |
| [internal/services/abi.go](https://codecov.io/gh/NethermindEth/juno/pull/226/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth#diff-aW50ZXJuYWwvc2VydmljZXMvYWJpLmdv) | `100.00% <100.00%> (ø)` | |
| ... and [8 more](https://codecov.io/gh/NethermindEth/juno/pull/226/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/NethermindEth/juno/pull/226?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/NethermindEth/juno/pull/226?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth). Last update [d88ff20...3b5ed3b](https://codecov.io/gh/NethermindEth/juno/pull/226?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth).

D-DePablos: For the sake of completeness, everything works locally for me, and the db was able to continue sync with previously created state (had ~60 blocks), so sync continued correctly.

Patch:
diff --git a/cmd/juno/cli/root.go b/cmd/juno/cli/root.go
index 5f24084b..dfb13766 100644
--- a/cmd/juno/cli/root.go
+++ b/cmd/juno/cli/root.go
@@ -61,15 +61,17 @@ var (
 			// the config.
 			if config.Runtime.RPC.Enabled {
 				s := rpc.NewServer(":"+strconv.Itoa(config.Runtime.RPC.Port), feederGatewayClient)
+				// Initialize the RPC Service.
 				processHandler.Add("RPC", s.ListenAndServe, s.Close)
 			}
 
 			if config.Runtime.Metrics.Enabled {
 				s := metric.SetupMetric(":" + strconv.Itoa(config.Runtime.Metrics.Port))
+				// Initialize the Metrics Service.
 				processHandler.Add("Metrics", s.ListenAndServe, s.Close)
 			}
 
-			if err := db.InitializeDatabaseEnv(config.Runtime.DbPath, 10, 0); err != nil {
+			if err := db.InitializeMDBXEnv(config.Runtime.DbPath, 100, 0); err != nil {
 				log.Default.With("Error", err).Fatal("Error starting the database environment")
 			}
 
@@ -100,11 +102,16 @@ var (
 					}
 				}
 				// Synchronizer for Starknet State
-				synchronizerDb, err := db.GetDatabase("SYNCHRONIZER")
+				env, err := db.GetMDBXEnv()
+				if err != nil {
+					log.Default.Fatal(err)
+				}
+				synchronizerDb, err := db.NewMDBXDatabase(env, "SYNCHRONIZER")
 				if err != nil {
 					log.Default.With("Error", err).Fatal("Error starting the SYNCHRONIZER database")
 				}
 				stateSynchronizer := starknet.NewSynchronizer(synchronizerDb, ethereumClient, feederGatewayClient)
+				// Initialize the Starknet Synchronizer Service.
 				processHandler.Add("Starknet Synchronizer", stateSynchronizer.UpdateState,
 					stateSynchronizer.Close)
 			}
@@ -113,6 +120,7 @@ var (
 			// the config.
 			if config.Runtime.REST.Enabled {
 				s := rest.NewServer(":"+strconv.Itoa(config.Runtime.REST.Port), config.Runtime.Starknet.FeederGateway, config.Runtime.REST.Prefix)
+				// Initialize the REST Service.
 				processHandler.Add("REST", s.ListenAndServe, s.Close)
 			}
 
diff --git a/docs/docs/features/database.mdx b/docs/docs/features/database.mdx
new file mode 100644
index 00000000..35d227cf
--- /dev/null
+++ b/docs/docs/features/database.mdx
@@ -0,0 +1,67 @@
+---
+title: Database
+---
+
+# General characteristics
+
+Juno defines a database as an object that can store **key-value** pairs in a persistent way. Keys and values are
+arrays of bytes, that permit storing any value that can be serialized as a batch of bytes, and the same happens with the
+keys. Juno does not define the way the database must be initialized but defines what are the operations a database
+needs, which are:
+
+- **Has**: checks if the key already exists on the database.
+- **Get**: returns the associated value to the given key if the key exists on the database.
+- **Put**: stores a new value associated with the given key. If the key already exists, the value is overwritten.
+- **Delete**: deletes the given key from the database and its associated value.
+- **NumberOfItems**: returns the number of items (keys) on the database.
+
+All of those operations are described by this interface in the code:
+
+```go
+type DatabaseOperations interface {
+	Has(key []byte) (bool, error)
+	Get(key []byte) ([]byte, error)
+	Put(key, value []byte) error
+	Delete(key []byte) error
+	NumberOfItems() (uint64, error)
+}
+```
+
+Juno defines a database as the union of the above operations and a **Close** function to cleanly close the database,
+described by this interface in the code:
+
+```go
+type Database interface {
+	DatabaseOperations
+	Close()
+}
+```
+
+# Transactions
+
+A transactional database is a database that supports all the database functionalities and a new functionality called
+**RunTxn** to run a batch of operations in the database inside a unique transaction. This behavior is described by
+this interface in the code:
+
+```go
+type DatabaseTransactional interface {
+	Database
+	RunTxn(DatabaseTxOp) error
+}
+
+type DatabaseTxOp func(txn DatabaseOperations) error
+```
+
+**RunTXn** receives a function that has a unique param that can do all the database operations, those operations are
+committed only if the `DatabaseTxOp` function ends without error.
+
+# MDBX Database
+
+Now Juno uses an MDBX database to store all its data. An MDBX database is an environment (a database file) that can
+have multiple scopes or named databases. With that characteristic, Juno has only one MDBX environment and multiple
+named databases, one for each database on the application.
+
+To know more about the MDBX Database and the package Juno uses, see these links:
+
+- [`mdbx` Go package](https://pkg.go.dev/github.com/torquem-ch/mdbx-go/mdbx)
+- [lmdb documentation](http://www.lmdb.tech/doc/)
diff --git a/internal/db/abi/manager.go b/internal/db/abi/manager.go
index 10430c0f..ab084e43 100644
--- a/internal/db/abi/manager.go
+++ b/internal/db/abi/manager.go
@@ -16,11 +16,11 @@ var (
 
 // Manager is a database to store and get the contracts ABI.
 type Manager struct {
-	database db.Databaser
+	database db.Database
 }
 
 // NewABIManager creates a new Manager instance.
-func NewABIManager(database db.Databaser) *Manager {
+func NewABIManager(database db.Database) *Manager {
 	return &Manager{database}
 }
 
diff --git a/internal/db/block/manager.go b/internal/db/block/manager.go
index 90ac272a..edfc8d5f 100644
--- a/internal/db/block/manager.go
+++ b/internal/db/block/manager.go
@@ -10,11 +10,11 @@ import (
 
 // Manager is a Block database manager to save and search the blocks.
 type Manager struct {
-	database db.Databaser
+	database db.Database
 }
 
 // NewManager returns a new Block manager using the given database.
-func NewManager(database db.Databaser) *Manager {
+func NewManager(database db.Database) *Manager {
 	return &Manager{database: database}
 }
 
diff --git a/internal/db/block_specific.go b/internal/db/block_specific.go
index 5d261ec9..adf9a75f 100644
--- a/internal/db/block_specific.go
+++ b/internal/db/block_specific.go
@@ -11,11 +11,11 @@ import (
 // BlockSpecificDatabase is a database to store values that must have a history of versions on the blockchain.
 // To get and put objects in the database is needed the key and a block number.
 type BlockSpecificDatabase struct {
-	database Databaser
+	database Database
 }
 
 // NewBlockSpecificDatabase creates a new instance of BlockSpecificDatabase
-func NewBlockSpecificDatabase(database Databaser) *BlockSpecificDatabase {
+func NewBlockSpecificDatabase(database Database) *BlockSpecificDatabase {
 	return &BlockSpecificDatabase{database: database}
 }
 
diff --git a/internal/db/db.go b/internal/db/db.go
index 115512c5..ec3b5736 100644
--- a/internal/db/db.go
+++ b/internal/db/db.go
@@ -1,155 +1,30 @@
-// Package db provides a key-value database and functions related to
-// operating one.
 package db
 
-import (
-	"github.com/NethermindEth/juno/internal/log"
-	"github.com/torquem-ch/mdbx-go/mdbx"
-)
-
-// Databaser describes methods relating to an abstract key-value
-// database.
-type Databaser interface {
-	// Has returns true if the value at the provided key is in the
-	// database.
+// DatabaseOperations represents all the core operations
+// needed to store and search values on a key-value database.
+type DatabaseOperations interface {
 	Has(key []byte) (bool, error)
-	// Get returns the value associated with the provided key in the
-	// database or returns an error otherwise.
 	Get(key []byte) ([]byte, error)
-	// Put inserts a key-value pair into the database.
 	Put(key, value []byte) error
-	// Delete removes a previous inserted key or returns an error
-	// otherwise.
 	Delete(key []byte) error
-	// NumberOfItems returns the number of items in the database.
 	NumberOfItems() (uint64, error)
-	// Close closes the environment.
-	Close()
-	// GetEnv returns the environment of the database
-	GetEnv() *mdbx.Env
-}
-
-// KeyValueDb represents the middleware for an MDBX key-value store.
-type KeyValueDb struct {
-	env  *mdbx.Env
-	path string
-}
-
-// GetEnv returns the environment of the database
-func (d *KeyValueDb) GetEnv() *mdbx.Env {
-	return d.env
 }
 
-func NewKeyValueDb(path string, flags uint) *KeyValueDb {
-	env, err := mdbx.NewEnv()
-	if err != nil {
-		// notest
-		return nil
-	}
-
-	// Set flags.
-	// Based on https://github.com/torquem-ch/mdbx-go/blob/96f31f483af593377e52358a079e834256d5af55/mdbx/env_test.go#L495
-	err = env.SetOption(mdbx.OptMaxDB, 1)
-	if err != nil {
-		// notest
-		return nil
-	}
-	const pageSize = 4096
-	err = env.SetGeometry(268435456, 268435456, 1025769803776, 268435456, 268435456, pageSize)
-	if err != nil {
-		// notest
-		return nil
-	}
-	err = env.Open(path, flags|mdbx.Exclusive, 0o664)
-	if err != nil {
-		// notest
-		log.Default.With("Error", err).Panic("Couldn't open db")
-		return nil
-	}
-	return &KeyValueDb{env: env, path: path}
-}
-
-// Has returns true if the value at the provided key is in the
-// database.
-func (d *KeyValueDb) Has(key []byte) (has bool, err error) {
-	val, err := d.getOne(key)
-	if err != nil {
-		return false, err
-	}
-	return val != nil, nil
-}
-
-// getOne returns the value associated with the provided key in the
-// database or returns an error otherwise.
-func (d *KeyValueDb) getOne(key []byte) (val []byte, err error) {
-	var dbi mdbx.DBI
-	if err := d.env.View(func(txn *mdbx.Txn) error {
-		dbi, err = txn.OpenRoot(mdbx.Create)
-		if err != nil {
-			return err
-		}
-		val, err = txn.Get(dbi, key)
-		if err != nil {
-			if mdbx.IsNotFound(err) {
-				err = nil
-				return nil
-			}
-			return err
-		}
-		return nil
-	}); err != nil {
-		// Log already printed in the previous call.
-		return nil, err
-	}
-	return val, err
-}
-
-// Get returns the value associated with the provided key in the
-// database or returns an error otherwise.
-func (d *KeyValueDb) Get(key []byte) ([]byte, error) {
-	return d.getOne(key)
-}
-
-// Put inserts a key-value pair into the database.
-func (d *KeyValueDb) Put(key, value []byte) error {
-	err := d.env.Update(func(txn *mdbx.Txn) error {
-		dbi, err := txn.OpenRoot(mdbx.Create)
-		if err != nil {
-			return err
-		}
-		return txn.Put(dbi, key, value, 0)
-	})
-	return err
-}
-
-// Delete removes a previous inserted key or returns an error otherwise.
-func (d *KeyValueDb) Delete(key []byte) error {
-	err := d.env.Update(func(txn *mdbx.Txn) error {
-		db, err := txn.OpenRoot(mdbx.Create)
-		if err != nil {
-			return err
-		}
-		err = txn.Del(db, key, nil)
-		if mdbx.IsNotFound(err) {
-			return nil
-		}
-		return err
-	})
-	return err
+// Database represents a database behavior.
+type Database interface {
+	DatabaseOperations
+	Close()
 }
 
-// NumberOfItems returns the number of items in the database.
-func (d *KeyValueDb) NumberOfItems() (uint64, error) {
-	stats, err := d.env.Stat()
-	if err != nil {
-		// notest
-		log.Default.With("Error", err).Info("Unable to get stats from env.")
-		return 0, err
-	}
-	return stats.Entries, err
+// DatabaseTransactional represents a database with the
+// possibility of make transactions.
+type DatabaseTransactional interface {
+	Database
+	RunTxn(DatabaseTxOp) error
 }
 
-// Close closes the environment.
-func (d *KeyValueDb) Close() {
-	d.env.Close()
-}
+// DatabaseTxOp executes all the operations inside the
+// txn function. If the functions returns an error then
+// the transaction is aborted, on another case the transaction
+// is committed.
+type DatabaseTxOp func(txn DatabaseOperations) error
diff --git a/internal/db/kv_storer.go b/internal/db/kv_storer.go
index 85124414..80d4cd53 100644
--- a/internal/db/kv_storer.go
+++ b/internal/db/kv_storer.go
@@ -2,11 +2,11 @@ package db
 
 // KeyValueStore implement the Storer interface that use a Databaser
 type KeyValueStore struct {
-	db     Databaser
+	db     DatabaseOperations
 	prefix []byte
 }
 
-func NewKeyValueStore(db Databaser, prefix string) KeyValueStore {
+func NewKeyValueStore(db DatabaseOperations, prefix string) KeyValueStore {
 	return KeyValueStore{
 		db:     db,
 		prefix: []byte(prefix),
@@ -43,7 +43,3 @@ func (k KeyValueStore) Begin() {
 
 func (k KeyValueStore) Rollback() {
 }
-
-func (k KeyValueStore) Close() {
-	k.db.Close()
-}
diff --git a/internal/db/mdbx.go b/internal/db/mdbx.go
new file mode 100644
index 00000000..dcef4f0a
--- /dev/null
+++ b/internal/db/mdbx.go
@@ -0,0 +1,264 @@
+package db
+
+import (
+	"errors"
+	"fmt"
+	"runtime"
+
+	"github.com/torquem-ch/mdbx-go/mdbx"
+)
+
+var (
+	// ErrInternal represents an internal database error.
+	ErrInternal = errors.New("internal error")
+	// ErrNotFound is used when a key is not found in the database.
+	ErrNotFound = errors.New("not found error")
+	// ErrTx is returned when a transaction fails for some reason.
+	ErrTx = errors.New("transaction error")
+)
+
+// MDBXDatabase is a Database that works with the LMDB database. A database is a
+// named database (isolated collection stored on the same file) of a certain
+// environment (database file). One environment can have many named databases.
+// The environment must be initialized and configured with the correct number of
+// named databases before creating the MDBXDatabase instances.
+type MDBXDatabase struct {
+	env *mdbx.Env
+	dbi mdbx.DBI
+}
+
+// NewMDBXDatabase creates a new MDBXDatabase with the given environment and name.
+func NewMDBXDatabase(env *mdbx.Env, name string) (*MDBXDatabase, error) {
+	var dbi mdbx.DBI
+	// Start a READ transaction
+	err := env.Update(func(txn *mdbx.Txn) error {
+		// Get all the current DBI
+		dbis, err := txn.ListDBI()
+		if err != nil {
+			return newDbError(ErrInternal, err)
+		}
+		// Search if already exists a DBI with the given name
+		for _, dbiName := range dbis {
+			if dbiName == name {
+				dbi, err = openDBI(txn, name)
+				if err != nil {
+					return newDbError(ErrInternal, err)
+				}
+				return nil
+			}
+		}
+		// Create a new DBI if it does not exist
+		dbi, err = txn.CreateDBI(name)
+		if err != nil {
+			return newDbError(ErrInternal, err)
+		}
+		return nil
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	return &MDBXDatabase{
+		env: env,
+		dbi: dbi,
+	}, nil
+}
+
+// Has searches on the database if the key already exists.
+func (x *MDBXDatabase) Has(key []byte) (bool, error) {
+	var exists bool
+
+	// Start READ transaction
+	err := x.env.View(func(txn *mdbx.Txn) error {
+		var err error
+		// Search for the key on the DBI
+		exists, err = has(txn, x.dbi, key)
+		return err
+	})
+
+	return exists, err
+}
+
+// Get returns the associated value with the given key. If the key does not
+// exist it returns an ErrNotFound.
+func (x *MDBXDatabase) Get(key []byte) ([]byte, error) {
+	var value []byte
+	// Start a READ transaction
+	err := x.env.View(func(txn *mdbx.Txn) error {
+		var err error
+		// Search for the key value on the DBI
+		value, err = get(txn, x.dbi, key)
+		return err
+	})
+	return value, err
+}
+
+// Put store/override the given value on the given key.
+func (x *MDBXDatabase) Put(key, val []byte) error {
+	// Start a READ-WRITE transaction
+	return x.env.Update(func(txn *mdbx.Txn) error {
+		// Put the key-value pair on the DBI
+		return put(txn, x.dbi, key, val)
+	})
+}
+
+// Delete deletes the given key and its value.
+func (x *MDBXDatabase) Delete(key []byte) error {
+	// Start a READ-WRITE transaction
+	return x.env.Update(func(txn *mdbx.Txn) error {
+		// Delete the key-value pair on the DBI
+		return del(txn, x.dbi, key)
+	})
+}
+
+// NumberOfItems returns the number of keys on the database.
+func (x *MDBXDatabase) NumberOfItems() (uint64, error) {
+	var entries uint64
+
+	// Start READ transaction
+	err := x.env.View(func(txn *mdbx.Txn) error {
+		var err error
+		// Get the number of items on the DBI
+		entries, err = numberOfItems(txn, x.dbi)
+		return err
+	})
+
+	return entries, err
+}
+
+// Close closes the database. Notice this function does not close the
+// environment.
+func (x *MDBXDatabase) Close() {
+	x.env.CloseDBI(x.dbi)
+}
+
+// RunTxn runs a function on a database transaction. If the function returns an
+// error then the transaction is aborted. To guarantee the transaction is
+// thread-safe, the function calls runtime.LockOSThread at the start and
+// runtime.UnlockOSThread at the end.
+func (x *MDBXDatabase) RunTxn(op DatabaseTxOp) error {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	// Initialize the transaction
+	mdbxTxn, err := x.env.BeginTxn(nil, 0)
+	if err != nil {
+		return newDbError(ErrInternal, err)
+	}
+	txn := MDBXTransaction{
+		txn: mdbxTxn,
+		dbi: x.dbi,
+	}
+	// Run the operations
+	err = op(txn)
+	if err != nil {
+		// Abort if error
+		mdbxTxn.Abort()
+		return newDbError(ErrTx, err)
+	}
+	// Commit
+	_, err = mdbxTxn.Commit()
+	if err != nil {
+		return newDbError(ErrTx, err)
+	}
+	return nil
+}
+
+// MDBXTransaction represents a transaction of the MDBXDatabase.
+type MDBXTransaction struct {
+	txn *mdbx.Txn
+	dbi mdbx.DBI
+}
+
+// Has searches on the database if the key already exists.
+func (tx MDBXTransaction) Has(key []byte) (bool, error) {
+	return has(tx.txn, tx.dbi, key)
+}
+
+// Get returns the associated value with the given key. If the key does not
+// exist the returns ErrNotFound.
+func (tx MDBXTransaction) Get(key []byte) ([]byte, error) {
+	return get(tx.txn, tx.dbi, key)
+}
+
+// Put store/override the given value on the given key.
+func (tx MDBXTransaction) Put(key, val []byte) error {
+	return put(tx.txn, tx.dbi, key, val)
+}
+
+// Delete deletes the given key and its value.
+func (tx MDBXTransaction) Delete(key []byte) error {
+	return del(tx.txn, tx.dbi, key)
+}
+
+func (tx MDBXTransaction) NumberOfItems() (uint64, error) {
+	return numberOfItems(tx.txn, tx.dbi)
+}
+
+// IsNotFound checks is the given error is an ErrNotFound.
+func IsNotFound(err error) bool {
+	return errors.Is(err, ErrNotFound)
+}
+
+func has(txn *mdbx.Txn, dbi mdbx.DBI, key []byte) (bool, error) {
+	_, err := txn.Get(dbi, key)
+	if err != nil {
+		if mdbx.IsNotFound(err) {
+			return false, nil
+		}
+		// notest
+		return false, newDbError(ErrInternal, err)
+	}
+	return true, nil
+}
+
+func get(txn *mdbx.Txn, dbi mdbx.DBI, key []byte) ([]byte, error) {
+	value, err := txn.Get(dbi, key)
+	if err != nil {
+		if mdbx.IsNotFound(err) {
+			return nil, ErrNotFound
+		}
+		// notest
+		return nil, newDbError(ErrInternal, err)
+	}
+	return value, nil
+}
+
+func put(txn *mdbx.Txn, dbi mdbx.DBI, key, value []byte) error {
+	err := txn.Put(dbi, key, value, 0)
+	if err != nil {
+		// notest
+		return newDbError(ErrInternal, err)
+	}
+	return nil
+}
+
+func del(txn *mdbx.Txn, dbi mdbx.DBI, key []byte) error {
+	err := txn.Del(dbi, key, nil)
+	if err != nil {
+		// notest
+		return newDbError(ErrInternal, err)
+	}
+	return nil
+}
+
+func numberOfItems(txn *mdbx.Txn, dbi mdbx.DBI) (uint64, error) {
+	stats, err := txn.StatDBI(dbi)
+	if err != nil {
+		// notest
+		return 0, newDbError(ErrInternal, err)
+	}
+	return stats.Entries, nil
+}
+
+func openDBI(txn *mdbx.Txn, name string) (mdbx.DBI, error) {
+	dbi, err := txn.OpenDBISimple(name, 0)
+	if err != nil {
+		return 0, newDbError(ErrInternal, err)
+	}
+	return dbi, nil
+}
+
+func newDbError(dbError, err error) error {
+	return fmt.Errorf("%w: %s", dbError, err)
+}
diff --git a/internal/db/mdbx_env.go b/internal/db/mdbx_env.go
new file mode 100644
index 00000000..d00e8e76
--- /dev/null
+++ b/internal/db/mdbx_env.go
@@ -0,0 +1,59 @@
+package db
+
+import (
+	"errors"
+
+	"github.com/torquem-ch/mdbx-go/mdbx"
+)
+
+var (
+	env         *mdbx.Env
+	initialized bool
+)
+
+var ErrEnvNoInitialized = errors.New("environment is no initialize")
+
+// InitializeMDBXEnv initializes the Juno LMDB environment.
+func InitializeMDBXEnv(path string, optMaxDB uint64, flags uint) (err error) {
+	defer func() {
+		if err == nil {
+			initialized = true
+		}
+	}()
+
+	env, err = NewMDBXEnv(path, optMaxDB, flags)
+	return err
+}
+
+func NewMDBXEnv(path string, optMaxDB uint64, flags uint) (*mdbx.Env, error) {
+	env, err := mdbx.NewEnv()
+	if err != nil {
+		// notest
+		return nil, err
+	}
+	err = env.SetOption(mdbx.OptMaxDB, optMaxDB)
+	if err != nil {
+		// notest
+		return nil, err
+	}
+	err = env.SetGeometry(268435456, 268435456, 25769803776, 268435456, 268435456, 4096)
+	if err != nil {
+		// notest
+		return nil, err
+	}
+	err = env.Open(path, flags|mdbx.Exclusive, 0o664)
+	if err != nil {
+		// notest
+		return nil, err
+	}
+	return env, nil
+}
+
+// GetMDBXEnv returns the Juno LMDB environment. If the environment is not
+// initialized then ErrEnvNoInitialized is returned.
+func GetMDBXEnv() (*mdbx.Env, error) {
+	if !initialized {
+		return nil, ErrEnvNoInitialized
+	}
+	return env, nil
+}
diff --git a/internal/db/named_db.go b/internal/db/named_db.go
deleted file mode 100644
index 2ff5eb98..00000000
--- a/internal/db/named_db.go
+++ /dev/null
@@ -1,275 +0,0 @@
-package db
-
-import (
-	"errors"
-	"fmt"
-	"runtime"
-
-	"github.com/NethermindEth/juno/internal/log"
-
-	"go.uber.org/zap"
-
-	"github.com/torquem-ch/mdbx-go/mdbx"
-)
-
-var (
-	ErrInternal = errors.New("internal error")
-	ErrNotFound = errors.New("not found error")
-	ErrTxInit   = errors.New("initialize transaction error")
-	ErrTxCommit = errors.New("transaction commit error")
-)
-
-var (
-	env    *mdbx.Env
-	logger *zap.SugaredLogger
-)
-
-func InitializeDatabaseEnv(path string, optMaxDB uint64, flags uint) error {
-	_env, err := mdbx.NewEnv()
-	if err != nil {
-		// notest
-		return fmt.Errorf("%w: %s", ErrInternal, err.Error())
-	}
-	err = _env.SetOption(mdbx.OptMaxDB, optMaxDB)
-	if err != nil {
-		// notest
-		return fmt.Errorf("%w: %s", ErrInternal, err.Error())
-	}
-	err = _env.SetGeometry(268435456, 268435456, 25769803776, 268435456, 268435456, 4096)
-	if err != nil {
-		// notest
-		return fmt.Errorf("%w: %s", ErrInternal, err.Error())
-	}
-	err = _env.Open(path, flags|mdbx.Exclusive, 0o664)
-	if err != nil {
-		// notest
-		return fmt.Errorf("%w: %s", ErrInternal, err.Error())
-	}
-	env = _env
-	logger = log.Default.Named("Database")
-	return nil
-}
-
-func GetDatabase(name string) (*NamedDatabase, error) {
-	var ndb *NamedDatabase
-	err := env.Update(func(txn *mdbx.Txn) error {
-		databases, err := txn.ListDBI()
-		if err != nil {
-			// notest
-			logger.Error(err)
-			return fmt.Errorf("%w: %s", ErrInternal, err.Error())
-		}
-		for _, db := range databases {
-			// Database already exists
-			if db == name {
-				// Open the DBI
-				// notest
-				dbi, err := txn.OpenDBISimple(name, 0)
-				if err != nil {
-					return fmt.Errorf("%w: %s", ErrInternal, err.Error())
-				}
-				ndb = NewNamedDatabase(name, dbi)
-
-				return nil
-			}
-		}
-		// Create the DBI
-		dbi, err := txn.CreateDBI(name)
-		if err != nil {
-			// notest
-			logger.With("error", err).Error("error creating a dbi")
-			return fmt.Errorf("%w: %s", ErrInternal, err.Error())
-		}
-		logger.With("database", name).Info("new named database")
-		ndb = NewNamedDatabase(name, dbi)
-		return nil
-	})
-	if err != nil {
-		return nil, err
-	}
-	return ndb, nil
-}
-
-type NamedDatabase struct {
-	name   string
-	dbi    mdbx.DBI
-	logger *zap.SugaredLogger
-}
-
-func NewNamedDatabase(name string, dbi mdbx.DBI) *NamedDatabase {
-	return &NamedDatabase{
-		name:   name,
-		dbi:    dbi,
-		logger: logger.Named(name),
-	}
-}
-
-func (db *NamedDatabase) Has(key []byte) (bool, error) {
-	var exists bool
-	err := env.View(func(txn *mdbx.Txn) error {
-		var err error
-		exists, err = has(txn, db.dbi, key)
-		return err
-	})
-	return exists, err
-}
-
-func (db *NamedDatabase) Get(key []byte) ([]byte, error) {
-	var value []byte
-	err := env.View(func(txn *mdbx.Txn) error {
-		var err error
-		value, err = get(txn, db.dbi, key)
-		return err
-	})
-	return value, err
-}
-
-func (db *NamedDatabase) Put(key, value []byte) error {
-	return env.Update(func(txn *mdbx.Txn) error {
-		return put(txn, db.dbi, key, value)
-	})
-}
-
-func (db *NamedDatabase) Delete(key []byte) error {
-	return env.Update(func(txn *mdbx.Txn) error {
-		return del(txn, db.dbi, key)
-	})
-}
-
-func (db *NamedDatabase) NumberOfItems() (uint64, error) {
-	var entries uint64
-	err := env.View(func(txn *mdbx.Txn) error {
-		var err error
-		entries, err = numberOfItems(txn, db.dbi)
-		return err
-	})
-	return entries, err
-}
-
-func (db *NamedDatabase) Close() {
-	env.CloseDBI(db.dbi)
-}
-
-func (db *NamedDatabase) GetEnv() *mdbx.Env {
-	return env
-}
-
-func (db *NamedDatabase) Begin() (Transaction, error) {
-	runtime.LockOSThread()
-	txn, err := env.BeginTxn(nil, 0)
-	if err != nil {
-		// notest
-		return nil, fmt.Errorf("%w: %s", ErrTxInit, err.Error())
-	}
-	return &NamedDatabaseTx{
-		db:      db,
-		mdbxTxn: txn,
-	}, nil
-}
-
-type NamedDatabaseTx struct {
-	db      *NamedDatabase
-	mdbxTxn *mdbx.Txn
-}
-
-func (txn *NamedDatabaseTx) Has(key []byte) (bool, error) {
-	return has(txn.mdbxTxn, txn.db.dbi, key)
-}
-
-func (txn *NamedDatabaseTx) Get(key []byte) ([]byte, error) {
-	return get(txn.mdbxTxn, txn.db.dbi, key)
-}
-
-func (txn *NamedDatabaseTx) Put(key, value []byte) error {
-	return put(txn.mdbxTxn, txn.db.dbi, key, value)
-}
-
-func (txn *NamedDatabaseTx) Delete(key []byte) error {
-	return del(txn.mdbxTxn, txn.db.dbi, key)
-}
-
-func (txn *NamedDatabaseTx) NumberOfItems() (uint64, error) {
-	return numberOfItems(txn.mdbxTxn, txn.db.dbi)
-}
-
-func (txn *NamedDatabaseTx) Close() {
-	// notest
-	txn.db.Close()
-}
-
-func (txn *NamedDatabaseTx) GetEnv() *mdbx.Env {
-	return txn.db.GetEnv()
-}
-
-func (txn *NamedDatabaseTx) Commit() error {
-	_, err := txn.mdbxTxn.Commit()
-	runtime.UnlockOSThread()
-	if err != nil {
-		// notest
-		txn.db.logger.With("error", err).Info("Commit Error")
-		return fmt.Errorf("%w: %s", ErrTxCommit, err.Error())
-	} else {
-		txn.db.logger.Info("Commit OK")
-	}
-	return nil
-}
-
-func (txn *NamedDatabaseTx) Rollback() {
-	txn.mdbxTxn.Abort()
-	runtime.UnlockOSThread()
-}
-
-func has(txn *mdbx.Txn, dbi mdbx.DBI, key []byte) (bool, error) {
-	_, err := txn.Get(dbi, key)
-	if err != nil {
-		if mdbx.IsNotFound(err) {
-			return false, nil
-		}
-		// notest
-		return false, fmt.Errorf("%w: %s", ErrInternal, err.Error())
-	}
-	return true, nil
-}
-
-func get(txn *mdbx.Txn, dbi mdbx.DBI, key []byte) ([]byte, error) {
-	value, err := txn.Get(dbi, key)
-	if err != nil {
-		if mdbx.IsNotFound(err) {
-			return nil, ErrNotFound
-		}
-		// notest
-		return nil, fmt.Errorf("%w: %s", ErrInternal, err.Error())
-	}
-	return value, nil
-}
-
-func put(txn *mdbx.Txn, dbi mdbx.DBI, key, value []byte) error {
-	err := txn.Put(dbi, key, value, 0)
-	if err != nil {
-		// notest
-		return fmt.Errorf("%w: %s", ErrInternal, err.Error())
-	}
-	return nil
-}
-
-func del(txn *mdbx.Txn, dbi mdbx.DBI, key []byte) error {
-	err := txn.Del(dbi, key, nil)
-	if err != nil {
-		// notest
-		return fmt.Errorf("%w: %s", ErrInternal, err.Error())
-	}
-	return nil
-}
-
-func numberOfItems(txn *mdbx.Txn, dbi mdbx.DBI) (uint64, error) {
-	stats, err := txn.StatDBI(dbi)
-	if err != nil {
-		// notest
-		return 0, fmt.Errorf("%w: %s", ErrInternal, err.Error())
-	}
-	return stats.Entries, nil
-}
-
-func IsNotFound(err error) bool {
-	return errors.Is(err, ErrNotFound)
-}
diff --git a/internal/db/state/state.go b/internal/db/state/state.go
index 67c75bb0..cb42d083 100644
--- a/internal/db/state/state.go
+++ b/internal/db/state/state.go
@@ -7,12 +7,12 @@ import (
 // Manager is a database manager, with the objective of managing
 // the contract codes and contract storages databases.
 type Manager struct {
-	codeDatabase    db.Databaser
+	codeDatabase    db.Database
 	storageDatabase *db.BlockSpecificDatabase
 }
 
 // NewStateManager returns a new instance of Manager with the given database sources.
-func NewStateManager(codeDatabase db.Databaser, storageDatabase *db.BlockSpecificDatabase) *Manager {
+func NewStateManager(codeDatabase db.Database, storageDatabase *db.BlockSpecificDatabase) *Manager {
 	return &Manager{codeDatabase, storageDatabase}
 }
 
diff --git a/internal/db/transaction/manager.go b/internal/db/transaction/manager.go
index 3ed40dd0..2b675f8c 100644
--- a/internal/db/transaction/manager.go
+++ b/internal/db/transaction/manager.go
@@ -13,12 +13,12 @@ import (
 // communications with the transactions' database must be made with this manager.
 // Transactions can have two types: DeployTransaction and InvokeFunctionTransaction.
 type Manager struct {
-	txDb      db.Databaser
-	receiptDb db.Databaser
+	txDb      db.Database
+	receiptDb db.Database
 }
 
 // NewManager returns a new instance of the Manager.
-func NewManager(txDb, receiptDb db.Databaser) *Manager {
+func NewManager(txDb, receiptDb db.Database) *Manager {
 	return &Manager{txDb, receiptDb}
 }
 
diff --git a/internal/db/transaction_db.go b/internal/db/transaction_db.go
deleted file mode 100644
index 8e1c7699..00000000
--- a/internal/db/transaction_db.go
+++ /dev/null
@@ -1,154 +0,0 @@
-package db
-
-import (
-	"runtime"
-
-	"github.com/NethermindEth/juno/internal/log"
-	"github.com/torquem-ch/mdbx-go/mdbx"
-)
-
-// Transactioner describes methods relating to an abstract key-value
-// database oriented to transactions.
-type Transactioner interface {
-	// Begin starts a new transaction.
-	Begin() Transaction
-}
-
-type Transactioner2 interface {
-	Begin() (Transaction, error)
-}
-
-type TransactionalDb interface {
-	Databaser
-	Transactioner2
-}
-
-type Transaction interface {
-	Databaser
-	Commit() error
-	Rollback()
-}
-
-type TransactionDb struct {
-	env *mdbx.Env
-}
-
-type transaction struct {
-	txn *mdbx.Txn
-	env *mdbx.Env
-}
-
-// NewTransactionDb creates a new key-value database based on transactions.
-func NewTransactionDb(env *mdbx.Env) *TransactionDb {
-	return &TransactionDb{env: env}
-}
-
-func (d *TransactionDb) Begin() Transaction {
-	txn, err := d.env.BeginTxn(nil, 0)
-	if err != nil {
-		panic(any(err))
-	}
-	return &transaction{txn: txn, env: d.env}
-}
-
-// GetEnv returns the environment of the database
-func (d *transaction) GetEnv() *mdbx.Env {
-	return d.env
-}
-
-// Has returns true if the value at the provided key is in the
-// database.
-func (d *transaction) Has(key []byte) (has bool, err error) {
-	val, err := d.getOne(key)
-	if err != nil {
-		return false, err
-	}
-	return val != nil, nil
-}
-
-// getOne returns the value associated with the provided key in the
-// database or returns an error otherwise.
-func (d *transaction) getOne(key []byte) (val []byte, err error) {
-	var dbi mdbx.DBI
-	dbi, err = d.txn.OpenRoot(mdbx.Create)
-	if err != nil {
-		return nil, err
-	}
-	runtime.LockOSThread()
-	val, err = d.txn.Get(dbi, key)
-	if err != nil {
-		if mdbx.IsNotFound(err) {
-			err = nil
-			return nil, nil
-		}
-		return nil, err
-	}
-	runtime.UnlockOSThread()
-	return val, nil
-}
-
-// Get returns the value associated with the provided key in the
-// database or returns an error otherwise.
-func (d *transaction) Get(key []byte) ([]byte, error) {
-	return d.getOne(key)
-}
-
-// Put inserts a key-value pair into the database.
-func (d *transaction) Put(key, value []byte) error {
-	dbi, err := d.txn.OpenRoot(mdbx.Create)
-	if err != nil {
-		return err
-	}
-	runtime.LockOSThread()
-	err = d.txn.Put(dbi, key, value, 0)
-	runtime.UnlockOSThread()
-
-	return err
-}
-
-// Delete removes a previous inserted key or returns an error otherwise.
-func (d *transaction) Delete(key []byte) error {
-	db, err := d.txn.OpenRoot(mdbx.Create)
-	if err != nil {
-		return err
-	}
-	err = d.txn.Del(db, key, nil)
-	if mdbx.IsNotFound(err) {
-		return nil
-	}
-	return err
-}
-
-// NumberOfItems returns the number of items in the database.
-func (d *transaction) NumberOfItems() (uint64, error) {
-	stats, err := d.env.Stat()
-	if err != nil {
-		log.Default.With("Error", err).Info("Unable to get stats from env.")
-		return 0, err
-	}
-	return stats.Entries, err
-}
-
-// Close closes the environment.
-func (d *transaction) Close() {
-	d.env.Close()
-}
-
-// Commit saves all the information included in the current transaction
-func (d *transaction) Commit() error {
-	if d.txn != nil {
-		_, err := d.txn.Commit()
-		if err != nil {
-			d.txn = nil
-			return err
-		}
-	}
-	return nil
-}
-
-// Rollback rolls back the database to a previous state.
-func (d *transaction) Rollback() {
-	if d.txn != nil {
-		d.txn.Abort()
-	}
-}
diff --git a/internal/services/abi.go b/internal/services/abi.go
index a8cc3ceb..3ffc1e94 100644
--- a/internal/services/abi.go
+++ b/internal/services/abi.go
@@ -20,7 +20,7 @@ type abiService struct {
 }
 
 // Setup sets the service configuration, service must be not running.
-func (s *abiService) Setup(database db.Databaser) {
+func (s *abiService) Setup(database db.Database) {
 	if s.Running() {
 		// notest
 		s.logger.Panic("trying to Setup with service running")
@@ -46,7 +46,11 @@ func (s *abiService) Run() error {
 func (s *abiService) setDefaults() error {
 	if s.manager == nil {
 		// notest
-		database, err := db.GetDatabase("ABI")
+		env, err := db.GetMDBXEnv()
+		if err != nil {
+			return err
+		}
+		database, err := db.NewMDBXDatabase(env, "ABI")
 		if err != nil {
 			return err
 		}
diff --git a/internal/services/block.go b/internal/services/block.go
index e9a47486..5f89281d 100644
--- a/internal/services/block.go
+++ b/internal/services/block.go
@@ -22,7 +22,7 @@ type blockService struct {
 
 // Setup is used to configure the service before it's started. The database
 // param is the database where the transactions will be stored.
-func (s *blockService) Setup(database db.Databaser) {
+func (s *blockService) Setup(database db.Database) {
 	if s.service.Running() {
 		// notest
 		s.logger.Panic("trying to Setup with service running")
@@ -48,7 +48,11 @@ func (s *blockService) Run() error {
 func (s *blockService) setDefaults() error {
 	if s.manager == nil {
 		// notest
-		database, err := db.GetDatabase("BLOCK")
+		env, err := db.GetMDBXEnv()
+		if err != nil {
+			return err
+		}
+		database, err := db.NewMDBXDatabase(env, "BLOCK")
 		if err != nil {
 			return err
 		}
diff --git a/internal/services/contractHash.go b/internal/services/contractHash.go
index 634a1ac0..544c30ca 100644
--- a/internal/services/contractHash.go
+++ b/internal/services/contractHash.go
@@ -12,10 +12,10 @@ var ContractHashService contractHashService
 
 type contractHashService struct {
 	service
-	db db.Databaser
+	db db.Database
 }
 
-func (s *contractHashService) Setup(database db.Databaser) {
+func (s *contractHashService) Setup(database db.Database) {
 	if s.Running() {
 		// notest
 		s.logger.Panic("trying to Setup with service running")
@@ -38,7 +38,11 @@ func (s *contractHashService) Run() error {
 func (s *contractHashService) setDefaults() error {
 	if s.db == nil {
 		// notest
-		database, err := db.GetDatabase("CONTRACT_HASH")
+		env, err := db.GetMDBXEnv()
+		if err != nil {
+			return err
+		}
+		database, err := db.NewMDBXDatabase(env, "CONTRACT_HASH")
 		if err != nil {
 			return err
 		}
diff --git a/internal/services/service.go b/internal/services/service.go
index 3acd15bc..15f4afbb 100644
--- a/internal/services/service.go
+++ b/internal/services/service.go
@@ -2,11 +2,16 @@ package services
 
 import (
 	"context"
+	"errors"
 	"sync"
 
 	"go.uber.org/zap"
 )
 
+// ErrAlreadyRunning is returned when you try to perform an invalid action
+// while the service is running.
+var ErrAlreadyRunning = errors.New("service is already running")
+
 // Service describes the basic functionalities that all the services have in
 // common.
 type Service interface {
@@ -28,7 +33,7 @@ func (s *service) Run() error {
 	// Check if the service is already started
 	if s.Running() {
 		// notest
-		s.logger.Panic("service is already running")
+		return ErrAlreadyRunning
 	}
 	s.running = true
 	s.logger.Info("Service started")
diff --git a/internal/services/state.go b/internal/services/state.go
index 72f31a84..faf246bc 100644
--- a/internal/services/state.go
+++ b/internal/services/state.go
@@ -16,7 +16,7 @@ type stateService struct {
 	manager *state.Manager
 }
 
-func (s *stateService) Setup(codeDatabase db.Databaser, storageDatabase *db.BlockSpecificDatabase) {
+func (s *stateService) Setup(codeDatabase db.Database, storageDatabase *db.BlockSpecificDatabase) {
 	if s.Running() {
 		// notest
 		s.logger.Panic("service is already running")
@@ -40,11 +40,15 @@ func (s *stateService) Run() error {
 func (s *stateService) setDefaults() error {
 	if s.manager == nil {
 		// notest
-		codeDb, err := db.GetDatabase("CODE")
+		env, err := db.GetMDBXEnv()
 		if err != nil {
 			return err
 		}
-		storageDb, err := db.GetDatabase("STORAGE")
+		codeDb, err := db.NewMDBXDatabase(env, "CODE")
+		if err != nil {
+			return err
+		}
+		storageDb, err := db.NewMDBXDatabase(env, "STORAGE")
 		if err != nil {
 			return err
 		}
diff --git a/internal/services/transactions.go b/internal/services/transactions.go
index 22fe04d7..43f2fb4c 100644
--- a/internal/services/transactions.go
+++ b/internal/services/transactions.go
@@ -23,7 +23,7 @@ type transactionService struct {
 
 // Setup is used to configure the service before it's started. The database
 // param is the database where the transactions will be stored.
-func (s *transactionService) Setup(txDb, receiptDb db.Databaser) {
+func (s *transactionService) Setup(txDb, receiptDb db.Database) {
 	if s.service.Running() {
 		// notest
 		s.logger.Panic("trying to Setup with service running")
@@ -49,11 +49,15 @@ func (s *transactionService) Run() error {
 func (s *transactionService) setDefaults() error {
 	if s.manager == nil {
 		// notest
-		txDb, err := db.GetDatabase("TRANSACTION")
+		env, err := db.GetMDBXEnv()
 		if err != nil {
 			return err
 		}
-		receiptDb, err := db.GetDatabase("RECEIPT")
+		txDb, err := db.NewMDBXDatabase(env, "TRANSACTION")
+		if err != nil {
+			return err
+		}
+		receiptDb, err := db.NewMDBXDatabase(env, "RECEIPT")
 		if err != nil {
 			return err
 		}
diff --git a/pkg/starknet/state.go b/pkg/starknet/state.go
index 4a79ff9a..615c4432 100644
--- a/pkg/starknet/state.go
+++ b/pkg/starknet/state.go
@@ -31,8 +31,7 @@ import (
 type Synchronizer struct {
 	ethereumClient      *ethclient.Client
 	feederGatewayClient *feeder.Client
-	database            db.Databaser
-	transactioner       db.Transactioner2
+	database            db.DatabaseTransactional
 	memoryPageHash      *starknetTypes.Dictionary
 	gpsVerifier         *starknetTypes.Dictionary
 	facts               *starknetTypes.Dictionary
@@ -40,7 +39,7 @@ type Synchronizer struct {
 }
 
 // NewSynchronizer creates a new Synchronizer
-func NewSynchronizer(txnDb db.TransactionalDb, client *ethclient.Client, fClient *feeder.Client) *Synchronizer {
+func NewSynchronizer(txnDb db.DatabaseTransactional, client *ethclient.Client, fClient *feeder.Client) *Synchronizer {
 	var chainID *big.Int
 	if client == nil {
 		// notest
@@ -65,7 +64,6 @@ func NewSynchronizer(txnDb db.TransactionalDb, client *ethclient.Client, fClient
 		gpsVerifier:         starknetTypes.NewDictionary(txnDb, "gps_verifier"),
 		facts:               starknetTypes.NewDictionary(txnDb, "facts"),
 		chainID:             chainID.Int64(),
-		transactioner:       txnDb,
 	}
 }
 
@@ -381,21 +379,16 @@ func (s *Synchronizer) updateAndCommitState(
 		formattedAddress := remove0x(contractAddress)
 		contractHashMap[formattedAddress] = services.ContractHashService.GetContractHash(formattedAddress)
 	}
-	txn, err := s.transactioner.Begin()
-	if err != nil {
-		log.Default.Fatal(err)
-	}
-	_, err = updateState(txn, contractHashMap, stateDiff, newRoot, sequenceNumber)
+
+	err := s.database.RunTxn(func(txn db.DatabaseOperations) error {
+		_, err := updateState(txn, contractHashMap, stateDiff, newRoot, sequenceNumber)
+		return err
+	})
 	if err != nil {
 		metr.IncreaseCountStarknetStateFailed()
-		log.Default.With("Error", err).Panic("Couldn't update state")
-	} else {
-		err := txn.Commit()
-		if err != nil {
-			metr.IncreaseCountStarknetStateFailed()
-			log.Default.Panic("Couldn't commit to the database")
-		}
+		log.Default.Fatal(err)
 	}
+
 	metr.IncreaseCountStarknetStateSuccess()
 	duration := time.Since(start)
 	metr.UpdateStarknetSyncTime(duration.Seconds())
@@ -444,7 +437,7 @@ func getFactInfo(starknetLogs []types.Log, contract ethAbi.ABI, fact string, lat
 }
 
 // Close closes the client for the Layer 1 Ethereum node
-func (s *Synchronizer) Close(ctx context.Context) {
+func (s *Synchronizer) Close(_ context.Context) {
 	// notest
 	log.Default.Info("Closing Layer 1 Synchronizer")
 	if s.ethereumClient != nil {
@@ -509,7 +502,7 @@ func (s *Synchronizer) updateStateForOneBlock(blockIterator uint64, lastBlockHas
 	return blockIterator + 1, update.BlockHash
 }
 
-// processPagesHashes takes an arrays of arrays of pages' hashes and
+// processPagesHashes takes an array of arrays of pages' hashes and
 // converts them into memory pages by querying an ethereum client.
 // notest
 func (s *Synchronizer) processPagesHashes(pagesHashes [][32]byte, memoryContract ethAbi.ABI) [][]*big.Int {
diff --git a/pkg/starknet/types/map.go b/pkg/starknet/types/map.go
index b29a9bbf..b9c85385 100644
--- a/pkg/starknet/types/map.go
+++ b/pkg/starknet/types/map.go
@@ -17,11 +17,11 @@ type IValue interface {
 
 // Dictionary - the dictionary object with key of type IKey & value of type IValue
 type Dictionary struct {
-	database db.Databaser
+	database db.Database
 	prefix   []byte
 }
 
-func NewDictionary(database db.Databaser, prefix string) *Dictionary {
+func NewDictionary(database db.Database, prefix string) *Dictionary {
 	return &Dictionary{
 		database: database,
 		prefix:   []byte(prefix),
diff --git a/pkg/starknet/utils.go b/pkg/starknet/utils.go
index 23d0d19b..c2e8cd54 100644
--- a/pkg/starknet/utils.go
+++ b/pkg/starknet/utils.go
@@ -22,7 +22,7 @@ import (
 )
 
 // newTrie returns a new Trie
-func newTrie(database db.Databaser, prefix string) trie.Trie {
+func newTrie(database db.DatabaseOperations, prefix string) trie.Trie {
 	store := db.NewKeyValueStore(database, prefix)
 	return trie.New(store, 251)
 }
@@ -128,7 +128,7 @@ func initialBlockForStarknetContract(id int64) int64 {
 }
 
 // getNumericValueFromDB get the value associated to a key and convert it to integer
-func getNumericValueFromDB(database db.Databaser, key string) (uint64, error) {
+func getNumericValueFromDB(database db.Database, key string) (uint64, error) {
 	value, err := database.Get([]byte(key))
 	if err != nil {
 		// notest
@@ -138,6 +138,7 @@ func getNumericValueFromDB(database db.Databaser, key string) (uint64, error) {
 		return 0, err
 	}
 	if value == nil {
+		// notest
 		return 0, nil
 	}
 	var ret uint64
@@ -150,7 +151,7 @@ func getNumericValueFromDB(database db.Databaser, key string) (uint64, error) {
 }
 
 // updateNumericValueFromDB update the value in the database for a key increasing the value in 1
-func updateNumericValueFromDB(database db.Databaser, key string, value uint64) error {
+func updateNumericValueFromDB(database db.DatabaseOperations, key string, value uint64) error {
 	b := make([]byte, 8)
 	binary.BigEndian.PutUint64(b, value+1)
 	err := database.Put([]byte(key), b)
@@ -165,7 +166,7 @@ func updateNumericValueFromDB(database db.Databaser, key string, value uint64) e
 // updateState is a pure function (besides logging) that applies the
 // `update` StateDiff to the database transaction `txn`.
 func updateState(
-	txn db.Transaction,
+	txn db.DatabaseOperations,
 	contractHashMap map[string]*big.Int,
 	update *starknetTypes.StateDiff,
 	stateRoot string,
@@ -287,7 +288,7 @@ func feederBlockToDBBlock(b *feeder.StarknetBlock) *types.Block {
 	for _, data := range b.Transactions {
 		txnsHash = append(txnsHash, types.TransactionHash(types.HexToFelt(data.TransactionHash)))
 	}
-	status, _ := types.BlockStatusValue[string(b.Status)]
+	status, _ := types.BlockStatusValue[b.Status]
 	return &types.Block{
 		BlockHash:   types.HexToBlockHash(b.BlockHash),
 		BlockNumber: uint64(b.BlockNumber),


Test patch:
diff --git a/internal/db/abi/manager_test.go b/internal/db/abi/manager_test.go
index 5d1ec60b..201e4c26 100644
--- a/internal/db/abi/manager_test.go
+++ b/internal/db/abi/manager_test.go
@@ -7,11 +7,11 @@ import (
 )
 
 func TestManager(t *testing.T) {
-	err := db.InitializeDatabaseEnv(t.TempDir(), 1, 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 1, 0)
 	if err != nil {
 		t.Error(err)
 	}
-	database, err := db.GetDatabase("ABI")
+	database, err := db.NewMDBXDatabase(env, "ABI")
 	if err != nil {
 		t.Error(err)
 	}
diff --git a/internal/db/block/block_test.go b/internal/db/block/block_test.go
index 27f5b1b9..794a2a05 100644
--- a/internal/db/block/block_test.go
+++ b/internal/db/block/block_test.go
@@ -30,11 +30,14 @@ func TestManager(t *testing.T) {
 			EventCommitment: types.HexToFelt("0"),
 		},
 	}
-	err := db.InitializeDatabaseEnv(t.TempDir(), 1, 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 1, 0)
+	if err != nil {
+		t.Error(err)
+	}
+	database, err := db.NewMDBXDatabase(env, "ABI")
 	if err != nil {
 		t.Error(err)
 	}
-	database, err := db.GetDatabase("ABI")
 	manager := NewManager(database)
 	for _, block := range blocks {
 		key := block.BlockHash
diff --git a/internal/db/block_specific_test.go b/internal/db/block_specific_test.go
index 37e3136f..c291942f 100644
--- a/internal/db/block_specific_test.go
+++ b/internal/db/block_specific_test.go
@@ -43,7 +43,14 @@ func TestBlockSpecificDatabase_Put(t *testing.T) {
 		},
 	}
 
-	database := NewKeyValueDb(t.TempDir(), 0)
+	env, err := NewMDBXEnv(t.TempDir(), 1, 0)
+	if err != nil {
+		t.Error(err)
+	}
+	database, err := NewMDBXDatabase(env, "BlockSpecific")
+	if err != nil {
+		t.Error(err)
+	}
 	db := NewBlockSpecificDatabase(database)
 
 	for _, test := range tests {
@@ -83,7 +90,14 @@ func TestBlockSpecificDatabase_Get(t *testing.T) {
 		},
 	}
 
-	database := NewKeyValueDb(t.TempDir(), 0)
+	env, err := NewMDBXEnv(t.TempDir(), 1, 0)
+	if err != nil {
+		t.Error(err)
+	}
+	database, err := NewMDBXDatabase(env, "BlockSpecific")
+	if err != nil {
+		t.Error(err)
+	}
 	db := NewBlockSpecificDatabase(database)
 
 	for _, d := range data {
diff --git a/internal/db/db_test.go b/internal/db/db_test.go
deleted file mode 100644
index a92c926a..00000000
--- a/internal/db/db_test.go
+++ /dev/null
@@ -1,268 +0,0 @@
-package db_test
-
-import (
-	"strconv"
-	"testing"
-
-	"github.com/NethermindEth/juno/internal/db"
-)
-
-var keyValueTest = map[string]string{}
-
-func init() {
-	for i := 0; i < 350; i++ {
-		val := strconv.Itoa(i)
-		keyValueTest["key"+val] = "value" + val
-	}
-}
-
-// setupDatabaseForTest creates a new KVDatabase for Tests
-func setupDatabaseForTest(path string) *db.KeyValueDb {
-	return db.NewKeyValueDb(path, 0)
-}
-
-// TestAddKey Check that a single value is inserted without error
-func TestAddKey(t *testing.T) {
-	database := setupDatabaseForTest(t.TempDir())
-	err := database.Put([]byte("key"), []byte("value"))
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-	}
-}
-
-// TestNumberOfItems Checks that in every moment the collection contains the right amount of items
-func TestNumberOfItems(t *testing.T) {
-	database := setupDatabaseForTest(t.TempDir())
-	n, err := database.NumberOfItems()
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-		return
-	}
-	if n != 0 {
-		t.Log(err)
-		t.Fail()
-		return
-	}
-	for k, v := range keyValueTest {
-		err := database.Put([]byte(k), []byte(v))
-		if err != nil {
-			t.Log(err)
-			t.Fail()
-			return
-		}
-	}
-	n, err = database.NumberOfItems()
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-		return
-	}
-	if int(n) != len(keyValueTest) {
-		t.Log(err)
-		t.Fail()
-	}
-}
-
-// TestAddMultipleKeys Checks that after insert some keys the collection contains the right amount of items
-func TestAddMultipleKeys(t *testing.T) {
-	database := setupDatabaseForTest(t.TempDir())
-	for k, v := range keyValueTest {
-		err := database.Put([]byte(k), []byte(v))
-		if err != nil {
-			t.Log(err)
-			t.Fail()
-			return
-		}
-	}
-	n, err := database.NumberOfItems()
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-		return
-	}
-	if int(n) != len(keyValueTest) {
-		t.Log(err)
-		t.Fail()
-	}
-}
-
-// TestHasKey Check that one key exist after insertion
-func TestHasKey(t *testing.T) {
-	database := setupDatabaseForTest(t.TempDir())
-	goodKey := []byte("good_key")
-	err := database.Put(goodKey, []byte("value"))
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-		return
-	}
-	has, err := database.Has(goodKey)
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-		return
-	}
-	if !has {
-		t.Log(err)
-		t.Fail()
-		return
-	}
-}
-
-// TestHasNotKey Check that a key don't exist
-func TestHasNotKey(t *testing.T) {
-	database := setupDatabaseForTest(t.TempDir())
-	goodKey := []byte("good_key")
-	badKey := []byte("bad_key")
-	err := database.Put(goodKey, []byte("value"))
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-		return
-	}
-	has2, err := database.Has(badKey)
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-		return
-	}
-	if has2 {
-		t.Log(err)
-		t.Fail()
-	}
-}
-
-// TestGetKey Check that a key is property retrieved
-func TestGetKey(t *testing.T) {
-	database := setupDatabaseForTest(t.TempDir())
-	goodKey := []byte("good_key")
-	goodValue := []byte("value")
-	err := database.Put(goodKey, goodValue)
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-		return
-	}
-	val, err := database.Get(goodKey)
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-		return
-	}
-	if string(val) != string(goodValue) {
-		t.Log(err)
-		t.Fail()
-	}
-}
-
-// TestGetNotKey Check that a key don't exist and what happen if it doesn't exist
-func TestGetNotKey(t *testing.T) {
-	database := setupDatabaseForTest(t.TempDir())
-	goodKey := []byte("good_key")
-	goodValue := []byte("value")
-	badKey := []byte("bad_key")
-	err := database.Put(goodKey, goodValue)
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-	}
-	key, err := database.Get(badKey)
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-		return
-	}
-	if key != nil {
-		t.Log(err)
-		t.Fail()
-		return
-	}
-}
-
-func TestDelete(t *testing.T) {
-	database := setupDatabaseForTest(t.TempDir())
-	goodKey := []byte("good_key")
-	goodValue := []byte("value")
-	err := database.Put(goodKey, goodValue)
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-	}
-	err = database.Delete(goodKey)
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-		return
-	}
-	key, err := database.Has(goodKey)
-	if key {
-		t.Log(err)
-		t.Fail()
-		return
-	}
-	err = database.Delete(goodKey)
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-	}
-}
-
-func TestClose(t *testing.T) {
-	database := setupDatabaseForTest(t.TempDir())
-	database.Close()
-}
-
-func TestKeyValueDbIsDatabaser(t *testing.T) {
-	a := new(db.KeyValueDb)
-	_ = db.Databaser(a)
-}
-
-// BenchmarkEntriesInDatabase Benchmark the entry of key-value pairs to the db
-func BenchmarkEntriesInDatabase(b *testing.B) {
-	database := setupDatabaseForTest(b.TempDir())
-	for i := 0; i < b.N; i++ {
-		val := []byte(strconv.Itoa(i))
-		err := database.Put(val, val)
-		if err != nil {
-			b.Error("Benchmarking fails, error storing values")
-			return
-		}
-	}
-	n, err := database.NumberOfItems()
-	if err != nil {
-		b.Errorf("Benchmarking fails, error getting the number of items: %s\n", err)
-		b.Fail()
-		return
-	}
-	if int(n) != b.N {
-		b.Error("Benchmarking fails, mismatch between number of items to insert and the number inside db")
-		b.Fail()
-		return
-	}
-}
-
-// BenchmarkConsultsToDatabase Benchmark the consult to a db
-func BenchmarkConsultsToDatabase(b *testing.B) {
-	database := setupDatabaseForTest(b.TempDir())
-	for i := 0; i < b.N; i++ {
-		val := []byte(strconv.Itoa(i))
-		err := database.Put(val, val)
-		if err != nil {
-			b.Error("Benchmarking fails, error storing values")
-			b.Fail()
-			return
-		}
-		get, err := database.Get(val)
-		if err != nil {
-			b.Errorf("Benchmarking fails, error getting values: %s\n", err)
-			b.Fail()
-			return
-		}
-		if string(get) != string(val) {
-			b.Error("Benchmarking fails, mismatch between expected return value and returned value")
-			b.Fail()
-		}
-	}
-}
diff --git a/internal/db/kv_storer_test.go b/internal/db/kv_storer_test.go
index c00bf43e..51e9f50d 100644
--- a/internal/db/kv_storer_test.go
+++ b/internal/db/kv_storer_test.go
@@ -5,13 +5,20 @@ import (
 )
 
 // setupTransactionDbTest creates a new TransactionDb for Tests
-func setupKvStoreTest(database Databaser) KeyValueStore {
+func setupKvStoreTest(database Database) KeyValueStore {
 	return NewKeyValueStore(database, "test")
 }
 
 // TestAddKeyToTransaction Check that a single value is stored after made commit
 func TestKeyValueStoreNewDbAndCommit(t *testing.T) {
-	dbKV := NewKeyValueDb(t.TempDir(), 0)
+	env, err := NewMDBXEnv(t.TempDir(), 1, 0)
+	if err != nil {
+		t.Error(err)
+	}
+	dbKV, err := NewMDBXDatabase(env, "KeyValueStore")
+	if err != nil {
+		t.Error(err)
+	}
 	database := setupKvStoreTest(dbKV)
 	database.Begin()
 
@@ -34,5 +41,5 @@ func TestKeyValueStoreNewDbAndCommit(t *testing.T) {
 	}
 	database.Rollback()
 
-	database.Close()
+	dbKV.Close()
 }
diff --git a/internal/db/named_db_test.go b/internal/db/mdbx_test.go
similarity index 61%
rename from internal/db/named_db_test.go
rename to internal/db/mdbx_test.go
index aadcb038..3bccc467 100644
--- a/internal/db/named_db_test.go
+++ b/internal/db/mdbx_test.go
@@ -2,11 +2,27 @@ package db
 
 import (
 	"bytes"
+	"errors"
 	"fmt"
 	"testing"
 )
 
-func TestNamedDatabase_Has(t *testing.T) {
+func TestNewMDBXDatabase(t *testing.T) {
+	env, err := NewMDBXEnv(t.TempDir(), 1, 0)
+	if err != nil {
+		t.Error(err)
+	}
+	_, err = NewMDBXDatabase(env, "DATABASE")
+	if err != nil {
+		t.Error(err)
+	}
+	_, err = NewMDBXDatabase(env, "DATABASE")
+	if err != nil {
+		t.Error(err)
+	}
+}
+
+func TestMDBXDatabase_Has(t *testing.T) {
 	dbs := initDatabases(t, 2)
 	defer closeDatabases(dbs)
 	key := []byte("key")
@@ -27,7 +43,7 @@ func TestNamedDatabase_Has(t *testing.T) {
 	}
 }
 
-func TestNamedDatabase_Get(t *testing.T) {
+func TestMDBXDatabase_Get(t *testing.T) {
 	dbs := initDatabases(t, 2)
 	defer closeDatabases(dbs)
 	db1 := dbs[0]
@@ -53,7 +69,7 @@ func TestNamedDatabase_Get(t *testing.T) {
 	}
 }
 
-func TestNamedDatabase_Get_NotFound(t *testing.T) {
+func TestMDBXDatabase_Get_NotFound(t *testing.T) {
 	dbs := initDatabases(t, 1)
 	defer closeDatabases(dbs)
 
@@ -67,7 +83,7 @@ func TestNamedDatabase_Get_NotFound(t *testing.T) {
 	}
 }
 
-func TestNamedDatabase_Delete(t *testing.T) {
+func TestMDBXDatabase_Delete(t *testing.T) {
 	dbs := initDatabases(t, 2)
 	defer closeDatabases(dbs)
 
@@ -93,21 +109,11 @@ func TestNamedDatabase_Delete(t *testing.T) {
 	}
 }
 
-func TestNamedDatabase_NumberOfItems(t *testing.T) {
+func TestMDBXDatabase_NumberOfItems(t *testing.T) {
 	db := initDatabases(t, 1)[0]
 	defer db.Close()
 
-	assertNumberOfItems := func(value uint64) {
-		count, err := db.NumberOfItems()
-		if err != nil {
-			t.Errorf("unexpected error during getting the number of items")
-		}
-		if count != value {
-			t.Errorf("number of items does not match, %d, want: %d", count, value)
-		}
-	}
-
-	assertNumberOfItems(0)
+	assertNumberOfItems(t, db, 0)
 
 	for i := 0; i < 10; i++ {
 		err := db.Put([]byte(fmt.Sprintf("key_%d", i)), []byte("value"))
@@ -116,7 +122,7 @@ func TestNamedDatabase_NumberOfItems(t *testing.T) {
 		}
 	}
 
-	assertNumberOfItems(10)
+	assertNumberOfItems(t, db, 10)
 
 	for i := 0; i < 5; i++ {
 		err := db.Delete([]byte(fmt.Sprintf("key_%d", i)))
@@ -125,80 +131,89 @@ func TestNamedDatabase_NumberOfItems(t *testing.T) {
 		}
 	}
 
-	assertNumberOfItems(5)
+	assertNumberOfItems(t, db, 5)
 }
 
-func TestNamedDatabase_GetEnv(t *testing.T) {
-	dbs := initDatabases(t, 10)
-	defer closeDatabases(dbs)
-
-	for _, db := range dbs {
-		if env != db.GetEnv() {
-			t.Errorf("unexpected env")
-		}
-	}
-}
-
-func TestNamedDatabaseTx(t *testing.T) {
+func TestMDBXDatabase_RunTxn(t *testing.T) {
 	dbs := initDatabases(t, 1)
 	defer closeDatabases(dbs)
 	db := dbs[0]
 	assertNumberOfItems(t, db, 0)
-	txn, err := db.Begin()
-	if err != nil {
-		t.Error(err)
-	}
-	if env != txn.GetEnv() {
-		t.Errorf("unexpected env")
-	}
-	assertNumberOfItems(t, txn, 0)
-	if err := txn.Put([]byte("key"), []byte("value1")); err != nil {
-		t.Error(err)
-	}
-	ok, err := txn.Has([]byte("key"))
+	err := db.RunTxn(func(txn DatabaseOperations) error {
+		assertNumberOfItems(t, txn, 0)
+		if err := txn.Put([]byte("key"), []byte("value1")); err != nil {
+			return err
+		}
+		ok, err := txn.Has([]byte("key"))
+		if err != nil {
+			return err
+		}
+		if !ok {
+			return fmt.Errorf("key not fund after Put")
+		}
+		assertNumberOfItems(t, txn, 1)
+		err = txn.Delete([]byte("key"))
+		if err != nil {
+			return err
+		}
+		assertNumberOfItems(t, txn, 0)
+		return nil
+	})
 	if err != nil {
 		t.Error(err)
 	}
-	if !ok {
-		t.Errorf("key not fund after Put")
+
+	assertNumberOfItems(t, db, 0)
+}
+
+func TestNewDbError(t *testing.T) {
+	err := newDbError(ErrInternal, fmt.Errorf(""))
+	if !errors.Is(err, ErrInternal) {
+		t.Error("unexpecteed error type")
 	}
-	assertNumberOfItems(t, txn, 1)
-	err = txn.Delete([]byte("key"))
+}
+
+func TestInitializeMDBXEnv(t *testing.T) {
+	err := InitializeMDBXEnv(t.TempDir(), 1, 0)
 	if err != nil {
 		t.Error(err)
 	}
-	assertNumberOfItems(t, txn, 0)
-	if err := txn.Commit(); err != nil {
-		t.Error(err)
+	if !initialized {
+		t.Errorf("initialized must be true after environment initialization")
 	}
-	assertNumberOfItems(t, db, 0)
 }
 
-func TestNamedDatabaseTx_Rollback(t *testing.T) {
-	dbs := initDatabases(t, 1)
-	defer closeDatabases(dbs)
-	db := dbs[0]
-	txn, err := db.Begin()
+func TestGetMDBXEnv(t *testing.T) {
+	env = nil
+	initialized = false
+	_, err := GetMDBXEnv()
+	if !errors.Is(err, ErrEnvNoInitialized) {
+		t.Errorf("expected ErrEnvNoInitialized error")
+	}
+	err = InitializeMDBXEnv(t.TempDir(), 1, 0)
 	if err != nil {
 		t.Error(err)
 	}
-	assertNumberOfItems(t, txn, 0)
-	err = txn.Put([]byte("key"), []byte("value"))
+	if !initialized {
+		t.Errorf("initialized must be true after environment initialization")
+	}
+	e, err := GetMDBXEnv()
 	if err != nil {
-		t.Error(err)
+		t.Error("unexpected error")
+	}
+	if e != env {
+		t.Error("unexpected environment")
 	}
-	txn.Rollback()
-	assertNumberOfItems(t, db, 0)
 }
 
-func initDatabases(t *testing.T, count int) []*NamedDatabase {
-	out := make([]*NamedDatabase, count)
-	err := InitializeDatabaseEnv(t.TempDir(), uint64(count), 0)
+func initDatabases(t *testing.T, count int) []*MDBXDatabase {
+	out := make([]*MDBXDatabase, count)
+	env, err := NewMDBXEnv(t.TempDir(), uint64(count), 0)
 	if err != nil {
 		t.Fatal(err)
 	}
 	for i := 0; i < count; i++ {
-		out[i], err = GetDatabase(fmt.Sprintf("db_%d", i))
+		out[i], err = NewMDBXDatabase(env, fmt.Sprintf("db_%d", i))
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -206,13 +221,13 @@ func initDatabases(t *testing.T, count int) []*NamedDatabase {
 	return out
 }
 
-func closeDatabases(dbs []*NamedDatabase) {
+func closeDatabases(dbs []*MDBXDatabase) {
 	for _, db := range dbs {
 		db.Close()
 	}
 }
 
-func assertNumberOfItems(t *testing.T, db Databaser, expected uint64) {
+func assertNumberOfItems(t *testing.T, db DatabaseOperations, expected uint64) {
 	count, err := db.NumberOfItems()
 	if err != nil {
 		t.Error(err)
diff --git a/internal/db/state/code_test.go b/internal/db/state/code_test.go
index dd1e47ae..23e071fb 100644
--- a/internal/db/state/code_test.go
+++ b/internal/db/state/code_test.go
@@ -28,8 +28,19 @@ var codes = []struct {
 }
 
 func TestManager_Code(t *testing.T) {
-	codeDatabase := db.NewKeyValueDb(t.TempDir(), 0)
-	storageDatabase := db.NewBlockSpecificDatabase(db.NewKeyValueDb(t.TempDir(), 0))
+	env, err := db.NewMDBXEnv(t.TempDir(), 2, 0)
+	if err != nil {
+		t.Error(err)
+	}
+	codeDatabase, err := db.NewMDBXDatabase(env, "CODE")
+	if err != nil {
+		t.Error(err)
+	}
+	storageDb, err := db.NewMDBXDatabase(env, "STORAGE")
+	if err != nil {
+		t.Error(err)
+	}
+	storageDatabase := db.NewBlockSpecificDatabase(storageDb)
 	manager := NewStateManager(codeDatabase, storageDatabase)
 	for _, code := range codes {
 		manager.PutCode(code.Address, code.Code)
diff --git a/internal/db/state/storage_test.go b/internal/db/state/storage_test.go
index 02b2c1f8..7c6b3e5e 100644
--- a/internal/db/state/storage_test.go
+++ b/internal/db/state/storage_test.go
@@ -31,15 +31,15 @@ func TestManager_Storage(t *testing.T) {
 		},
 	}
 
-	err := db.InitializeDatabaseEnv(t.TempDir(), 2, 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 2, 0)
 	if err != nil {
 		t.Error(err)
 	}
-	codeDb, err := db.GetDatabase("CODE")
+	codeDb, err := db.NewMDBXDatabase(env, "CODE")
 	if err != nil {
 		t.Error(err)
 	}
-	storageDb, err := db.GetDatabase("STORAGE")
+	storageDb, err := db.NewMDBXDatabase(env, "STORAGE")
 	if err != nil {
 		t.Error(err)
 	}
diff --git a/internal/db/transaction/manager_test.go b/internal/db/transaction/manager_test.go
index 6adacad0..535ef4db 100644
--- a/internal/db/transaction/manager_test.go
+++ b/internal/db/transaction/manager_test.go
@@ -69,15 +69,15 @@ var txs = []types.IsTransaction{
 }
 
 func initManager(t *testing.T) *Manager {
-	err := db.InitializeDatabaseEnv(t.TempDir(), 2, 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 2, 0)
 	if err != nil {
 		t.Error(err)
 	}
-	txDb, err := db.GetDatabase("TRANSACTION")
+	txDb, err := db.NewMDBXDatabase(env, "TRANSACTION")
 	if err != nil {
 		t.Error(err)
 	}
-	receiptDb, err := db.GetDatabase("RECEIPT")
+	receiptDb, err := db.NewMDBXDatabase(env, "RECEIPT")
 	if err != nil {
 		t.Error(err)
 	}
diff --git a/internal/db/transaction_db_test.go b/internal/db/transaction_db_test.go
deleted file mode 100644
index 7b236513..00000000
--- a/internal/db/transaction_db_test.go
+++ /dev/null
@@ -1,138 +0,0 @@
-package db
-
-import (
-	"testing"
-)
-
-// setupTransactionDbTest creates a new TransactionDb for Tests
-func setupTransactionDbTest(database Databaser) *TransactionDb {
-	return NewTransactionDb(database.GetEnv())
-}
-
-// TestAddKeyToTransaction Check that a single value is stored after made commit
-func TestInsertKeyOnTransactionDbAndCommit(t *testing.T) {
-	dbKV := NewKeyValueDb(t.TempDir(), 0)
-	dbTest := setupTransactionDbTest(dbKV)
-
-	database := dbTest.Begin()
-
-	_ = database.GetEnv()
-
-	err := database.Put([]byte("key"), []byte("value"))
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-	}
-
-	err = database.Commit()
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-	}
-
-	database = dbTest.Begin()
-
-	get, err := database.Get([]byte("key"))
-	if err != nil || get == nil {
-		t.Log(err)
-		t.Fail()
-	}
-
-	if string(get) != "value" {
-		t.Fail()
-	}
-
-	database.Close()
-}
-
-// TestInsertKeyOnTransactionDbAndRollback Check that a single is deleted after a rollback
-func TestInsertKeyOnTransactionDbAndRollback(t *testing.T) {
-	dbKV := NewKeyValueDb(t.TempDir(), 0)
-	dbTest := setupTransactionDbTest(dbKV)
-
-	database := dbTest.Begin()
-
-	numItems, _ := database.NumberOfItems()
-	if numItems != 0 {
-		t.Fail()
-	}
-
-	err := database.Put([]byte("key"), []byte("value"))
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-	}
-
-	numItems, _ = database.NumberOfItems()
-	if numItems != 1 {
-		t.Fail()
-	}
-
-	database.Rollback()
-
-	database = dbTest.Begin()
-
-	has, err := database.Has([]byte("key"))
-	if err != nil || has {
-		t.Log(err)
-		t.Fail()
-	}
-
-	numItems, _ = database.NumberOfItems()
-	if numItems != 0 {
-		t.Fail()
-	}
-
-	database.Close()
-}
-
-// TestDeletionOnTransactionDb Check that a key is inserted and deleted properly
-func TestDeletionOnTransactionDb(t *testing.T) {
-	dbKV := NewKeyValueDb(t.TempDir(), 0)
-	dbTest := setupTransactionDbTest(dbKV)
-
-	database := dbTest.Begin()
-
-	err := database.Delete([]byte("not_key"))
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-	}
-
-	err = database.Put([]byte("key"), []byte("value"))
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-	}
-
-	err = database.Commit()
-	if err != nil {
-		t.Fail()
-		return
-	}
-
-	database = dbTest.Begin()
-
-	err = database.Delete([]byte("key"))
-	if err != nil {
-		t.Log(err)
-		t.Fail()
-	}
-
-	has, err := database.Has([]byte("key"))
-	if err != nil || has {
-		t.Log(err)
-		t.Fail()
-	}
-
-	database.Rollback()
-
-	database = dbTest.Begin()
-	has, err = database.Has([]byte("key"))
-	if err != nil || !has {
-		t.Log(err)
-		t.Fail()
-	}
-
-	database.Close()
-}
diff --git a/internal/services/abi_test.go b/internal/services/abi_test.go
index 94a2591e..32445c54 100644
--- a/internal/services/abi_test.go
+++ b/internal/services/abi_test.go
@@ -9,11 +9,11 @@ import (
 )
 
 func TestAbiService_StoreGet(t *testing.T) {
-	err := db.InitializeDatabaseEnv(t.TempDir(), 1, 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 1, 0)
 	if err != nil {
 		t.Error(err)
 	}
-	database, err := db.GetDatabase("ABI")
+	database, err := db.NewMDBXDatabase(env, "ABI")
 	if err != nil {
 		t.Error(err)
 	}
diff --git a/internal/services/block_test.go b/internal/services/block_test.go
index e31c310c..f95baeba 100644
--- a/internal/services/block_test.go
+++ b/internal/services/block_test.go
@@ -31,11 +31,14 @@ func TestService(t *testing.T) {
 			EventCommitment: types.HexToFelt("0"),
 		},
 	}
-	err := db.InitializeDatabaseEnv(t.TempDir(), 1, 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 1, 0)
+	if err != nil {
+		t.Error(err)
+	}
+	database, err := db.NewMDBXDatabase(env, "BLOCK")
 	if err != nil {
 		t.Error(err)
 	}
-	database, err := db.GetDatabase("BLOCK")
 	BlockService.Setup(database)
 	err = BlockService.Run()
 	if err != nil {
diff --git a/internal/services/state_test.go b/internal/services/state_test.go
index 347a70cf..feec34e9 100644
--- a/internal/services/state_test.go
+++ b/internal/services/state_test.go
@@ -30,15 +30,15 @@ var codes = []struct {
 }
 
 func stateServiceInitServices(t *testing.T) {
-	err := db.InitializeDatabaseEnv(t.TempDir(), 2, 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 2, 0)
 	if err != nil {
 		t.Error(err)
 	}
-	codeDb, err := db.GetDatabase("CODE")
+	codeDb, err := db.NewMDBXDatabase(env, "CODE")
 	if err != nil {
 		t.Error(err)
 	}
-	storageDb, err := db.GetDatabase("STORAGE")
+	storageDb, err := db.NewMDBXDatabase(env, "STORAGE")
 	if err != nil {
 		t.Error(err)
 	}
diff --git a/internal/services/transactions_test.go b/internal/services/transactions_test.go
index 7e476c3b..535f05df 100644
--- a/internal/services/transactions_test.go
+++ b/internal/services/transactions_test.go
@@ -70,15 +70,15 @@ var txs = []types.IsTransaction{
 }
 
 func initServices(t *testing.T) {
-	err := db.InitializeDatabaseEnv(t.TempDir(), 2, 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 2, 0)
 	if err != nil {
 		t.Error(err)
 	}
-	txDb, err := db.GetDatabase("TRANSACTION")
+	txDb, err := db.NewMDBXDatabase(env, "TRANSACTION")
 	if err != nil {
 		t.Error(err)
 	}
-	receiptDb, err := db.GetDatabase("RECEIPT")
+	receiptDb, err := db.NewMDBXDatabase(env, "RECEIPT")
 	if err != nil {
 		t.Error(err)
 	}
diff --git a/pkg/rpc/api_test.go b/pkg/rpc/api_test.go
index fb38ed25..53ce8b99 100644
--- a/pkg/rpc/api_test.go
+++ b/pkg/rpc/api_test.go
@@ -62,11 +62,19 @@ func buildResponse(result interface{}) string {
 }
 
 func TestStarknetGetStorageAt(t *testing.T) {
-	err := db.InitializeDatabaseEnv(t.TempDir(), 1, 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 3, 0)
 	if err != nil {
 		t.Error(err)
 	}
-	blockDb, err := db.GetDatabase("BLOCK")
+	blockDb, err := db.NewMDBXDatabase(env, "BLOCK")
+	if err != nil {
+		t.Error(err)
+	}
+	codeDb, err := db.NewMDBXDatabase(env, "CODE")
+	if err != nil {
+		t.Error(err)
+	}
+	storageDb, err := db.NewMDBXDatabase(env, "STORAGE")
 	if err != nil {
 		t.Error(err)
 	}
@@ -101,8 +109,8 @@ func TestStarknetGetStorageAt(t *testing.T) {
 	services.BlockService.StoreBlock(blockHash, block)
 
 	services.StateService.Setup(
-		db.NewKeyValueDb(t.TempDir(), 0),
-		db.NewBlockSpecificDatabase(db.NewKeyValueDb(t.TempDir(), 0)),
+		codeDb,
+		db.NewBlockSpecificDatabase(storageDb),
 	)
 	if err := services.StateService.Run(); err != nil {
 		t.Fatalf("unexpected error starting state service: %s", err)
@@ -144,11 +152,19 @@ func TestStarknetGetStorageAt(t *testing.T) {
 }
 
 func TestStarknetGetCode(t *testing.T) {
-	err := db.InitializeDatabaseEnv(t.TempDir(), 1, 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 3, 0)
+	if err != nil {
+		t.Error(err)
+	}
+	abiDb, err := db.NewMDBXDatabase(env, "BLOCK")
+	if err != nil {
+		t.Error(err)
+	}
+	codeDb, err := db.NewMDBXDatabase(env, "CODE")
 	if err != nil {
 		t.Error(err)
 	}
-	abiDb, err := db.GetDatabase("ABI")
+	storageDb, err := db.NewMDBXDatabase(env, "STORAGE")
 	if err != nil {
 		t.Error(err)
 	}
@@ -242,8 +258,8 @@ func TestStarknetGetCode(t *testing.T) {
 	}
 
 	services.StateService.Setup(
-		db.NewKeyValueDb(t.TempDir(), 0),
-		db.NewBlockSpecificDatabase(db.NewKeyValueDb(t.TempDir(), 0)),
+		codeDb,
+		db.NewBlockSpecificDatabase(storageDb),
 	)
 	if err := services.StateService.Run(); err != nil {
 		t.Fatalf("unexpected error starting state service: %s", err)
@@ -519,19 +535,19 @@ var (
 )
 
 func TestGetBlock(t *testing.T) {
-	err := db.InitializeDatabaseEnv(t.TempDir(), 3, 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 3, 0)
 	if err != nil {
 		t.Error(err)
 	}
-	txDb, err := db.GetDatabase("TRANSACTION")
+	txDb, err := db.NewMDBXDatabase(env, "TRANSACTION")
 	if err != nil {
 		t.Error(err)
 	}
-	receiptDb, err := db.GetDatabase("RECEIPT")
+	receiptDb, err := db.NewMDBXDatabase(env, "RECEIPT")
 	if err != nil {
 		t.Error(err)
 	}
-	blockDb, err := db.GetDatabase("BLOCK")
+	blockDb, err := db.NewMDBXDatabase(env, "BLOCK")
 	if err != nil {
 		t.Error(err)
 	}
@@ -846,15 +862,15 @@ func TestGetBlockByTag(t *testing.T) {
 }
 
 func TestGetTransactionByHash(t *testing.T) {
-	err := db.InitializeDatabaseEnv(t.TempDir(), 2, 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 2, 0)
 	if err != nil {
 		t.Error(err)
 	}
-	txDb, err := db.GetDatabase("TRANSACTION")
+	txDb, err := db.NewMDBXDatabase(env, "TRANSACTION")
 	if err != nil {
 		t.Error(err)
 	}
-	receiptDb, err := db.GetDatabase("RECEIPT")
+	receiptDb, err := db.NewMDBXDatabase(env, "RECEIPT")
 	if err != nil {
 		t.Error(err)
 	}
@@ -925,19 +941,19 @@ func TestStarknetPendingTransactions(t *testing.T) {
 }
 
 func TestGetTransactionByBlockHashAndIndex(t *testing.T) {
-	err := db.InitializeDatabaseEnv(t.TempDir(), 3, 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 3, 0)
 	if err != nil {
 		t.Error(err)
 	}
-	txDb, err := db.GetDatabase("TRANSACTION")
+	txDb, err := db.NewMDBXDatabase(env, "TRANSACTION")
 	if err != nil {
 		t.Error(err)
 	}
-	receiptDb, err := db.GetDatabase("RECEIPT")
+	receiptDb, err := db.NewMDBXDatabase(env, "RECEIPT")
 	if err != nil {
 		t.Error(err)
 	}
-	blockDb, err := db.GetDatabase("BLOCK")
+	blockDb, err := db.NewMDBXDatabase(env, "BLOCK")
 	if err != nil {
 		t.Error(err)
 	}
@@ -1022,19 +1038,19 @@ func TestGetTransactionByBlockHashAndIndex(t *testing.T) {
 }
 
 func TestGetTransactionByBlockNumberAndIndex(t *testing.T) {
-	err := db.InitializeDatabaseEnv(t.TempDir(), 3, 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 3, 0)
 	if err != nil {
 		t.Error(err)
 	}
-	txDb, err := db.GetDatabase("TRANSACTION")
+	txDb, err := db.NewMDBXDatabase(env, "TRANSACTION")
 	if err != nil {
 		t.Error(err)
 	}
-	receiptDb, err := db.GetDatabase("RECEIPT")
+	receiptDb, err := db.NewMDBXDatabase(env, "RECEIPT")
 	if err != nil {
 		t.Error(err)
 	}
-	blockDb, err := db.GetDatabase("BLOCK")
+	blockDb, err := db.NewMDBXDatabase(env, "BLOCK")
 	if err != nil {
 		t.Error(err)
 	}
diff --git a/pkg/starknet/state_test.go b/pkg/starknet/state_test.go
index cbb97001..8199bc15 100644
--- a/pkg/starknet/state_test.go
+++ b/pkg/starknet/state_test.go
@@ -172,10 +172,11 @@ func TestProcessPagesHashes(t *testing.T) {
 	defer backendClose()
 	defer rpcClose()
 
-	if err := db.InitializeDatabaseEnv(t.TempDir(), 1, 0); err != nil {
+	env, err := db.NewMDBXEnv(t.TempDir(), 1, 0)
+	if err != nil {
 		t.Error(err)
 	}
-	synchronizerDb, err := db.GetDatabase("SYNCHRONIZER")
+	synchronizerDb, err := db.NewMDBXDatabase(env, "SYNCHRONIZER")
 	if err != nil {
 		t.Error(err)
 	}
@@ -310,7 +311,19 @@ func TestParsePages(t *testing.T) {
 }
 
 func TestUpdateAndCommitState(t *testing.T) {
-	services.ContractHashService.Setup(db.NewKeyValueDb(t.TempDir(), 0))
+	env, err := db.NewMDBXEnv(t.TempDir(), 2, 0)
+	if err != nil {
+		t.Error(err)
+	}
+	contractHashDb, err := db.NewMDBXDatabase(env, "CONTRACT-HASH")
+	if err != nil {
+		t.Error(err)
+	}
+	synchronizerDb, err := db.NewMDBXDatabase(env, "SYNCHRONIZER")
+	if err != nil {
+		t.Error(err)
+	}
+	services.ContractHashService.Setup(contractHashDb)
 	if err := services.ContractHashService.Run(); err != nil {
 		t.Error(err)
 	}
@@ -324,22 +337,13 @@ func TestUpdateAndCommitState(t *testing.T) {
 			},
 		},
 	}
-	// Manually create the synchronizer without calling NewSynchronizer because
-	// we don't want to create an ethclient mock for this test
-	if err := db.InitializeDatabaseEnv(t.TempDir(), 1, 0); err != nil {
-		t.Error(err)
-	}
-	txnDb, err := db.GetDatabase("SYNCHRONIZER")
-	if err != nil {
-		t.Error(err)
-	}
+
 	s := &Synchronizer{
-		database:       txnDb,
-		memoryPageHash: starknetTypes.NewDictionary(txnDb, "memory_pages"),
-		gpsVerifier:    starknetTypes.NewDictionary(txnDb, "gps_verifier"),
-		facts:          starknetTypes.NewDictionary(txnDb, "facts"),
+		database:       synchronizerDb,
+		memoryPageHash: starknetTypes.NewDictionary(synchronizerDb, "memory_pages"),
+		gpsVerifier:    starknetTypes.NewDictionary(synchronizerDb, "gps_verifier"),
+		facts:          starknetTypes.NewDictionary(synchronizerDb, "facts"),
 		chainID:        1,
-		transactioner:  txnDb,
 	}
 	sequenceNumber := uint64(0)
 	s.updateAndCommitState(stateDiff, "", sequenceNumber)
diff --git a/pkg/starknet/types/map_test.go b/pkg/starknet/types/map_test.go
index bedd0c9d..00c8e7c9 100644
--- a/pkg/starknet/types/map_test.go
+++ b/pkg/starknet/types/map_test.go
@@ -7,12 +7,19 @@ import (
 	"github.com/ethereum/go-ethereum/common"
 )
 
-func newDict(database db.Databaser, prefix string) *Dictionary {
+func newDict(database db.Database, prefix string) *Dictionary {
 	return NewDictionary(database, prefix)
 }
 
 func TestMapUsingTransactionHash(t *testing.T) {
-	database := db.NewKeyValueDb(t.TempDir(), 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 1, 0)
+	if err != nil {
+		t.Error(err)
+	}
+	database, err := db.NewMDBXDatabase(env, "DICT")
+	if err != nil {
+		t.Error(err)
+	}
 
 	// create a new Dictionary
 	dict := newDict(database, "test")
@@ -50,7 +57,14 @@ func TestMapUsingTransactionHash(t *testing.T) {
 }
 
 func TestMapUsingPagesHash(t *testing.T) {
-	database := db.NewKeyValueDb(t.TempDir(), 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 1, 0)
+	if err != nil {
+		t.Error(err)
+	}
+	database, err := db.NewMDBXDatabase(env, "DICT")
+	if err != nil {
+		t.Error(err)
+	}
 
 	// create a new Dictionary
 	dict := newDict(database, "test")
@@ -92,7 +106,14 @@ func TestMapUsingPagesHash(t *testing.T) {
 }
 
 func TestMapUsingFact(t *testing.T) {
-	database := db.NewKeyValueDb(t.TempDir(), 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 1, 0)
+	if err != nil {
+		t.Error(err)
+	}
+	database, err := db.NewMDBXDatabase(env, "DICT")
+	if err != nil {
+		t.Error(err)
+	}
 
 	// create a new Dictionary
 	dict := newDict(database, "test")
diff --git a/pkg/starknet/utils_test.go b/pkg/starknet/utils_test.go
index d54b7e30..52fb909b 100644
--- a/pkg/starknet/utils_test.go
+++ b/pkg/starknet/utils_test.go
@@ -126,12 +126,19 @@ func TestStateUpdateResponseToStateDiff(t *testing.T) {
 }
 
 func TestGetAndUpdateValueOnDB(t *testing.T) {
-	database := db.NewKeyValueDb(t.TempDir(), 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 1, 0)
+	if err != nil {
+		t.Error(err)
+	}
+	database, err := db.NewMDBXDatabase(env, "TEST")
+	if err != nil {
+		t.Error(err)
+	}
 
 	key := "key"
 	value := 0
 
-	err := updateNumericValueFromDB(database, key, uint64(value))
+	err = updateNumericValueFromDB(database, key, uint64(value))
 	if err != nil {
 		t.Fail()
 		return
@@ -266,13 +273,23 @@ func TestUpdateState(t *testing.T) {
 	contractHashMap := map[string]*big.Int{
 		"1": big.NewInt(1),
 	}
-	txnDb := db.NewTransactionDb(db.NewKeyValueDb(t.TempDir(), 0).GetEnv())
-	txn := txnDb.Begin()
-	stateCommitment, err := updateState(txn, contractHashMap, &stateDiff, "", 0)
+	env, err := db.NewMDBXEnv(t.TempDir(), 1, 0)
+	if err != nil {
+		t.Error(err)
+	}
+	database, err := db.NewMDBXDatabase(env, "TEST-DB")
+	if err != nil {
+		t.Error(err)
+	}
+
+	var stateCommitment string
+	err = database.RunTxn(func(txn db.DatabaseOperations) (err error) {
+		stateCommitment, err = updateState(txn, contractHashMap, &stateDiff, "", 0)
+		return err
+	})
 	if err != nil {
 		t.Error("Error updating state")
 	}
-	txn.Commit()
 
 	want := stateTrie.Commitment()
 	commitment, _ := new(big.Int).SetString(stateCommitment, 16)