From aae4b1ec84f55fa75c895b364ad91f3d58ff2ee5 Mon Sep 17 00:00:00 2001
From: Hans Moog <hm@mkjc.net>
Date: Sun, 5 Apr 2020 23:47:55 +0200
Subject: [PATCH] Message refactor (#322)

* Feat: refactored message + started to add tests

* Refactor: go mod tidy

* Refactor: continued to refactor message

* Feat: updated to last hive.go + added Signature() methid

* Feat: go mod tidy

* Feat: added mutex to the signature write in Bytes()

* Fix: fixed Signature method

* Feat: refactored message methods

* Feat: refactored output

* Fix: fixed signature mismatch in tangle factory methods

* Refactor: go mod tidy

* Feat: added solditification logic to value tangle

* Feat: fixed some code related to objectstorage factories

* Feat: model refactor

* Fix: fixed a bug in the models of the valuetangle

* Feat: refactored storageprefix framework

* Feat: refactored some code

* Refactor: additional refactor in OS logic

* Refactor: refactored MissingPayload model

* Refactor: refactored further models
---
 go.mod                                        |  2 +-
 go.sum                                        |  4 +
 .../messagelayer/tangle/storageprefixes.go    |  8 ++
 packages/binary/messagelayer/tangle/tangle.go | 20 ++---
 .../binary/messagelayer/tangle/tangle_test.go |  4 +-
 .../binary/storageprefix/storageprefix.go     | 25 ++----
 .../binary/valuetransfer/payload/payload.go   | 62 ++++++++------
 .../binary/valuetransfer/tangle/attachment.go | 61 +++++++------
 .../binary/valuetransfer/tangle/consumer.go   | 11 ++-
 .../valuetransfer/tangle/missingoutput.go     | 78 +++++++++++------
 .../valuetransfer/tangle/missingpayload.go    | 67 ++++++++++-----
 .../valuetransfer/tangle/objectstorage.go     | 55 ++++++++++++
 .../valuetransfer/tangle/payloadapprover.go   | 58 ++++++++++---
 .../valuetransfer/tangle/payloadmetadata.go   | 85 +++++++++++--------
 .../binary/valuetransfer/tangle/tangle.go     | 35 +++-----
 .../valuetransfer/tangle/tangle_test.go       |  2 +-
 .../valuetransfer/transaction/output.go       | 10 +--
 plugins/messagelayer/plugin.go                |  3 +-
 18 files changed, 369 insertions(+), 221 deletions(-)
 create mode 100644 packages/binary/messagelayer/tangle/storageprefixes.go
 create mode 100644 packages/binary/valuetransfer/tangle/objectstorage.go

diff --git a/go.mod b/go.mod
index f0c5e1eb..039b84fd 100644
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,7 @@ require (
 	github.com/googollee/go-engine.io v1.4.3-0.20190924125625-798118fc0dd2
 	github.com/googollee/go-socket.io v1.4.3-0.20191204093753-683f8725b6d0
 	github.com/gorilla/websocket v1.4.1
-	github.com/iotaledger/hive.go v0.0.0-20200330121034-e4a505bcf2cd
+	github.com/iotaledger/hive.go v0.0.0-20200403132600-4c10556e08a0
 	github.com/iotaledger/iota.go v1.0.0-beta.14
 	github.com/labstack/echo v3.3.10+incompatible
 	github.com/labstack/gommon v0.3.0 // indirect
diff --git a/go.sum b/go.sum
index 956e2e53..cbba30d8 100644
--- a/go.sum
+++ b/go.sum
@@ -133,6 +133,10 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/iotaledger/hive.go v0.0.0-20200330121034-e4a505bcf2cd h1:GZ9zGBj+tK1jHqTD5+OoPLVVlk/sB2pkKmQt9vjR8uY=
 github.com/iotaledger/hive.go v0.0.0-20200330121034-e4a505bcf2cd/go.mod h1:LYUD1U+BxF+OY6zCZ4xp38vzjp/QWbUdCw9iwmxkGnc=
+github.com/iotaledger/hive.go v0.0.0-20200402231254-50e5bddb0da0 h1:Es3rPblh28a68LctnLwqhUOphmtkD8Q3UVKZoZYSlDM=
+github.com/iotaledger/hive.go v0.0.0-20200402231254-50e5bddb0da0/go.mod h1:LYUD1U+BxF+OY6zCZ4xp38vzjp/QWbUdCw9iwmxkGnc=
+github.com/iotaledger/hive.go v0.0.0-20200403132600-4c10556e08a0 h1:CyUsunZHlWuD1s9GVz+XqAIZVpRDxJBspb4DheJVknw=
+github.com/iotaledger/hive.go v0.0.0-20200403132600-4c10556e08a0/go.mod h1:LYUD1U+BxF+OY6zCZ4xp38vzjp/QWbUdCw9iwmxkGnc=
 github.com/iotaledger/iota.go v1.0.0-beta.9/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8=
 github.com/iotaledger/iota.go v1.0.0-beta.14 h1:Oeb28MfBuJEeXcGrLhTCJFtbsnc8y1u7xidsAmiOD5A=
 github.com/iotaledger/iota.go v1.0.0-beta.14/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8=
diff --git a/packages/binary/messagelayer/tangle/storageprefixes.go b/packages/binary/messagelayer/tangle/storageprefixes.go
new file mode 100644
index 00000000..24a31eea
--- /dev/null
+++ b/packages/binary/messagelayer/tangle/storageprefixes.go
@@ -0,0 +1,8 @@
+package tangle
+
+const (
+	PrefixMessage byte = iota
+	PrefixMessageMetadata
+	PrefixApprovers
+	PrefixMissingMessage
+)
diff --git a/packages/binary/messagelayer/tangle/tangle.go b/packages/binary/messagelayer/tangle/tangle.go
index be387753..86ef2ab3 100644
--- a/packages/binary/messagelayer/tangle/tangle.go
+++ b/packages/binary/messagelayer/tangle/tangle.go
@@ -20,8 +20,6 @@ const (
 )
 
 type Tangle struct {
-	storageId []byte
-
 	messageStorage         *objectstorage.ObjectStorage
 	messageMetadataStorage *objectstorage.ObjectStorage
 	approverStorage        *objectstorage.ObjectStorage
@@ -47,13 +45,14 @@ func missingMessageFactory(key []byte) (objectstorage.StorableObject, error, int
 }
 
 // Constructor for the tangle.
-func New(badgerInstance *badger.DB, storageId []byte) (result *Tangle) {
+func New(badgerInstance *badger.DB) (result *Tangle) {
+	osFactory := objectstorage.NewFactory(badgerInstance, storageprefix.MessageLayer)
+
 	result = &Tangle{
-		storageId:              storageId,
-		messageStorage:         objectstorage.New(badgerInstance, append(storageId, storageprefix.Layer0Message...), messageFactory, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
-		messageMetadataStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.Layer0MessageMetadata...), MessageMetadataFromStorageKey, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
-		approverStorage:        objectstorage.New(badgerInstance, append(storageId, storageprefix.Layer0Approvers...), approverFactory, objectstorage.CacheTime(10*time.Second), objectstorage.PartitionKey(message.IdLength, message.IdLength), objectstorage.LeakDetectionEnabled(false)),
-		missingMessageStorage:  objectstorage.New(badgerInstance, append(storageId, storageprefix.Layer0MissingMessage...), missingMessageFactory, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
+		messageStorage:         osFactory.New(PrefixMessage, messageFactory, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
+		messageMetadataStorage: osFactory.New(PrefixMessageMetadata, MessageMetadataFromStorageKey, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
+		approverStorage:        osFactory.New(PrefixApprovers, approverFactory, objectstorage.CacheTime(10*time.Second), objectstorage.PartitionKey(message.IdLength, message.IdLength), objectstorage.LeakDetectionEnabled(false)),
+		missingMessageStorage:  osFactory.New(PrefixMissingMessage, missingMessageFactory, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
 
 		Events: *newEvents(),
 	}
@@ -63,11 +62,6 @@ func New(badgerInstance *badger.DB, storageId []byte) (result *Tangle) {
 	return
 }
 
-// Returns the storage id of this tangle (can be used to create ontologies that follow the storage of the main tangle).
-func (tangle *Tangle) StorageId() []byte {
-	return tangle.storageId
-}
-
 // Attaches a new transaction to the tangle.
 func (tangle *Tangle) AttachMessage(transaction *message.Message) {
 	tangle.storeMessageWorkerPool.Submit(func() { tangle.storeMessageWorker(transaction) })
diff --git a/packages/binary/messagelayer/tangle/tangle_test.go b/packages/binary/messagelayer/tangle/tangle_test.go
index e16243a2..af4bed90 100644
--- a/packages/binary/messagelayer/tangle/tangle_test.go
+++ b/packages/binary/messagelayer/tangle/tangle_test.go
@@ -24,7 +24,7 @@ func BenchmarkTangle_AttachTransaction(b *testing.B) {
 	// use the tempdir for the database
 	config.Node.Set(database.CFG_DIRECTORY, dir)
 
-	tangle := New(database.GetBadgerInstance(), []byte("TEST_BINARY_TANGLE"))
+	tangle := New(database.GetBadgerInstance())
 	if err := tangle.Prune(); err != nil {
 		b.Error(err)
 
@@ -55,7 +55,7 @@ func TestTangle_AttachTransaction(t *testing.T) {
 	// use the tempdir for the database
 	config.Node.Set(database.CFG_DIRECTORY, dir)
 
-	messageTangle := New(database.GetBadgerInstance(), []byte("TEST_BINARY_TANGLE"))
+	messageTangle := New(database.GetBadgerInstance())
 	if err := messageTangle.Prune(); err != nil {
 		t.Error(err)
 
diff --git a/packages/binary/storageprefix/storageprefix.go b/packages/binary/storageprefix/storageprefix.go
index 10bb2099..28ad9403 100644
--- a/packages/binary/storageprefix/storageprefix.go
+++ b/packages/binary/storageprefix/storageprefix.go
@@ -1,23 +1,10 @@
 package storageprefix
 
-var (
-	MainNet = []byte{0}
+const (
+	// the following values are a list of prefixes defined as an enum
+	_ byte = iota
 
-	Layer0Message         = []byte{1}
-	Layer0MessageMetadata = []byte{2}
-	Layer0Approvers       = []byte{3}
-	Layer0MissingMessage  = []byte{4}
-
-	ValueTransferPayload         = []byte{5}
-	ValueTransferPayloadMetadata = []byte{6}
-	ValueTransferApprover        = []byte{7}
-	ValueTransferMissingPayload  = []byte{8}
-	ValueTransferAttachment      = []byte{9}
-	ValueTransferConsumer        = []byte{10}
-	ValueTangleOutputs           = []byte{11}
-
-	LedgerStateTransferOutput        = []byte{12}
-	LedgerStateTransferOutputBooking = []byte{13}
-	LedgerStateReality               = []byte{14}
-	LedgerStateConflictSet           = []byte{15}
+	// package specific prefixes used for the objectstorage in the corresponding packages
+	MessageLayer
+	ValueTransfers
 )
diff --git a/packages/binary/valuetransfer/payload/payload.go b/packages/binary/valuetransfer/payload/payload.go
index d41e1439..33fdf159 100644
--- a/packages/binary/valuetransfer/payload/payload.go
+++ b/packages/binary/valuetransfer/payload/payload.go
@@ -43,8 +43,16 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Payload) (result *Payload,
 	return
 }
 
-func StorableObjectFromKey(key []byte) (result objectstorage.StorableObject, err error, consumedBytes int) {
-	result = &Payload{}
+func FromStorageKey(key []byte, optionalTargetObject ...*Payload) (result *Payload, err error, consumedBytes int) {
+	// determine the target object that will hold the unmarshaled information
+	switch len(optionalTargetObject) {
+	case 0:
+		result = &Payload{}
+	case 1:
+		result = optionalTargetObject[0]
+	default:
+		panic("too many arguments in call to MissingPayloadFromStorageKey")
+	}
 
 	// parse the properties that are stored in the key
 	marshalUtil := marshalutil.New(key)
@@ -53,7 +61,7 @@ func StorableObjectFromKey(key []byte) (result objectstorage.StorableObject, err
 
 		return
 	} else {
-		result.(*Payload).id = &payloadId
+		result.id = &payloadId
 	}
 	consumedBytes = marshalUtil.ReadOffset()
 
@@ -127,7 +135,28 @@ func (payload *Payload) Transaction() *transaction.Transaction {
 	return payload.transaction
 }
 
-func (payload *Payload) Bytes() (bytes []byte) {
+func (payload *Payload) Bytes() []byte {
+	return payload.ObjectStorageValue()
+}
+
+func (payload *Payload) String() string {
+	return stringify.Struct("Payload",
+		stringify.StructField("id", payload.Id()),
+		stringify.StructField("trunk", payload.TrunkId()),
+		stringify.StructField("branch", payload.BranchId()),
+		stringify.StructField("transfer", payload.Transaction()),
+	)
+}
+
+// region Payload implementation ///////////////////////////////////////////////////////////////////////////////////////
+
+var Type = payload.Type(1)
+
+func (payload *Payload) Type() payload.Type {
+	return Type
+}
+
+func (payload *Payload) ObjectStorageValue() (bytes []byte) {
 	// acquire lock for reading bytes
 	payload.bytesMutex.RLock()
 
@@ -167,27 +196,6 @@ func (payload *Payload) Bytes() (bytes []byte) {
 	return
 }
 
-func (payload *Payload) String() string {
-	return stringify.Struct("Payload",
-		stringify.StructField("id", payload.Id()),
-		stringify.StructField("trunk", payload.TrunkId()),
-		stringify.StructField("branch", payload.BranchId()),
-		stringify.StructField("transfer", payload.Transaction()),
-	)
-}
-
-// region Payload implementation ///////////////////////////////////////////////////////////////////////////////////////
-
-var Type = payload.Type(1)
-
-func (payload *Payload) Type() payload.Type {
-	return Type
-}
-
-func (payload *Payload) ObjectStorageValue() []byte {
-	return payload.Bytes()
-}
-
 func (payload *Payload) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) {
 	marshalUtil := marshalutil.New(data)
 
@@ -248,9 +256,7 @@ var _ payload.Payload = &Payload{}
 // UnmarshalObjectStorageValue(data []byte) (err error) already implemented by Payload
 
 func (payload *Payload) ObjectStorageKey() []byte {
-	id := payload.Id()
-
-	return id[:]
+	return payload.Id().Bytes()
 }
 
 func (payload *Payload) Update(other objectstorage.StorableObject) {
diff --git a/packages/binary/valuetransfer/tangle/attachment.go b/packages/binary/valuetransfer/tangle/attachment.go
index ebeb7a7d..ae79f941 100644
--- a/packages/binary/valuetransfer/tangle/attachment.go
+++ b/packages/binary/valuetransfer/tangle/attachment.go
@@ -36,6 +36,39 @@ func NewAttachment(transactionId transaction.Id, payloadId payload.Id) *Attachme
 // AttachmentFromBytes unmarshals an Attachment from a sequence of bytes - it either creates a new object or fills the
 // optionally provided one with the parsed information.
 func AttachmentFromBytes(bytes []byte, optionalTargetObject ...*Attachment) (result *Attachment, err error, consumedBytes int) {
+	marshalUtil := marshalutil.New(bytes)
+	result, err = ParseAttachment(marshalUtil, optionalTargetObject...)
+	consumedBytes = marshalUtil.ReadOffset()
+
+	return
+}
+
+// Parse is a wrapper for simplified unmarshaling of Attachments from a byte stream using the marshalUtil package.
+func ParseAttachment(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*Attachment) (result *Attachment, err error) {
+	if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) {
+		return AttachmentFromStorageKey(data, optionalTargetObject...)
+	}); parseErr != nil {
+		err = parseErr
+
+		return
+	} else {
+		result = parsedObject.(*Attachment)
+	}
+
+	if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) {
+		parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data)
+
+		return
+	}); err != nil {
+		return
+	}
+
+	return
+}
+
+// AttachmentFromStorageKey gets called when we restore an Attachment from the storage - it parses the key bytes and
+// returns the new object.
+func AttachmentFromStorageKey(key []byte, optionalTargetObject ...*Attachment) (result *Attachment, err error, consumedBytes int) {
 	// determine the target object that will hold the unmarshaled information
 	switch len(optionalTargetObject) {
 	case 0:
@@ -43,43 +76,23 @@ func AttachmentFromBytes(bytes []byte, optionalTargetObject ...*Attachment) (res
 	case 1:
 		result = optionalTargetObject[0]
 	default:
-		panic("too many arguments in call to AttachmentFromBytes")
+		panic("too many arguments in call to AttachmentFromStorageKey")
 	}
 
-	// parse the bytes
-	marshalUtil := marshalutil.New(bytes)
+	// parse the properties that are stored in the key
+	marshalUtil := marshalutil.New(key)
 	if result.transactionId, err = transaction.ParseId(marshalUtil); err != nil {
 		return
 	}
 	if result.payloadId, err = payload.ParseId(marshalUtil); err != nil {
 		return
 	}
-	result.storageKey = marshalutil.New(bytes[:AttachmentLength]).Bytes(true)
 	consumedBytes = marshalUtil.ReadOffset()
+	result.storageKey = marshalutil.New(key[:consumedBytes]).Bytes(true)
 
 	return
 }
 
-// Parse is a wrapper for simplified unmarshaling of Attachments from a byte stream using the marshalUtil package.
-func ParseAttachment(marshalUtil *marshalutil.MarshalUtil) (*Attachment, error) {
-	if attachment, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return AttachmentFromBytes(data) }); err != nil {
-		return nil, err
-	} else {
-		return attachment.(*Attachment), nil
-	}
-}
-
-// AttachmentFromStorageKey gets called when we restore an Attachment from the storage - it parses the key bytes and
-// returns the new object.
-func AttachmentFromStorageKey(keyBytes []byte) (objectstorage.StorableObject, error, int) {
-	result, err, _ := AttachmentFromBytes(keyBytes)
-	if err != nil {
-		return nil, err, 0
-	}
-
-	return result, nil, 0
-}
-
 // TransactionId returns the transaction id of this Attachment.
 func (attachment *Attachment) TransactionId() transaction.Id {
 	return attachment.transactionId
diff --git a/packages/binary/valuetransfer/tangle/consumer.go b/packages/binary/valuetransfer/tangle/consumer.go
index bbb5bfc4..b1ff096c 100644
--- a/packages/binary/valuetransfer/tangle/consumer.go
+++ b/packages/binary/valuetransfer/tangle/consumer.go
@@ -5,9 +5,12 @@ import (
 	"github.com/iotaledger/hive.go/objectstorage"
 	"github.com/iotaledger/hive.go/stringify"
 
+	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction"
 )
 
+var ConsumerPartitionKeys = objectstorage.PartitionKey([]int{address.Length, transaction.IdLength, transaction.IdLength}...)
+
 // Consumer stores the information which transaction output was consumed by which transaction. We need this to be able
 // to perform reverse lookups from transaction outputs to their corresponding consuming transactions.
 type Consumer struct {
@@ -64,7 +67,7 @@ func ParseConsumer(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ..
 	return
 }
 
-func ConsumerFromStorageKey(key []byte, optionalTargetObject ...*Consumer) (result objectstorage.StorableObject, err error, consumedBytes int) {
+func ConsumerFromStorageKey(key []byte, optionalTargetObject ...*Consumer) (result *Consumer, err error, consumedBytes int) {
 	// determine the target object that will hold the unmarshaled information
 	switch len(optionalTargetObject) {
 	case 0:
@@ -77,14 +80,14 @@ func ConsumerFromStorageKey(key []byte, optionalTargetObject ...*Consumer) (resu
 
 	// parse the properties that are stored in the key
 	marshalUtil := marshalutil.New(key)
-	if result.(*Consumer).consumedInput, err = transaction.ParseOutputId(marshalUtil); err != nil {
+	if result.consumedInput, err = transaction.ParseOutputId(marshalUtil); err != nil {
 		return
 	}
-	if result.(*Consumer).transactionId, err = transaction.ParseId(marshalUtil); err != nil {
+	if result.transactionId, err = transaction.ParseId(marshalUtil); err != nil {
 		return
 	}
-	result.(*Consumer).storageKey = marshalutil.New(key[:marshalUtil.ReadOffset()]).Bytes(true)
 	consumedBytes = marshalUtil.ReadOffset()
+	result.storageKey = marshalutil.New(key[:consumedBytes]).Bytes(true)
 
 	return
 }
diff --git a/packages/binary/valuetransfer/tangle/missingoutput.go b/packages/binary/valuetransfer/tangle/missingoutput.go
index 6e5e05d5..671eec10 100644
--- a/packages/binary/valuetransfer/tangle/missingoutput.go
+++ b/packages/binary/valuetransfer/tangle/missingoutput.go
@@ -6,9 +6,12 @@ import (
 	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/objectstorage"
 
+	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction"
 )
 
+var MissingOutputKeyPartitions = objectstorage.PartitionKey([]int{address.Length, transaction.IdLength}...)
+
 // MissingPayload represents an Output that was referenced by a Transaction, but that is missing in our object storage.
 type MissingOutput struct {
 	objectstorage.StorableObjectFlags
@@ -28,6 +31,38 @@ func NewMissingOutput(outputId transaction.OutputId) *MissingOutput {
 // MissingOutputFromBytes unmarshals a MissingOutput from a sequence of bytes - it either creates a new object or fills
 // the optionally provided one with the parsed information.
 func MissingOutputFromBytes(bytes []byte, optionalTargetObject ...*MissingOutput) (result *MissingOutput, err error, consumedBytes int) {
+	marshalUtil := marshalutil.New(bytes)
+	result, err = ParseMissingOutput(marshalUtil, optionalTargetObject...)
+	consumedBytes = marshalUtil.ReadOffset()
+
+	return
+}
+
+func ParseMissingOutput(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*MissingOutput) (result *MissingOutput, err error) {
+	if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) {
+		return MissingOutputFromStorageKey(data, optionalTargetObject...)
+	}); parseErr != nil {
+		err = parseErr
+
+		return
+	} else {
+		result = parsedObject.(*MissingOutput)
+	}
+
+	if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) {
+		parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data)
+
+		return
+	}); err != nil {
+		return
+	}
+
+	return
+}
+
+// MissingOutputFromStorageKey gets called when we restore a MissingOutput from the storage. The content will be
+// unmarshaled by an external caller using the binary.ObjectStorageValue interface.
+func MissingOutputFromStorageKey(key []byte, optionalTargetObject ...*MissingOutput) (result *MissingOutput, err error, consumedBytes int) {
 	// determine the target object that will hold the unmarshaled information
 	switch len(optionalTargetObject) {
 	case 0:
@@ -35,35 +70,18 @@ func MissingOutputFromBytes(bytes []byte, optionalTargetObject ...*MissingOutput
 	case 1:
 		result = optionalTargetObject[0]
 	default:
-		panic("too many arguments in call to MissingOutputFromBytes")
+		panic("too many arguments in call to MissingOutputFromStorageKey")
 	}
 
-	// parse the bytes
-	marshalUtil := marshalutil.New(bytes)
+	// parse the properties that are stored in the key
+	marshalUtil := marshalutil.New(key)
 	if result.outputId, err = transaction.ParseOutputId(marshalUtil); err != nil {
 		return
 	}
-	if result.missingSince, err = marshalUtil.ReadTime(); err != nil {
-		return
-	}
-	consumedBytes = marshalUtil.ReadOffset()
 
 	return
 }
 
-// MissingOutputFromStorageKey gets called when we restore a MissingOutput from the storage. The content will be
-// unmarshaled by an external caller using the binary.ObjectStorageValue interface.
-func MissingOutputFromStorageKey(keyBytes []byte) (objectstorage.StorableObject, error, int) {
-	outputId, err, _ := transaction.OutputIdFromBytes(keyBytes)
-	if err != nil {
-		panic(err)
-	}
-
-	return &MissingOutput{
-		outputId: outputId,
-	}, nil, transaction.OutputIdLength
-}
-
 // Id returns the id of the Output that is missing.
 func (missingOutput *MissingOutput) Id() transaction.OutputId {
 	return missingOutput.outputId
@@ -76,12 +94,10 @@ func (missingOutput *MissingOutput) MissingSince() time.Time {
 
 // Bytes marshals the MissingOutput into a sequence of bytes.
 func (missingOutput *MissingOutput) Bytes() []byte {
-	marshalUtil := marshalutil.New()
-
-	marshalUtil.WriteBytes(missingOutput.outputId.Bytes())
-	marshalUtil.WriteTime(missingOutput.missingSince)
-
-	return marshalUtil.Bytes()
+	return marshalutil.New(transaction.OutputIdLength + marshalutil.TIME_SIZE).
+		WriteBytes(missingOutput.ObjectStorageKey()).
+		WriteBytes(missingOutput.ObjectStorageValue()).
+		Bytes()
 }
 
 // ObjectStorageKey returns the key that is used to store the object in the object storage.
@@ -92,13 +108,19 @@ func (missingOutput *MissingOutput) ObjectStorageKey() []byte {
 // ObjectStorageValue returns a bytes representation of the Transaction by implementing the encoding.BinaryMarshaler
 // interface.
 func (missingOutput *MissingOutput) ObjectStorageValue() []byte {
-	return missingOutput.Bytes()
+	return marshalutil.New(marshalutil.TIME_SIZE).
+		WriteTime(missingOutput.missingSince).
+		Bytes()
 }
 
 // UnmarshalObjectStorageValue restores the values of a MissingOutput from a sequence of bytes using the  encoding.BinaryUnmarshaler
 // interface.
 func (missingOutput *MissingOutput) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) {
-	_, err, consumedBytes = MissingOutputFromBytes(data, missingOutput)
+	marshalUtil := marshalutil.New(data)
+	if missingOutput.missingSince, err = marshalUtil.ReadTime(); err != nil {
+		return
+	}
+	consumedBytes = marshalUtil.ReadOffset()
 
 	return
 }
diff --git a/packages/binary/valuetransfer/tangle/missingpayload.go b/packages/binary/valuetransfer/tangle/missingpayload.go
index 395365a2..10a6dabb 100644
--- a/packages/binary/valuetransfer/tangle/missingpayload.go
+++ b/packages/binary/valuetransfer/tangle/missingpayload.go
@@ -29,6 +29,38 @@ func NewMissingPayload(payloadId payload.Id) *MissingPayload {
 // MissingPayloadFromBytes unmarshals an entry for a missing value transfer payload from a sequence of bytes.
 // It either creates a new entry or fills the optionally provided one with the parsed information.
 func MissingPayloadFromBytes(bytes []byte, optionalTargetObject ...*MissingPayload) (result *MissingPayload, err error, consumedBytes int) {
+	marshalUtil := marshalutil.New(bytes)
+	result, err = ParseMissingPayload(marshalUtil, optionalTargetObject...)
+	consumedBytes = marshalUtil.ReadOffset()
+
+	return
+}
+
+func ParseMissingPayload(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*MissingPayload) (result *MissingPayload, err error) {
+	if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) {
+		return MissingPayloadFromStorageKey(data, optionalTargetObject...)
+	}); parseErr != nil {
+		err = parseErr
+
+		return
+	} else {
+		result = parsedObject.(*MissingPayload)
+	}
+
+	if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) {
+		parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data)
+
+		return
+	}); err != nil {
+		return
+	}
+
+	return
+}
+
+// MissingPayloadFromStorageKey gets called when we restore an entry for a missing value transfer payload from the storage. The bytes and
+// the content will be unmarshaled by an external caller using the binary.ObjectStorageValue interface.
+func MissingPayloadFromStorageKey(key []byte, optionalTargetObject ...*MissingPayload) (result *MissingPayload, err error, consumedBytes int) {
 	// determine the target object that will hold the unmarshaled information
 	switch len(optionalTargetObject) {
 	case 0:
@@ -36,28 +68,19 @@ func MissingPayloadFromBytes(bytes []byte, optionalTargetObject ...*MissingPaylo
 	case 1:
 		result = optionalTargetObject[0]
 	default:
-		panic("too many arguments in call to MissingPayloadFromBytes")
+		panic("too many arguments in call to MissingPayloadFromStorageKey")
 	}
 
-	// parse the bytes
-	marshalUtil := marshalutil.New(bytes)
+	// parse the properties that are stored in the key
+	marshalUtil := marshalutil.New(key)
 	if result.payloadId, err = payload.ParseId(marshalUtil); err != nil {
 		return
 	}
-	if result.missingSince, err = marshalUtil.ReadTime(); err != nil {
-		return
-	}
 	consumedBytes = marshalUtil.ReadOffset()
 
 	return
 }
 
-// MissingPayloadFromStorageKey gets called when we restore an entry for a missing value transfer payload from the storage. The bytes and
-// the content will be unmarshaled by an external caller using the binary.ObjectStorageValue interface.
-func MissingPayloadFromStorageKey([]byte) (result objectstorage.StorableObject, err error, consumedBytes int) {
-	return
-}
-
 // GetId returns the payload id, that is missing.
 func (missingPayload *MissingPayload) GetId() payload.Id {
 	return missingPayload.payloadId
@@ -70,12 +93,10 @@ func (missingPayload *MissingPayload) GetMissingSince() time.Time {
 
 // Bytes marshals the missing payload into a sequence of bytes.
 func (missingPayload *MissingPayload) Bytes() []byte {
-	marshalUtil := marshalutil.New()
-
-	marshalUtil.WriteBytes(missingPayload.payloadId.Bytes())
-	marshalUtil.WriteTime(missingPayload.missingSince)
-
-	return marshalUtil.Bytes()
+	return marshalutil.New(payload.IdLength + marshalutil.TIME_SIZE).
+		WriteBytes(missingPayload.ObjectStorageKey()).
+		WriteBytes(missingPayload.ObjectStorageValue()).
+		Bytes()
 }
 
 // Update is disabled and panics if it ever gets called - updates are supposed to happen through the setters.
@@ -92,12 +113,18 @@ func (missingPayload *MissingPayload) ObjectStorageKey() []byte {
 
 // ObjectStorageValue is required to match the encoding.BinaryMarshaler interface.
 func (missingPayload *MissingPayload) ObjectStorageValue() (data []byte) {
-	return missingPayload.Bytes()
+	return marshalutil.New(marshalutil.TIME_SIZE).
+		WriteTime(missingPayload.missingSince).
+		Bytes()
 }
 
 // UnmarshalObjectStorageValue is required to match the encoding.BinaryUnmarshaler interface.
 func (missingPayload *MissingPayload) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) {
-	_, err, consumedBytes = MissingPayloadFromBytes(data, missingPayload)
+	marshalUtil := marshalutil.New(data)
+	if missingPayload.missingSince, err = marshalUtil.ReadTime(); err != nil {
+		return
+	}
+	consumedBytes = marshalUtil.ReadOffset()
 
 	return
 }
diff --git a/packages/binary/valuetransfer/tangle/objectstorage.go b/packages/binary/valuetransfer/tangle/objectstorage.go
new file mode 100644
index 00000000..e02ee3b3
--- /dev/null
+++ b/packages/binary/valuetransfer/tangle/objectstorage.go
@@ -0,0 +1,55 @@
+package tangle
+
+import (
+	"github.com/iotaledger/hive.go/objectstorage"
+
+	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload"
+	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction"
+)
+
+const (
+	// the following values are a list of prefixes defined as an enum
+	_ byte = iota
+
+	// prefixes used for the objectstorage
+	osPayload
+	osPayloadMetadata
+	osMissingPayload
+	osApprover
+	osAttachment
+	osOutput
+	osMissingOutput
+	osConsumer
+)
+
+func osPayloadFactory(key []byte) (objectstorage.StorableObject, error, int) {
+	return payload.FromStorageKey(key)
+}
+
+func osPayloadMetadataFactory(key []byte) (objectstorage.StorableObject, error, int) {
+	return PayloadMetadataFromStorageKey(key)
+}
+
+func osMissingPayloadFactory(key []byte) (objectstorage.StorableObject, error, int) {
+	return MissingPayloadFromStorageKey(key)
+}
+
+func osPayloadApproverFactory(key []byte) (objectstorage.StorableObject, error, int) {
+	return PayloadApproverFromStorageKey(key)
+}
+
+func osAttachmentFactory(key []byte) (objectstorage.StorableObject, error, int) {
+	return AttachmentFromStorageKey(key)
+}
+
+func osOutputFactory(key []byte) (objectstorage.StorableObject, error, int) {
+	return transaction.OutputFromStorageKey(key)
+}
+
+func osMissingOutputFactory(key []byte) (objectstorage.StorableObject, error, int) {
+	return MissingOutputFromStorageKey(key)
+}
+
+func osConsumerFactory(key []byte) (objectstorage.StorableObject, error, int) {
+	return ConsumerFromStorageKey(key)
+}
diff --git a/packages/binary/valuetransfer/tangle/payloadapprover.go b/packages/binary/valuetransfer/tangle/payloadapprover.go
index 4664cb16..26aa76f6 100644
--- a/packages/binary/valuetransfer/tangle/payloadapprover.go
+++ b/packages/binary/valuetransfer/tangle/payloadapprover.go
@@ -31,28 +31,60 @@ func NewPayloadApprover(referencedPayload payload.Id, approvingPayload payload.I
 	}
 }
 
-// PayloadApproverFromStorageKey get's called when we restore transaction metadata from the storage.
-// In contrast to other database models, it unmarshals the information from the key and does not use the UnmarshalObjectStorageValue
-// method.
-func PayloadApproverFromStorageKey(idBytes []byte) (result objectstorage.StorableObject, err error, consumedBytes int) {
-	marshalUtil := marshalutil.New(idBytes)
+func PayloadApproverFromBytes(bytes []byte, optionalTargetObject ...*PayloadApprover) (result *PayloadApprover, err error, consumedBytes int) {
+	marshalUtil := marshalutil.New(bytes)
+	result, err = ParsePayloadApprover(marshalUtil, optionalTargetObject...)
+	consumedBytes = marshalUtil.ReadOffset()
+
+	return
+}
+
+func ParsePayloadApprover(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*PayloadApprover) (result *PayloadApprover, err error) {
+	if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) {
+		return PayloadApproverFromStorageKey(data, optionalTargetObject...)
+	}); parseErr != nil {
+		err = parseErr
 
-	referencedPayloadId, err := payload.ParseId(marshalUtil)
-	if err != nil {
 		return
+	} else {
+		result = parsedObject.(*PayloadApprover)
 	}
-	approvingPayloadId, err := payload.ParseId(marshalUtil)
-	if err != nil {
+
+	if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) {
+		parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data)
+
+		return
+	}); err != nil {
 		return
 	}
 
-	result = &PayloadApprover{
-		referencedPayloadId: referencedPayloadId,
-		approvingPayloadId:  approvingPayloadId,
-		storageKey:          marshalUtil.Bytes(true),
+	return
+}
+
+// PayloadApproverFromStorageKey get's called when we restore transaction metadata from the storage.
+// In contrast to other database models, it unmarshals the information from the key and does not use the UnmarshalObjectStorageValue
+// method.
+func PayloadApproverFromStorageKey(key []byte, optionalTargetObject ...*PayloadApprover) (result *PayloadApprover, err error, consumedBytes int) {
+	// determine the target object that will hold the unmarshaled information
+	switch len(optionalTargetObject) {
+	case 0:
+		result = &PayloadApprover{}
+	case 1:
+		result = optionalTargetObject[0]
+	default:
+		panic("too many arguments in call to PayloadApproverFromStorageKey")
 	}
 
+	// parse the properties that are stored in the key
+	marshalUtil := marshalutil.New(key)
+	if result.referencedPayloadId, err = payload.ParseId(marshalUtil); err != nil {
+		return
+	}
+	if result.approvingPayloadId, err = payload.ParseId(marshalUtil); err != nil {
+		return
+	}
 	consumedBytes = marshalUtil.ReadOffset()
+	result.storageKey = marshalutil.New(key[:consumedBytes]).Bytes(true)
 
 	return
 }
diff --git a/packages/binary/valuetransfer/tangle/payloadmetadata.go b/packages/binary/valuetransfer/tangle/payloadmetadata.go
index 4308e595..981e64bc 100644
--- a/packages/binary/valuetransfer/tangle/payloadmetadata.go
+++ b/packages/binary/valuetransfer/tangle/payloadmetadata.go
@@ -34,39 +34,52 @@ func NewPayloadMetadata(payloadId payload.Id) *PayloadMetadata {
 // PayloadMetadataFromBytes unmarshals a container with the metadata of a value transfer payload from a sequence of bytes.
 // It either creates a new container or fills the optionally provided container with the parsed information.
 func PayloadMetadataFromBytes(bytes []byte, optionalTargetObject ...*PayloadMetadata) (result *PayloadMetadata, err error, consumedBytes int) {
-	// determine the target object that will hold the unmarshaled information
-	switch len(optionalTargetObject) {
-	case 0:
-		result = &PayloadMetadata{}
-	case 1:
-		result = optionalTargetObject[0]
-	default:
-		panic("too many arguments in call to PayloadMetadataFromBytes")
-	}
-
-	// parse the bytes
 	marshalUtil := marshalutil.New(bytes)
-	if result.payloadId, err = payload.ParseId(marshalUtil); err != nil {
+	result, err = ParsePayloadMetadata(marshalUtil, optionalTargetObject...)
+	consumedBytes = marshalUtil.ReadOffset()
+
+	return
+}
+
+// ParsePayloadMetadata is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package.
+func ParsePayloadMetadata(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*PayloadMetadata) (result *PayloadMetadata, err error) {
+	if parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, error, int) {
+		return PayloadMetadataFromStorageKey(data, optionalTargetObject...)
+	}); parseErr != nil {
+		err = parseErr
+
 		return
+	} else {
+		result = parsedObject.(*PayloadMetadata)
 	}
-	if result.solidificationTime, err = marshalUtil.ReadTime(); err != nil {
+
+	if _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parseErr error, parsedBytes int) {
+		parseErr, parsedBytes = result.UnmarshalObjectStorageValue(data)
+
 		return
-	}
-	if result.solid, err = marshalUtil.ReadBool(); err != nil {
+	}); err != nil {
 		return
 	}
-	consumedBytes = marshalUtil.ReadOffset()
 
 	return
 }
 
 // PayloadMetadataFromStorageKey gets called when we restore transaction metadata from the storage. The bytes and the content will be
 // unmarshaled by an external caller using the binary.ObjectStorageValue interface.
-func PayloadMetadataFromStorageKey(id []byte) (result objectstorage.StorableObject, err error, consumedBytes int) {
-	result = &PayloadMetadata{}
+func PayloadMetadataFromStorageKey(id []byte, optionalTargetObject ...*PayloadMetadata) (result *PayloadMetadata, err error, consumedBytes int) {
+	// determine the target object that will hold the unmarshaled information
+	switch len(optionalTargetObject) {
+	case 0:
+		result = &PayloadMetadata{}
+	case 1:
+		result = optionalTargetObject[0]
+	default:
+		panic("too many arguments in call to PayloadMetadataFromStorageKey")
+	}
 
+	// parse the properties that are stored in the key
 	marshalUtil := marshalutil.New(id)
-	if result.(*PayloadMetadata).payloadId, err = payload.ParseId(marshalUtil); err != nil {
+	if result.payloadId, err = payload.ParseId(marshalUtil); err != nil {
 		return
 	}
 	consumedBytes = marshalUtil.ReadOffset()
@@ -74,15 +87,6 @@ func PayloadMetadataFromStorageKey(id []byte) (result objectstorage.StorableObje
 	return
 }
 
-// ParsePayloadMetadata is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package.
-func ParsePayloadMetadata(marshalUtil *marshalutil.MarshalUtil) (*PayloadMetadata, error) {
-	if payloadMetadata, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return PayloadMetadataFromBytes(data) }); err != nil {
-		return nil, err
-	} else {
-		return payloadMetadata.(*PayloadMetadata), nil
-	}
-}
-
 // GetPayloadId return the id of the payload that this metadata is associated to.
 func (payloadMetadata *PayloadMetadata) GetPayloadId() payload.Id {
 	return payloadMetadata.payloadId
@@ -136,13 +140,10 @@ func (payloadMetadata *PayloadMetadata) GetSoldificationTime() time.Time {
 
 // Bytes marshals the metadata into a sequence of bytes.
 func (payloadMetadata *PayloadMetadata) Bytes() []byte {
-	marshalUtil := marshalutil.New()
-
-	marshalUtil.WriteBytes(payloadMetadata.payloadId.Bytes())
-	marshalUtil.WriteTime(payloadMetadata.solidificationTime)
-	marshalUtil.WriteBool(payloadMetadata.solid)
-
-	return marshalUtil.Bytes()
+	return marshalutil.New(payload.IdLength + marshalutil.TIME_SIZE + marshalutil.BOOL_SIZE).
+		WriteBytes(payloadMetadata.ObjectStorageKey()).
+		WriteBytes(payloadMetadata.ObjectStorageValue()).
+		Bytes()
 }
 
 // String creates a human readable version of the metadata (for debug purposes).
@@ -168,12 +169,22 @@ func (payloadMetadata *PayloadMetadata) Update(other objectstorage.StorableObjec
 
 // ObjectStorageValue is required to match the encoding.BinaryMarshaler interface.
 func (payloadMetadata *PayloadMetadata) ObjectStorageValue() []byte {
-	return payloadMetadata.Bytes()
+	return marshalutil.New(marshalutil.TIME_SIZE + marshalutil.BOOL_SIZE).
+		WriteTime(payloadMetadata.solidificationTime).
+		WriteBool(payloadMetadata.solid).
+		Bytes()
 }
 
 // UnmarshalObjectStorageValue is required to match the encoding.BinaryUnmarshaler interface.
 func (payloadMetadata *PayloadMetadata) UnmarshalObjectStorageValue(data []byte) (err error, consumedBytes int) {
-	_, err, consumedBytes = PayloadMetadataFromBytes(data, payloadMetadata)
+	marshalUtil := marshalutil.New(data)
+	if payloadMetadata.solidificationTime, err = marshalUtil.ReadTime(); err != nil {
+		return
+	}
+	if payloadMetadata.solid, err = marshalUtil.ReadBool(); err != nil {
+		return
+	}
+	consumedBytes = marshalUtil.ReadOffset()
 
 	return
 }
diff --git a/packages/binary/valuetransfer/tangle/tangle.go b/packages/binary/valuetransfer/tangle/tangle.go
index 61bb3ca1..f19490fd 100644
--- a/packages/binary/valuetransfer/tangle/tangle.go
+++ b/packages/binary/valuetransfer/tangle/tangle.go
@@ -19,8 +19,6 @@ import (
 // Tangle represents the value tangle that consists out of value payloads.
 // It is an independent ontology, that lives inside the tangle.
 type Tangle struct {
-	storageId []byte
-
 	payloadStorage         *objectstorage.ObjectStorage
 	payloadMetadataStorage *objectstorage.ObjectStorage
 	approverStorage        *objectstorage.ObjectStorage
@@ -38,24 +36,21 @@ type Tangle struct {
 	cleanupWorkerPool      async.WorkerPool
 }
 
-func New(badgerInstance *badger.DB, storageId []byte) (result *Tangle) {
-	result = &Tangle{
-		storageId: storageId,
+func New(badgerInstance *badger.DB) (result *Tangle) {
+	osFactory := objectstorage.NewFactory(badgerInstance, storageprefix.ValueTransfers)
 
+	result = &Tangle{
 		// payload related storage
-		payloadStorage:         objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferPayload...), payload.StorableObjectFromKey, objectstorage.CacheTime(time.Second)),
-		payloadMetadataStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferPayloadMetadata...), PayloadMetadataFromStorageKey, objectstorage.CacheTime(time.Second)),
-		missingPayloadStorage:  objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferMissingPayload...), MissingPayloadFromStorageKey, objectstorage.CacheTime(time.Second)),
-		approverStorage:        objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferApprover...), PayloadApproverFromStorageKey, objectstorage.CacheTime(time.Second), objectstorage.PartitionKey(payload.IdLength, payload.IdLength), objectstorage.KeysOnly(true)),
-
-		// transaction related storage
-		outputStorage:        objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTangleOutputs...), outputFromStorageKey, objectstorage.PartitionKey(transaction.OutputKeyPartitions...), objectstorage.CacheTime(time.Second)),
-		missingOutputStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferMissingPayload...), MissingOutputFromStorageKey, objectstorage.CacheTime(time.Second)),
-		consumerStorage:      objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferConsumer...), consumerFromStorageKey, objectstorage.CacheTime(time.Second)),
-
-		attachmentStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferAttachment...), AttachmentFromStorageKey, objectstorage.CacheTime(time.Second)),
+		payloadStorage:         osFactory.New(osPayload, osPayloadFactory, objectstorage.CacheTime(time.Second)),
+		payloadMetadataStorage: osFactory.New(osPayloadMetadata, osPayloadMetadataFactory, objectstorage.CacheTime(time.Second)),
+		missingPayloadStorage:  osFactory.New(osMissingPayload, osMissingPayloadFactory, objectstorage.CacheTime(time.Second)),
+		approverStorage:        osFactory.New(osApprover, osPayloadApproverFactory, objectstorage.CacheTime(time.Second), objectstorage.PartitionKey(payload.IdLength, payload.IdLength), objectstorage.KeysOnly(true)),
 
 		// transaction related storage
+		attachmentStorage:    osFactory.New(osAttachment, osAttachmentFactory, objectstorage.CacheTime(time.Second)),
+		outputStorage:        osFactory.New(osOutput, osOutputFactory, transaction.OutputKeyPartitions, objectstorage.CacheTime(time.Second)),
+		missingOutputStorage: osFactory.New(osMissingOutput, osMissingOutputFactory, MissingOutputKeyPartitions, objectstorage.CacheTime(time.Second)),
+		consumerStorage:      osFactory.New(osConsumer, osConsumerFactory, ConsumerPartitionKeys, objectstorage.CacheTime(time.Second)),
 
 		Events: *newEvents(),
 	}
@@ -425,11 +420,3 @@ func (tangle *Tangle) isPayloadMarkedAsSolid(payloadId payload.Id) bool {
 
 	return true
 }
-
-func outputFromStorageKey(key []byte) (objectstorage.StorableObject, error, int) {
-	return transaction.OutputFromStorageKey(key)
-}
-
-func consumerFromStorageKey(key []byte) (objectstorage.StorableObject, error, int) {
-	return ConsumerFromStorageKey(key)
-}
diff --git a/packages/binary/valuetransfer/tangle/tangle_test.go b/packages/binary/valuetransfer/tangle/tangle_test.go
index f2f371ec..2b21059b 100644
--- a/packages/binary/valuetransfer/tangle/tangle_test.go
+++ b/packages/binary/valuetransfer/tangle/tangle_test.go
@@ -45,7 +45,7 @@ func TestTangle_AttachPayload(t *testing.T) {
 
 	config.Node.Set(database.CFG_DIRECTORY, dir)
 
-	tangle := New(database.GetBadgerInstance(), []byte("TEST_BINARY_TANGLE"))
+	tangle := New(database.GetBadgerInstance())
 	if err := tangle.Prune(); err != nil {
 		t.Error(err)
 
diff --git a/packages/binary/valuetransfer/transaction/output.go b/packages/binary/valuetransfer/transaction/output.go
index 2fa3a6e9..78535f4f 100644
--- a/packages/binary/valuetransfer/transaction/output.go
+++ b/packages/binary/valuetransfer/transaction/output.go
@@ -11,7 +11,7 @@ import (
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/balance"
 )
 
-var OutputKeyPartitions = []int{address.Length, IdLength}
+var OutputKeyPartitions = objectstorage.PartitionKey([]int{address.Length, IdLength}...)
 
 // Output represents the output of a Transaction and contains the balances and the identifiers for this output.
 type Output struct {
@@ -76,7 +76,7 @@ func ParseOutput(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*
 // OutputFromStorageKey get's called when we restore a Output from the storage.
 // In contrast to other database models, it unmarshals some information from the key so we simply store the key before
 // it gets handed over to UnmarshalObjectStorageValue (by the ObjectStorage).
-func OutputFromStorageKey(keyBytes []byte, optionalTargetObject ...*Output) (result objectstorage.StorableObject, err error, consumedBytes int) {
+func OutputFromStorageKey(keyBytes []byte, optionalTargetObject ...*Output) (result *Output, err error, consumedBytes int) {
 	// determine the target object that will hold the unmarshaled information
 	switch len(optionalTargetObject) {
 	case 0:
@@ -89,15 +89,15 @@ func OutputFromStorageKey(keyBytes []byte, optionalTargetObject ...*Output) (res
 
 	// parse information
 	marshalUtil := marshalutil.New(keyBytes)
-	result.(*Output).address, err = address.Parse(marshalUtil)
+	result.address, err = address.Parse(marshalUtil)
 	if err != nil {
 		return
 	}
-	result.(*Output).transactionId, err = ParseId(marshalUtil)
+	result.transactionId, err = ParseId(marshalUtil)
 	if err != nil {
 		return
 	}
-	result.(*Output).storageKey = marshalutil.New(keyBytes[:OutputIdLength]).Bytes(true)
+	result.storageKey = marshalutil.New(keyBytes[:OutputIdLength]).Bytes(true)
 	consumedBytes = marshalUtil.ReadOffset()
 
 	return
diff --git a/plugins/messagelayer/plugin.go b/plugins/messagelayer/plugin.go
index 1957f750..7e0ad510 100644
--- a/plugins/messagelayer/plugin.go
+++ b/plugins/messagelayer/plugin.go
@@ -14,7 +14,6 @@ import (
 	"github.com/iotaledger/goshimmer/packages/binary/messagelayer/tipselector"
 	"github.com/iotaledger/goshimmer/packages/binary/messagelayer/transactionparser"
 	"github.com/iotaledger/goshimmer/packages/binary/messagelayer/transactionrequester"
-	"github.com/iotaledger/goshimmer/packages/binary/storageprefix"
 	"github.com/iotaledger/goshimmer/packages/database"
 	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/goshimmer/plugins/autopeering/local"
@@ -46,7 +45,7 @@ func configure(*node.Plugin) {
 	TransactionParser = transactionparser.New()
 	TransactionRequester = transactionrequester.New()
 	TipSelector = tipselector.New()
-	Tangle = tangle.New(database.GetBadgerInstance(), storageprefix.MainNet)
+	Tangle = tangle.New(database.GetBadgerInstance())
 
 	// Setup MessageFactory (behavior + logging))
 	MessageFactory = messagefactory.New(database.GetBadgerInstance(), local.GetInstance().LocalIdentity(), TipSelector, []byte(DB_SEQUENCE_NUMBER))
-- 
GitLab