diff --git a/packages/bitutils/bitmask.go b/packages/bitutils/bitmask.go
new file mode 100644
index 0000000000000000000000000000000000000000..ac3a34bb6dcf1406f85464c944014337caeb0e2d
--- /dev/null
+++ b/packages/bitutils/bitmask.go
@@ -0,0 +1,15 @@
+package bitutils
+
+type BitMask byte
+
+func (bitmask BitMask) SetFlag(pos uint) BitMask {
+    return bitmask | (1 << pos)
+}
+
+func (bitmask BitMask) ClearFlag(pos uint) BitMask {
+    return bitmask & ^(1 << pos)
+}
+
+func (bitmask BitMask) HasFlag(pos uint) bool {
+    return (bitmask & (1 << pos) > 0)
+}
\ No newline at end of file
diff --git a/packages/bitutils/bitmask_test.go b/packages/bitutils/bitmask_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..38dfb40839793724f40291c70d86e7b86e7865b4
--- /dev/null
+++ b/packages/bitutils/bitmask_test.go
@@ -0,0 +1,35 @@
+package bitutils
+
+import (
+    "testing"
+)
+
+func TestBitmask(t *testing.T) {
+    var b BitMask
+
+    if b.HasFlag(0) {
+        t.Error("flag at pos 0 should not be set")
+    }
+    if b.HasFlag(1) {
+        t.Error("flag at pos 1 should not be set")
+    }
+
+    b = b.SetFlag(0)
+    if !b.HasFlag(0) {
+        t.Error("flag at pos 0 should be set")
+    }
+    b = b.SetFlag(1)
+    if !b.HasFlag(1) {
+        t.Error("flag at pos 1 should be set")
+    }
+
+    b = b.ClearFlag(0)
+    if b.HasFlag(0) {
+        t.Error("flag at pos 0 should not be set")
+    }
+    b = b.ClearFlag(1)
+    if b.HasFlag(1) {
+        t.Error("flag at pos 1 should not be set")
+    }
+}
+
diff --git a/packages/ternary/ternary.go b/packages/ternary/ternary.go
index 3261e1bf212b66c7d0978627447f4e1a58c8cae5..84034c5b7c678a05d19e03ea867fd220502d809b 100644
--- a/packages/ternary/ternary.go
+++ b/packages/ternary/ternary.go
@@ -1,11 +1,26 @@
 package ternary
 
+import (
+    "reflect"
+    "unsafe"
+)
+
 // a Trit can have the values 0, 1 and -1
 type Trit = int8
 
-// a Trinary consists out of many Trits
+// Trits consists out of many Trits
 type Trits []Trit
 
