diff --git a/packages/model/approvers/approvers.go b/packages/model/approvers/approvers.go
index 0633e0f55a9a88b41fac9a04ab88a8d74b68420d..3f74b5ea7cebf3b1a6b62e2707b4c136296d058f 100644
--- a/packages/model/approvers/approvers.go
+++ b/packages/model/approvers/approvers.go
@@ -55,6 +55,13 @@ func (approvers *Approvers) GetHash() (result ternary.Trinary) {
 	return
 }
 
+func (approvers *Approvers) GetModified() bool {
+	return true
+}
+
+func (approvers *Approvers) SetModified(modified bool) {
+}
+
 func (approvers *Approvers) Marshal() (result []byte) {
 	result = make([]byte, MARSHALED_APPROVERS_MIN_SIZE+len(approvers.hashes)*MARSHALED_APPROVERS_HASH_SIZE)
 
diff --git a/packages/model/transactionmetadata/const.go b/packages/model/transactionmetadata/const.go
new file mode 100644
index 0000000000000000000000000000000000000000..100a51ddaafa9632f30ed2d5d7888f116860df01
--- /dev/null
+++ b/packages/model/transactionmetadata/const.go
@@ -0,0 +1,21 @@
+package transactionmetadata
+
+// region constants and variables //////////////////////////////////////////////////////////////////////////////////////
+
+const (
+	MARSHALED_HASH_START          = 0
+	MARSHALED_RECEIVED_TIME_START = MARSHALED_HASH_END
+	MARSHALED_FLAGS_START         = MARSHALED_RECEIVED_TIME_END
+
+	MARSHALED_HASH_END          = MARSHALED_HASH_START + MARSHALED_HASH_SIZE
+	MARSHALED_RECEIVED_TIME_END = MARSHALED_RECEIVED_TIME_START + MARSHALED_RECEIVED_TIME_SIZE
+	MARSHALED_FLAGS_END         = MARSHALED_FLAGS_START + MARSHALED_FLAGS_SIZE
+
+	MARSHALED_HASH_SIZE          = 81
+	MARSHALED_RECEIVED_TIME_SIZE = 15
+	MARSHALED_FLAGS_SIZE         = 1
+
+	MARSHALED_TOTAL_SIZE = MARSHALED_FLAGS_END
+)
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/packages/model/transactionmetadata/errors.go b/packages/model/transactionmetadata/errors.go
new file mode 100644
index 0000000000000000000000000000000000000000..b8cfc2239971e878bf9943290b83194bb7972a2a
--- /dev/null
+++ b/packages/model/transactionmetadata/errors.go
@@ -0,0 +1,12 @@
+package transactionmetadata
+
+import "github.com/iotaledger/goshimmer/packages/errors"
+
+// region errors ///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+var (
+	ErrUnmarshalFailed = errors.Wrap(errors.New("unmarshall failed"), "input data is corrupted")
+	ErrMarshallFailed  = errors.Wrap(errors.New("marshal failed"), "the source object contains invalid values")
+)
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/packages/model/transactionmetadata/transactionmetadata.go b/packages/model/transactionmetadata/transactionmetadata.go
new file mode 100644
index 0000000000000000000000000000000000000000..df255a22d3f39b75f09113e20fd7b2b969ddb0cc
--- /dev/null
+++ b/packages/model/transactionmetadata/transactionmetadata.go
@@ -0,0 +1,251 @@
+package transactionmetadata
+
+import (
+	"sync"
+	"time"
+
+	"github.com/iotaledger/goshimmer/packages/bitutils"
+	"github.com/iotaledger/goshimmer/packages/errors"
+	"github.com/iotaledger/goshimmer/packages/ternary"
+	"github.com/iotaledger/goshimmer/packages/typeutils"
+)
+
+// region type definition and constructor //////////////////////////////////////////////////////////////////////////////
+
+type TransactionMetadata struct {
+	hash              ternary.Trinary
+	hashMutex         sync.RWMutex
+	receivedTime      time.Time
+	receivedTimeMutex sync.RWMutex
+	solid             bool
+	solidMutex        sync.RWMutex
+	liked             bool
+	likedMutex        sync.RWMutex
+	finalized         bool
+	finalizedMutex    sync.RWMutex
+	modified          bool
+	modifiedMutex     sync.RWMutex
+}
+
+func New(hash ternary.Trinary) *TransactionMetadata {
+	return &TransactionMetadata{
+		hash:         hash,
+		receivedTime: time.Now(),
+		solid:        false,
+		liked:        false,
+		finalized:    false,
+		modified:     true,
+	}
+}
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// region getters and setters //////////////////////////////////////////////////////////////////////////////////////////
+
+func (metadata *TransactionMetadata) GetHash() ternary.Trinary {
+	metadata.hashMutex.RLock()
+	defer metadata.hashMutex.RUnlock()
+
+	return metadata.hash
+}
+
+func (metadata *TransactionMetadata) SetHash(hash ternary.Trinary) {
+	metadata.hashMutex.RLock()
+	if metadata.hash != hash {
+		metadata.hashMutex.RUnlock()
+		metadata.hashMutex.Lock()
+		defer metadata.hashMutex.Unlock()
+		if metadata.hash != hash {
+			metadata.hash = hash
+
+			metadata.SetModified(true)
+		}
+	} else {
+		metadata.hashMutex.RUnlock()
+	}
+}
+
+func (metadata *TransactionMetadata) GetReceivedTime() time.Time {
+	metadata.receivedTimeMutex.RLock()
+	defer metadata.receivedTimeMutex.RUnlock()
+
+	return metadata.receivedTime
+}
+
+func (metadata *TransactionMetadata) SetReceivedTime(receivedTime time.Time) {
+	metadata.receivedTimeMutex.RLock()
+	if metadata.receivedTime != receivedTime {
+		metadata.receivedTimeMutex.RUnlock()
+		metadata.receivedTimeMutex.Lock()
+		defer metadata.receivedTimeMutex.Unlock()
+		if metadata.receivedTime != receivedTime {
+			metadata.receivedTime = receivedTime
+
+			metadata.SetModified(true)
+		}
+	} else {
+		metadata.receivedTimeMutex.RUnlock()
+	}
+}
+
+func (metadata *TransactionMetadata) GetSolid() bool {
+	metadata.solidMutex.RLock()
+	defer metadata.solidMutex.RUnlock()
+
+	return metadata.solid
+}
+
+func (metadata *TransactionMetadata) SetSolid(solid bool) bool {
+	metadata.solidMutex.RLock()
+	if metadata.solid != solid {
+		metadata.solidMutex.RUnlock()
+		metadata.solidMutex.Lock()
+		defer metadata.solidMutex.Unlock()
+		if metadata.solid != solid {
+			metadata.solid = solid
+
+			metadata.SetModified(true)
+
+			return true
+		}
+	} else {
+		metadata.solidMutex.RUnlock()
+	}
+
+	return false
+}
+
+func (metadata *TransactionMetadata) GetLiked() bool {
+	metadata.likedMutex.RLock()
+	defer metadata.likedMutex.RUnlock()
+
+	return metadata.liked
+}
+
+func (metadata *TransactionMetadata) SetLiked(liked bool) {
+	metadata.likedMutex.RLock()
+	if metadata.liked != liked {
+		metadata.likedMutex.RUnlock()
+		metadata.likedMutex.Lock()
+		defer metadata.likedMutex.Unlock()
+		if metadata.liked != liked {
+			metadata.liked = liked
+
+			metadata.SetModified(true)
+		}
+	} else {
+		metadata.likedMutex.RUnlock()
+	}
+}
+
+func (metadata *TransactionMetadata) GetFinalized() bool {
+	metadata.finalizedMutex.RLock()
+	defer metadata.finalizedMutex.RUnlock()
+
+	return metadata.finalized
+}
+
+func (metadata *TransactionMetadata) SetFinalized(finalized bool) {
+	metadata.finalizedMutex.RLock()
+	if metadata.finalized != finalized {
+		metadata.finalizedMutex.RUnlock()
+		metadata.finalizedMutex.Lock()
+		defer metadata.finalizedMutex.Unlock()
+		if metadata.finalized != finalized {
+			metadata.finalized = finalized
+
+			metadata.SetModified(true)
+		}
+	} else {
+		metadata.finalizedMutex.RUnlock()
+	}
+}
+
+// returns true if the transaction contains unsaved changes (supports concurrency)
+func (metadata *TransactionMetadata) GetModified() bool {
+	metadata.modifiedMutex.RLock()
+	defer metadata.modifiedMutex.RUnlock()
+
+	return metadata.modified
+}
+
+// sets the modified flag which controls if a transaction is going to be saved (supports concurrency)
+func (metadata *TransactionMetadata) SetModified(modified bool) {
+	metadata.modifiedMutex.Lock()
+	defer metadata.modifiedMutex.Unlock()
+
+	metadata.modified = modified
+}
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// region marshaling functions /////////////////////////////////////////////////////////////////////////////////////////
+
+func (metadata *TransactionMetadata) Marshal() ([]byte, errors.IdentifiableError) {
+	marshaledMetadata := make([]byte, MARSHALED_TOTAL_SIZE)
+
+	metadata.receivedTimeMutex.RLock()
+	defer metadata.receivedTimeMutex.RUnlock()
+	metadata.solidMutex.RLock()
+	defer metadata.solidMutex.RUnlock()
+	metadata.likedMutex.RLock()
+	defer metadata.likedMutex.RUnlock()
+	metadata.finalizedMutex.RLock()
+	defer metadata.finalizedMutex.RUnlock()
+
+	copy(marshaledMetadata[MARSHALED_HASH_START:MARSHALED_HASH_END], metadata.hash.CastToBytes())
+
+	marshaledReceivedTime, err := metadata.receivedTime.MarshalBinary()
+	if err != nil {
+		return nil, ErrMarshallFailed.Derive(err, "failed to marshal received time")
+	}
+	copy(marshaledMetadata[MARSHALED_RECEIVED_TIME_START:MARSHALED_RECEIVED_TIME_END], marshaledReceivedTime)
+
+	var booleanFlags bitutils.BitMask
+	if metadata.solid {
+		booleanFlags = booleanFlags.SetFlag(0)
+	}
+	if metadata.liked {
+		booleanFlags = booleanFlags.SetFlag(1)
+	}
+	if metadata.finalized {
+		booleanFlags = booleanFlags.SetFlag(2)
+	}
+	marshaledMetadata[MARSHALED_FLAGS_START] = byte(booleanFlags)
+
+	return marshaledMetadata, nil
+}
+
+func (metadata *TransactionMetadata) Unmarshal(data []byte) errors.IdentifiableError {
+	metadata.hashMutex.Lock()
+	defer metadata.hashMutex.Unlock()
+	metadata.receivedTimeMutex.Lock()
+	defer metadata.receivedTimeMutex.Unlock()
+	metadata.solidMutex.Lock()
+	defer metadata.solidMutex.Unlock()
+	metadata.likedMutex.Lock()
+	defer metadata.likedMutex.Unlock()
+	metadata.finalizedMutex.Lock()
+	defer metadata.finalizedMutex.Unlock()
+
+	metadata.hash = ternary.Trinary(typeutils.BytesToString(data[MARSHALED_HASH_START:MARSHALED_HASH_END]))
+
+	if err := metadata.receivedTime.UnmarshalBinary(data[MARSHALED_RECEIVED_TIME_START:MARSHALED_RECEIVED_TIME_END]); err != nil {
+		return ErrUnmarshalFailed.Derive(err, "could not unmarshal the received time")
+	}
+
+	booleanFlags := bitutils.BitMask(data[MARSHALED_FLAGS_START])
+	if booleanFlags.HasFlag(0) {
+		metadata.solid = true
+	}
+	if booleanFlags.HasFlag(1) {
+		metadata.liked = true
+	}
+	if booleanFlags.HasFlag(2) {
+		metadata.finalized = true
+	}
+
+	return nil
+}
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/plugins/tangle/api.go b/plugins/tangle/api.go
deleted file mode 100644
index 3e40d0caa2ca91f45ff0d617d7ba178182b6963f..0000000000000000000000000000000000000000
--- a/plugins/tangle/api.go
+++ /dev/null
@@ -1,101 +0,0 @@
-package tangle
-
-import (
-	"github.com/iotaledger/goshimmer/packages/datastructure"
-	"github.com/iotaledger/goshimmer/packages/errors"
-	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
-	"github.com/iotaledger/goshimmer/packages/ternary"
-)
-
-// region transaction api //////////////////////////////////////////////////////////////////////////////////////////////
-
-var transactionCache = datastructure.NewLRUCache(TRANSACTION_CACHE_SIZE, &datastructure.LRUCacheOptions{
-	EvictionCallback: func(key interface{}, value interface{}) {
-		go func(evictedTransaction *value_transaction.ValueTransaction) {
-			if err := storeTransactionInDatabase(evictedTransaction); err != nil {
-				panic(err)
-			}
-		}(value.(*value_transaction.ValueTransaction))
-	},
-})
-
-func StoreTransaction(transaction *value_transaction.ValueTransaction) {
-	transactionCache.Set(transaction.GetHash(), transaction)
-}
-
-func GetTransaction(transactionHash ternary.Trinary, computeIfAbsent ...func(ternary.Trinary) *value_transaction.ValueTransaction) (result *value_transaction.ValueTransaction, err errors.IdentifiableError) {
-	if cacheResult := transactionCache.ComputeIfAbsent(transactionHash, func() interface{} {
-		if transaction, dbErr := getTransactionFromDatabase(transactionHash); dbErr != nil {
-			err = dbErr
-
-			return nil
-		} else if transaction != nil {
-			return transaction
-		} else {
-			if len(computeIfAbsent) >= 1 {
-				return computeIfAbsent[0](transactionHash)
-			}
-
-			return nil
-		}
-	}); cacheResult != nil {
-		result = cacheResult.(*value_transaction.ValueTransaction)
-	}
-
-	return
-}
-
-func ContainsTransaction(transactionHash ternary.Trinary) (result bool, err errors.IdentifiableError) {
-	if transactionCache.Get(transactionHash) != nil {
-		result = true
-	} else {
-		result, err = databaseContainsTransaction(transactionHash)
-	}
-
-	return
-}
-
-// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-// region transactionmetadata api //////////////////////////////////////////////////////////////////////////////////////
-
-var metadataCache = datastructure.NewLRUCache(METADATA_CACHE_SIZE, &datastructure.LRUCacheOptions{
-	EvictionCallback: func(key interface{}, value interface{}) {
-		go func(evictedMetadata *TransactionMetadata) {
-			if err := storeTransactionMetadataInDatabase(evictedMetadata); err != nil {
-				panic(err)
-			}
-		}(value.(*TransactionMetadata))
-	},
-})
-
-func GetTransactionMetadata(transactionHash ternary.Trinary, computeIfAbsent ...func(ternary.Trinary) *TransactionMetadata) (result *TransactionMetadata, err errors.IdentifiableError) {
-	if transactionMetadata := metadataCache.ComputeIfAbsent(transactionHash, func() interface{} {
-		if result, err = getTransactionMetadataFromDatabase(transactionHash); err == nil && result == nil && len(computeIfAbsent) >= 1 {
-			result = computeIfAbsent[0](transactionHash)
-		}
-
-		return result
-	}); transactionMetadata != nil && transactionMetadata.(*TransactionMetadata) != nil {
-		result = transactionMetadata.(*TransactionMetadata)
-	}
-
-	return
-}
-
-func ContainsTransactionMetadata(transactionHash ternary.Trinary) (result bool, err errors.IdentifiableError) {
-	if metadataCache.Get(transactionHash) != nil {
-		result = true
-	} else {
-		result, err = databaseContainsTransactionMetadata(transactionHash)
-	}
-
-	return
-}
-
-// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-const (
-	TRANSACTION_CACHE_SIZE = 10000
-	METADATA_CACHE_SIZE    = 10000
-)
diff --git a/plugins/tangle/approvers.go b/plugins/tangle/approvers.go
index 93d8877ec08498f66d2f4076f312a9d4ade06b43..72c659d97e6534de27869f0b4867cfff74525b07 100644
--- a/plugins/tangle/approvers.go
+++ b/plugins/tangle/approvers.go
@@ -2,31 +2,33 @@ package tangle
 
 import (
 	"github.com/dgraph-io/badger"
+	"github.com/iotaledger/goshimmer/packages/database"
 	"github.com/iotaledger/goshimmer/packages/datastructure"
 	"github.com/iotaledger/goshimmer/packages/errors"
 	"github.com/iotaledger/goshimmer/packages/model/approvers"
+	"github.com/iotaledger/goshimmer/packages/node"
 	"github.com/iotaledger/goshimmer/packages/ternary"
 )
 
 // region global public api ////////////////////////////////////////////////////////////////////////////////////////////
 
