diff --git a/go.mod b/go.mod
index d65cf1acc15f196883e4bc197833e596c55f3781..6f415327efd874ccdf06ab1a92b2a60dae45e273 100644
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,7 @@ go 1.13
 require (
 	github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
 	github.com/dgraph-io/badger v1.6.0
+	github.com/dgraph-io/badger/v2 v2.0.0
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/emicklei/dot v0.10.1
 	github.com/ethereum/go-ethereum v1.9.3
@@ -14,7 +15,7 @@ require (
 	github.com/golang/protobuf v1.3.2 // indirect
 	github.com/google/open-location-code/go v0.0.0-20190903173953-119bc96a3a51
 	github.com/gorilla/websocket v1.4.1
-	github.com/iotaledger/hive.go v0.0.0-20191227143712-0ef454eb5509
+	github.com/iotaledger/hive.go v0.0.0-20200101211541-ea7950f4c2f2
 	github.com/iotaledger/iota.go v1.0.0-beta.9
 	github.com/kr/text v0.1.0
 	github.com/labstack/echo v3.3.10+incompatible
@@ -23,11 +24,11 @@ require (
 	github.com/mr-tron/base58 v1.1.3
 	github.com/oasislabs/ed25519 v0.0.0-20191122104632-9d9ffc15f526
 	github.com/panjf2000/ants/v2 v2.2.2
-	github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
 	github.com/pkg/errors v0.8.1
 	github.com/rivo/tview v0.0.0-20190829161255-f8bc69b90341
 	github.com/rivo/uniseg v0.1.0 // indirect
-	github.com/sasha-s/go-deadlock v0.2.0 // indirect
+	github.com/spf13/pflag v1.0.5
+	github.com/spf13/viper v1.5.0
 	github.com/stretchr/testify v1.4.0
 	golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba
 	golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297
diff --git a/go.sum b/go.sum
index 432405f948c81be01dfc2ef19b9c15430ee6f46d..87df5300ce1af58a0f0951ba3eeaf0a71e2274ad 100644
--- a/go.sum
+++ b/go.sum
@@ -6,6 +6,8 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08=
 github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
+github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
+github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -13,6 +15,7 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5
 github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
@@ -28,6 +31,10 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
 github.com/dgraph-io/badger v1.5.4/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ=
 github.com/dgraph-io/badger v1.6.0 h1:DshxFxZWXUcO0xX476VJC07Xsr6ZCBVRHKZ93Oh7Evo=
 github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
+github.com/dgraph-io/badger/v2 v2.0.0 h1:Cr05o2TUd2IcLbEY0aGd8mbjm1YyQpy+dswo3BcDXrE=
+github.com/dgraph-io/badger/v2 v2.0.0/go.mod h1:YoRSIp1LmAJ7zH7tZwRvjNMUYLxB4wl3ebYkaIruZ04=
+github.com/dgraph-io/ristretto v0.0.0-20191025175511-c1f00be0418e h1:aeUNgwup7PnDOBAD1BOKAqzb/W/NksOj6r3dwKKuqfg=
+github.com/dgraph-io/ristretto v0.0.0-20191025175511-c1f00be0418e/go.mod h1:edzKIzGvqUCMzhTVWbiTSe75zD9Xxq0GtSBtFmaUTZs=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgryski/go-farm v0.0.0-20190323231341-8198c7b169ec/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
@@ -64,6 +71,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -85,6 +93,14 @@ github.com/iotaledger/hive.go v0.0.0-20191208004610-567900b261bd h1:hh8iusLOBylW
 github.com/iotaledger/hive.go v0.0.0-20191208004610-567900b261bd/go.mod h1:7iqun29a1x0lymTrn0UJ3Z/yy0sUzUpoOZ1OYMrYN20=
 github.com/iotaledger/hive.go v0.0.0-20191227143712-0ef454eb5509 h1:5mztG+IZqH6Y25YVxf+oXMBhtUWDBXnobjTnz4dW82c=
 github.com/iotaledger/hive.go v0.0.0-20191227143712-0ef454eb5509/go.mod h1:7iqun29a1x0lymTrn0UJ3Z/yy0sUzUpoOZ1OYMrYN20=
+github.com/iotaledger/hive.go v0.0.0-20191229015822-a119170bec84 h1:pZawocQ/B7HQYhizd9CANf42vqPhdd+P1Xg12ORR6cY=
+github.com/iotaledger/hive.go v0.0.0-20191229015822-a119170bec84/go.mod h1:7iqun29a1x0lymTrn0UJ3Z/yy0sUzUpoOZ1OYMrYN20=
+github.com/iotaledger/hive.go v0.0.0-20191229233341-c3732738ee20 h1:ZIJAeQSEdmVbmZNIW2198IwD23+wBteb4WE4pyjxk+c=
+github.com/iotaledger/hive.go v0.0.0-20191229233341-c3732738ee20/go.mod h1:7iqun29a1x0lymTrn0UJ3Z/yy0sUzUpoOZ1OYMrYN20=
+github.com/iotaledger/hive.go v0.0.0-20200101185538-ae70241fee7f h1:vxfLVJOsHHEbsooLij/JN+ues0AglB1pB8Dui/C3TUg=
+github.com/iotaledger/hive.go v0.0.0-20200101185538-ae70241fee7f/go.mod h1:vrZrvGaWT1o5kz3Jj2B/PcUtqsFzZnLWrO3zEsGSuwk=
+github.com/iotaledger/hive.go v0.0.0-20200101211541-ea7950f4c2f2 h1:S84ohGcHKq6NFOY77HUXLvqYfOveJhzzphSeimTUtTw=
+github.com/iotaledger/hive.go v0.0.0-20200101211541-ea7950f4c2f2/go.mod h1:vrZrvGaWT1o5kz3Jj2B/PcUtqsFzZnLWrO3zEsGSuwk=
 github.com/iotaledger/iota.go v1.0.0-beta.9 h1:c654s9pkdhMBkABUvWg+6k91MEBbdtmZXP1xDfQpajg=
 github.com/iotaledger/iota.go v1.0.0-beta.9/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
@@ -163,6 +179,7 @@ github.com/simia-tech/env v0.1.0/go.mod h1:eVRQ7W5NXXHifpPAcTJ3r5EmoGgMn++dXfSVb
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
 github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
@@ -257,6 +274,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 gopkg.in/h2non/gock.v1 v1.0.14/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
diff --git a/packages/binary/tangle/solidifier.go b/packages/binary/tangle/solidifier.go
new file mode 100644
index 0000000000000000000000000000000000000000..417b6033fff4b4ce617b21a62c300f7986df7e2c
--- /dev/null
+++ b/packages/binary/tangle/solidifier.go
@@ -0,0 +1,128 @@
+package tangle
+
+import (
+	"container/list"
+
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/approvers"
+	"github.com/iotaledger/goshimmer/packages/binary/transaction"
+	"github.com/iotaledger/goshimmer/packages/binary/transactionmetadata"
+	"github.com/iotaledger/hive.go/async"
+	"github.com/iotaledger/hive.go/objectstorage"
+)
+
+type solidifier struct {
+	tangle *Tangle
+
+	workerPool async.WorkerPool
+}
+
+func newSolidifier(tangle *Tangle) (result *solidifier) {
+	result = &solidifier{
+		tangle: tangle,
+	}
+
+	result.workerPool.Tune(1024)
+
+	return
+}
+
+func (solidifier *solidifier) Shutdown() {
+	solidifier.workerPool.ShutdownGracefully()
+}
+
+func (solidifier *solidifier) Solidify(cachedTransaction *objectstorage.CachedObject, cachedTransactionMetadata *objectstorage.CachedObject) {
+	solidifier.workerPool.Submit(func() { solidifier.solidify(cachedTransaction, cachedTransactionMetadata) })
+}
+
+func (solidifier *solidifier) solidify(cachedTransaction *objectstorage.CachedObject, cachedTransactionMetadata *objectstorage.CachedObject) {
+	// initialize the stack
+	solidificationStack := list.New()
+	solidificationStack.PushBack([2]*objectstorage.CachedObject{cachedTransaction, cachedTransactionMetadata})
+
+	// process transactions that are supposed to be checked for solidity recursively
+	for solidificationStack.Len() > 0 {
+		// pop first element from stack
+		currentSolidificationEntry := solidificationStack.Front()
+		currentCachedTransaction := currentSolidificationEntry.Value.([2]*objectstorage.CachedObject)[0]
+		currentCachedTransactionMetadata := currentSolidificationEntry.Value.([2]*objectstorage.CachedObject)[1]
+		solidificationStack.Remove(currentSolidificationEntry)
+
+		// retrieve transaction from cached result
+		var currentTransaction *transaction.Transaction
+		if _tmp := currentCachedTransaction.Get(); _tmp != nil {
+			currentTransaction = _tmp.(*transaction.Transaction)
+		} else {
+			currentCachedTransaction.Release()
+			currentCachedTransactionMetadata.Release()
+
+			continue
+		}
+
+		// retrieve metadata from cached result
+		var currentTransactionMetadata *transactionmetadata.TransactionMetadata
+		if _tmp := currentCachedTransactionMetadata.Get(); _tmp != nil {
+			currentTransactionMetadata = _tmp.(*transactionmetadata.TransactionMetadata)
+		} else {
+			currentCachedTransaction.Release()
+			currentCachedTransactionMetadata.Release()
+
+			continue
+		}
+
+		// if current transaction is solid and was not marked as solid before: mark as solid and propagate
+		if solidifier.isTransactionSolid(currentTransaction, currentTransactionMetadata) && currentTransactionMetadata.SetSolid(true) {
+			// fmt.Println("SOLID", currentTransaction.GetId())
+
+			solidifier.tangle.GetApprovers(currentTransaction.GetId()).Consume(func(object objectstorage.StorableObject) {
+				for approverTransactionId := range object.(*approvers.Approvers).Get() {
+					solidificationStack.PushBack([2]*objectstorage.CachedObject{
+						solidifier.tangle.GetTransaction(approverTransactionId),
+						solidifier.tangle.GetTransactionMetadata(approverTransactionId),
+					})
+				}
+			})
+		}
+
+		// release cached results
+		currentCachedTransaction.Release()
+		currentCachedTransactionMetadata.Release()
+	}
+}
+
+func (solidifier *solidifier) isTransactionSolid(transaction *transaction.Transaction, transactionMetadata *transactionmetadata.TransactionMetadata) bool {
+	if transaction == nil || transaction.IsDeleted() {
+		return false
+	}
+
+	if transactionMetadata == nil || transactionMetadata.IsDeleted() {
+		return false
+	}
+
+	if transactionMetadata.IsSolid() {
+		return true
+	}
+
+	// 1. check tangle solidity
+	if solidifier.isTransactionSolidInTangle(transaction.GetTrunkTransactionId()) && solidifier.isTransactionSolidInTangle(transaction.GetBranchTransactionId()) {
+		// 2. check payload solidity
+		return true
+	}
+
+	return false
+}
+
+func (solidifier *solidifier) isTransactionSolidInTangle(transactionId transaction.Id) bool {
+	if transactionId != transaction.EmptyId {
+		cachedTransactionMetadata := solidifier.tangle.GetTransactionMetadata(transactionId)
+
+		if transactionMetadata := cachedTransactionMetadata.Get().(*transactionmetadata.TransactionMetadata); transactionMetadata == nil || transactionMetadata.IsDeleted() || !transactionMetadata.IsSolid() {
+			cachedTransactionMetadata.Release()
+
+			return false
+		}
+
+		cachedTransactionMetadata.Release()
+	}
+
+	return true
+}
diff --git a/packages/binary/tangle/tangle.go b/packages/binary/tangle/tangle.go
index 5197c2eb9d18697f8af7be141ab91decc5955734..ee1e9cee68f7f389026bc12a3fd022c0274f1990 100644
--- a/packages/binary/tangle/tangle.go
+++ b/packages/binary/tangle/tangle.go
@@ -3,29 +3,119 @@ package tangle
 import (
 	"github.com/iotaledger/goshimmer/packages/binary/tangle/approvers"
 	"github.com/iotaledger/goshimmer/packages/binary/transaction"
+	"github.com/iotaledger/goshimmer/packages/binary/transactionmetadata"
+	"github.com/iotaledger/goshimmer/packages/storageprefix"
+	"github.com/iotaledger/hive.go/async"
 	"github.com/iotaledger/hive.go/objectstorage"
 )
 
 type Tangle struct {
-	transactionStorage *objectstorage.ObjectStorage
-	approversStorage   *objectstorage.ObjectStorage
+	solidifier                 *solidifier
+	transactionStorage         *objectstorage.ObjectStorage
+	transactionMetadataStorage *objectstorage.ObjectStorage
+	approversStorage           *objectstorage.ObjectStorage
+
+	verifyTransactionsWorkerPool async.WorkerPool
+	storeTransactionsWorkerPool  async.WorkerPool
 }
 
-func New(storageId string) *Tangle {
-	return &Tangle{
-		transactionStorage: objectstorage.New(storageId+"TANGLE_TRANSACTION_STORAGE", transactionFactory),
-		approversStorage:   objectstorage.New(storageId+"TANGLE_APPROVERS_STORAGE", approversFactory),
+func New(storageId []byte) (result *Tangle) {
+	result = &Tangle{
+		transactionStorage:         objectstorage.New(append(storageId, storageprefix.TangleTransaction...), transactionFactory),
+		transactionMetadataStorage: objectstorage.New(append(storageId, storageprefix.TangleTransactionMetadata...), transactionFactory),
+		approversStorage:           objectstorage.New(append(storageId, storageprefix.TangleApprovers...), approversFactory),
 	}
+
+	result.solidifier = newSolidifier(result)
+
+	return
 }
 
-func transactionFactory(key []byte) objectstorage.StorableObject {
-	result := transaction.FromStorage(key)
+func (tangle *Tangle) Prune() error {
+	if err := tangle.transactionStorage.Prune(); err != nil {
+		return err
+	}
 
-	return result
+	if err := tangle.transactionMetadataStorage.Prune(); err != nil {
+		return err
+	}
+
+	if err := tangle.approversStorage.Prune(); err != nil {
+		return err
+	}
+
+	return nil
 }
 
-func approversFactory(key []byte) objectstorage.StorableObject {
-	result := approvers.FromStorage(key)
+func (tangle *Tangle) AttachTransaction(transaction *transaction.Transaction) {
+	tangle.verifyTransactionsWorkerPool.Submit(func() { tangle.verifyTransaction(transaction) })
+}
 
-	return result
+func (tangle *Tangle) GetTransaction(transactionId transaction.Id) *objectstorage.CachedObject {
+	return tangle.transactionStorage.Load(transactionId[:])
+}
+
+func (tangle *Tangle) GetTransactionMetadata(transactionId transaction.Id) *objectstorage.CachedObject {
+	return tangle.transactionMetadataStorage.Load(transactionId[:])
+}
+
+func (tangle *Tangle) GetApprovers(transactionId transaction.Id) *objectstorage.CachedObject {
+	return tangle.approversStorage.Load(transactionId[:])
+}
+
+func (tangle *Tangle) verifyTransaction(transaction *transaction.Transaction) {
+	if !transaction.VerifySignature() {
+		// err = errors.New("transaction has invalid signature")
+
+		return
+	}
+
+	tangle.storeTransactionsWorkerPool.Submit(func() { tangle.storeTransaction(transaction) })
+}
+
+func (tangle *Tangle) storeTransaction(transaction *transaction.Transaction) {
+	cachedTransaction, transactionIsNew := tangle.transactionStorage.StoreIfAbsent(transaction.GetStorageKey(), transaction)
+	if !transactionIsNew {
+		return
+	}
+
+	cachedTransactionMetadata := tangle.createTransactionMetadata(transaction)
+
+	tangle.addTransactionToApprovers(transaction, transaction.GetTrunkTransactionId())
+	tangle.addTransactionToApprovers(transaction, transaction.GetBranchTransactionId())
+
+	tangle.solidifier.Solidify(cachedTransaction, cachedTransactionMetadata)
+}
+
+// Marks the tangle as stopped, so it will not accept any new transactions, and then waits for all backgroundTasks to
+// finish.
+func (tangle *Tangle) Shutdown() *Tangle {
+	tangle.verifyTransactionsWorkerPool.ShutdownGracefully()
+	tangle.storeTransactionsWorkerPool.ShutdownGracefully()
+
+	tangle.solidifier.Shutdown()
+
+	return tangle
+}
+
+func (tangle *Tangle) createTransactionMetadata(transaction *transaction.Transaction) *objectstorage.CachedObject {
+	transactionMetadata := transactionmetadata.New(transaction.GetId())
+
+	return tangle.transactionMetadataStorage.Store(transactionMetadata)
+}
+
+func (tangle *Tangle) addTransactionToApprovers(transaction *transaction.Transaction, trunkTransactionId transaction.Id) {
+	tangle.approversStorage.ComputeIfAbsent(trunkTransactionId[:], func([]byte) objectstorage.StorableObject {
+		return approvers.New(trunkTransactionId)
+	}).Consume(func(object objectstorage.StorableObject) {
+		object.(*approvers.Approvers).Add(transaction.GetId())
+	})
+}
+
+func transactionFactory(key []byte) objectstorage.StorableObject {
+	return transaction.FromStorage(key)
+}
+
+func approversFactory(key []byte) objectstorage.StorableObject {
+	return approvers.FromStorage(key)
 }
diff --git a/packages/binary/tangle/tangle_test.go b/packages/binary/tangle/tangle_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..94e19ba97788e7f87bbfd7a25b0a7fd0727db456
--- /dev/null
+++ b/packages/binary/tangle/tangle_test.go
@@ -0,0 +1,58 @@
+package tangle
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/iotaledger/goshimmer/packages/binary/identity"
+	"github.com/iotaledger/goshimmer/packages/binary/transaction"
+	"github.com/iotaledger/goshimmer/packages/binary/transaction/payload/data"
+)
+
+func BenchmarkTangle_AttachTransaction(b *testing.B) {
+	tangle := New([]byte("TEST_BINARY_TANGLE"))
+	if err := tangle.Prune(); err != nil {
+		b.Error(err)
+
+		return
+	}
+
+	transactionBytes := make([][]byte, b.N)
+	for i := 0; i < b.N; i++ {
+		transactionBytes[i] = transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("some data"))).GetBytes()
+	}
+
+	b.ResetTimer()
+
+	for i := 0; i < b.N; i++ {
+		if txToAttach, err := transaction.FromBytes(transactionBytes[i]); err != nil {
+			b.Error(err)
+
+			return
+		} else {
+			tangle.AttachTransaction(txToAttach)
+		}
+	}
+
+	tangle.Shutdown()
+}
+
+func TestTangle_AttachTransaction(t *testing.T) {
+	tangle := New([]byte("TEST_BINARY_TANGLE"))
+	if err := tangle.Prune(); err != nil {
+		t.Error(err)
+
+		return
+	}
+
+	newTransaction1 := transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("some data")))
+	newTransaction2 := transaction.New(newTransaction1.GetId(), transaction.EmptyId, identity.Generate(), data.New([]byte("some other data")))
+
+	fmt.Println("ATTACH", newTransaction2.GetId())
+	tangle.AttachTransaction(newTransaction2)
+
+	fmt.Println("ATTACH", newTransaction1.GetId())
+	tangle.AttachTransaction(newTransaction1)
+
+	tangle.Shutdown()
+}
diff --git a/packages/binary/transaction/test/transaction_test.go b/packages/binary/transaction/test/transaction_test.go
index c04c62b4627198f3db813e98c57e516a161638a1..15a4be905482fb370a11b1f75f134e0cd4095f41 100644
--- a/packages/binary/transaction/test/transaction_test.go
+++ b/packages/binary/transaction/test/transaction_test.go
@@ -2,9 +2,12 @@ package test
 
 import (
 	"fmt"
+	"runtime"
 	"sync"
 	"testing"
 
+	"github.com/iotaledger/goshimmer/packages/binary/async"
+
 	"github.com/iotaledger/goshimmer/packages/binary/signature/ed25119"
 
 	"github.com/iotaledger/goshimmer/packages/ledgerstate/coloredcoins"
@@ -23,6 +26,9 @@ import (
 )
 
 func BenchmarkVerifyDataTransactions(b *testing.B) {
+	var pool async.WorkerPool
+	pool.Tune(runtime.NumCPU() * 2)
+
 	transactions := make([][]byte, b.N)
 	for i := 0; i < b.N; i++ {
 		tx := transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("some data")))
@@ -34,31 +40,26 @@ func BenchmarkVerifyDataTransactions(b *testing.B) {
 		}
 	}
 
-	var wg sync.WaitGroup
-
 	b.ResetTimer()
 
 	for i := 0; i < b.N; i++ {
-		wg.Add(1)
-
 		currentIndex := i
-		if err := ants.Submit(func() {
+		pool.Submit(func() {
 			if tx, err := transaction.FromBytes(transactions[currentIndex]); err != nil {
 				b.Error(err)
 			} else {
 				tx.VerifySignature()
 			}
-
-			wg.Done()
-		}); err != nil {
-			b.Error(err)
-		}
+		})
 	}
 
-	wg.Wait()
+	pool.Shutdown()
 }
 
 func BenchmarkVerifyValueTransactions(b *testing.B) {
+	var pool async.WorkerPool
+	pool.Tune(runtime.NumCPU() * 2)
+
 	keyPairOfSourceAddress := ed25119.GenerateKeyPair()
 	keyPairOfTargetAddress := ed25119.GenerateKeyPair()
 
@@ -76,32 +77,26 @@ func BenchmarkVerifyValueTransactions(b *testing.B) {
 		}
 	}
 
-	var wg sync.WaitGroup
-
 	b.ResetTimer()
 
 	for i := 0; i < b.N; i++ {
-		wg.Add(1)
-
 		currentIndex := i
-		if err := ants.Submit(func() {
+		pool.Submit(func() {
 			if tx, err := transaction.FromBytes(transactions[currentIndex]); err != nil {
 				b.Error(err)
 			} else {
 				tx.VerifySignature()
 				tx.GetPayload().(*valuetransfer.ValueTransfer).VerifySignatures()
 			}
-
-			wg.Done()
-		}); err != nil {
-			b.Error(err)
-		}
+		})
 	}
 
-	wg.Wait()
+	pool.Shutdown()
 }
 
 func BenchmarkVerifySignature(b *testing.B) {
+	pool, _ := ants.NewPool(80, ants.WithNonblocking(false))
+
 	transactions := make([]*transaction.Transaction, b.N)
 	for i := 0; i < b.N; i++ {
 		transactions[i] = transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("test")))