+// Trinary is a string representation of the Trits
+type Trinary string
+
+// simply changes the type of this Trinary to a byte array without copying any data
+func (trinary Trinary) CastToBytes() []byte {
+    hdr := (*reflect.StringHeader)(unsafe.Pointer(&trinary))
+
+    return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{Data: hdr.Data, Len:  hdr.Len, Cap:  hdr.Len}))
+}
+
 func (this Trits) ToBytes() []byte {
     tritsLength := len(this)
     bytesLength := (tritsLength + NUMBER_OF_TRITS_IN_A_BYTE - 1) / NUMBER_OF_TRITS_IN_A_BYTE
@@ -62,4 +77,8 @@ func (this Trits) ToUint64() uint64 {
 
 func (this Trits) ToString() string {
     return TritsToString(this, 0, len(this))
-}
\ No newline at end of file
+}
+
+func (this Trits) ToTrinary() Trinary {
+    return Trinary(TritsToString(this, 0, len(this)))
+}
diff --git a/packages/timeutil/sleep.go b/packages/timeutil/sleep.go
new file mode 100644
index 0000000000000000000000000000000000000000..68facd320d528cede103eb981fff18d206b9d154
--- /dev/null
+++ b/packages/timeutil/sleep.go
@@ -0,0 +1,16 @@
+package timeutil
+
+import (
+    "github.com/iotaledger/goshimmer/packages/daemon"
+    "time"
+)
+
+func Sleep(interval time.Duration) bool {
+    select {
+    case <-daemon.ShutdownSignal:
+        return false
+
+    case <-time.After(interval):
+        return true
+    }
+}
\ No newline at end of file
diff --git a/packages/transaction/constants.go b/packages/transaction/constants.go
index 6d632b6077adaa0fd064a8f7f77d7056068de635..594890c09a6ee1ded5b8e16409a7125adb305a9d 100644
--- a/packages/transaction/constants.go
+++ b/packages/transaction/constants.go
@@ -12,7 +12,6 @@ const (
     TRUNK_TRANSACTION_HASH_SIZE             = 243
     BRANCH_TRANSACTION_HASH_SIZE            = 243
     TAG_SIZE                                = 81
-    NODE_ID_SIZE                            = 243
     NONCE_SIZE                              = 81
 
     // offsets of the transaction fields
@@ -26,8 +25,7 @@ const (
     TRUNK_TRANSACTION_HASH_OFFSET           = BUNDLE_HASH_END
     BRANCH_TRANSACTION_HASH_OFFSET          = TRUNK_TRANSACTION_HASH_END
     TAG_OFFSET                              = BRANCH_TRANSACTION_HASH_END
-    NODE_ID_OFFSET                          = TAG_END
-    NONCE_OFFSET                            = NODE_ID_END
+    NONCE_OFFSET                            = TAG_END
 
     // ends of the transaction fields
     SIGNATURE_MESSAGE_FRAGMENT_END          = SIGNATURE_MESSAGE_FRAGMENT_OFFSET + SIGNATURE_MESSAGE_FRAGMENT_SIZE
@@ -40,7 +38,6 @@ const (
     TRUNK_TRANSACTION_HASH_END              = TRUNK_TRANSACTION_HASH_OFFSET + TRUNK_TRANSACTION_HASH_SIZE
     BRANCH_TRANSACTION_HASH_END             = BRANCH_TRANSACTION_HASH_OFFSET + BRANCH_TRANSACTION_HASH_SIZE
     TAG_END                                 = TAG_OFFSET + TAG_SIZE
-    NODE_ID_END                             = NODE_ID_OFFSET + NODE_ID_SIZE
     NONCE_END                               = NONCE_OFFSET + NONCE_SIZE
 
     // the full size of a transaction
diff --git a/packages/transaction/transaction.go b/packages/transaction/transaction.go
index 2fc31aba22768cdf840ed2b5e2a1dc48c4fb1cdc..871f6b2924484bbdfa6d9a2c48d88c53cfccac47 100644
--- a/packages/transaction/transaction.go
+++ b/packages/transaction/transaction.go
@@ -8,15 +8,14 @@ import (
 type Transaction struct {
     SignatureMessageFragment      ternary.Trits
     Address                       ternary.Trits
-    Value                         int64
-    Timestamp                     uint64
-    CurrentIndex                  uint64
-    LatestIndex                   uint64
+    Value                         ternary.Trits
+    Timestamp                     ternary.Trits
+    CurrentIndex                  ternary.Trits
+    LatestIndex                   ternary.Trits
     BundleHash                    ternary.Trits
     TrunkTransactionHash          ternary.Trits
     BranchTransactionHash         ternary.Trits
     Tag                           ternary.Trits
-    NodeId                        ternary.Trits
     Nonce                         ternary.Trits
 
     Hash                          ternary.Trits
@@ -31,15 +30,14 @@ func FromTrits(trits ternary.Trits, optionalHash ...ternary.Trits) *Transaction
     transaction := &Transaction{
         SignatureMessageFragment:      trits[SIGNATURE_MESSAGE_FRAGMENT_OFFSET:SIGNATURE_MESSAGE_FRAGMENT_END],
         Address:                       trits[ADDRESS_OFFSET:ADDRESS_END],
-        Value:                         trits[VALUE_OFFSET:VALUE_END].ToInt64(),
-        Timestamp:                     trits[TIMESTAMP_OFFSET:TIMESTAMP_END].ToUint64(),
-        CurrentIndex:                  trits[CURRENT_INDEX_OFFSET:CURRENT_INDEX_END].ToUint64(),
-        LatestIndex:                   trits[LATEST_INDEX_OFFSET:LATEST_INDEX_END].ToUint64(),
+        Value:                         trits[VALUE_OFFSET:VALUE_END],
+        Timestamp:                     trits[TIMESTAMP_OFFSET:TIMESTAMP_END],
+        CurrentIndex:                  trits[CURRENT_INDEX_OFFSET:CURRENT_INDEX_END],
+        LatestIndex:                   trits[LATEST_INDEX_OFFSET:LATEST_INDEX_END],
         BundleHash:                    trits[BUNDLE_HASH_OFFSET:BUNDLE_HASH_END],
         TrunkTransactionHash:          trits[TRUNK_TRANSACTION_HASH_OFFSET:TRUNK_TRANSACTION_HASH_END],
         BranchTransactionHash:         trits[BRANCH_TRANSACTION_HASH_OFFSET:BRANCH_TRANSACTION_HASH_END],
         Tag:                           trits[TAG_OFFSET:TAG_END],
-        NodeId:                        trits[NODE_ID_OFFSET:NODE_ID_END],
         Nonce:                         trits[NONCE_OFFSET:NONCE_END],
 
         Hash:                          hash,
diff --git a/packages/typeconversion/typeconversion.go b/packages/typeconversion/typeconversion.go
index e820a9b66019d0a5f9c724aa9f9c47cc39d9632c..729b48d96a1cb1606cf131d6f558df1428f3970e 100644
--- a/packages/typeconversion/typeconversion.go
+++ b/packages/typeconversion/typeconversion.go
@@ -9,4 +9,10 @@ func BytesToString(b []byte) string {
     bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
 
     return *(*string)(unsafe.Pointer(&reflect.StringHeader{bh.Data, bh.Len}))
+}
+
+func StringToBytes(str string) []byte {
+    hdr := (*reflect.StringHeader)(unsafe.Pointer(&str))
+
+    return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{Data: hdr.Data, Len:  hdr.Len, Cap:  hdr.Len}))
 }
\ No newline at end of file
diff --git a/plugins/analysis/client/plugin.go b/plugins/analysis/client/plugin.go
index c4c3970d009ca403711c37c286b5968427b09133..663bf6cba2bbdfaeacd4af175425da8c10131ef0 100644
--- a/plugins/analysis/client/plugin.go
+++ b/plugins/analysis/client/plugin.go
@@ -6,6 +6,7 @@ import (
     "github.com/iotaledger/goshimmer/packages/events"
     "github.com/iotaledger/goshimmer/packages/network"
     "github.com/iotaledger/goshimmer/packages/node"
+    "github.com/iotaledger/goshimmer/packages/timeutil"
     "github.com/iotaledger/goshimmer/plugins/analysis/types/addnode"
     "github.com/iotaledger/goshimmer/plugins/analysis/types/connectnodes"
     "github.com/iotaledger/goshimmer/plugins/analysis/types/disconnectnodes"
@@ -21,17 +22,26 @@ import (
 func Run(plugin *node.Plugin) {
     daemon.BackgroundWorker(func() {
         shuttingDown := false
+
         for !shuttingDown {
-            if conn, err := net.Dial("tcp", *SERVER_ADDRESS.Value); err != nil {
-                plugin.LogDebug("Could not connect to reporting server: " + err.Error())
-            } else {
-                managedConn := network.NewManagedConnection(conn)
-                eventDispatchers := getEventDispatchers(managedConn)
+            select {
+            case <-daemon.ShutdownSignal:
+                return
+
+            default:
+                if conn, err := net.Dial("tcp", *SERVER_ADDRESS.Value); err != nil {
+                    plugin.LogDebug("Could not connect to reporting server: " + err.Error())
 
-                reportCurrentStatus(eventDispatchers)
-                setupHooks(managedConn, eventDispatchers)
+                    timeutil.Sleep(1 * time.Second)
+                } else {
+                    managedConn := network.NewManagedConnection(conn)
+                    eventDispatchers := getEventDispatchers(managedConn)
 
-                shuttingDown = keepConnectionAlive(managedConn)
+                    reportCurrentStatus(eventDispatchers)
+                    setupHooks(managedConn, eventDispatchers)
+
+                    shuttingDown = keepConnectionAlive(managedConn)
+                }
             }
         }
     })
diff --git a/plugins/tangle/api.go b/plugins/tangle/api.go
new file mode 100644
index 0000000000000000000000000000000000000000..c184762e75f348a8755156296d889d1f94f098e8
--- /dev/null
+++ b/plugins/tangle/api.go
@@ -0,0 +1,46 @@
+package tangle
+
+import (
+    "github.com/iotaledger/goshimmer/packages/errors"
+    "github.com/iotaledger/goshimmer/packages/ternary"
+)
+
+// region transaction api //////////////////////////////////////////////////////////////////////////////////////////////
+
+func GetTransaction(transactionHash ternary.Trinary) (*Transaction, errors.IdentifiableError) {
+    if transaction := getTransactionFromMemPool(transactionHash); transaction != nil {
+        return transaction, nil
+    }
+
+    return getTransactionFromDatabase(transactionHash)
+}
+
+func ContainsTransaction(transactionHash ternary.Trinary) (bool, errors.IdentifiableError) {
+    if memPoolContainsTransaction(transactionHash) {
+        return true, nil
+    }
+
+    return databaseContainsTransaction(transactionHash)
+}
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// region transactionmetadata api //////////////////////////////////////////////////////////////////////////////////////
+
+func GetTransactionMetadata(transactionHash ternary.Trinary) (*TransactionMetadata, errors.IdentifiableError) {
+    if transaction := getTransactionFromMemPool(transactionHash); transaction != nil {
+        return transaction.GetMetaData()
+    }
+
+    return getTransactionMetadataFromDatabase(transactionHash)
+}
+
+func ContainsTransactionMetadata(transactionHash ternary.Trinary) (bool, errors.IdentifiableError) {
+    if memPoolContainsTransaction(transactionHash) {
+        return true, nil
+    }
+
+    return databaseContainsTransactionMetadata(transactionHash)
+}
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
\ No newline at end of file
diff --git a/plugins/tangle/database.go b/plugins/tangle/database.go
new file mode 100644
index 0000000000000000000000000000000000000000..88fca65165a8eab6f97540216046668ada7b2e43
--- /dev/null
+++ b/plugins/tangle/database.go
@@ -0,0 +1,89 @@
+package tangle
+
+import (
+    "fmt"
+    "github.com/dgraph-io/badger"
+    "github.com/iotaledger/goshimmer/packages/database"
+    "github.com/iotaledger/goshimmer/packages/errors"
+    "github.com/iotaledger/goshimmer/packages/node"
+    "github.com/iotaledger/goshimmer/packages/ternary"
+    "github.com/iotaledger/goshimmer/packages/transaction"
+)
+
+// region plugin module setup //////////////////////////////////////////////////////////////////////////////////////////
+
+func configureDatabase(plugin *node.Plugin) {
+    if db, err := database.Get("transaction"); err != nil {
+        panic(err)
+    } else {
+        transactionDatabase = db
+    }
+
+    if db, err := database.Get("transactionMetadata"); err != nil {
+        panic(err)
+    } else {
+        transactionMetadataDatabase = db
+    }
+}
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// region internal utility functions ///////////////////////////////////////////////////////////////////////////////////
+
+func getTransactionFromDatabase(transactionHash ternary.Trinary) (*Transaction, errors.IdentifiableError) {
+    txData, err := transactionDatabase.Get(transactionHash.CastToBytes())
+    if err != nil {
+        if err == badger.ErrKeyNotFound {
+            return nil, nil
+        } else {
+            return nil, ErrDatabaseError.Derive(err, "failed to retrieve transaction")
+        }
+    }
+
+    return &Transaction{
+        rawTransaction: transaction.FromBytes(txData),
+    }, nil
+}
+
+func databaseContainsTransaction(transactionHash ternary.Trinary) (bool, errors.IdentifiableError) {
+    if contains, err := transactionDatabase.Contains(transactionHash.CastToBytes()); err != nil {
+        return contains, ErrDatabaseError.Derive(err, "failed to check if the transaction exists")
+    } else {
+        return contains, 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")
+        }
+    }
+
+    if false {
+        fmt.Println(txMetadata)
+    }
+
+    return &TransactionMetadata{}, 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
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/plugins/tangle/errors.go b/plugins/tangle/errors.go
new file mode 100644
index 0000000000000000000000000000000000000000..809e6a6587827ee71d979f76d9e30640753967be
--- /dev/null
+++ b/plugins/tangle/errors.go
@@ -0,0 +1,9 @@
+package tangle
+
+import "github.com/iotaledger/goshimmer/packages/errors"
+
+var (
+    ErrDatabaseError = errors.Wrap(errors.New("database error"), "failed to access the database")
+    ErrUnmarshalFailed = errors.Wrap(errors.New("unmarshall failed"), "input data is corrupted")
+    ErrMarshallFailed = errors.Wrap(errors.New("marshal failed"), "the source object contains invalid values")
+)
diff --git a/plugins/tangle/events.go b/plugins/tangle/events.go
new file mode 100644
index 0000000000000000000000000000000000000000..cc58a4898181793fa9f5f79c6957693ebba73743
--- /dev/null
+++ b/plugins/tangle/events.go
@@ -0,0 +1,17 @@
+package tangle
+
+import (
+    "github.com/iotaledger/goshimmer/packages/events"
+)
+
+var Events = pluginEvents{
+    TransactionStored: events.NewEvent(transactionCaller),
+    TransactionSolid:  events.NewEvent(transactionCaller),
+}
+
+type pluginEvents struct {
+    TransactionStored *events.Event
+    TransactionSolid  *events.Event
+}
+
+func transactionCaller(handler interface{}, params ...interface{}) { handler.(func(*Transaction))(params[0].(*Transaction)) }
diff --git a/plugins/tangle/mempool.go b/plugins/tangle/mempool.go
new file mode 100644
index 0000000000000000000000000000000000000000..7f80d5bcaf54e95bda754e114bfd6e55ba93941a
--- /dev/null
+++ b/plugins/tangle/mempool.go
@@ -0,0 +1,130 @@
+package tangle
+
+import (
+    "github.com/iotaledger/goshimmer/packages/daemon"
+    "github.com/iotaledger/goshimmer/packages/events"
+    "github.com/iotaledger/goshimmer/packages/node"
+    "github.com/iotaledger/goshimmer/packages/ternary"
+    "github.com/iotaledger/goshimmer/packages/transaction"
+    "github.com/iotaledger/goshimmer/plugins/gossip"
+    "sync"
+    "time"
+)
+
+// region plugin module setup //////////////////////////////////////////////////////////////////////////////////////////
+
+func configureMemPool(plugin *node.Plugin) {
+    gossip.Events.ReceiveTransaction.Attach(events.NewClosure(func(transaction *transaction.Transaction) {
+        memPoolQueue <- &Transaction{rawTransaction: transaction}
+    }))
+}
+
+func runMemPool(plugin *node.Plugin) {
+    plugin.LogInfo("Starting Mempool ...")
+
+    daemon.BackgroundWorker(createMemPoolWorker(plugin))
+}
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// region internal utility functions ///////////////////////////////////////////////////////////////////////////////////
+
+func createMemPoolWorker(plugin *node.Plugin) func() {
+    return func() {
+        plugin.LogSuccess("Starting Mempool ... done")
+
+        shuttingDown := false
+
+        for !shuttingDown {
+            flushTimer := time.After(MEMPOOL_FLUSH_INTERVAL)
+
+            select {
+            case <-daemon.ShutdownSignal:
+                plugin.LogInfo("Stopping Mempool ...")
+
+                shuttingDown = true
+
+                continue
+
+            case <-flushTimer:
+                // store transactions in database
+
+            case tx := <-memPoolQueue:
+                // skip transactions that we have processed already
+                if transactionStoredAlready, err := ContainsTransaction(tx.GetHash()); err != nil {
+                    plugin.LogFailure(err.Error())
+
+                    return
+                } else if transactionStoredAlready {
+                    continue
+                }
+
+                // store tx in memPool
+                memPoolMutex.Lock()
+                memPool[tx.GetHash()] = tx
+                memPoolMutex.Unlock()
+
+                // update solidity of transactions
+                _, err := UpdateSolidity(tx)
+                if err != nil {
+                    plugin.LogFailure(err.Error())
+
+                    return
+                }
+
+                go func() {
+                    <-time.After(1 * time.Minute)
+
+                    err := tx.Store()
+                    if err != nil {
+                        plugin.LogFailure(err.Error())
+                    }
+
+                    memPoolMutex.Lock()
+                    delete(memPool, tx.GetHash())
+                    memPoolMutex.Unlock()
+                }()
+            }
+        }
+
+        plugin.LogSuccess("Stopping Mempool ... done")
+    }
+}
+
+func getTransactionFromMemPool(transactionHash ternary.Trinary) *Transaction {
+    memPoolMutex.RLock()
+    defer memPoolMutex.RUnlock()
+
+    if cacheEntry, exists := memPool[transactionHash]; exists {
+        return cacheEntry
+    }
+
+    return nil
+}
+
+func memPoolContainsTransaction(transactionHash ternary.Trinary) bool {
+    memPoolMutex.RLock()
+    defer memPoolMutex.RUnlock()
+
+    _, exists := memPool[transactionHash]
+
+    return exists
+}
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// region constants and variables //////////////////////////////////////////////////////////////////////////////////////
+
+var memPoolQueue = make(chan *Transaction, MEM_POOL_QUEUE_SIZE)
+
+var memPool = make(map[ternary.Trinary]*Transaction)
+
+var memPoolMutex sync.RWMutex
+
+const (
+    MEM_POOL_QUEUE_SIZE = 1000
+
+    MEMPOOL_FLUSH_INTERVAL = 500 * time.Millisecond
+)
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/plugins/tangle/plugin.go b/plugins/tangle/plugin.go
index 556dda07205e263aa036a883070e259c322be51a..e41f763217f87c7c15097bb5b435e7043ec36b2a 100644
--- a/plugins/tangle/plugin.go
+++ b/plugins/tangle/plugin.go
@@ -1,64 +1,20 @@
 package tangle
 
 import (
-    "fmt"
-    "github.com/iotaledger/goshimmer/packages/database"
-    "github.com/iotaledger/goshimmer/packages/events"
     "github.com/iotaledger/goshimmer/packages/node"
-    "github.com/iotaledger/goshimmer/packages/transaction"
-    "github.com/iotaledger/goshimmer/plugins/gossip"
 )
 
 // region plugin module setup //////////////////////////////////////////////////////////////////////////////////////////
 
 var PLUGIN = node.NewPlugin("Tangle", configure, run)
 
-func configure(node *node.Plugin) {
-    if db, err := database.Get("transactions"); err != nil {
-        panic(err)
-    } else {
-        transactionDatabase = db
-    }
-
-    gossip.Events.ReceiveTransaction.Attach(events.NewClosure(func(transaction *transaction.Transaction) {
-        if transactionStoredAlready, err := transactionDatabase.Contains(transaction.Hash.ToBytes()); err != nil {
-            panic(err)
-        } else {
-            if !transactionStoredAlready {
-
-                fmt.Println(transaction.Hash.ToString())
-                // process transaction
-            }
-        }
-    }))
+func configure(plugin *node.Plugin) {
+    configureDatabase(plugin)
+    configureMemPool(plugin)
 }
 
-func run(node *node.Plugin) {
-    /*
-    if accountability.OWN_ID.StringIdentifier == "72f84aaee02af4542672cb25aceb9d9e458ef2a3" {
-        go func() {
-            txCounter := 0
-
-            for {
-                txCounter++
-
-                dummyTx := make([]byte, transaction.MARSHALLED_TOTAL_SIZE / ternary.NUMBER_OF_TRITS_IN_A_BYTE)
-                for i := 0; i < 1620; i++ {
-                    dummyTx[i] = byte((i + txCounter) % 128)
-                }
-
-                gossip.SendTransaction(transaction.FromBytes(dummyTx))
-
-                <- time.After(1000 * time.Millisecond)
-            }
-        }()
-    }*/
+func run(plugin *node.Plugin) {
+    runMemPool(plugin)
 }
 
 // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-// region constants and variables //////////////////////////////////////////////////////////////////////////////////////
-
-var transactionDatabase database.Database
-
-// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/plugins/tangle/solidifier.go b/plugins/tangle/solidifier.go
new file mode 100644
index 0000000000000000000000000000000000000000..4fa57cc29885645c32f4fea38fbc9e4dea1ba6a9
--- /dev/null
+++ b/plugins/tangle/solidifier.go
@@ -0,0 +1,57 @@
+package tangle
+
+import (
+    "github.com/iotaledger/goshimmer/packages/errors"
+    "github.com/iotaledger/goshimmer/packages/ternary"
+)
+
+func UpdateSolidity(transaction *Transaction) (bool, errors.IdentifiableError) {
+    // abort if transaction is solid already
+    txMetadata, err := transaction.GetMetaData()
+    if err != nil {
+        return false, err
+    } else if txMetadata.GetSolid() {
+        return true, nil
+    }
+
+    // check solidity of branch transaction if it is not genesis
+    if branchTransactionHash := transaction.GetBranchTransactionHash(); branchTransactionHash != ternary.Trinary("999999") {
+        // abort if branch transaction is missing
+        branchTransaction, err := GetTransaction(branchTransactionHash)
+        if err != nil {
+            return false, err
+        } else if branchTransaction == nil {
+            return false, nil
+        }
+
+        // abort if branch transaction is not solid
+        if branchTransactionMetadata, err := branchTransaction.GetMetaData(); err != nil {
+            return false, err
+        } else if !branchTransactionMetadata.GetSolid() {
+            return false, nil
+        }
+    }
+
+    // check solidity of branch transaction if it is not genesis
+    if trunkTransactionHash := transaction.GetBranchTransactionHash(); trunkTransactionHash != ternary.Trinary("999999") {
+        // abort if trunk transaction is missing
+        trunkTransaction, err := GetTransaction(trunkTransactionHash)
+        if err != nil {
+            return false, err
+        } else if trunkTransaction == nil {
+            return false, nil
+        }
+
+        // abort if trunk transaction is not solid
+        if trunkTransactionMetadata, err := trunkTransaction.GetMetaData(); err != nil {
+            return false, err
+        } else if !trunkTransactionMetadata.GetSolid() {
+            return false, nil
+        }
+    }
+
+    // propagate solidity to all approvers
+    txMetadata.SetSolid(true)
+
+    return true, nil
+}
\ No newline at end of file
diff --git a/plugins/tangle/transaction.go b/plugins/tangle/transaction.go
new file mode 100644
index 0000000000000000000000000000000000000000..034eb0d177a613a82a05789bd0d57c05cd429021
--- /dev/null
+++ b/plugins/tangle/transaction.go
@@ -0,0 +1,644 @@
+package tangle
+
+import (
+    "github.com/iotaledger/goshimmer/packages/errors"
+    "github.com/iotaledger/goshimmer/packages/ternary"
+    "github.com/iotaledger/goshimmer/packages/transaction"
+    "sync"
+)
+
+// region type definition and constructor //////////////////////////////////////////////////////////////////////////////
+
+type Transaction struct {
+    // wrapped objects
+    rawTransaction   *transaction.Transaction
+    rawMetaData      *TransactionMetadata
+    rawMetaDataMutex sync.RWMutex
+
+    // mapped raw transaction properties
+    hash                          *ternary.Trinary
+    hashMutex                     sync.RWMutex
+    signatureMessageFragment      *ternary.Trinary
+    signatureMessageFragmentMutex sync.RWMutex
+    address                       *ternary.Trinary
+    addressMutex                  sync.RWMutex
+    value                         *int64
+    valueMutex                    sync.RWMutex
+    timestamp                     *uint64
+    timestampMutex                sync.RWMutex
+    currentIndex                  *uint64
+    currentIndexMutex             sync.RWMutex
+    latestIndex                   *uint64
+    latestIndexMutex              sync.RWMutex
+    bundleHash                    *ternary.Trinary
+    bundleHashMutex               sync.RWMutex
+    trunkTransactionHash          *ternary.Trinary
+    trunkTransactionHashMutex     sync.RWMutex
+    branchTransactionHash         *ternary.Trinary
+    branchTransactionHashMutex    sync.RWMutex
+    tag                           *ternary.Trinary
+    tagMutex                      sync.RWMutex
+    nonce                         *ternary.Trinary
+    nonceMutex                    sync.RWMutex
+
+    // additional runtime specific metadata
+    modified      bool
+    modifiedMutex sync.RWMutex
+}
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// region getters and setters //////////////////////////////////////////////////////////////////////////////////////////
+
+func (transaction *Transaction) GetMetaData() (*TransactionMetadata, errors.IdentifiableError) {
+    transaction.rawMetaDataMutex.RLock()
+    if transaction.rawMetaData == nil {
+        transaction.rawMetaDataMutex.RUnlock()
+        transaction.rawMetaDataMutex.Lock()
+        defer transaction.rawMetaDataMutex.Unlock()
+        if transaction.rawMetaData == nil {
+            if metaData, err := getTransactionMetadataFromDatabase(transaction.GetHash()); err != nil {
+                return nil, err
+            } else if metaData == nil {
+                transaction.rawMetaData = NewTransactionMetadata(transaction.GetHash())
+            } else {
+                transaction.rawMetaData = metaData
+            }
+
+            return transaction.rawMetaData, nil
+        }
+    }
+
+    defer transaction.rawMetaDataMutex.RUnlock()
+
+    return transaction.rawMetaData, nil
+}
+
+// getter for the hash (supports concurrency)
+func (transaction *Transaction) GetHash() ternary.Trinary {
+    transaction.hashMutex.RLock()
+    if transaction.hash == nil {
+        transaction.hashMutex.RUnlock()
+        transaction.hashMutex.Lock()
+        defer transaction.hashMutex.Unlock()
+        if transaction.hash == nil {
+            return transaction.parseHash()
+        }
+    }
+
+    defer transaction.hashMutex.RUnlock()
+
+    return *transaction.hash
+}
+
+// setter for the hash (supports concurrency)
+func (transaction *Transaction) SetHash(hash ternary.Trinary) {
+    transaction.hashMutex.RLock()
+    if transaction.hash == nil || *transaction.hash != hash {
+        transaction.hashMutex.RUnlock()
+        transaction.hashMutex.Lock()
+        defer transaction.hashMutex.Unlock()
+        if transaction.hash == nil || *transaction.hash != hash {
+            *transaction.hash = hash
+
+            transaction.SetModified(true)
+        }
+    } else {
+        transaction.hashMutex.RUnlock()
+    }
+}
+
+// restores the hash from the underlying raw transaction (supports concurrency)
+func (transaction *Transaction) ParseHash() ternary.Trinary {
+    transaction.hashMutex.Lock()
+    defer transaction.hashMutex.Unlock()
+
+    return transaction.parseHash()
+}
+
+// parses the hash from the underlying raw transaction (without locking - internal usage)
+func (transaction *Transaction) parseHash() ternary.Trinary {
+    *transaction.hash = transaction.rawTransaction.Hash.ToTrinary()
+
+    return *transaction.hash
+}
+
+// getter for the address (supports concurrency)
+func (transaction *Transaction) GetAddress() ternary.Trinary {
+    transaction.addressMutex.RLock()
+    if transaction.address == nil {
+        transaction.addressMutex.RUnlock()
+        transaction.addressMutex.Lock()
+        defer transaction.addressMutex.Unlock()
+        if transaction.address == nil {
+            return transaction.parseAddress()
+        }
+    }
+
+    defer transaction.addressMutex.RUnlock()
+
+    return *transaction.address
+}
+
+// setter for the address (supports concurrency)
+func (transaction *Transaction) SetAddress(address ternary.Trinary) {
+    transaction.addressMutex.RLock()
+    if transaction.address == nil || *transaction.address != address {
+        transaction.addressMutex.RUnlock()
+        transaction.addressMutex.Lock()
+        defer transaction.addressMutex.Unlock()
+        if transaction.address == nil || *transaction.address != address {
+            *transaction.address = address
+
+            transaction.SetModified(true)
+        }
+    } else {
+        transaction.addressMutex.RUnlock()
+    }
+}
+
+// restores the address from the underlying raw transaction (supports concurrency)
+func (transaction *Transaction) ParseAddress() ternary.Trinary {
+    transaction.addressMutex.Lock()
+    defer transaction.addressMutex.Unlock()
+
+    return transaction.parseAddress()
+}
+
+// parses the address from the underlying raw transaction (without locking - internal usage)
+func (transaction *Transaction) parseAddress() ternary.Trinary {
+    *transaction.address = transaction.rawTransaction.Hash.ToTrinary()
+
+    return *transaction.address
+}
+
+// getter for the value (supports concurrency)
+func (transaction *Transaction) GetValue() int64 {
+    transaction.valueMutex.RLock()
+    if transaction.value == nil {
+        transaction.valueMutex.RUnlock()
+        transaction.valueMutex.Lock()
+        defer transaction.valueMutex.Unlock()
+        if transaction.value == nil {
+            return transaction.parseValue()
+        }
+    }
+
+    defer transaction.valueMutex.RUnlock()
+
+    return *transaction.value
+}
+
+// setter for the value (supports concurrency)
+func (transaction *Transaction) SetValue(value int64) {
+    transaction.valueMutex.RLock()
+    if transaction.value == nil || *transaction.value != value {
+        transaction.valueMutex.RUnlock()
+        transaction.valueMutex.Lock()
+        defer transaction.valueMutex.Unlock()
+        if transaction.value == nil || *transaction.value != value {
+            *transaction.value = value
+
+            transaction.SetModified(true)
+        }
+    } else {
+        transaction.valueMutex.RUnlock()
+    }
+}
+
+// restores the value from the underlying raw transaction (supports concurrency)
+func (transaction *Transaction) ParseValue() int64 {
+    transaction.valueMutex.Lock()
+    defer transaction.valueMutex.Unlock()
+
+    return transaction.parseValue()
+}
+
+// parses the value from the underlying raw transaction (without locking - internal usage)
+func (transaction *Transaction) parseValue() int64 {
+    *transaction.value = transaction.rawTransaction.Value.ToInt64()
+
+    return *transaction.value
+}
+
+// getter for the timestamp (supports concurrency)
+func (transaction *Transaction) GetTimestamp() uint64 {
+    transaction.timestampMutex.RLock()
+    if transaction.timestamp == nil {
+        transaction.timestampMutex.RUnlock()
+        transaction.timestampMutex.Lock()
+        defer transaction.timestampMutex.Unlock()
+        if transaction.timestamp == nil {
+            return transaction.parseTimestamp()
+        }
+    }
+
+    defer transaction.timestampMutex.RUnlock()
+
+    return *transaction.timestamp
+}
+
+// setter for the timestamp (supports concurrency)
+func (transaction *Transaction) SetTimestamp(timestamp uint64) {
+    transaction.timestampMutex.RLock()
+    if transaction.timestamp == nil || *transaction.timestamp != timestamp {
+        transaction.timestampMutex.RUnlock()
+        transaction.timestampMutex.Lock()
+        defer transaction.timestampMutex.Unlock()
+        if transaction.timestamp == nil || *transaction.timestamp != timestamp {
+            *transaction.timestamp = timestamp
+
+            transaction.SetModified(true)
+        }
+    } else {
+        transaction.timestampMutex.RUnlock()
+    }
+}
+
+// restores the timestamp from the underlying raw transaction (supports concurrency)
+func (transaction *Transaction) ParseTimestamp() uint64 {
+    transaction.timestampMutex.Lock()
+    defer transaction.timestampMutex.Unlock()
+
+    return transaction.parseTimestamp()
+}
+
+// parses the timestamp from the underlying raw transaction (without locking - internal usage)
+func (transaction *Transaction) parseTimestamp() uint64 {
+    *transaction.timestamp = transaction.rawTransaction.Timestamp.ToUint64()
+
+    return *transaction.timestamp
+}
+
+// getter for the currentIndex (supports concurrency)
+func (transaction *Transaction) GetCurrentIndex() uint64 {
+    transaction.currentIndexMutex.RLock()
+    if transaction.currentIndex == nil {
+        transaction.currentIndexMutex.RUnlock()
+        transaction.currentIndexMutex.Lock()
+        defer transaction.currentIndexMutex.Unlock()
+        if transaction.currentIndex == nil {
+            return transaction.parseCurrentIndex()
+        }
+    }
+
+    defer transaction.currentIndexMutex.RUnlock()
+
+    return *transaction.currentIndex
+}
+
+// setter for the currentIndex (supports concurrency)
+func (transaction *Transaction) SetCurrentIndex(currentIndex uint64) {
+    transaction.currentIndexMutex.RLock()
+    if transaction.currentIndex == nil || *transaction.currentIndex != currentIndex {
+        transaction.currentIndexMutex.RUnlock()
+        transaction.currentIndexMutex.Lock()
+        defer transaction.currentIndexMutex.Unlock()
+        if transaction.currentIndex == nil || *transaction.currentIndex != currentIndex {
+            *transaction.currentIndex = currentIndex
+
+            transaction.SetModified(true)
+        }
+    } else {
+        transaction.currentIndexMutex.RUnlock()
+    }
+}
+
+// restores the currentIndex from the underlying raw transaction (supports concurrency)
+func (transaction *Transaction) ParseCurrentIndex() uint64 {
+    transaction.currentIndexMutex.Lock()
+    defer transaction.currentIndexMutex.Unlock()
+
+    return transaction.parseCurrentIndex()
+}
+
+// parses the currentIndex from the underlying raw transaction (without locking - internal usage)
+func (transaction *Transaction) parseCurrentIndex() uint64 {
+    *transaction.currentIndex = transaction.rawTransaction.CurrentIndex.ToUint64()
+
+    return *transaction.currentIndex
+}
+
+// getter for the latestIndex (supports concurrency)
+func (transaction *Transaction) GetLatestIndex() uint64 {
+    transaction.latestIndexMutex.RLock()
+    if transaction.latestIndex == nil {
+        transaction.latestIndexMutex.RUnlock()
+        transaction.latestIndexMutex.Lock()
+        defer transaction.latestIndexMutex.Unlock()
+        if transaction.latestIndex == nil {
+            return transaction.parseLatestIndex()
+        }
+    }
+
+    defer transaction.latestIndexMutex.RUnlock()
+
+    return *transaction.latestIndex
+}
+
+// setter for the latestIndex (supports concurrency)
+func (transaction *Transaction) SetLatestIndex(latestIndex uint64) {
+    transaction.latestIndexMutex.RLock()
+    if transaction.latestIndex == nil || *transaction.latestIndex != latestIndex {
+        transaction.latestIndexMutex.RUnlock()
+        transaction.latestIndexMutex.Lock()
+        defer transaction.latestIndexMutex.Unlock()
+        if transaction.latestIndex == nil || *transaction.latestIndex != latestIndex {
+            *transaction.latestIndex = latestIndex
+
+            transaction.SetModified(true)
+        }
+    } else {
+        transaction.latestIndexMutex.RUnlock()
+    }
+}
+
+// restores the latestIndex from the underlying raw transaction (supports concurrency)
+func (transaction *Transaction) ParseLatestIndex() uint64 {
+    transaction.latestIndexMutex.Lock()
+    defer transaction.latestIndexMutex.Unlock()
+
+    return transaction.parseLatestIndex()
+}
+
+// parses the latestIndex from the underlying raw transaction (without locking - internal usage)
+func (transaction *Transaction) parseLatestIndex() uint64 {
+    *transaction.latestIndex = transaction.rawTransaction.LatestIndex.ToUint64()
+
+    return *transaction.latestIndex
+}
+
+// getter for the bundleHash (supports concurrency)
+func (transaction *Transaction) GetBundleHash() ternary.Trinary {
+    transaction.bundleHashMutex.RLock()
+    if transaction.bundleHash == nil {
+        transaction.bundleHashMutex.RUnlock()
+        transaction.bundleHashMutex.Lock()
+        defer transaction.bundleHashMutex.Unlock()
+        if transaction.bundleHash == nil {
+            return transaction.parseBundleHash()
+        }
+    }
+
+    defer transaction.bundleHashMutex.RUnlock()
+
+    return *transaction.bundleHash
+}
+
+// setter for the bundleHash (supports concurrency)
+func (transaction *Transaction) SetBundleHash(bundleHash ternary.Trinary) {
+    transaction.bundleHashMutex.RLock()
+    if transaction.bundleHash == nil || *transaction.bundleHash != bundleHash {
+        transaction.bundleHashMutex.RUnlock()
+        transaction.bundleHashMutex.Lock()
+        defer transaction.bundleHashMutex.Unlock()
+        if transaction.bundleHash == nil || *transaction.bundleHash != bundleHash {
+            *transaction.bundleHash = bundleHash
+
+            transaction.SetModified(true)
+        }
+    } else {
+        transaction.bundleHashMutex.RUnlock()
+    }
+}
+
+// restores the bundleHash from the underlying raw transaction (supports concurrency)
+func (transaction *Transaction) ParseBundleHash() ternary.Trinary {
+    transaction.bundleHashMutex.Lock()
+    defer transaction.bundleHashMutex.Unlock()
+
+    return transaction.parseBundleHash()
+}
+
+// parses the bundleHash from the underlying raw transaction (without locking - internal usage)
+func (transaction *Transaction) parseBundleHash() ternary.Trinary {
+    *transaction.bundleHash = transaction.rawTransaction.BundleHash.ToTrinary()
+
+    return *transaction.bundleHash
+}
+
+// getter for the trunkTransactionHash (supports concurrency)
+func (transaction *Transaction) GetTrunkTransactionHash() ternary.Trinary {
+    transaction.trunkTransactionHashMutex.RLock()
+    if transaction.trunkTransactionHash == nil {
+        transaction.trunkTransactionHashMutex.RUnlock()
+        transaction.trunkTransactionHashMutex.Lock()
+        defer transaction.trunkTransactionHashMutex.Unlock()
+        if transaction.trunkTransactionHash == nil {
+            return transaction.parseTrunkTransactionHash()
+        }
+    }
+
+    defer transaction.trunkTransactionHashMutex.RUnlock()
+
+    return *transaction.trunkTransactionHash
+}
+
+// setter for the trunkTransactionHash (supports concurrency)
+func (transaction *Transaction) SetTrunkTransactionHash(trunkTransactionHash ternary.Trinary) {
+    transaction.trunkTransactionHashMutex.RLock()
+    if transaction.trunkTransactionHash == nil || *transaction.trunkTransactionHash != trunkTransactionHash {
+        transaction.trunkTransactionHashMutex.RUnlock()
+        transaction.trunkTransactionHashMutex.Lock()
+        defer transaction.trunkTransactionHashMutex.Unlock()
+        if transaction.trunkTransactionHash == nil || *transaction.trunkTransactionHash != trunkTransactionHash {
+            *transaction.trunkTransactionHash = trunkTransactionHash
+
+            transaction.SetModified(true)
+        }
+    } else {
+        transaction.trunkTransactionHashMutex.RUnlock()
+    }
+}
+
+// restores the trunkTransactionHash from the underlying raw transaction (supports concurrency)
+func (transaction *Transaction) ParseTrunkTransactionHash() ternary.Trinary {
+    transaction.trunkTransactionHashMutex.Lock()
+    defer transaction.trunkTransactionHashMutex.Unlock()
+
+    return transaction.parseTrunkTransactionHash()
+}
+
+// parses the trunkTransactionHash from the underlying raw transaction (without locking - internal usage)
+func (transaction *Transaction) parseTrunkTransactionHash() ternary.Trinary {
+    *transaction.trunkTransactionHash = transaction.rawTransaction.TrunkTransactionHash.ToTrinary()
+
+    return *transaction.trunkTransactionHash
+}
+
+// getter for the branchTransactionHash (supports concurrency)
+func (transaction *Transaction) GetBranchTransactionHash() ternary.Trinary {
+    transaction.branchTransactionHashMutex.RLock()
+    if transaction.branchTransactionHash == nil {
+        transaction.branchTransactionHashMutex.RUnlock()
+        transaction.branchTransactionHashMutex.Lock()
+        defer transaction.branchTransactionHashMutex.Unlock()
+        if transaction.branchTransactionHash == nil {
+            return transaction.parseBranchTransactionHash()
+        }
+    }
+
+    defer transaction.branchTransactionHashMutex.RUnlock()
+
+    return *transaction.branchTransactionHash
+}
+
+// setter for the branchTransactionHash (supports concurrency)
+func (transaction *Transaction) SetBranchTransactionHash(branchTransactionHash ternary.Trinary) {
+    transaction.branchTransactionHashMutex.RLock()
+    if transaction.branchTransactionHash == nil || *transaction.branchTransactionHash != branchTransactionHash {
+        transaction.branchTransactionHashMutex.RUnlock()
+        transaction.branchTransactionHashMutex.Lock()
+        defer transaction.branchTransactionHashMutex.Unlock()
+        if transaction.branchTransactionHash == nil || *transaction.branchTransactionHash != branchTransactionHash {
+            *transaction.branchTransactionHash = branchTransactionHash
+
+            transaction.SetModified(true)
+        }
+    } else {
+        transaction.branchTransactionHashMutex.RUnlock()
+    }
+}
+
+// restores the branchTransactionHash from the underlying raw transaction (supports concurrency)
+func (transaction *Transaction) ParseBranchTransactionHash() ternary.Trinary {
+    transaction.branchTransactionHashMutex.Lock()
+    defer transaction.branchTransactionHashMutex.Unlock()
+
+    return transaction.parseBranchTransactionHash()
+}
+
+// parses the branchTransactionHash from the underlying raw transaction (without locking - internal usage)
+func (transaction *Transaction) parseBranchTransactionHash() ternary.Trinary {
+    *transaction.branchTransactionHash = transaction.rawTransaction.BranchTransactionHash.ToTrinary()
+
+    return *transaction.branchTransactionHash
+}
+
+// getter for the tag (supports concurrency)
+func (transaction *Transaction) GetTag() ternary.Trinary {
+    transaction.tagMutex.RLock()
+    if transaction.tag == nil {
+        transaction.tagMutex.RUnlock()
+        transaction.tagMutex.Lock()
+        defer transaction.tagMutex.Unlock()
+        if transaction.tag == nil {
+            return transaction.parseTag()
+        }
+    }
+
+    defer transaction.tagMutex.RUnlock()
+
+    return *transaction.tag
+}
+
+// setter for the tag (supports concurrency)
+func (transaction *Transaction) SetTag(tag ternary.Trinary) {
+    transaction.tagMutex.RLock()
+    if transaction.tag == nil || *transaction.tag != tag {
+        transaction.tagMutex.RUnlock()
+        transaction.tagMutex.Lock()
+        defer transaction.tagMutex.Unlock()
+        if transaction.tag == nil || *transaction.tag != tag {
+            *transaction.tag = tag
+
+            transaction.SetModified(true)
+        }
+    } else {
+        transaction.tagMutex.RUnlock()
+    }
+}
+
+// restores the tag from the underlying raw transaction (supports concurrency)
+func (transaction *Transaction) ParseTag() ternary.Trinary {
+    transaction.tagMutex.Lock()
+    defer transaction.tagMutex.Unlock()
+
+    return transaction.parseTag()
+}
+
+// parses the tag from the underlying raw transaction (without locking - internal usage)
+func (transaction *Transaction) parseTag() ternary.Trinary {
+    *transaction.tag = transaction.rawTransaction.Tag.ToTrinary()
+
+    return *transaction.tag
+}
+
+// getter for the nonce (supports concurrency)
+func (transaction *Transaction) GetNonce() ternary.Trinary {
+    transaction.nonceMutex.RLock()
+    if transaction.nonce == nil {
+        transaction.nonceMutex.RUnlock()
+        transaction.nonceMutex.Lock()
+        defer transaction.nonceMutex.Unlock()
+        if transaction.nonce == nil {
+            return transaction.parseNonce()
+        }
+    }
+
+    defer transaction.nonceMutex.RUnlock()
+
+    return *transaction.nonce
+}
+
+// setter for the nonce (supports concurrency)
+func (transaction *Transaction) SetNonce(nonce ternary.Trinary) {
+    transaction.nonceMutex.RLock()
+    if transaction.nonce == nil || *transaction.nonce != nonce {
+        transaction.nonceMutex.RUnlock()
+        transaction.nonceMutex.Lock()
+        defer transaction.nonceMutex.Unlock()
+        if transaction.nonce == nil || *transaction.nonce != nonce {
+            *transaction.nonce = nonce
+
+            transaction.SetModified(true)
+        }
+    } else {
+        transaction.nonceMutex.RUnlock()
+    }
+}
+
+// restores the nonce from the underlying raw transaction (supports concurrency)
+func (transaction *Transaction) ParseNonce() ternary.Trinary {
+    transaction.nonceMutex.Lock()
+    defer transaction.nonceMutex.Unlock()
+
+    return transaction.parseNonce()
+}
+
+// parses the nonce from the underlying raw transaction (without locking - internal usage)
+func (transaction *Transaction) parseNonce() ternary.Trinary {
+    *transaction.nonce = transaction.rawTransaction.Nonce.ToTrinary()
+
+    return *transaction.nonce
+}
+
+// returns true if the transaction contains unsaved changes (supports concurrency)
+func (transaction *Transaction) GetModified() bool {
+    transaction.modifiedMutex.RLock()
+    defer transaction.modifiedMutex.RUnlock()
+
+    return transaction.modified
+}
+
+// sets the modified flag which controls if a transaction is going to be saved (supports concurrency)
+func (transaction *Transaction) SetModified(modified bool) {
+    transaction.modifiedMutex.Lock()
+    defer transaction.modifiedMutex.Unlock()
+
+    transaction.modified = modified
+}
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// region database functions ///////////////////////////////////////////////////////////////////////////////////////////
+
+func (transaction *Transaction) Store() errors.IdentifiableError {
+    if err := transactionDatabase.Set(transaction.rawTransaction.Hash.ToBytes(), transaction.rawTransaction.Bytes); err != nil {
+        return ErrDatabaseError.Derive(err, "failed to store the transaction")
+    }
+
+    return nil
+}
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/plugins/tangle/transaction_metadata.go b/plugins/tangle/transaction_metadata.go
new file mode 100644
index 0000000000000000000000000000000000000000..ce0e7f08ddf00be51c8365aa1d4a39bf10cba000
--- /dev/null
+++ b/plugins/tangle/transaction_metadata.go
@@ -0,0 +1,287 @@
+package tangle
+
+import (
+    "github.com/iotaledger/goshimmer/packages/bitutils"
+    "github.com/iotaledger/goshimmer/packages/errors"
+    "github.com/iotaledger/goshimmer/packages/ternary"
+    "github.com/iotaledger/goshimmer/packages/typeconversion"
+    "sync"
+    "time"
+)
+
+// 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 NewTransactionMetadata(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) {
+    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)
+        }
+    } else {
+        metaData.solidMutex.RUnlock()
+    }
+}
+
+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 marshalling functions ////////////////////////////////////////////////////////////////////////////////////////
+
+func (metadata *TransactionMetadata) Marshal() ([]byte, errors.IdentifiableError) {
+    marshalledMetadata := make([]byte, MARSHALLED_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(marshalledMetadata[MARSHALLED_HASH_START:MARSHALLED_HASH_END], metadata.hash.CastToBytes())
+
+    marshalledReceivedTime, err := metadata.receivedTime.MarshalBinary()
+    if err != nil {
+        return nil, ErrMarshallFailed.Derive(err, "failed to marshal received time")
+    }
+    copy(marshalledMetadata[MARSHALLED_RECEIVED_TIME_START:MARSHALLED_RECEIVED_TIME_END], marshalledReceivedTime)
+
+    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)
+    }
+    marshalledMetadata[MARSHALLED_FLAGS_START] = byte(booleanFlags)
+
+    return marshalledMetadata, 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(typeconversion.BytesToString(data[MARSHALLED_HASH_START:MARSHALLED_HASH_END]))
+
+    if err := metadata.receivedTime.UnmarshalBinary(data[MARSHALLED_RECEIVED_TIME_START:MARSHALLED_RECEIVED_TIME_END]); err != nil {
+        return ErrUnmarshalFailed.Derive(err, "could not unmarshal the received time")
+    }
+
+    booleanFlags := bitutils.BitMask(data[MARSHALLED_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 ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// region database functions ///////////////////////////////////////////////////////////////////////////////////////////
+
+func (metadata *TransactionMetadata) Store() 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 the transaction")
+        }
+
+        metadata.SetModified(false)
+    }
+
+    return nil
+}
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// region constants and variables //////////////////////////////////////////////////////////////////////////////////////
+
+const (
+    MARSHALLED_HASH_START          = 0
+    MARSHALLED_RECEIVED_TIME_START = MARSHALLED_HASH_END
+    MARSHALLED_FLAGS_START         = MARSHALLED_RECEIVED_TIME_END
+
+    MARSHALLED_HASH_END          = MARSHALLED_HASH_START + MARSHALLED_HASH_SIZE
+    MARSHALLED_RECEIVED_TIME_END = MARSHALLED_RECEIVED_TIME_START + MARSHALLED_RECEIVED_TIME_SIZE
+    MARSHALLED_FLAGS_END         = MARSHALLED_FLAGS_START + MARSHALLED_FLAGS_SIZE
+
+    MARSHALLED_HASH_SIZE          = 81
+    MARSHALLED_RECEIVED_TIME_SIZE = 15
+    MARSHALLED_FLAGS_SIZE         = 1
+
+    MARSHALLED_TOTAL_SIZE = MARSHALLED_FLAGS_END
+)
+
+// endregion ////////////////////////////////////////////////////////////////////////////////////////////////////////////