-var approversCache = datastructure.NewLRUCache(METADATA_CACHE_SIZE)
-
-func StoreApprovers(approvers *approvers.Approvers) {
-	hash := approvers.GetHash()
-
-	approversCache.Set(hash, approvers)
-}
-
 func GetApprovers(transactionHash ternary.Trinary, computeIfAbsent ...func(ternary.Trinary) *approvers.Approvers) (result *approvers.Approvers, err errors.IdentifiableError) {
-	if appr := approversCache.ComputeIfAbsent(transactionHash, func() interface{} {
-		if result, err = getApproversFromDatabase(transactionHash); err == nil && result == nil && len(computeIfAbsent) >= 1 {
-			result = computeIfAbsent[0](transactionHash)
+	if cacheResult := approversCache.ComputeIfAbsent(transactionHash, func() interface{} {
+		if dbApprovers, dbErr := getApproversFromDatabase(transactionHash); dbErr != nil {
+			err = dbErr
+
+			return nil
+		} else if dbApprovers != nil {
+			return dbApprovers
+		} else {
+			if len(computeIfAbsent) >= 1 {
+				return computeIfAbsent[0](transactionHash)
+			}
+
+			return nil
 		}
-
-		return result
-	}); appr != nil && appr.(*approvers.Approvers) != nil {
-		result = appr.(*approvers.Approvers)
+	}); cacheResult != nil && cacheResult.(*approvers.Approvers) != nil {
+		result = cacheResult.(*approvers.Approvers)
 	}
 
 	return
@@ -42,29 +44,80 @@ func ContainsApprovers(transactionHash ternary.Trinary) (result bool, err errors
 	return
 }
 
-func getApproversFromDatabase(transactionHash ternary.Trinary) (result *approvers.Approvers, err errors.IdentifiableError) {
-	approversData, dbErr := approversDatabase.Get(transactionHash.CastToBytes())
-	if dbErr != nil {
-		if dbErr != badger.ErrKeyNotFound {
-			err = ErrDatabaseError.Derive(err, "failed to retrieve transaction")
+func StoreApprovers(approvers *approvers.Approvers) {
+	approversCache.Set(approvers.GetHash(), approvers)
+}
+
+// region lru cache ////////////////////////////////////////////////////////////////////////////////////////////////////
+
+var approversCache = datastructure.NewLRUCache(APPROVERS_CACHE_SIZE, &datastructure.LRUCacheOptions{
+	EvictionCallback: onEvictApprovers,
+})
+
+func onEvictApprovers(_ interface{}, value interface{}) {
+	if evictedApprovers := value.(*approvers.Approvers); evictedApprovers.GetModified() {
+		go func(evictedApprovers *approvers.Approvers) {
+			if err := storeApproversInDatabase(evictedApprovers); err != nil {
+				panic(err)
+			}
+		}(evictedApprovers)
+	}
+}
+
+const (
+	APPROVERS_CACHE_SIZE = 50000
+)
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// region database /////////////////////////////////////////////////////////////////////////////////////////////////////
+
+var approversDatabase database.Database
+
+func configureApproversDatabase(plugin *node.Plugin) {
+	if db, err := database.Get("approvers"); err != nil {
+		panic(err)
+	} else {
+		approversDatabase = db
+	}
+}
+
+func storeApproversInDatabase(approvers *approvers.Approvers) errors.IdentifiableError {
+	if approvers.GetModified() {
+		if err := transactionMetadataDatabase.Set(approvers.GetHash().CastToBytes(), approvers.Marshal()); err != nil {
+			return ErrDatabaseError.Derive(err, "failed to store transaction metadata")
 		}
 
-		return
+		approvers.SetModified(false)
 	}
 
-	result = approvers.New(transactionHash)
+	return nil
+}
+
+func getApproversFromDatabase(transactionHash ternary.Trinary) (*approvers.Approvers, errors.IdentifiableError) {
+	approversData, err := approversDatabase.Get(transactionHash.CastToBytes())
+	if err != nil {
+		if err == badger.ErrKeyNotFound {
+			return nil, nil
+		} else {
+			return nil, ErrDatabaseError.Derive(err, "failed to retrieve approvers")
+		}
+	}
+
+	var result approvers.Approvers
 	if err = result.Unmarshal(approversData); err != nil {
-		result = nil
+		panic(err)
 	}
 
-	return
+	return &result, nil
 }
 
 func databaseContainsApprovers(transactionHash ternary.Trinary) (bool, errors.IdentifiableError) {
-	result, err := approversDatabase.Contains(transactionHash.CastToBytes())
-	if err != nil {
-		return false, ErrDatabaseError.Derive(err, "failed to check if the transaction exists")
+	if contains, err := approversDatabase.Contains(transactionHash.CastToBytes()); err != nil {
+		return false, ErrDatabaseError.Derive(err, "failed to check if the approvers exists")
+	} else {
+		return contains, nil
 	}
-
-	return result, nil
 }
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/plugins/tangle/plugin.go b/plugins/tangle/plugin.go
index 113969bdb2f51e1a6cda38c31e2538eea620b9f3..00f2dfaea6bc8481e11720ed9d8124f11e40ee93 100644
--- a/plugins/tangle/plugin.go
+++ b/plugins/tangle/plugin.go
@@ -9,7 +9,9 @@ import (
 var PLUGIN = node.NewPlugin("Tangle", configure, run)
 
 func configure(plugin *node.Plugin) {
-	configureDatabase(plugin)
+	configureTransactionDatabase(plugin)
+	configureTransactionMetaDataDatabase(plugin)
+	configureApproversDatabase(plugin)
 	configureSolidifier(plugin)
 }
 
diff --git a/plugins/tangle/solidifier.go b/plugins/tangle/solidifier.go
index 405f3dd07294d57918d51d187c102941cb43c4f6..7b9e6c8c755d9ed62f8705cef3ca6fce900d756b 100644
--- a/plugins/tangle/solidifier.go
+++ b/plugins/tangle/solidifier.go
@@ -1,10 +1,12 @@
 package tangle
 
 import (
+	"github.com/iotaledger/goshimmer/packages/daemon"
 	"github.com/iotaledger/goshimmer/packages/errors"
 	"github.com/iotaledger/goshimmer/packages/events"
 	"github.com/iotaledger/goshimmer/packages/model/approvers"
 	"github.com/iotaledger/goshimmer/packages/model/meta_transaction"
+	"github.com/iotaledger/goshimmer/packages/model/transactionmetadata"
 	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
 	"github.com/iotaledger/goshimmer/packages/node"
 	"github.com/iotaledger/goshimmer/packages/ternary"
@@ -23,37 +25,19 @@ func configureSolidifier(plugin *node.Plugin) {
 	for i := 0; i < NUMBER_OF_WORKERS; i++ {
 		go func() {
 			for {
-				rawTransaction := <-tasksChan
-
-				processMetaTransaction(plugin, rawTransaction)
+				select {
+				case <-daemon.ShutdownSignal:
+					return
+				case rawTransaction := <-tasksChan:
+					processMetaTransaction(plugin, rawTransaction)
+				}
 			}
 		}()
 	}
 
 	gossip.Events.ReceiveTransaction.Attach(events.NewClosure(func(rawTransaction *meta_transaction.MetaTransaction) {
 		tasksChan <- rawTransaction
-
-		//go processMetaTransaction(plugin, rawTransaction)
 	}))
-	/*
-		for i := 0; i < NUMBER_OF_WORKERS; i++ {
-			go func() {
-				for transaction := range solidifierChan {
-					select {
-					case <-daemon.ShutdownSignal:
-						return
-
-					default:
-						// update the solidity flags of this transaction and its approvers
-						if _, err := IsSolid(transaction); err != nil {
-							plugin.LogFailure(err.Error())
-
-							return
-						}
-					}
-				}
-			}()
-		}*/
 }
 
 // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -61,7 +45,7 @@ func configureSolidifier(plugin *node.Plugin) {
 // Checks and updates the solid flag of a single transaction.
 func checkSolidity(transaction *value_transaction.ValueTransaction) (result bool, err errors.IdentifiableError) {
 	// abort if transaction is solid already
-	txMetadata, metaDataErr := GetTransactionMetadata(transaction.GetHash(), NewTransactionMetadata)
+	txMetadata, metaDataErr := GetTransactionMetadata(transaction.GetHash(), transactionmetadata.New)
 	if metaDataErr != nil {
 		err = metaDataErr
 
@@ -81,7 +65,7 @@ func checkSolidity(transaction *value_transaction.ValueTransaction) (result bool
 			return
 		} else if branchTransaction == nil {
 			return
-		} else if branchTransactionMetadata, branchErr := GetTransactionMetadata(branchTransaction.GetHash(), NewTransactionMetadata); branchErr != nil {
+		} else if branchTransactionMetadata, branchErr := GetTransactionMetadata(branchTransaction.GetHash(), transactionmetadata.New); branchErr != nil {
 			err = branchErr
 
 			return
@@ -98,7 +82,7 @@ func checkSolidity(transaction *value_transaction.ValueTransaction) (result bool
 			return
 		} else if trunkTransaction == nil {
 			return
-		} else if trunkTransactionMetadata, trunkErr := GetTransactionMetadata(trunkTransaction.GetHash(), NewTransactionMetadata); trunkErr != nil {
+		} else if trunkTransactionMetadata, trunkErr := GetTransactionMetadata(trunkTransaction.GetHash(), transactionmetadata.New); trunkErr != nil {
 			err = trunkErr
 
 			return
diff --git a/plugins/tangle/approvers_test.go b/plugins/tangle/solidifier_test.go
similarity index 97%
rename from plugins/tangle/approvers_test.go
rename to plugins/tangle/solidifier_test.go
index d5f7cfccb0db544d44c45a20205658952bcc0f66..7bfbe02b14cc09f957c8d8144412ffa33572a03e 100644
--- a/plugins/tangle/approvers_test.go
+++ b/plugins/tangle/solidifier_test.go
@@ -12,7 +12,7 @@ import (
 
 func TestSolidifier(t *testing.T) {
 	// initialize plugin
-	configureDatabase(nil)
+	configureApproversDatabase(nil)
 	configureSolidifier(nil)
 
 	// create transactions and chain them together
diff --git a/plugins/tangle/database.go b/plugins/tangle/transaction.go
similarity index 53%
rename from plugins/tangle/database.go
rename to plugins/tangle/transaction.go
index 511d52d2cb5bc3d053a5ca96c11cfd6841c33a6a..22913eddb7fce9566648a781ae3fdf441e3518d5 100644
--- a/plugins/tangle/database.go
+++ b/plugins/tangle/transaction.go
@@ -3,37 +3,87 @@ package tangle
 import (
 	"github.com/dgraph-io/badger"
 	"github.com/iotaledger/goshimmer/packages/database"
+	"github.com/iotaledger/goshimmer/packages/datastructure"
 	"github.com/iotaledger/goshimmer/packages/errors"
 	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
 	"github.com/iotaledger/goshimmer/packages/node"
 	"github.com/iotaledger/goshimmer/packages/ternary"
+	"github.com/iotaledger/goshimmer/packages/typeutils"
 )
 
-// region plugin module setup //////////////////////////////////////////////////////////////////////////////////////////
+// region public api ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-func configureDatabase(plugin *node.Plugin) {
-	if db, err := database.Get("transaction"); err != nil {
-		panic(err)
-	} else {
-		transactionDatabase = db
+func GetTransaction(transactionHash ternary.Trinary, computeIfAbsent ...func(ternary.Trinary) *value_transaction.ValueTransaction) (result *value_transaction.ValueTransaction, err errors.IdentifiableError) {
+	if cacheResult := transactionCache.ComputeIfAbsent(transactionHash, func() interface{} {
+		if transaction, dbErr := getTransactionFromDatabase(transactionHash); dbErr != nil {
+			err = dbErr
+
+			return nil
+		} else if transaction != nil {
+			return transaction
+		} else {
+			if len(computeIfAbsent) >= 1 {
+				return computeIfAbsent[0](transactionHash)
+			}
+
+			return nil
+		}
+	}); !typeutils.IsInterfaceNil(cacheResult) {
+		result = cacheResult.(*value_transaction.ValueTransaction)
 	}
 
-	if db, err := database.Get("transactionMetadata"); err != nil {
-		panic(err)
+	return
+}
+
+func ContainsTransaction(transactionHash ternary.Trinary) (result bool, err errors.IdentifiableError) {
+	if transactionCache.Contains(transactionHash) {
+		result = true
 	} else {
-		transactionMetadataDatabase = db
+		result, err = databaseContainsTransaction(transactionHash)
 	}
 
-	if db, err := database.Get("approvers"); err != nil {
-		panic(err)
-	} else {
-		approversDatabase = db
+	return
+}
+
+func StoreTransaction(transaction *value_transaction.ValueTransaction) {
+	transactionCache.Set(transaction.GetHash(), transaction)
+}
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// region lru cache ////////////////////////////////////////////////////////////////////////////////////////////////////
+
+var transactionCache = datastructure.NewLRUCache(TRANSACTION_CACHE_SIZE, &datastructure.LRUCacheOptions{
+	EvictionCallback: onEvictTransaction,
+})
+
+func onEvictTransaction(_ interface{}, value interface{}) {
+	if evictedTransaction := value.(*value_transaction.ValueTransaction); evictedTransaction.GetModified() {
+		go func(evictedTransaction *value_transaction.ValueTransaction) {
+			if err := storeTransactionInDatabase(evictedTransaction); err != nil {
+				panic(err)
+			}
+		}(evictedTransaction)
 	}
 }
 
+const (
+	TRANSACTION_CACHE_SIZE = 50000
+)
+
 // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-// region internal utility functions ///////////////////////////////////////////////////////////////////////////////////
+// region database /////////////////////////////////////////////////////////////////////////////////////////////////////
+
+var transactionDatabase database.Database
+
+func configureTransactionDatabase(plugin *node.Plugin) {
+	if db, err := database.Get("transaction"); err != nil {
+		panic(err)
+	} else {
+		transactionDatabase = db
+	}
+}
 
 func storeTransactionInDatabase(transaction *value_transaction.ValueTransaction) errors.IdentifiableError {
 	if transaction.GetModified() {
@@ -68,57 +118,4 @@ func databaseContainsTransaction(transactionHash ternary.Trinary) (bool, errors.
 	}
 }
 
-func storeTransactionMetadataInDatabase(metadata *TransactionMetadata) errors.IdentifiableError {
-	if metadata.GetModified() {
-		marshalledMetadata, err := metadata.Marshal()
-		if err != nil {
-			return err
-		}
-
-		if err := transactionMetadataDatabase.Set(metadata.GetHash().CastToBytes(), marshalledMetadata); err != nil {
-			return ErrDatabaseError.Derive(err, "failed to store transaction metadata")
-		}
-
-		metadata.SetModified(false)
-	}
-
-	return nil
-}
-
-func getTransactionMetadataFromDatabase(transactionHash ternary.Trinary) (*TransactionMetadata, errors.IdentifiableError) {
-	txMetadata, err := transactionMetadataDatabase.Get(transactionHash.CastToBytes())
-	if err != nil {
-		if err == badger.ErrKeyNotFound {
-			return nil, nil
-		} else {
-			return nil, ErrDatabaseError.Derive(err, "failed to retrieve transaction")
-		}
-	}
-
-	var result TransactionMetadata
-	if err := result.Unmarshal(txMetadata); err != nil {
-		panic(err)
-	}
-
-	return &result, nil
-}
-
-func databaseContainsTransactionMetadata(transactionHash ternary.Trinary) (bool, errors.IdentifiableError) {
-	if contains, err := transactionMetadataDatabase.Contains(transactionHash.CastToBytes()); err != nil {
-		return contains, ErrDatabaseError.Derive(err, "failed to check if the transaction metadata exists")
-	} else {
-		return contains, nil
-	}
-}
-
-// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-// region constants and variables //////////////////////////////////////////////////////////////////////////////////////
-
-var transactionDatabase database.Database
-
-var transactionMetadataDatabase database.Database
-
-var approversDatabase database.Database
-
 // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/plugins/tangle/transaction_metadata.go b/plugins/tangle/transaction_metadata.go
index 7798e0396857691537b9423f7fa2faad25053cad..b7d056d17e9161417aed77fd357d01d67e2196bb 100644
--- a/plugins/tangle/transaction_metadata.go
+++ b/plugins/tangle/transaction_metadata.go
@@ -1,275 +1,130 @@
 package tangle
 
 import (
-	"sync"
-	"time"
-
-	"github.com/iotaledger/goshimmer/packages/bitutils"
+	"github.com/dgraph-io/badger"
+	"github.com/iotaledger/goshimmer/packages/database"
+	"github.com/iotaledger/goshimmer/packages/datastructure"
 	"github.com/iotaledger/goshimmer/packages/errors"
+	"github.com/iotaledger/goshimmer/packages/model/transactionmetadata"
+	"github.com/iotaledger/goshimmer/packages/node"
 	"github.com/iotaledger/goshimmer/packages/ternary"
 	"github.com/iotaledger/goshimmer/packages/typeutils"
 )
 
-// region type definition and constructor //////////////////////////////////////////////////////////////////////////////
+// region public api ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-type TransactionMetadata struct {
-	hash              ternary.Trinary
-	hashMutex         sync.RWMutex
-	receivedTime      time.Time
-	receivedTimeMutex sync.RWMutex
-	solid             bool
-	solidMutex        sync.RWMutex
-	liked             bool
-	likedMutex        sync.RWMutex
-	finalized         bool
-	finalizedMutex    sync.RWMutex
-	modified          bool
-	modifiedMutex     sync.RWMutex
-}
+func GetTransactionMetadata(transactionHash ternary.Trinary, computeIfAbsent ...func(ternary.Trinary) *transactionmetadata.TransactionMetadata) (result *transactionmetadata.TransactionMetadata, err errors.IdentifiableError) {
+	if cacheResult := transactionMetadataCache.ComputeIfAbsent(transactionHash, func() interface{} {
+		if transactionMetadata, dbErr := getTransactionMetadataFromDatabase(transactionHash); dbErr != nil {
+			err = dbErr
 
-func NewTransactionMetadata(hash ternary.Trinary) *TransactionMetadata {
-	return &TransactionMetadata{
-		hash:         hash,
-		receivedTime: time.Now(),
-		solid:        false,
-		liked:        false,
-		finalized:    false,
-		modified:     true,
-	}
-}
+			return nil
+		} else if transactionMetadata != nil {
+			return transactionMetadata
+		} else {
+			if len(computeIfAbsent) >= 1 {
+				return computeIfAbsent[0](transactionHash)
+			}
 
-// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-// region getters and setters //////////////////////////////////////////////////////////////////////////////////////////
-
-func (metadata *TransactionMetadata) GetHash() ternary.Trinary {
-	metadata.hashMutex.RLock()
-	defer metadata.hashMutex.RUnlock()
-
-	return metadata.hash
-}
-
-func (metadata *TransactionMetadata) SetHash(hash ternary.Trinary) {
-	metadata.hashMutex.RLock()
-	if metadata.hash != hash {
-		metadata.hashMutex.RUnlock()
-		metadata.hashMutex.Lock()
-		defer metadata.hashMutex.Unlock()
-		if metadata.hash != hash {
-			metadata.hash = hash
-
-			metadata.SetModified(true)
+			return nil
 		}
-	} else {
-		metadata.hashMutex.RUnlock()
+	}); !typeutils.IsInterfaceNil(cacheResult) {
+		result = cacheResult.(*transactionmetadata.TransactionMetadata)
 	}
-}
 
-func (metadata *TransactionMetadata) GetReceivedTime() time.Time {
-	metadata.receivedTimeMutex.RLock()
-	defer metadata.receivedTimeMutex.RUnlock()
-
-	return metadata.receivedTime
+	return
 }
 
-func (metadata *TransactionMetadata) SetReceivedTime(receivedTime time.Time) {
-	metadata.receivedTimeMutex.RLock()
-	if metadata.receivedTime != receivedTime {
-		metadata.receivedTimeMutex.RUnlock()
-		metadata.receivedTimeMutex.Lock()
-		defer metadata.receivedTimeMutex.Unlock()
-		if metadata.receivedTime != receivedTime {
-			metadata.receivedTime = receivedTime
-
-			metadata.SetModified(true)
-		}
+func ContainsTransactionMetadata(transactionHash ternary.Trinary) (result bool, err errors.IdentifiableError) {
+	if transactionMetadataCache.Contains(transactionHash) {
+		result = true
 	} else {
-		metadata.receivedTimeMutex.RUnlock()
+		result, err = databaseContainsTransactionMetadata(transactionHash)
 	}
-}
 
-func (metadata *TransactionMetadata) GetSolid() bool {
-	metadata.solidMutex.RLock()
-	defer metadata.solidMutex.RUnlock()
-
-	return metadata.solid
+	return
 }
 
-func (metadata *TransactionMetadata) SetSolid(solid bool) bool {
-	metadata.solidMutex.RLock()
-	if metadata.solid != solid {
-		metadata.solidMutex.RUnlock()
-		metadata.solidMutex.Lock()
-		defer metadata.solidMutex.Unlock()
-		if metadata.solid != solid {
-			metadata.solid = solid
-
-			metadata.SetModified(true)
-
-			return true
-		}
-	} else {
-		metadata.solidMutex.RUnlock()
-	}
-
-	return false
+func StoreTransactionMetadata(transactionMetadata *transactionmetadata.TransactionMetadata) {
+	transactionMetadataCache.Set(transactionMetadata.GetHash(), transactionMetadata)
 }
 
-func (metadata *TransactionMetadata) GetLiked() bool {
-	metadata.likedMutex.RLock()
-	defer metadata.likedMutex.RUnlock()
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-	return metadata.liked
-}
+// region lru cache ////////////////////////////////////////////////////////////////////////////////////////////////////
 
-func (metadata *TransactionMetadata) SetLiked(liked bool) {
-	metadata.likedMutex.RLock()
-	if metadata.liked != liked {
-		metadata.likedMutex.RUnlock()
-		metadata.likedMutex.Lock()
-		defer metadata.likedMutex.Unlock()
-		if metadata.liked != liked {
-			metadata.liked = liked
+var transactionMetadataCache = datastructure.NewLRUCache(TRANSACTION_METADATA_CACHE_SIZE, &datastructure.LRUCacheOptions{
+	EvictionCallback: onEvictTransactionMetadata,
+})
 
-			metadata.SetModified(true)
-		}
-	} else {
-		metadata.likedMutex.RUnlock()
+func onEvictTransactionMetadata(_ interface{}, value interface{}) {
+	if evictedTransactionMetadata := value.(*transactionmetadata.TransactionMetadata); evictedTransactionMetadata.GetModified() {
+		go func(evictedTransactionMetadata *transactionmetadata.TransactionMetadata) {
+			if err := storeTransactionMetadataInDatabase(evictedTransactionMetadata); err != nil {
+				panic(err)
+			}
+		}(evictedTransactionMetadata)
 	}
 }
 
-func (metadata *TransactionMetadata) GetFinalized() bool {
-	metadata.finalizedMutex.RLock()
-	defer metadata.finalizedMutex.RUnlock()
+const (
+	TRANSACTION_METADATA_CACHE_SIZE = 50000
+)
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-	return metadata.finalized
-}
+// region database /////////////////////////////////////////////////////////////////////////////////////////////////////
 
-func (metadata *TransactionMetadata) SetFinalized(finalized bool) {
-	metadata.finalizedMutex.RLock()
-	if metadata.finalized != finalized {
-		metadata.finalizedMutex.RUnlock()
-		metadata.finalizedMutex.Lock()
-		defer metadata.finalizedMutex.Unlock()
-		if metadata.finalized != finalized {
-			metadata.finalized = finalized
+var transactionMetadataDatabase database.Database
 
-			metadata.SetModified(true)
-		}
+func configureTransactionMetaDataDatabase(plugin *node.Plugin) {
+	if db, err := database.Get("transactionMetadata"); err != nil {
+		panic(err)
 	} else {
-		metadata.finalizedMutex.RUnlock()
+		transactionMetadataDatabase = db
 	}
 }
 
-// returns true if the transaction contains unsaved changes (supports concurrency)
-func (metadata *TransactionMetadata) GetModified() bool {
-	metadata.modifiedMutex.RLock()
-	defer metadata.modifiedMutex.RUnlock()
+func storeTransactionMetadataInDatabase(metadata *transactionmetadata.TransactionMetadata) errors.IdentifiableError {
+	if metadata.GetModified() {
+		if marshaledMetadata, err := metadata.Marshal(); err != nil {
+			return err
+		} else {
+			if err := transactionMetadataDatabase.Set(metadata.GetHash().CastToBytes(), marshaledMetadata); err != nil {
+				return ErrDatabaseError.Derive(err, "failed to store transaction metadata")
+			}
 
-	return metadata.modified
-}
-
-// sets the modified flag which controls if a transaction is going to be saved (supports concurrency)
-func (metadata *TransactionMetadata) SetModified(modified bool) {
-	metadata.modifiedMutex.Lock()
-	defer metadata.modifiedMutex.Unlock()
+			metadata.SetModified(false)
+		}
+	}
 
-	metadata.modified = modified
+	return nil
 }
 
-// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-// region marshaling functions ////////////////////////////////////////////////////////////////////////////////////////
-
-func (metadata *TransactionMetadata) Marshal() ([]byte, errors.IdentifiableError) {
-	marshaledMetadata := make([]byte, MARSHALED_TOTAL_SIZE)
-
-	metadata.receivedTimeMutex.RLock()
-	defer metadata.receivedTimeMutex.RUnlock()
-	metadata.solidMutex.RLock()
-	defer metadata.solidMutex.RUnlock()
-	metadata.likedMutex.RLock()
-	defer metadata.likedMutex.RUnlock()
-	metadata.finalizedMutex.RLock()
-	defer metadata.finalizedMutex.RUnlock()
-
-	copy(marshaledMetadata[MARSHALED_HASH_START:MARSHALED_HASH_END], metadata.hash.CastToBytes())
-
-	marshaledReceivedTime, err := metadata.receivedTime.MarshalBinary()
+func getTransactionMetadataFromDatabase(transactionHash ternary.Trinary) (*transactionmetadata.TransactionMetadata, errors.IdentifiableError) {
+	txMetadata, err := transactionMetadataDatabase.Get(transactionHash.CastToBytes())
 	if err != nil {
-		return nil, ErrMarshallFailed.Derive(err, "failed to marshal received time")
+		if err == badger.ErrKeyNotFound {
+			return nil, nil
+		} else {
+			return nil, ErrDatabaseError.Derive(err, "failed to retrieve transaction")
+		}
 	}
-	copy(marshaledMetadata[MARSHALED_RECEIVED_TIME_START:MARSHALED_RECEIVED_TIME_END], marshaledReceivedTime)
 
-	var booleanFlags bitutils.BitMask
-	if metadata.solid {
-		booleanFlags = booleanFlags.SetFlag(0)
-	}
-	if metadata.liked {
-		booleanFlags = booleanFlags.SetFlag(1)
+	var result transactionmetadata.TransactionMetadata
+	if err := result.Unmarshal(txMetadata); err != nil {
+		panic(err)
 	}
-	if metadata.finalized {
-		booleanFlags = booleanFlags.SetFlag(2)
-	}
-	marshaledMetadata[MARSHALED_FLAGS_START] = byte(booleanFlags)
 
-	return marshaledMetadata, nil
+	return &result, nil
 }
 
-func (metadata *TransactionMetadata) Unmarshal(data []byte) errors.IdentifiableError {
-	metadata.hashMutex.Lock()
-	defer metadata.hashMutex.Unlock()
-	metadata.receivedTimeMutex.Lock()
-	defer metadata.receivedTimeMutex.Unlock()
-	metadata.solidMutex.Lock()
-	defer metadata.solidMutex.Unlock()
-	metadata.likedMutex.Lock()
-	defer metadata.likedMutex.Unlock()
-	metadata.finalizedMutex.Lock()
-	defer metadata.finalizedMutex.Unlock()
-
-	metadata.hash = ternary.Trinary(typeutils.BytesToString(data[MARSHALED_HASH_START:MARSHALED_HASH_END]))
-
-	if err := metadata.receivedTime.UnmarshalBinary(data[MARSHALED_RECEIVED_TIME_START:MARSHALED_RECEIVED_TIME_END]); err != nil {
-		return ErrUnmarshalFailed.Derive(err, "could not unmarshal the received time")
-	}
-
-	booleanFlags := bitutils.BitMask(data[MARSHALED_FLAGS_START])
-	if booleanFlags.HasFlag(0) {
-		metadata.solid = true
-	}
-	if booleanFlags.HasFlag(1) {
-		metadata.liked = true
-	}
-	if booleanFlags.HasFlag(2) {
-		metadata.finalized = true
+func databaseContainsTransactionMetadata(transactionHash ternary.Trinary) (bool, errors.IdentifiableError) {
+	if contains, err := transactionMetadataDatabase.Contains(transactionHash.CastToBytes()); err != nil {
+		return contains, ErrDatabaseError.Derive(err, "failed to check if the transaction metadata exists")
+	} else {
+		return contains, nil
 	}
-
-	return nil
 }
 
 // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-// region database functions ///////////////////////////////////////////////////////////////////////////////////////////
-
-// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-// region constants and variables //////////////////////////////////////////////////////////////////////////////////////
-
-const (
-	MARSHALED_HASH_START          = 0
-	MARSHALED_RECEIVED_TIME_START = MARSHALED_HASH_END
-	MARSHALED_FLAGS_START         = MARSHALED_RECEIVED_TIME_END
-
-	MARSHALED_HASH_END          = MARSHALED_HASH_START + MARSHALED_HASH_SIZE
-	MARSHALED_RECEIVED_TIME_END = MARSHALED_RECEIVED_TIME_START + MARSHALED_RECEIVED_TIME_SIZE
-	MARSHALED_FLAGS_END         = MARSHALED_FLAGS_START + MARSHALED_FLAGS_SIZE
-
-	MARSHALED_HASH_SIZE          = 81
-	MARSHALED_RECEIVED_TIME_SIZE = 15
-	MARSHALED_FLAGS_SIZE         = 1
-
-	MARSHALED_TOTAL_SIZE = MARSHALED_FLAGS_END
-)
-
-// endregion ////////////////////////////////////////////////////////////////////////////////////////////////////////////