diff --git a/packages/binary/tangle/tangle.go b/packages/binary/tangle/tangle.go
new file mode 100644
index 0000000000000000000000000000000000000000..2d6210fc7f80559cdf879af4ca652c34a1474db3
--- /dev/null
+++ b/packages/binary/tangle/tangle.go
@@ -0,0 +1,22 @@
+package tangle
+
+import (
+	"github.com/iotaledger/goshimmer/packages/binary/transaction"
+	"github.com/iotaledger/hive.go/objectstorage"
+)
+
+type Tangle struct {
+	transactionStorage *objectstorage.ObjectStorage
+}
+
+func New(storageId string) *Tangle {
+	return &Tangle{
+		transactionStorage: objectstorage.New(storageId+"TANGLE_TRANSACTION_STORAGE", transactionFactory),
+	}
+}
+
+func transactionFactory(key []byte) objectstorage.StorableObject {
+	result := transaction.FromStorage(key)
+
+	return result
+}
diff --git a/packages/binary/transaction/id.go b/packages/binary/transaction/id.go
new file mode 100644
index 0000000000000000000000000000000000000000..be29a8b8c95e09ad30ed5e0a1f5704ef5cba8dd6
--- /dev/null
+++ b/packages/binary/transaction/id.go
@@ -0,0 +1,5 @@
+package transaction
+
+type Id [transactionIdLength]byte
+
+const transactionIdLength = 64
diff --git a/packages/binary/transaction/payload.go b/packages/binary/transaction/payload.go
new file mode 100644
index 0000000000000000000000000000000000000000..13cb0d6160cf0cc45163fc70ff4f60c30bcc4884
--- /dev/null
+++ b/packages/binary/transaction/payload.go
@@ -0,0 +1,12 @@
+package transaction
+
+import (
+	"encoding"
+)
+
+type Payload interface {
+	encoding.BinaryMarshaler
+	encoding.BinaryUnmarshaler
+
+	GetType() int
+}
diff --git a/packages/binary/transaction/payload_id.go b/packages/binary/transaction/payload_id.go
new file mode 100644
index 0000000000000000000000000000000000000000..ca8edef87c597ee853b9fcb1d304dd94d2c28777
--- /dev/null
+++ b/packages/binary/transaction/payload_id.go
@@ -0,0 +1,5 @@
+package transaction
+
+type PayloadId [payloadIdLength]byte
+
+const payloadIdLength = 64
diff --git a/packages/binary/transaction/transaction.go b/packages/binary/transaction/transaction.go
new file mode 100644
index 0000000000000000000000000000000000000000..06a0e56ced017f453f19d489ad639bccce80669b
--- /dev/null
+++ b/packages/binary/transaction/transaction.go
@@ -0,0 +1,164 @@
+package transaction
+
+import (
+	"sync"
+
+	"github.com/iotaledger/hive.go/objectstorage"
+
+	"golang.org/x/crypto/blake2b"
+)
+
+type Transaction struct {
+	// base functionality of StorableObject
+	objectstorage.StorableObjectFlags
+
+	// core properties (they are part of the transaction when being sent)
+	trunkTransactionId  Id
+	branchTransactionId Id
+	payload             Payload
+
+	// derived properties
+	id             *Id
+	idMutex        sync.RWMutex
+	payloadId      *PayloadId
+	payloadIdMutex sync.RWMutex
+	bytes          []byte
+	bytesMutex     sync.RWMutex
+}
+
+func FromStorage(id []byte) (result *Transaction) {
+	var transactionId Id
+	copy(transactionId[:], id)
+
+	result = &Transaction{
+		id: &transactionId,
+	}
+
+	return
+}
+
+func (transaction *Transaction) GetId() (result Id) {
+	transaction.idMutex.RLock()
+	if transaction.id == nil {
+		transaction.idMutex.RLock()
+
+		transaction.idMutex.Lock()
+		if transaction.id == nil {
+			result = transaction.calculateTransactionId()
+
+			transaction.id = &result
+		} else {
+			result = *transaction.id
+		}
+		transaction.idMutex.Unlock()
+	} else {
+		result = *transaction.id
+
+		transaction.idMutex.RLock()
+	}
+
+	return
+}
+
+func (transaction *Transaction) GetPayloadId() (result PayloadId) {
+	transaction.payloadIdMutex.RLock()
+	if transaction.payloadId == nil {
+		transaction.payloadIdMutex.RLock()
+
+		transaction.payloadIdMutex.Lock()
+		if transaction.payloadId == nil {
+			result = transaction.calculatePayloadId()
+
+			transaction.payloadId = &result
+		} else {
+			result = *transaction.payloadId
+		}
+		transaction.payloadIdMutex.Unlock()
+	} else {
+		result = *transaction.payloadId
+
+		transaction.payloadIdMutex.RLock()
+	}
+
+	return
+}
+
+func (transaction *Transaction) GetBytes() (result []byte) {
+	transaction.bytesMutex.RLock()
+	if transaction.bytes == nil {
+		transaction.bytesMutex.RLock()
+
+		transaction.bytesMutex.Lock()
+		if transaction.bytes == nil {
+			var err error
+
+			if result, err = transaction.MarshalBinary(); err != nil {
+				// this should never happen
+				panic(err)
+			}
+
+			transaction.bytes = result
+		} else {
+			result = transaction.bytes
+		}
+		transaction.bytesMutex.Unlock()
+	} else {
+		result = transaction.bytes
+
+		transaction.bytesMutex.RLock()
+	}
+
+	return
+}
+
+func (transaction *Transaction) calculateTransactionId() Id {
+	payloadId := transaction.GetPayloadId()
+
+	hashBase := make([]byte, transactionIdLength+transactionIdLength+payloadIdLength)
+	offset := 0
+
+	copy(hashBase[offset:], transaction.trunkTransactionId[:])
+	offset += transactionIdLength
+
+	copy(hashBase[offset:], transaction.branchTransactionId[:])
+	offset += transactionIdLength
+
+	copy(hashBase[offset:], payloadId[:])
+	offset += payloadIdLength
+
+	return blake2b.Sum512(hashBase)
+}
+
+func (transaction *Transaction) calculatePayloadId() PayloadId {
+	bytes := transaction.GetBytes()
+
+	return blake2b.Sum512(bytes[2*transactionIdLength:])
+}
+
+func (transaction *Transaction) MarshalBinary() (result []byte, err error) {
+	result = make([]byte, 2*transactionIdLength)
+
+	if serializedPayload, serializationErr := transaction.payload.MarshalBinary(); serializationErr != nil {
+		err = serializationErr
+
+		return
+	} else {
+		result = append(result, serializedPayload...)
+	}
+
+	return
+}
+
+// TODO: FINISH
+func (transaction *Transaction) UnmarshalBinary(date []byte) (err error) {
+	return
+}
+
+func (transaction *Transaction) GetStorageKey() []byte {
+	transactionId := transaction.GetId()
+
+	return transactionId[:]
+}
+
+// TODO: FINISH
+func (transaction *Transaction) Update(other objectstorage.StorableObject) {}
diff --git a/packages/bitutils/offset.go b/packages/bitutils/offset.go
new file mode 100644
index 0000000000000000000000000000000000000000..9ecd43c274407a5aa9022939dce996855a995fff
--- /dev/null
+++ b/packages/bitutils/offset.go
@@ -0,0 +1,21 @@
+package bitutils
+
+import (
+	"unsafe"
+)
+
+type Offset int
+
+func NewOffset() *Offset {
+	offset := Offset(0)
+
+	return &offset
+}
+
+func (offset *Offset) Inc(delta int) (newOffset int) {
+	newOffset = *(*int)(unsafe.Pointer(offset)) + delta
+
+	*offset = *(*Offset)(unsafe.Pointer(&newOffset))
+
+	return
+}
diff --git a/packages/bitutils/offset_test.go b/packages/bitutils/offset_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..345df662a3558eb12ca9de67d906755d8e70d46f
--- /dev/null
+++ b/packages/bitutils/offset_test.go
@@ -0,0 +1,38 @@
+package bitutils
+
+import (
+	"fmt"
+	"testing"
+)
+
+func BenchmarkOffset_Inc(b *testing.B) {
+	var x Offset
+
+	for i := 0; i < b.N; i++ {
+		x.Inc(1)
+	}
+}
+
+func Benchmark_Inc(b *testing.B) {
+	x := 0
+
+	for i := 0; i < b.N; i++ {
+		x++
+	}
+}
+
+func TestOffset_Inc(t *testing.T) {
+	q := 3
+
+	j := &q
+
+	*j = 12
+
+	fmt.Println(q)
+
+	var x Offset
+
+	x.Inc(4)
+
+	fmt.Println(x)
+}
diff --git a/packages/ledgerstate/ledgerstate_test.go b/packages/ledgerstate/ledgerstate_test.go
index be5cdf81d3f91ae00ae2acb3b83a8d93b6e50f57..84dbfd10b923ce21a36cd549436bd1fc0ebb8179 100644
--- a/packages/ledgerstate/ledgerstate_test.go
+++ b/packages/ledgerstate/ledgerstate_test.go
@@ -222,8 +222,8 @@ func TestAggregateAggregatedRealities(t *testing.T) {
 	outputs1 := multiSpend(ledgerState, 2, multiSpend(ledgerState, 1, transferOutputs[1])[0])
 	multiSpend(ledgerState, 1, transferOutputs[1])
 
-	multiSpend(ledgerState, 1, transferOutputs[2])
 	outputs2 := multiSpend(ledgerState, 2, multiSpend(ledgerState, 1, transferOutputs[2])[0])
+	multiSpend(ledgerState, 1, transferOutputs[2])
 
 	aggregatedOutputs0 := multiSpend(ledgerState, 2, outputs0[0], outputs1[0])
 	aggregatedOutputs1 := multiSpend(ledgerState, 2, outputs1[1], outputs2[1])
diff --git a/packages/ledgerstate/outputs1.png b/packages/ledgerstate/outputs1.png
index dfd470d7176c3bbe1ba5a22a683236185ada77c0..3113c75833e458ab2bcf84e6596befc8c8e46a30 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 1091bb3948e28c5185f490646c85590d67c257aa..7b2d13e78682f509b9c425714dbee0bc3dc068fc 100644
Binary files a/packages/ledgerstate/outputs2.png and b/packages/ledgerstate/outputs2.png differ
diff --git a/packages/ledgerstate/realities1.png b/packages/ledgerstate/realities1.png
index 632f38af62b17e2feb2609e6e40df9b14e7555ab..9506a61b894d1193dd33faa6375a3182b042bc4c 100644
Binary files a/packages/ledgerstate/realities1.png and b/packages/ledgerstate/realities1.png differ
diff --git a/packages/ledgerstate/realities2.png b/packages/ledgerstate/realities2.png
index 51d0e54970a4ad8e61be95e328557918dc07a4cc..cd86247171dbc3800c20dc35df1b532eef937ede 100644
Binary files a/packages/ledgerstate/realities2.png and b/packages/ledgerstate/realities2.png differ
diff --git a/packages/ledgerstate/reality.objectstorage.go b/packages/ledgerstate/reality.objectstorage.go
index a43ae432b8edf747726eaf19567b0233022d8888..fac42376ff3104ca79619217c4686232bcb442be 100644
--- a/packages/ledgerstate/reality.objectstorage.go
+++ b/packages/ledgerstate/reality.objectstorage.go
@@ -3,6 +3,8 @@ package ledgerstate
 import (
 	"encoding/binary"
 
+	"github.com/iotaledger/hive.go/bitmask"
+
 	"github.com/iotaledger/hive.go/objectstorage"
 )
 
@@ -26,11 +28,21 @@ func (reality *Reality) MarshalBinary() ([]byte, error) {
 	parentRealityCount := len(reality.parentRealityIds)
 	subRealityCount := len(reality.subRealityIds)
 
-	marshaledReality := make([]byte, 4+4+4+1+parentRealityCount*realityIdLength+subRealityCount*realityIdLength)
+	marshaledReality := make([]byte, 1+4+4+4+parentRealityCount*realityIdLength+subRealityCount*realityIdLength)
 
 	offset := 0
 
-	binary.LittleEndian.PutUint32(marshaledReality, uint32(reality.GetTransferOutputCount()))
+	var flags bitmask.BitMask
+	if reality.IsPreferred() {
+		flags = flags.SetFlag(0)
+	}
+	if reality.IsLiked() {
+		flags = flags.SetFlag(1)
+	}
+	marshaledReality[offset] = byte(flags)
+	offset += 1
+
+	binary.LittleEndian.PutUint32(marshaledReality[offset:], reality.GetTransferOutputCount())
 	offset += 4
 
 	binary.LittleEndian.PutUint32(marshaledReality[offset:], uint32(parentRealityCount))
@@ -49,59 +61,87 @@ func (reality *Reality) MarshalBinary() ([]byte, error) {
 		offset += realityIdLength
 	}
 
-	if reality.liked {
-		marshaledReality[offset] = 1
-	} else {
-		marshaledReality[offset] = 0
-	}
-	//offset += 1
-
 	reality.parentRealityIdsMutex.RUnlock()
 
 	return marshaledReality, nil
 }
 
-func (reality *Reality) UnmarshalBinary(serializedObject []byte) error {
-	if err := reality.id.UnmarshalBinary(reality.storageKey[:realityIdLength]); err != nil {
-		return err
+func (reality *Reality) UnmarshalBinary(serializedObject []byte) (err error) {
+	if err = reality.id.UnmarshalBinary(reality.storageKey[:realityIdLength]); err != nil {
+		return
 	}
 
-	reality.parentRealityIds = NewRealityIdSet()
-	reality.subRealityIds = NewRealityIdSet()
-
 	offset := 0
 
-	reality.transferOutputCount = binary.LittleEndian.Uint32(serializedObject)
-	offset += 4
+	reality.unmarshalBinaryFlags(serializedObject, &offset)
 
-	parentRealityCount := int(binary.LittleEndian.Uint32(serializedObject[offset:]))
-	offset += 4
+	reality.unmarshalBinaryTransferOutputCount(serializedObject, &offset)
+
+	if err = reality.unmarshalBinaryParentRealities(serializedObject, &offset); err != nil {
+		return
+	}
+
+	if err = reality.unmarshalBinarySubRealities(serializedObject, &offset); err != nil {
+		return
+	}
+
+	return nil
+}
+
+func (reality *Reality) unmarshalBinaryFlags(serializedObject []byte, offset *int) {
+	var flags = bitmask.BitMask(serializedObject[*offset])
+
+	if flags.HasFlag(0) {
+		reality.preferred = true
+	}
+
+	if flags.HasFlag(1) {
+		reality.liked = true
+	}
+
+	*offset += 1
+}
+
+func (reality *Reality) unmarshalBinaryTransferOutputCount(serializedObject []byte, offset *int) {
+	reality.transferOutputCount = binary.LittleEndian.Uint32(serializedObject[*offset:])
+
+	*offset = *offset + 4
+}
+
+func (reality *Reality) unmarshalBinaryParentRealities(serializedObject []byte, offset *int) (err error) {
+	reality.parentRealityIds = NewRealityIdSet()
+
+	parentRealityCount := int(binary.LittleEndian.Uint32(serializedObject[*offset:]))
+	*offset += 4
 
 	for i := 0; i < parentRealityCount; i++ {
 		var restoredRealityId RealityId
-		if err := restoredRealityId.UnmarshalBinary(serializedObject[offset:]); err != nil {
-			return err
+		if err = restoredRealityId.UnmarshalBinary(serializedObject[*offset:]); err != nil {
+			return
 		}
-		offset += realityIdLength
+		*offset += realityIdLength
 
 		reality.parentRealityIds[restoredRealityId] = void
 	}
 
-	subRealityCount := int(binary.LittleEndian.Uint32(serializedObject[offset:]))
-	offset += 4
+	return
+}
+
+func (reality *Reality) unmarshalBinarySubRealities(serializedObject []byte, offset *int) (err error) {
+	reality.subRealityIds = NewRealityIdSet()
+
+	subRealityCount := int(binary.LittleEndian.Uint32(serializedObject[*offset:]))
+	*offset += 4
 
 	for i := 0; i < subRealityCount; i++ {
 		var restoredRealityId RealityId
-		if err := restoredRealityId.UnmarshalBinary(serializedObject[offset:]); err != nil {
-			return err
+		if err = restoredRealityId.UnmarshalBinary(serializedObject[*offset:]); err != nil {
+			return
 		}
-		offset += realityIdLength
+		*offset += realityIdLength
 
 		reality.subRealityIds[restoredRealityId] = void
 	}
 
-	reality.liked = serializedObject[offset] == 1
-	//offset += 1
-
-	return nil
+	return
 }