@@ -116,12 +111,14 @@ func BenchmarkVerifySignature(b *testing.B) {
 		wg.Add(1)
 
 		currentIndex := i
-		if err := ants.Submit(func() {
+		if err := pool.Submit(func() {
 			transactions[currentIndex].VerifySignature()
 
 			wg.Done()
 		}); err != nil {
 			b.Error(err)
+
+			return
 		}
 	}
 
diff --git a/packages/binary/transaction/transaction.go b/packages/binary/transaction/transaction.go
index 57ed71539a04311b6c4d383ebc34ec7cb2b41268..6ad2526587b724bfa25147758f80312fbbe22acf 100644
--- a/packages/binary/transaction/transaction.go
+++ b/packages/binary/transaction/transaction.go
@@ -99,6 +99,14 @@ func (transaction *Transaction) GetId() (result Id) {
 	return
 }
 
+func (transaction *Transaction) GetTrunkTransactionId() Id {
+	return transaction.trunkTransactionId
+}
+
+func (transaction *Transaction) GetBranchTransactionId() Id {
+	return transaction.branchTransactionId
+}
+
 func (transaction *Transaction) GetPayload() payload.Payload {
 	return transaction.payload
 }
diff --git a/packages/binary/transactionmetadata/transactionmetadata.go b/packages/binary/transactionmetadata/transactionmetadata.go
new file mode 100644
index 0000000000000000000000000000000000000000..f79599e4221a5973721d0fc5e5ddb76e072d63b7
--- /dev/null
+++ b/packages/binary/transactionmetadata/transactionmetadata.go
@@ -0,0 +1,73 @@
+package transactionmetadata
+
+import (
+	"sync"
+	"time"
+
+	"github.com/iotaledger/goshimmer/packages/binary/transaction"
+	"github.com/iotaledger/hive.go/objectstorage"
+)
+
+type TransactionMetadata struct {
+	objectstorage.StorableObjectFlags
+
+	transactionId      transaction.Id
+	receivedTime       time.Time
+	solid              bool
+	solidificationTime time.Time
+
+	solidMutex sync.RWMutex
+}
+
+func New(transactionId transaction.Id) *TransactionMetadata {
+	return &TransactionMetadata{
+		transactionId: transactionId,
+		receivedTime:  time.Now(),
+	}
+}
+
+func (transactionMetadata *TransactionMetadata) IsSolid() (result bool) {
+	transactionMetadata.solidMutex.RLock()
+	result = transactionMetadata.solid
+	transactionMetadata.solidMutex.RUnlock()
+
+	return
+}
+
+func (transactionMetadata *TransactionMetadata) SetSolid(solid bool) (modified bool) {
+	transactionMetadata.solidMutex.RLock()
+	if transactionMetadata.solid != solid {
+		transactionMetadata.solidMutex.RUnlock()
+
+		transactionMetadata.solidMutex.Lock()
+		if transactionMetadata.solid != solid {
+			transactionMetadata.solid = solid
+
+			transactionMetadata.SetModified()
+
+			modified = true
+		}
+		transactionMetadata.solidMutex.Unlock()
+
+	} else {
+		transactionMetadata.solidMutex.RUnlock()
+	}
+
+	return
+}
+
+func (transactionMetadata *TransactionMetadata) GetStorageKey() []byte {
+	return transactionMetadata.transactionId[:]
+}
+
+func (transactionMetadata *TransactionMetadata) Update(other objectstorage.StorableObject) {
+
+}
+
+func (transactionMetadata *TransactionMetadata) MarshalBinary() ([]byte, error) {
+	return nil, nil
+}
+
+func (transactionMetadata *TransactionMetadata) UnmarshalBinary([]byte) error {
+	return nil
+}
diff --git a/packages/ledgerstate/ledgerstate.go b/packages/ledgerstate/ledgerstate.go
index 2faad9c2b978ba4b30bc85c6639ae53fff06912d..48d48147ddb2cc3b58bf664442d9c7d793b2d807 100644
--- a/packages/ledgerstate/ledgerstate.go
+++ b/packages/ledgerstate/ledgerstate.go
@@ -7,6 +7,8 @@ import (
 	"strings"
 	"time"
 
+	"github.com/iotaledger/goshimmer/packages/storageprefix"
+
 	"github.com/iotaledger/goshimmer/packages/ledgerstate/coloredcoins"
 
 	"github.com/iotaledger/goshimmer/packages/binary/address"
@@ -31,13 +33,13 @@ type LedgerState struct {
 	conflictSets           *objectstorage.ObjectStorage
 }
 
-func NewLedgerState(storageId string) *LedgerState {
+func NewLedgerState(storageId []byte) *LedgerState {
 	result := &LedgerState{
-		storageId:              []byte(storageId),
-		transferOutputs:        objectstorage.New(storageId+"TRANSFER_OUTPUTS", transfer.OutputFactory, objectstorage.CacheTime(1*time.Second)),
-		transferOutputBookings: objectstorage.New(storageId+"TRANSFER_OUTPUT_BOOKING", transfer.OutputBookingFactory, objectstorage.CacheTime(1*time.Second)),
-		realities:              objectstorage.New(storageId+"REALITIES", realityFactory, objectstorage.CacheTime(1*time.Second)),
-		conflictSets:           objectstorage.New(storageId+"CONFLICT_SETS", conflict.Factory, objectstorage.CacheTime(1*time.Second)),
+		storageId:              storageId,
+		transferOutputs:        objectstorage.New(append(storageId, storageprefix.LedgerStateTransferOutput...), transfer.OutputFactory, objectstorage.CacheTime(1*time.Second)),
+		transferOutputBookings: objectstorage.New(append(storageId, storageprefix.LedgerStateTransferOutputBooking...), transfer.OutputBookingFactory, objectstorage.CacheTime(1*time.Second)),
+		realities:              objectstorage.New(append(storageId, storageprefix.LedgerStateReality...), realityFactory, objectstorage.CacheTime(1*time.Second)),
+		conflictSets:           objectstorage.New(append(storageId, storageprefix.LedgerStateConflictSet...), conflict.Factory, objectstorage.CacheTime(1*time.Second)),
 	}
 
 	mainReality := newReality(reality.MAIN_ID)
@@ -59,17 +61,14 @@ func (ledgerState *LedgerState) AddTransferOutput(transferHash transfer.Hash, ad
 }
 
 func (ledgerState *LedgerState) GetTransferOutput(transferOutputReference *transfer.OutputReference) *objectstorage.CachedObject {
-	if cachedTransferOutput, err := ledgerState.transferOutputs.Load(transferOutputReference.GetStorageKey()); err != nil {
-		panic(err)
-	} else {
-		if cachedTransferOutput.Exists() {
-			if transferOutput := cachedTransferOutput.Get().(*transfer.Output); transferOutput != nil {
-				transferOutput.OutputBookings = ledgerState.transferOutputBookings
-			}
+	cachedTransferOutput := ledgerState.transferOutputs.Load(transferOutputReference.GetStorageKey())
+	if cachedTransferOutput.Exists() {
+		if transferOutput := cachedTransferOutput.Get().(*transfer.Output); transferOutput != nil {
+			transferOutput.OutputBookings = ledgerState.transferOutputBookings
 		}
-
-		return cachedTransferOutput
 	}
+
+	return cachedTransferOutput
 }
 
 func (ledgerState *LedgerState) ForEachConflictSet(callback func(object *objectstorage.CachedObject) bool) {
@@ -130,29 +129,22 @@ func (ledgerState *LedgerState) CreateReality(id reality.Id) {
 	newReality := newReality(id, reality.MAIN_ID)
 	newReality.ledgerState = ledgerState
 
-	if mainReality, mainRealityErr := ledgerState.realities.Load(reality.MAIN_ID[:]); mainRealityErr != nil {
-		panic(mainRealityErr)
-	} else {
-		mainReality.Consume(func(object objectstorage.StorableObject) {
-			object.(*Reality).RegisterSubReality(id)
-		})
-	}
+	ledgerState.realities.Load(reality.MAIN_ID[:]).Consume(func(object objectstorage.StorableObject) {
+		object.(*Reality).RegisterSubReality(id)
+	})
 
 	ledgerState.realities.Store(newReality).Release()
 }
 
 func (ledgerState *LedgerState) GetReality(id reality.Id) *objectstorage.CachedObject {
-	if cachedObject, err := ledgerState.realities.Load(id[:]); err != nil {
-		panic(err)
-	} else {
-		if cachedObject.Exists() {
-			if reality := cachedObject.Get().(*Reality); reality != nil {
-				reality.ledgerState = ledgerState
-			}
+	cachedObject := ledgerState.realities.Load(id[:])
+	if cachedObject.Exists() {
+		if reality := cachedObject.Get().(*Reality); reality != nil {
+			reality.ledgerState = ledgerState
 		}
-
-		return cachedObject
 	}
+
+	return cachedObject
 }
 
 func (ledgerState *LedgerState) BookTransfer(transfer *transfer.Transfer) (err error) {
@@ -249,21 +241,15 @@ func (ledgerState *LedgerState) GenerateRealityVisualization(pngFilename string)
 func (ledgerState *LedgerState) AggregateRealities(realityIds ...reality.Id) *objectstorage.CachedObject {
 	switch len(realityIds) {
 	case 0:
-		if loadedReality, loadedRealityErr := ledgerState.realities.Load(reality.MAIN_ID[:]); loadedRealityErr != nil {
-			panic(loadedRealityErr)
-		} else {
-			loadedReality.Get().(*Reality).ledgerState = ledgerState
+		loadedReality := ledgerState.realities.Load(reality.MAIN_ID[:])
+		loadedReality.Get().(*Reality).ledgerState = ledgerState
 
-			return loadedReality
-		}
+		return loadedReality
 	case 1:
-		if loadedReality, loadedRealityErr := ledgerState.realities.Load(realityIds[0][:]); loadedRealityErr != nil {
-			panic(loadedRealityErr)
-		} else {
-			loadedReality.Get().(*Reality).ledgerState = ledgerState
+		loadedReality := ledgerState.realities.Load(realityIds[0][:])
+		loadedReality.Get().(*Reality).ledgerState = ledgerState
 
-			return loadedReality
-		}
+		return loadedReality
 	default:
 		aggregatedRealities := make(map[reality.Id]*objectstorage.CachedObject)
 
@@ -275,10 +261,8 @@ func (ledgerState *LedgerState) AggregateRealities(realityIds ...reality.Id) *ob
 			}
 
 			// load reality or abort if it fails
-			cachedReality, loadingErr := ledgerState.realities.Load(realityId[:])
-			if loadingErr != nil {
-				panic(loadingErr)
-			} else if !cachedReality.Exists() {
+			cachedReality := ledgerState.realities.Load(realityId[:])
+			if !cachedReality.Exists() {
 				panic(errors.New("referenced reality does not exist: " + realityId.String()))
 			}
 
@@ -340,7 +324,7 @@ func (ledgerState *LedgerState) AggregateRealities(realityIds ...reality.Id) *ob
 		aggregatedRealityId := ledgerState.generateAggregatedRealityId(ledgerState.sortRealityIds(parentConflictRealities))
 
 		newAggregatedRealityCreated := false
-		if newCachedAggregatedReality, err := ledgerState.realities.ComputeIfAbsent(aggregatedRealityId[:], func(key []byte) (object objectstorage.StorableObject, e error) {
+		newCachedAggregatedReality := ledgerState.realities.ComputeIfAbsent(aggregatedRealityId[:], func(key []byte) (object objectstorage.StorableObject) {
 			aggregatedReality := newReality(aggregatedRealityId, aggregatedRealityParentIds...)
 			aggregatedReality.ledgerState = ledgerState
 			aggregatedReality.SetPreferred(aggregatedRealityIsPreferred)
@@ -355,24 +339,22 @@ func (ledgerState *LedgerState) AggregateRealities(realityIds ...reality.Id) *ob
 
 			newAggregatedRealityCreated = true
 
-			return aggregatedReality, nil
-		}); err != nil {
-			panic(err)
-		} else {
-			if !newAggregatedRealityCreated {
-				aggregatedReality := newCachedAggregatedReality.Get().(*Reality)
-
-				for _, realityId := range aggregatedRealityParentIds {
-					if aggregatedReality.AddParentReality(realityId) {
-						ledgerState.GetReality(realityId).Consume(func(object objectstorage.StorableObject) {
-							object.(*Reality).RegisterSubReality(aggregatedRealityId)
-						})
-					}
+			return aggregatedReality
+		})
+
+		if !newAggregatedRealityCreated {
+			aggregatedReality := newCachedAggregatedReality.Get().(*Reality)
+
+			for _, realityId := range aggregatedRealityParentIds {
+				if aggregatedReality.AddParentReality(realityId) {
+					ledgerState.GetReality(realityId).Consume(func(object objectstorage.StorableObject) {
+						object.(*Reality).RegisterSubReality(aggregatedRealityId)
+					})
 				}
 			}
-
-			return newCachedAggregatedReality
 		}
+
+		return newCachedAggregatedReality
 	}
 }
 
diff --git a/packages/ledgerstate/ledgerstate_test.go b/packages/ledgerstate/ledgerstate_test.go
index c1d2df5423b689130bf6d23e67360eb93d428871..bcac9f2fe5ae44a49594fe11e191a23640705eae 100644
--- a/packages/ledgerstate/ledgerstate_test.go
+++ b/packages/ledgerstate/ledgerstate_test.go
@@ -12,7 +12,6 @@ import (
 	"github.com/iotaledger/goshimmer/packages/ledgerstate/reality"
 	"github.com/iotaledger/goshimmer/packages/ledgerstate/transfer"
 	"github.com/iotaledger/hive.go/objectstorage"
-	"github.com/iotaledger/hive.go/parameter"
 )
 
 var (
@@ -33,14 +32,8 @@ var (
 	pendingReality = reality.NewId("PENDING")
 )
 
-func init() {
-	if err := parameter.FetchConfig(false); err != nil {
-		panic(err)
-	}
-}
-
 func Benchmark(b *testing.B) {
-	ledgerState := NewLedgerState("testLedger").Prune().AddTransferOutput(
+	ledgerState := NewLedgerState([]byte("testLedger")).Prune().AddTransferOutput(
 		transferHash1, addressHash1, coloredcoins.NewColoredBalance(eth, 1024),
 	)
 
@@ -64,7 +57,7 @@ func Benchmark(b *testing.B) {
 }
 
 func Test(t *testing.T) {
-	ledgerState := NewLedgerState("testLedger").Prune().AddTransferOutput(
+	ledgerState := NewLedgerState([]byte("testLedger")).Prune().AddTransferOutput(
 		transferHash1, addressHash1, coloredcoins.NewColoredBalance(eth, 1337), coloredcoins.NewColoredBalance(iota_, 1338),
 	)
 
@@ -102,7 +95,7 @@ func Test(t *testing.T) {
 
 	time.Sleep(1000 * time.Millisecond)
 
-	objectstorage.WaitForWritesToFlush()
+	ledgerState.transferOutputs.WaitForWritesToFlush()
 
 	ledgerState.ForEachTransferOutput(func(object *objectstorage.CachedObject) bool {
 		object.Consume(func(object objectstorage.StorableObject) {
@@ -130,7 +123,7 @@ func generateRandomAddressHash() address.Address {
 }
 
 func initializeLedgerStateWithBalances(numberOfBalances int) (ledgerState *LedgerState, result []*transfer.OutputReference) {
-	ledgerState = NewLedgerState("testLedger").Prune()
+	ledgerState = NewLedgerState([]byte("testLedger")).Prune()
 
 	for i := 0; i < numberOfBalances; i++ {
 		transferHash := generateRandomTransferHash()
@@ -239,7 +232,7 @@ func TestAggregateAggregatedRealities(t *testing.T) {
 
 	time.Sleep(2000 * time.Millisecond)
 
-	objectstorage.WaitForWritesToFlush()
+	ledgerState.transferOutputs.WaitForWritesToFlush()
 
 	_ = ledgerState.GenerateRealityVisualization("realities1.png")
 	_ = NewVisualizer(ledgerState).RenderTransferOutputs("outputs1.png")
@@ -248,7 +241,7 @@ func TestAggregateAggregatedRealities(t *testing.T) {
 
 	time.Sleep(2000 * time.Millisecond)
 
-	objectstorage.WaitForWritesToFlush()
+	ledgerState.transferOutputs.WaitForWritesToFlush()
 
 	_ = ledgerState.GenerateRealityVisualization("realities2.png")
 	_ = NewVisualizer(ledgerState).RenderTransferOutputs("outputs2.png")
@@ -283,14 +276,14 @@ func TestElevateAggregatedReality(t *testing.T) {
 
 	time.Sleep(1000 * time.Millisecond)
 
-	objectstorage.WaitForWritesToFlush()
+	ledgerState.transferOutputs.WaitForWritesToFlush()
 
 	_ = ledgerState.GenerateRealityVisualization("realities.png")
 	_ = NewVisualizer(ledgerState).RenderTransferOutputs("outputs.png")
 }
 
 func TestElevate(t *testing.T) {
-	ledgerState := NewLedgerState("testLedger").Prune().AddTransferOutput(
+	ledgerState := NewLedgerState([]byte("testLedger")).Prune().AddTransferOutput(
 		transferHash1, addressHash1, coloredcoins.NewColoredBalance(eth, 1337), coloredcoins.NewColoredBalance(iota_, 1338),
 	)
 
@@ -352,7 +345,7 @@ func TestElevate(t *testing.T) {
 
 	time.Sleep(1000 * time.Millisecond)
 
-	objectstorage.WaitForWritesToFlush()
+	ledgerState.transferOutputs.WaitForWritesToFlush()
 
 	ledgerState.ForEachTransferOutput(func(object *objectstorage.CachedObject) bool {
 		object.Consume(func(object objectstorage.StorableObject) {
diff --git a/packages/ledgerstate/outputs1.png b/packages/ledgerstate/outputs1.png
index 639f9f9d70d5ff3d49ec4cfb86fd919dc28fe008..6da15b92f4a01206aa38ff8b10439123feb22e41 100644
Binary files a/packages/ledgerstate/outputs1.png and b/packages/ledgerstate/outputs1.png differ
diff --git a/packages/ledgerstate/outputs2.png b/packages/ledgerstate/outputs2.png
index b3de946340e39640db58e60567793234cea900ef..4628b918f78a8d522080837b68b29fb28159a0d8 100644
Binary files a/packages/ledgerstate/outputs2.png and b/packages/ledgerstate/outputs2.png differ
diff --git a/packages/ledgerstate/reality.go b/packages/ledgerstate/reality.go
index b6c17b8ecbc13c88642b6a1e180f5711245b65ff..09bb808a7df694f9c15af51fb5752fe77573fa89 100644
--- a/packages/ledgerstate/reality.go
+++ b/packages/ledgerstate/reality.go
@@ -596,9 +596,7 @@ func (mreality *Reality) processConflictingInput(input *transfer.Output, consume
 
 		err = mreality.createRealityForPreviouslyUnconflictingConsumers(consumersToElevate, cachedConflict.Get().(*conflict.Conflict))
 	} else {
-		if cachedConflict, err = mreality.ledgerState.conflictSets.Load(conflictId[:]); err != nil {
-			return
-		}
+		cachedConflict = mreality.ledgerState.conflictSets.Load(conflictId[:])
 	}
 
 	return
@@ -611,7 +609,7 @@ func (mreality *Reality) createRealityForPreviouslyUnconflictingConsumers(consum
 
 		// Retrieve the Reality for this Transfer or create one if no Reality exists, yet.
 		var realityIsNew bool
-		if cachedElevatedReality, realityErr := mreality.ledgerState.realities.ComputeIfAbsent(elevatedRealityId[:], func(key []byte) (object objectstorage.StorableObject, e error) {
+		cachedElevatedReality := mreality.ledgerState.realities.ComputeIfAbsent(elevatedRealityId[:], func(key []byte) (object objectstorage.StorableObject) {
 			newReality := newReality(elevatedRealityId, mreality.id)
 			newReality.ledgerState = mreality.ledgerState
 			newReality.SetPreferred()
@@ -623,30 +621,29 @@ func (mreality *Reality) createRealityForPreviouslyUnconflictingConsumers(consum
 
 			realityIsNew = true
 
-			return newReality, nil
-		}); realityErr != nil {
-			err = realityErr
-		} else {
-			cachedElevatedReality.Consume(func(object objectstorage.StorableObject) {
-				elevatedReality := object.(*Reality)
-
-				// We register every Conflict with the Reality (independent if it is "new" or not), to reflect its
-				// association to all corresponding Conflicts. (Note: A Reality can be part of multiple Conflicts if the
-				// Transfer that is associated to this Reality consumes multiple inputs.
-				conflict.AddReality(elevatedRealityId)
-				elevatedReality.AddConflict(conflict.GetId())
-
-				// A transaction can consume multiple inputs. We only elevate the consumers of a Reality once (when the
-				// Reality is created the first time).
-				if realityIsNew {
-					for _, addressHash := range addressHashes {
-						if err = mreality.elevateTransferOutput(transfer.NewOutputReference(transferHash, addressHash), elevatedReality); err != nil {
-							return
-						}
+			return newReality
+		})
+
+		cachedElevatedReality.Consume(func(object objectstorage.StorableObject) {
+			elevatedReality := object.(*Reality)
+
+			// We register every Conflict with the Reality (independent if it is "new" or not), to reflect its
+			// association to all corresponding Conflicts. (Note: A Reality can be part of multiple Conflicts if the
+			// Transfer that is associated to this Reality consumes multiple inputs.
+			conflict.AddReality(elevatedRealityId)
+			elevatedReality.AddConflict(conflict.GetId())
+
+			// A transaction can consume multiple inputs. We only elevate the consumers of a Reality once (when the
+			// Reality is created the first time).
+			if realityIsNew {
+				for _, addressHash := range addressHashes {
+					if err = mreality.elevateTransferOutput(transfer.NewOutputReference(transferHash, addressHash), elevatedReality); err != nil {
+						return
 					}
 				}
-			})
-		}
+			}
+		})
+
 	}
 
 	return
@@ -767,29 +764,26 @@ func (mreality *Reality) bookTransferOutput(transferOutput *transfer.Output) (er
 
 	// remove old booking if the Output is currently booked in another reality
 	if transferOutputRealityId != realityId {
-		if oldTransferOutputBooking, err := mreality.ledgerState.transferOutputBookings.Load(transfer.GenerateOutputBookingStorageKey(transferOutputRealityId, transferOutputAddressHash, transferOutput.IsSpent(), transferOutput.GetTransferHash())); err != nil {
-			return err
-		} else {
-			transferOutput.SetRealityId(realityId)
+		oldTransferOutputBooking := mreality.ledgerState.transferOutputBookings.Load(transfer.GenerateOutputBookingStorageKey(transferOutputRealityId, transferOutputAddressHash, transferOutput.IsSpent(), transferOutput.GetTransferHash()))
+		transferOutput.SetRealityId(realityId)
 
-			mreality.ledgerState.GetReality(transferOutputRealityId).Consume(func(object objectstorage.StorableObject) {
-				transferOutputReality := object.(*Reality)
+		mreality.ledgerState.GetReality(transferOutputRealityId).Consume(func(object objectstorage.StorableObject) {
+			transferOutputReality := object.(*Reality)
 
-				// decrease transferOutputCount and remove reality if it is empty
-				if transferOutputReality.DecreaseTransferOutputCount() == 0 && transferOutputReality.GetSubRealityIdCount() == 0 {
-					for _, cachedParentReality := range transferOutputReality.GetParentRealities() {
-						cachedParentReality.Consume(func(parentReality objectstorage.StorableObject) {
-							parentReality.(*Reality).UnregisterSubReality(transferOutputRealityId)
-						})
-					}
-					transferOutputReality.Delete()
+			// decrease transferOutputCount and remove reality if it is empty
+			if transferOutputReality.DecreaseTransferOutputCount() == 0 && transferOutputReality.GetSubRealityIdCount() == 0 {
+				for _, cachedParentReality := range transferOutputReality.GetParentRealities() {
+					cachedParentReality.Consume(func(parentReality objectstorage.StorableObject) {
+						parentReality.(*Reality).UnregisterSubReality(transferOutputRealityId)
+					})
 				}
-			})
+				transferOutputReality.Delete()
+			}
+		})
 
-			oldTransferOutputBooking.Consume(func(transferOutputBooking objectstorage.StorableObject) {
-				transferOutputBooking.Delete()
-			})
-		}
+		oldTransferOutputBooking.Consume(func(transferOutputBooking objectstorage.StorableObject) {
+			transferOutputBooking.Delete()
+		})
 	}
 
 	// book the Output into the current Reality
diff --git a/packages/ledgerstate/transfer/output.go b/packages/ledgerstate/transfer/output.go
index 7ac692e6c1aaabec8871717b94ca234c436312aa..9afeefb67a0fc12618199b078a5cb32dfbc11f2a 100644
--- a/packages/ledgerstate/transfer/output.go
+++ b/packages/ledgerstate/transfer/output.go
@@ -137,17 +137,12 @@ func (transferOutput *Output) markAsSpent() error {
 	transferOutput.bookingMutex.Lock()
 
 	currentBookingKey := GenerateOutputBookingStorageKey(transferOutput.GetRealityId(), transferOutput.addressHash, false, transferOutput.transferHash)
-	if oldTransferOutputBooking, err := transferOutput.OutputBookings.Load(currentBookingKey); err != nil {
-		transferOutput.bookingMutex.Unlock()
+	oldTransferOutputBooking := transferOutput.OutputBookings.Load(currentBookingKey)
+	transferOutput.OutputBookings.Store(NewTransferOutputBooking(transferOutput.GetRealityId(), transferOutput.addressHash, true, transferOutput.transferHash)).Release()
 
-		return err
-	} else {
-		transferOutput.OutputBookings.Store(NewTransferOutputBooking(transferOutput.GetRealityId(), transferOutput.addressHash, true, transferOutput.transferHash)).Release()
-
-		oldTransferOutputBooking.Consume(func(transferOutputBooking objectstorage.StorableObject) {
-			transferOutputBooking.Delete()
-		})
-	}
+	oldTransferOutputBooking.Consume(func(transferOutputBooking objectstorage.StorableObject) {
+		transferOutputBooking.Delete()
+	})
 
 	transferOutput.bookingMutex.Unlock()
 
diff --git a/packages/storageprefix/storageprefix.go b/packages/storageprefix/storageprefix.go
new file mode 100644
index 0000000000000000000000000000000000000000..7b2378eb5fadb2971676ba395af6e0104dfb4385
--- /dev/null
+++ b/packages/storageprefix/storageprefix.go
@@ -0,0 +1,12 @@
+package storageprefix
+
+var (
+	TangleTransaction         = []byte{0}
+	TangleTransactionMetadata = []byte{6}
+	TangleApprovers           = []byte{1}
+
+	LedgerStateTransferOutput        = []byte{2}
+	LedgerStateTransferOutputBooking = []byte{3}
+	LedgerStateReality               = []byte{4}
+	LedgerStateConflictSet           = []byte{5}
+)