diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000000000000000000000000000000000000..af293b4992dc6b3f39c22d87d49c315d040fcb00
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,20 @@
+module github.com/iotaledger/goshimmer
+
+go 1.12
+
+require (
+	github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 // indirect
+	github.com/dgraph-io/badger v2.0.0-rc.2.0.20190610165348-a804ffa35fb9+incompatible
+	github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect
+	github.com/dustin/go-humanize v1.0.0 // indirect
+	github.com/ethereum/go-ethereum v1.8.27
+	github.com/gdamore/tcell v1.1.2
+	github.com/golang/protobuf v1.3.1 // indirect
+	github.com/google/open-location-code/go v0.0.0-20190603181809-cf814bded323
+	github.com/magiconair/properties v1.8.1
+	github.com/pkg/errors v0.8.1
+	github.com/rivo/tview v0.0.0-20190609162513-b62197ade412
+	github.com/stretchr/testify v1.3.0 // indirect
+	golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5
+	golang.org/x/net v0.0.0-20190611141213-3f473d35a33a
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000000000000000000000000000000000000..63f8201a71105e02dd25090000c3cb389a239901
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,50 @@
+github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 h1:HD8gA2tkByhMAwYaFAX9w2l7vxvBQ5NMoxDrkhqhtn4=
+github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
+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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgraph-io/badger v2.0.0-rc.2.0.20190610165348-a804ffa35fb9+incompatible h1:FE+hrPTLWIHxQzGTbjReHgpkj7+hFWC+L6b2fAxBG+I=
+github.com/dgraph-io/badger v2.0.0-rc.2.0.20190610165348-a804ffa35fb9+incompatible/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ=
+github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
+github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
+github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/ethereum/go-ethereum v1.8.27 h1:d+gkiLaBDk5fn3Pe/xNVaMrB/ozI+AUB2IlVBp29IrY=
+github.com/ethereum/go-ethereum v1.8.27/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY=
+github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
+github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
+github.com/gdamore/tcell v1.1.2 h1:Afe8cU6SECC06UmvaJ55Jr3Eh0tz/ywLjqWYqjGZp3s=
+github.com/gdamore/tcell v1.1.2/go.mod h1:h3kq4HO9l2On+V9ed8w8ewqQEmGCSSHOgQ+2h8uzurE=
+github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/google/open-location-code/go v0.0.0-20190603181809-cf814bded323 h1:s+TV4ZPsmXNvFxr9gzRTOlqf7DT862ieiOGRWA9M3oM=
+github.com/google/open-location-code/go v0.0.0-20190603181809-cf814bded323/go.mod h1:eJfRN6aj+kR/rnua/rw9jAgYhqoMHldQkdTi+sePRKk=
+github.com/lucasb-eyer/go-colorful v1.0.2 h1:mCMFu6PgSozg9tDNMMK3g18oJBX7oYGrC09mS6CXfO4=
+github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
+github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
+github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rivo/tview v0.0.0-20190609162513-b62197ade412 h1:muOFMct2jVhlSw9S3MRrxevpsAIPJeTh4e1Z7pEEQhE=
+github.com/rivo/tview v0.0.0-20190609162513-b62197ade412/go.mod h1:+rKjP5+h9HMwWRpAfhIkkQ9KE3m3Nz5rwn7YtUpwgqk=
+github.com/rivo/uniseg v0.0.0-20190513083848-b9f5b9457d44 h1:XKCbzPvK4/BbMXoMJOkYP2ANxiAEO0HM1xn6psSbXxY=
+github.com/rivo/uniseg v0.0.0-20190513083848-b9f5b9457d44/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190611141213-3f473d35a33a h1:+KkCgOMgnKSgenxTBoiwkMqTiouMIy/3o8RLdmSbGoY=
+golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/main.go b/main.go
index 514f031a620ef1fd5af3b65c3178aa0f4c8a0300..2eb9d49f9bc77f40923a2f0f0846d38ffab50591 100644
--- a/main.go
+++ b/main.go
@@ -6,9 +6,15 @@ import (
 	"github.com/iotaledger/goshimmer/plugins/autopeering"
 	"github.com/iotaledger/goshimmer/plugins/cli"
 	"github.com/iotaledger/goshimmer/plugins/gossip"
+	gossip_on_solidification "github.com/iotaledger/goshimmer/plugins/gossip-on-solidification"
 	"github.com/iotaledger/goshimmer/plugins/gracefulshutdown"
 	"github.com/iotaledger/goshimmer/plugins/statusscreen"
+	statusscreen_tps "github.com/iotaledger/goshimmer/plugins/statusscreen-tps"
 	"github.com/iotaledger/goshimmer/plugins/tangle"
+	"github.com/iotaledger/goshimmer/plugins/tipselection"
+	"github.com/iotaledger/goshimmer/plugins/webapi"
+	webapi_gtta "github.com/iotaledger/goshimmer/plugins/webapi-gtta"
+	webapi_spammer "github.com/iotaledger/goshimmer/plugins/webapi-spammer"
 )
 
 func main() {
@@ -16,9 +22,17 @@ func main() {
 		cli.PLUGIN,
 		autopeering.PLUGIN,
 		gossip.PLUGIN,
+		gossip_on_solidification.PLUGIN,
 		tangle.PLUGIN,
 		analysis.PLUGIN,
-		statusscreen.PLUGIN,
 		gracefulshutdown.PLUGIN,
+		tipselection.PLUGIN,
+
+		statusscreen.PLUGIN,
+		statusscreen_tps.PLUGIN,
+
+		webapi.PLUGIN,
+		webapi_gtta.PLUGIN,
+		webapi_spammer.PLUGIN,
 	)
 }
diff --git a/packages/curl/batch_hasher.go b/packages/curl/batch_hasher.go
index 649550a0c1266d0d6a0b2b7f704e8745997c5f79..c139d50f9923a40d7ca3aa6507fd3a447809133d 100644
--- a/packages/curl/batch_hasher.go
+++ b/packages/curl/batch_hasher.go
@@ -15,6 +15,7 @@ type HashRequest struct {
 
 type BatchHasher struct {
 	hashRequests chan HashRequest
+	tasks        chan []HashRequest
 	hashLength   int
 	rounds       int
 }
@@ -24,13 +25,25 @@ func NewBatchHasher(hashLength int, rounds int) *BatchHasher {
 		hashLength:   hashLength,
 		rounds:       rounds,
 		hashRequests: make(chan HashRequest),
+		tasks:        make(chan []HashRequest, NUMBER_OF_WORKERS),
 	}
 
 	go this.startDispatcher()
+	this.startWorkers()
 
 	return this
 }
 
+func (this *BatchHasher) startWorkers() {
+	for i := 0; i < NUMBER_OF_WORKERS; i++ {
+		go func() {
+			for {
+				this.processHashes(<-this.tasks)
+			}
+		}()
+	}
+}
+
 func (this *BatchHasher) startDispatcher() {
 	for {
 		collectedHashRequests := make([]HashRequest, 0)
@@ -53,7 +66,7 @@ func (this *BatchHasher) startDispatcher() {
 			}
 		}
 
-		go this.processHashes(collectedHashRequests)
+		this.tasks <- collectedHashRequests
 	}
 }
 
@@ -102,3 +115,7 @@ func (this *BatchHasher) Hash(trinary ternary.Trits) chan ternary.Trits {
 
 	return hashRequest.output
 }
+
+const (
+	NUMBER_OF_WORKERS = 100
+)
diff --git a/packages/database/database.go b/packages/database/database.go
index 61d0fcbe031ec2c232c653130b8fcccb6d49f2c3..5efe6e63403010e870b275e5d80fc121d089b6fe 100644
--- a/packages/database/database.go
+++ b/packages/database/database.go
@@ -6,6 +6,7 @@ import (
 	"sync"
 
 	"github.com/dgraph-io/badger"
+	"github.com/dgraph-io/badger/options"
 )
 
 var databasesByName = make(map[string]*databaseImpl)
@@ -58,6 +59,7 @@ func (this *databaseImpl) Open() error {
 		opts.ValueDir = opts.Dir
 		opts.Logger = &logger{}
 		opts.Truncate = true
+		opts.TableLoadingMode = options.MemoryMap
 
 		db, err := badger.Open(opts)
 		if err != nil {
diff --git a/packages/datastructure/doubly_linked_list.go b/packages/datastructure/doubly_linked_list.go
index 34793818e926a513d659b71fec5afcf53a0565fd..91d2e067e6b7cb4a3f2a0aae850ec52a65b34ba3 100644
--- a/packages/datastructure/doubly_linked_list.go
+++ b/packages/datastructure/doubly_linked_list.go
@@ -238,22 +238,26 @@ func (list *DoublyLinkedList) removeEntry(entry *DoublyLinkedListEntry) errors.I
 		return ErrNoSuchElement.Derive("the entry is not part of the list")
 	}
 
+	prevEntry := entry.GetPrev()
 	nextEntry := entry.GetNext()
+
 	if nextEntry != nil {
-		nextEntry.SetPrev(entry.GetPrev())
+		nextEntry.SetPrev(prevEntry)
 	}
 	if list.head == entry {
 		list.head = nextEntry
 	}
 
-	prevEntry := entry.GetPrev()
 	if prevEntry != nil {
-		prevEntry.SetNext(entry.GetNext())
+		prevEntry.SetNext(nextEntry)
 	}
 	if list.tail == entry {
 		list.tail = prevEntry
 	}
 
+	entry.SetNext(nil)
+	entry.SetPrev(nil)
+
 	list.count--
 
 	return nil
diff --git a/packages/datastructure/lru_cache.go b/packages/datastructure/lru_cache.go
index a9e9c406eb9774b44eba80c58b10ddccf174824b..f2701bcc27e51d3b40318d3e9c99a1ae2ba855c4 100644
--- a/packages/datastructure/lru_cache.go
+++ b/packages/datastructure/lru_cache.go
@@ -2,6 +2,8 @@ package datastructure
 
 import (
 	"sync"
+
+	"github.com/iotaledger/goshimmer/packages/typeutils"
 )
 
 type lruCacheElement struct {
@@ -14,14 +16,23 @@ type LRUCache struct {
 	doublyLinkedList *DoublyLinkedList
 	capacity         int
 	size             int
+	options          *LRUCacheOptions
 	mutex            sync.RWMutex
 }
 
-func NewLRUCache(capacity int) *LRUCache {
+func NewLRUCache(capacity int, options ...*LRUCacheOptions) *LRUCache {
+	var currentOptions *LRUCacheOptions
+	if len(options) < 1 || options[0] == nil {
+		currentOptions = DEFAULT_OPTIONS
+	} else {
+		currentOptions = options[0]
+	}
+
 	return &LRUCache{
 		directory:        make(map[interface{}]*DoublyLinkedListEntry, capacity),
 		doublyLinkedList: &DoublyLinkedList{},
 		capacity:         capacity,
+		options:          currentOptions,
 	}
 }
 
@@ -49,7 +60,14 @@ func (cache *LRUCache) set(key interface{}, value interface{}) {
 			if element, err := cache.doublyLinkedList.removeLastEntry(); err != nil {
 				panic(err)
 			} else {
-				delete(directory, element.value.(*lruCacheElement).key)
+				lruCacheElement := element.value.(*lruCacheElement)
+				removedElementKey := lruCacheElement.key
+
+				delete(directory, removedElementKey)
+
+				if cache.options.EvictionCallback != nil {
+					cache.options.EvictionCallback(removedElementKey, lruCacheElement.value)
+				}
 			}
 		} else {
 			cache.size++
@@ -85,8 +103,10 @@ func (cache *LRUCache) ComputeIfPresent(key interface{}, callback func(value int
 	if entry, exists := cache.directory[key]; exists {
 		result = entry.GetValue().(*lruCacheElement).value
 
-		if result = callback(result); result != nil {
-			cache.set(key, result)
+		if callbackResult := callback(result); !typeutils.IsInterfaceNil(callbackResult) {
+			result = callbackResult
+
+			cache.set(key, callbackResult)
 		} else {
 			if err := cache.doublyLinkedList.removeEntry(entry); err != nil {
 				panic(err)
@@ -94,6 +114,10 @@ func (cache *LRUCache) ComputeIfPresent(key interface{}, callback func(value int
 			delete(cache.directory, key)
 
 			cache.size--
+
+			if cache.options.EvictionCallback != nil {
+				cache.options.EvictionCallback(key, result)
+			}
 		}
 	} else {
 		result = nil
@@ -166,6 +190,10 @@ func (cache *LRUCache) Delete(key interface{}) bool {
 
 		cache.size--
 
+		if cache.options.EvictionCallback != nil {
+			cache.options.EvictionCallback(key, entry.GetValue().(*lruCacheElement).key)
+		}
+
 		return true
 	}
 
diff --git a/packages/datastructure/lru_cache_options.go b/packages/datastructure/lru_cache_options.go
new file mode 100644
index 0000000000000000000000000000000000000000..61f0e9c1fabd4697e16ce48e58f24ce2c07d7238
--- /dev/null
+++ b/packages/datastructure/lru_cache_options.go
@@ -0,0 +1,15 @@
+package datastructure
+
+import (
+	"time"
+)
+
+type LRUCacheOptions struct {
+	EvictionCallback func(key interface{}, value interface{})
+	IdleTimeout      time.Duration
+}
+
+var DEFAULT_OPTIONS = &LRUCacheOptions{
+	EvictionCallback: nil,
+	IdleTimeout:      30 * time.Second,
+}
diff --git a/packages/datastructure/random_map.go b/packages/datastructure/random_map.go
new file mode 100644
index 0000000000000000000000000000000000000000..7e43230797dae96ac5fe2eb342276acd151e210c
--- /dev/null
+++ b/packages/datastructure/random_map.go
@@ -0,0 +1,121 @@
+package datastructure
+
+import (
+	"math/rand"
+	"sync"
+	"time"
+)
+
+func init() {
+	rand.Seed(time.Now().UnixNano())
+}
+
+type randomMapEntry struct {
+	key      interface{}
+	value    interface{}
+	keyIndex int
+}
+
+type RandomMap struct {
+	rawMap map[interface{}]*randomMapEntry
+	keys   []interface{}
+	size   int
+	mutex  sync.RWMutex
+}
+
+func NewRandomMap() *RandomMap {
+	return &RandomMap{
+		rawMap: make(map[interface{}]*randomMapEntry),
+		keys:   make([]interface{}, 0),
+	}
+}
+
+func (rmap *RandomMap) Set(key interface{}, value interface{}) {
+	rmap.mutex.Lock()
+
+	if entry, exists := rmap.rawMap[key]; exists {
+		entry.value = value
+	} else {
+		rmap.rawMap[key] = &randomMapEntry{
+			key:      key,
+			value:    value,
+			keyIndex: rmap.size,
+		}
+
+		rmap.keys = append(rmap.keys, key)
+
+		rmap.size++
+	}
+
+	rmap.mutex.Unlock()
+}
+
+func (rmap *RandomMap) Get(key interface{}) (result interface{}, exists bool) {
+	rmap.mutex.RLock()
+
+	if entry, entryExists := rmap.rawMap[key]; entryExists {
+		result = entry.value
+		exists = entryExists
+	}
+
+	rmap.mutex.RUnlock()
+
+	return
+}
+
+func (rmap *RandomMap) Delete(key interface{}) (result interface{}, exists bool) {
+	rmap.mutex.RLock()
+
+	if _, entryExists := rmap.rawMap[key]; entryExists {
+		rmap.mutex.RUnlock()
+		rmap.mutex.Lock()
+
+		if entry, entryExists := rmap.rawMap[key]; entryExists {
+			delete(rmap.rawMap, key)
+
+			rmap.size--
+
+			if entry.keyIndex != rmap.size {
+				oldKey := entry.keyIndex
+				movedKey := rmap.keys[rmap.size]
+
+				rmap.rawMap[movedKey].keyIndex = oldKey
+
+				rmap.keys[oldKey] = movedKey
+			}
+
+			rmap.keys = rmap.keys[:rmap.size]
+
+			result = entry.value
+			exists = true
+		}
+
+		rmap.mutex.Unlock()
+	} else {
+		rmap.mutex.RUnlock()
+	}
+
+	return
+}
+
+func (rmap *RandomMap) Size() (result int) {
+	rmap.mutex.RLock()
+
+	result = rmap.size
+
+	rmap.mutex.RUnlock()
+
+	return
+}
+
+func (rmap *RandomMap) RandomEntry() (result interface{}) {
+	rmap.mutex.RLock()
+
+	if rmap.size >= 1 {
+		result = rmap.rawMap[rmap.keys[rand.Intn(rmap.size)]].value
+	}
+
+	rmap.mutex.RUnlock()
+
+	return
+}
diff --git a/packages/events/event_test.go b/packages/events/event_test.go
index b153e4aca89e1af3efdc3dcfa0fa9cd4e8e5136f..45084ba6faa58371eb5eb55c2ba2d1b084f95a85 100644
--- a/packages/events/event_test.go
+++ b/packages/events/event_test.go
@@ -3,8 +3,23 @@ package events
 import (
 	"fmt"
 	"strconv"
+	"testing"
 )
 
+func BenchmarkEvent_Trigger(b *testing.B) {
+	event := NewEvent(intStringCaller)
+
+	event.Attach(NewClosure(func(param1 int, param2 string) {
+		// do nothing just get called
+	}))
+
+	b.ResetTimer()
+
+	for i := 0; i < b.N; i++ {
+		event.Trigger(4, "test")
+	}
+}
+
 // define how the event converts the generic parameters to the typed params - ugly but go has no generics :(
 func intStringCaller(handler interface{}, params ...interface{}) {
 	handler.(func(int, string))(params[0].(int), params[1].(string))
diff --git a/packages/filter/byte_array_filter.go b/packages/filter/byte_array_filter.go
index ba5aca0a4910142c3c570849b2861203466367b8..d8cb89fe010d8571331a2f4dbc0e31b328cbf275 100644
--- a/packages/filter/byte_array_filter.go
+++ b/packages/filter/byte_array_filter.go
@@ -3,7 +3,7 @@ package filter
 import (
 	"sync"
 
-	"github.com/iotaledger/goshimmer/packages/typeconversion"
+	"github.com/iotaledger/goshimmer/packages/typeutils"
 )
 
 type ByteArrayFilter struct {
@@ -25,20 +25,20 @@ func (filter *ByteArrayFilter) Contains(byteArray []byte) bool {
 	filter.mutex.RLock()
 	defer filter.mutex.RUnlock()
 
-	_, exists := filter.byteArraysByKey[typeconversion.BytesToString(byteArray)]
+	_, exists := filter.byteArraysByKey[typeutils.BytesToString(byteArray)]
 
 	return exists
 }
 
 func (filter *ByteArrayFilter) Add(byteArray []byte) bool {
-	key := typeconversion.BytesToString(byteArray)
+	key := typeutils.BytesToString(byteArray)
 
 	filter.mutex.Lock()
 	defer filter.mutex.Unlock()
 
 	if _, exists := filter.byteArraysByKey[key]; !exists {
 		if len(filter.byteArrays) == filter.size {
-			delete(filter.byteArraysByKey, typeconversion.BytesToString(filter.byteArrays[0]))
+			delete(filter.byteArraysByKey, typeutils.BytesToString(filter.byteArrays[0]))
 
 			filter.byteArrays = append(filter.byteArrays[1:], byteArray)
 		} else {
diff --git a/packages/model/approvers/approvers.go b/packages/model/approvers/approvers.go
new file mode 100644
index 0000000000000000000000000000000000000000..be5f753073d7adc2b1f1b9b754aa8fb957114253
--- /dev/null
+++ b/packages/model/approvers/approvers.go
@@ -0,0 +1,22 @@
+package approvers
+
+import (
+	"sync"
+
+	"github.com/iotaledger/goshimmer/packages/ternary"
+)
+
+type Approvers struct {
+	hash        ternary.Trinary
+	hashes      map[ternary.Trinary]bool
+	hashesMutex sync.RWMutex
+	modified    bool
+}
+
+func NewApprovers(hash ternary.Trinary) *Approvers {
+	return &Approvers{
+		hash:     hash,
+		hashes:   make(map[ternary.Trinary]bool),
+		modified: false,
+	}
+}
diff --git a/packages/model/meta_transaction/constants.go b/packages/model/meta_transaction/constants.go
new file mode 100644
index 0000000000000000000000000000000000000000..498b5798160d59feb6b1bc0690404078675428ba
--- /dev/null
+++ b/packages/model/meta_transaction/constants.go
@@ -0,0 +1,35 @@
+package meta_transaction
+
+import (
+	"github.com/iotaledger/goshimmer/packages/ternary"
+)
+
+const (
+	SHARD_MARKER_OFFSET            = 0
+	TRUNK_TRANSACTION_HASH_OFFSET  = SHARD_MARKER_END
+	BRANCH_TRANSACTION_HASH_OFFSET = TRUNK_TRANSACTION_HASH_END
+	HEAD_OFFSET                    = BRANCH_TRANSACTION_HASH_END
+	TAIL_OFFSET                    = HEAD_END
+	TRANSACTION_TYPE_OFFSET        = TAIL_END
+	DATA_OFFSET                    = TRANSACTION_TYPE_END
+
+	SHARD_MARKER_SIZE            = 11
+	TRUNK_TRANSACTION_HASH_SIZE  = 243
+	BRANCH_TRANSACTION_HASH_SIZE = 243
+	HEAD_SIZE                    = 1
+	TAIL_SIZE                    = 1
+	TRANSACTION_TYPE_SIZE        = 8
+	DATA_SIZE                    = 6993
+
+	SHARD_MARKER_END            = SHARD_MARKER_OFFSET + SHARD_MARKER_SIZE
+	TRUNK_TRANSACTION_HASH_END  = TRUNK_TRANSACTION_HASH_OFFSET + TRUNK_TRANSACTION_HASH_SIZE
+	BRANCH_TRANSACTION_HASH_END = BRANCH_TRANSACTION_HASH_OFFSET + BRANCH_TRANSACTION_HASH_SIZE
+	HEAD_END                    = HEAD_OFFSET + HEAD_SIZE
+	TAIL_END                    = TAIL_OFFSET + TAIL_SIZE
+	TRANSACTION_TYPE_END        = TRANSACTION_TYPE_OFFSET + TRANSACTION_TYPE_SIZE
+	DATA_END                    = DATA_OFFSET + DATA_SIZE
+
+	MARSHALLED_TOTAL_SIZE = DATA_END
+
+	BRANCH_NULL_HASH = ternary.Trinary("999999999999999999999999999999999999999999999999999999999999999999999999999999999")
+)
diff --git a/packages/model/meta_transaction/meta_transaction.go b/packages/model/meta_transaction/meta_transaction.go
new file mode 100644
index 0000000000000000000000000000000000000000..456e7e36f57dd58278ba81f8354671caacd9a69e
--- /dev/null
+++ b/packages/model/meta_transaction/meta_transaction.go
@@ -0,0 +1,478 @@
+package meta_transaction
+
+import (
+	"sync"
+
+	"github.com/iotaledger/goshimmer/packages/curl"
+	"github.com/iotaledger/goshimmer/packages/ternary"
+)
+
+type MetaTransaction struct {
+	hash            *ternary.Trinary
+	weightMagnitude int
+
+	shardMarker           *ternary.Trinary
+	trunkTransactionHash  *ternary.Trinary
+	branchTransactionHash *ternary.Trinary
+	head                  *bool
+	tail                  *bool
+	transactionType       *ternary.Trinary
+	data                  ternary.Trits
+	modified              bool
+
+	hasherMutex                sync.RWMutex
+	hashMutex                  sync.RWMutex
+	shardMarkerMutex           sync.RWMutex
+	trunkTransactionHashMutex  sync.RWMutex
+	branchTransactionHashMutex sync.RWMutex
+	headMutex                  sync.RWMutex
+	tailMutex                  sync.RWMutex
+	transactionTypeMutex       sync.RWMutex
+	dataMutex                  sync.RWMutex
+	bytesMutex                 sync.RWMutex
+	modifiedMutex              sync.RWMutex
+
+	trits ternary.Trits
+	bytes []byte
+}
+
+func New() *MetaTransaction {
+	return FromTrits(make(ternary.Trits, MARSHALLED_TOTAL_SIZE))
+}
+
+func FromTrits(trits ternary.Trits) *MetaTransaction {
+	return &MetaTransaction{
+		trits: trits,
+	}
+}
+
+func FromBytes(bytes []byte) (result *MetaTransaction) {
+	result = FromTrits(ternary.BytesToTrits(bytes)[:MARSHALLED_TOTAL_SIZE])
+	result.bytes = bytes
+
+	return
+}
+
+func (this *MetaTransaction) BlockHasher() {
+	this.hasherMutex.RLock()
+}
+
+func (this *MetaTransaction) UnblockHasher() {
+	this.hasherMutex.RUnlock()
+}
+
+func (this *MetaTransaction) ReHash() {
+	this.hashMutex.Lock()
+	defer this.hashMutex.Unlock()
+	this.hash = nil
+
+	this.bytesMutex.Lock()
+	defer this.bytesMutex.Unlock()
+	this.bytes = nil
+}
+
+// retrieves the hash of the transaction
+func (this *MetaTransaction) GetHash() (result ternary.Trinary) {
+	this.hashMutex.RLock()
+	if this.hash == nil {
+		this.hashMutex.RUnlock()
+		this.hashMutex.Lock()
+		defer this.hashMutex.Unlock()
+		if this.hash == nil {
+			this.hasherMutex.Lock()
+			this.parseHashRelatedDetails()
+			this.hasherMutex.Unlock()
+		}
+	} else {
+		defer this.hashMutex.RUnlock()
+	}
+
+	result = *this.hash
+
+	return
+}
+
+// retrieves weight magnitude of the transaction (amount of pow invested)
+func (this *MetaTransaction) GetWeightMagnitude() (result int) {
+	this.hashMutex.RLock()
+	if this.hash == nil {
+		this.hashMutex.RUnlock()
+		this.hashMutex.Lock()
+		defer this.hashMutex.Unlock()
+		if this.hash == nil {
+			this.hasherMutex.Lock()
+			this.parseHashRelatedDetails()
+			this.hasherMutex.Unlock()
+		}
+	} else {
+		defer this.hashMutex.RUnlock()
+	}
+
+	result = this.weightMagnitude
+
+	return
+}
+
+// hashes the transaction using curl (without locking - internal usage)
+func (this *MetaTransaction) parseHashRelatedDetails() {
+	hashTrits := <-curl.CURLP81.Hash(this.trits)
+	hashTrinary := hashTrits.ToTrinary()
+
+	this.hash = &hashTrinary
+	this.weightMagnitude = hashTrits.TrailingZeroes()
+}
+
+// getter for the shard marker (supports concurrency)
+func (this *MetaTransaction) GetShardMarker() (result ternary.Trinary) {
+	this.shardMarkerMutex.RLock()
+	if this.shardMarker == nil {
+		this.shardMarkerMutex.RUnlock()
+		this.shardMarkerMutex.Lock()
+		defer this.shardMarkerMutex.Unlock()
+		if this.shardMarker == nil {
+			shardMarker := this.trits[SHARD_MARKER_OFFSET:SHARD_MARKER_END].ToTrinary()
+
+			this.shardMarker = &shardMarker
+		}
+	} else {
+		defer this.shardMarkerMutex.RUnlock()
+	}
+
+	result = *this.shardMarker
+
+	return
+}
+
+// setter for the shard marker (supports concurrency)
+func (this *MetaTransaction) SetShardMarker(shardMarker ternary.Trinary) bool {
+	this.shardMarkerMutex.RLock()
+	if this.shardMarker == nil || *this.shardMarker != shardMarker {
+		this.shardMarkerMutex.RUnlock()
+		this.shardMarkerMutex.Lock()
+		defer this.shardMarkerMutex.Unlock()
+		if this.shardMarker == nil || *this.shardMarker != shardMarker {
+			this.shardMarker = &shardMarker
+
+			this.hasherMutex.RLock()
+			copy(this.trits[SHARD_MARKER_OFFSET:SHARD_MARKER_END], shardMarker.ToTrits()[:SHARD_MARKER_SIZE])
+			this.hasherMutex.RUnlock()
+
+			this.SetModified(true)
+			this.ReHash()
+
+			return true
+		}
+	} else {
+		this.shardMarkerMutex.RUnlock()
+	}
+
+	return false
+}
+
+// getter for the bundleHash (supports concurrency)
+func (this *MetaTransaction) GetTrunkTransactionHash() (result ternary.Trinary) {
+	this.trunkTransactionHashMutex.RLock()
+	if this.trunkTransactionHash == nil {
+		this.trunkTransactionHashMutex.RUnlock()
+		this.trunkTransactionHashMutex.Lock()
+		defer this.trunkTransactionHashMutex.Unlock()
+		if this.trunkTransactionHash == nil {
+			trunkTransactionHash := this.trits[TRUNK_TRANSACTION_HASH_OFFSET:TRUNK_TRANSACTION_HASH_END].ToTrinary()
+
+			this.trunkTransactionHash = &trunkTransactionHash
+		}
+	} else {
+		defer this.trunkTransactionHashMutex.RUnlock()
+	}
+
+	result = *this.trunkTransactionHash
+
+	return
+}
+
+// setter for the trunkTransactionHash (supports concurrency)
+func (this *MetaTransaction) SetTrunkTransactionHash(trunkTransactionHash ternary.Trinary) bool {
+	this.trunkTransactionHashMutex.RLock()
+	if this.trunkTransactionHash == nil || *this.trunkTransactionHash != trunkTransactionHash {
+		this.trunkTransactionHashMutex.RUnlock()
+		this.trunkTransactionHashMutex.Lock()
+		defer this.trunkTransactionHashMutex.Unlock()
+		if this.trunkTransactionHash == nil || *this.trunkTransactionHash != trunkTransactionHash {
+			this.trunkTransactionHash = &trunkTransactionHash
+
+			this.hasherMutex.RLock()
+			copy(this.trits[TRUNK_TRANSACTION_HASH_OFFSET:TRUNK_TRANSACTION_HASH_END], trunkTransactionHash.ToTrits()[:TRUNK_TRANSACTION_HASH_SIZE])
+			this.hasherMutex.RUnlock()
+
+			this.SetModified(true)
+			this.ReHash()
+
+			return true
+		}
+	} else {
+		this.trunkTransactionHashMutex.RUnlock()
+	}
+
+	return false
+}
+
+// getter for the bundleHash (supports concurrency)
+func (this *MetaTransaction) GetBranchTransactionHash() (result ternary.Trinary) {
+	this.branchTransactionHashMutex.RLock()
+	if this.branchTransactionHash == nil {
+		this.branchTransactionHashMutex.RUnlock()
+		this.branchTransactionHashMutex.Lock()
+		defer this.branchTransactionHashMutex.Unlock()
+		if this.branchTransactionHash == nil {
+			branchTransactionHash := this.trits[BRANCH_TRANSACTION_HASH_OFFSET:BRANCH_TRANSACTION_HASH_END].ToTrinary()
+
+			this.branchTransactionHash = &branchTransactionHash
+		}
+	} else {
+		defer this.branchTransactionHashMutex.RUnlock()
+	}
+
+	result = *this.branchTransactionHash
+
+	return
+}
+
+// setter for the trunkTransactionHash (supports concurrency)
+func (this *MetaTransaction) SetBranchTransactionHash(branchTransactionHash ternary.Trinary) bool {
+	this.branchTransactionHashMutex.RLock()
+	if this.branchTransactionHash == nil || *this.branchTransactionHash != branchTransactionHash {
+		this.branchTransactionHashMutex.RUnlock()
+		this.branchTransactionHashMutex.Lock()
+		defer this.branchTransactionHashMutex.Unlock()
+		if this.branchTransactionHash == nil || *this.branchTransactionHash != branchTransactionHash {
+			this.branchTransactionHash = &branchTransactionHash
+
+			this.hasherMutex.RLock()
+			copy(this.trits[BRANCH_TRANSACTION_HASH_OFFSET:BRANCH_TRANSACTION_HASH_END], branchTransactionHash.ToTrits()[:BRANCH_TRANSACTION_HASH_SIZE])
+			this.hasherMutex.RUnlock()
+
+			this.SetModified(true)
+			this.ReHash()
+
+			return true
+		}
+	} else {
+		this.branchTransactionHashMutex.RUnlock()
+	}
+
+	return false
+}
+
+// getter for the head flag (supports concurrency)
+func (this *MetaTransaction) GetHead() (result bool) {
+	this.headMutex.RLock()
+	if this.head == nil {
+		this.headMutex.RUnlock()
+		this.headMutex.Lock()
+		defer this.headMutex.Unlock()
+		if this.head == nil {
+			head := this.trits[HEAD_OFFSET] == 1
+
+			this.head = &head
+		}
+	} else {
+		defer this.headMutex.RUnlock()
+	}
+
+	result = *this.head
+
+	return
+}
+
+// setter for the head flag (supports concurrency)
+func (this *MetaTransaction) SetHead(head bool) bool {
+	this.headMutex.RLock()
+	if this.head == nil || *this.head != head {
+		this.headMutex.RUnlock()
+		this.headMutex.Lock()
+		defer this.headMutex.Unlock()
+		if this.head == nil || *this.head != head {
+			this.head = &head
+
+			this.hasherMutex.RLock()
+			if head {
+				this.trits[HEAD_OFFSET] = 1
+			} else {
+				this.trits[HEAD_OFFSET] = 0
+			}
+			this.hasherMutex.RUnlock()
+
+			this.SetModified(true)
+			this.ReHash()
+
+			return true
+		}
+	} else {
+		this.headMutex.RUnlock()
+	}
+
+	return false
+}
+
+// getter for the tail flag (supports concurrency)
+func (this *MetaTransaction) GetTail() (result bool) {
+	this.tailMutex.RLock()
+	if this.tail == nil {
+		this.tailMutex.RUnlock()
+		this.tailMutex.Lock()
+		defer this.tailMutex.Unlock()
+		if this.tail == nil {
+			tail := this.trits[TAIL_OFFSET] == 1
+
+			this.tail = &tail
+		}
+	} else {
+		defer this.tailMutex.RUnlock()
+	}
+
+	result = *this.tail
+
+	return
+}
+
+// setter for the tail flag (supports concurrency)
+func (this *MetaTransaction) SetTail(tail bool) bool {
+	this.tailMutex.RLock()
+	if this.tail == nil || *this.tail != tail {
+		this.tailMutex.RUnlock()
+		this.tailMutex.Lock()
+		defer this.tailMutex.Unlock()
+		if this.tail == nil || *this.tail != tail {
+			this.tail = &tail
+
+			this.hasherMutex.RLock()
+			if tail {
+				this.trits[TAIL_OFFSET] = 1
+			} else {
+				this.trits[TAIL_OFFSET] = 0
+			}
+			this.hasherMutex.RUnlock()
+
+			this.SetModified(true)
+			this.ReHash()
+
+			return true
+		}
+	} else {
+		this.tailMutex.RUnlock()
+	}
+
+	return false
+}
+
+// getter for the transaction type (supports concurrency)
+func (this *MetaTransaction) GetTransactionType() (result ternary.Trinary) {
+	this.transactionTypeMutex.RLock()
+	if this.transactionType == nil {
+		this.transactionTypeMutex.RUnlock()
+		this.transactionTypeMutex.Lock()
+		defer this.transactionTypeMutex.Unlock()
+		if this.transactionType == nil {
+			transactionType := this.trits[TRANSACTION_TYPE_OFFSET:TRANSACTION_TYPE_END].ToTrinary()
+
+			this.transactionType = &transactionType
+		}
+	} else {
+		defer this.transactionTypeMutex.RUnlock()
+	}
+
+	result = *this.transactionType
+
+	return
+}
+
+// setter for the transaction type (supports concurrency)
+func (this *MetaTransaction) SetTransactionType(transactionType ternary.Trinary) bool {
+	this.transactionTypeMutex.RLock()
+	if this.transactionType == nil || *this.transactionType != transactionType {
+		this.transactionTypeMutex.RUnlock()
+		this.transactionTypeMutex.Lock()
+		defer this.transactionTypeMutex.Unlock()
+		if this.transactionType == nil || *this.transactionType != transactionType {
+			this.transactionType = &transactionType
+
+			this.hasherMutex.RLock()
+			copy(this.trits[TRANSACTION_TYPE_OFFSET:TRANSACTION_TYPE_END], transactionType.ToTrits()[:TRANSACTION_TYPE_SIZE])
+			this.hasherMutex.RUnlock()
+
+			this.SetModified(true)
+			this.ReHash()
+
+			return true
+		}
+	} else {
+		this.transactionTypeMutex.RUnlock()
+	}
+
+	return false
+}
+
+// getter for the data slice (supports concurrency)
+func (this *MetaTransaction) GetData() (result ternary.Trits) {
+	this.dataMutex.RLock()
+	if this.data == nil {
+		this.dataMutex.RUnlock()
+		this.dataMutex.Lock()
+		defer this.dataMutex.Unlock()
+		if this.data == nil {
+			this.data = this.trits[DATA_OFFSET:DATA_END]
+		}
+	} else {
+		defer this.dataMutex.RUnlock()
+	}
+
+	result = this.data
+
+	return
+}
+
+func (this *MetaTransaction) GetTrits() (result ternary.Trits) {
+	result = make(ternary.Trits, len(this.trits))
+
+	this.hasherMutex.Lock()
+	copy(result, this.trits)
+	this.hasherMutex.Unlock()
+
+	return
+}
+
+func (this *MetaTransaction) GetBytes() (result []byte) {
+	this.bytesMutex.RLock()
+	if this.bytes == nil {
+		this.bytesMutex.RUnlock()
+		this.bytesMutex.Lock()
+		defer this.bytesMutex.Unlock()
+
+		this.hasherMutex.Lock()
+		this.bytes = this.trits.ToBytes()
+		this.hasherMutex.Unlock()
+	} else {
+		this.bytesMutex.RUnlock()
+	}
+
+	result = make([]byte, len(this.bytes))
+	copy(result, this.bytes)
+
+	return
+}
+
+// returns true if the transaction contains unsaved changes (supports concurrency)
+func (this *MetaTransaction) GetModified() bool {
+	this.modifiedMutex.RLock()
+	defer this.modifiedMutex.RUnlock()
+
+	return this.modified
+}
+
+// sets the modified flag which controls if a transaction is going to be saved (supports concurrency)
+func (this *MetaTransaction) SetModified(modified bool) {
+	this.modifiedMutex.Lock()
+	defer this.modifiedMutex.Unlock()
+
+	this.modified = modified
+}
diff --git a/packages/model/meta_transaction/meta_transaction_test.go b/packages/model/meta_transaction/meta_transaction_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..1c73e4b4b03d97a61fe717fdd01c6ab01d9e66ba
--- /dev/null
+++ b/packages/model/meta_transaction/meta_transaction_test.go
@@ -0,0 +1,54 @@
+package meta_transaction
+
+import (
+	"fmt"
+	"sync"
+	"testing"
+
+	"github.com/iotaledger/goshimmer/packages/ternary"
+	"github.com/magiconair/properties/assert"
+)
+
+func TestMetaTransaction_SettersGetters(t *testing.T) {
+	shardMarker := ternary.Trinary("NPHTQORL9XKA")
+	trunkTransactionHash := ternary.Trinary("99999999999999999999999999999999999999999999999999999999999999999999999999999999A")
+	branchTransactionHash := ternary.Trinary("99999999999999999999999999999999999999999999999999999999999999999999999999999999B")
+	head := true
+	tail := true
+	transactionType := ternary.Trinary("9999999999999999999999")
+
+	transaction := New()
+	transaction.SetShardMarker(shardMarker)
+	transaction.SetTrunkTransactionHash(trunkTransactionHash)
+	transaction.SetBranchTransactionHash(branchTransactionHash)
+	transaction.SetHead(head)
+	transaction.SetTail(tail)
+	transaction.SetTransactionType(transactionType)
+
+	assert.Equal(t, transaction.GetWeightMagnitude(), 0)
+	assert.Equal(t, transaction.GetShardMarker(), shardMarker)
+	assert.Equal(t, transaction.GetTrunkTransactionHash(), trunkTransactionHash)
+	assert.Equal(t, transaction.GetBranchTransactionHash(), branchTransactionHash)
+	assert.Equal(t, transaction.GetHead(), head)
+	assert.Equal(t, transaction.GetTail(), tail)
+	assert.Equal(t, transaction.GetTransactionType(), transactionType)
+	assert.Equal(t, transaction.GetHash(), FromBytes(transaction.GetBytes()).GetHash())
+
+	fmt.Println(transaction.GetHash())
+}
+
+func BenchmarkMetaTransaction_GetHash(b *testing.B) {
+	var waitGroup sync.WaitGroup
+
+	for i := 0; i < b.N; i++ {
+		waitGroup.Add(1)
+
+		go func() {
+			New().GetHash()
+
+			waitGroup.Done()
+		}()
+	}
+
+	waitGroup.Wait()
+}
diff --git a/packages/model/value_transaction/constants.go b/packages/model/value_transaction/constants.go
new file mode 100644
index 0000000000000000000000000000000000000000..3025e1c74d9526fbd10d88d5c217d9443fd797a6
--- /dev/null
+++ b/packages/model/value_transaction/constants.go
@@ -0,0 +1,23 @@
+package value_transaction
+
+const (
+	ADDRESS_OFFSET                    = 0
+	VALUE_OFFSET                      = ADDRESS_END
+	TIMESTAMP_OFFSET                  = VALUE_END
+	NONCE_OFFSET                      = TIMESTAMP_END
+	SIGNATURE_MESSAGE_FRAGMENT_OFFSET = NONCE_END
+
+	ADDRESS_SIZE                    = 243
+	VALUE_SIZE                      = 81
+	TIMESTAMP_SIZE                  = 27
+	NONCE_SIZE                      = 81
+	SIGNATURE_MESSAGE_FRAGMENT_SIZE = 6561
+
+	ADDRESS_END                    = ADDRESS_OFFSET + ADDRESS_SIZE
+	VALUE_END                      = VALUE_OFFSET + VALUE_SIZE
+	TIMESTAMP_END                  = TIMESTAMP_OFFSET + TIMESTAMP_SIZE
+	NONCE_END                      = NONCE_OFFSET + NONCE_SIZE
+	SIGNATURE_MESSAGE_FRAGMENT_END = SIGNATURE_MESSAGE_FRAGMENT_OFFSET + SIGNATURE_MESSAGE_FRAGMENT_SIZE
+
+	TOTAL_SIZE = SIGNATURE_MESSAGE_FRAGMENT_END
+)
diff --git a/packages/model/value_transaction/value_transaction.go b/packages/model/value_transaction/value_transaction.go
new file mode 100644
index 0000000000000000000000000000000000000000..6eff46bf9b0521cca88cf7552e549c8e7cafefd8
--- /dev/null
+++ b/packages/model/value_transaction/value_transaction.go
@@ -0,0 +1,287 @@
+package value_transaction
+
+import (
+	"sync"
+
+	"github.com/iotaledger/goshimmer/packages/model/meta_transaction"
+	"github.com/iotaledger/goshimmer/packages/ternary"
+)
+
+type ValueTransaction struct {
+	*meta_transaction.MetaTransaction
+
+	address                       *ternary.Trinary
+	addressMutex                  sync.RWMutex
+	value                         *int64
+	valueMutex                    sync.RWMutex
+	timestamp                     *uint
+	timestampMutex                sync.RWMutex
+	nonce                         *ternary.Trinary
+	nonceMutex                    sync.RWMutex
+	signatureMessageFragment      *ternary.Trinary
+	signatureMessageFragmentMutex sync.RWMutex
+
+	trits ternary.Trits
+}
+
+func New() (result *ValueTransaction) {
+	result = &ValueTransaction{
+		MetaTransaction: meta_transaction.New(),
+	}
+
+	result.trits = result.MetaTransaction.GetData()
+
+	return
+}
+
+func FromMetaTransaction(metaTransaction *meta_transaction.MetaTransaction) *ValueTransaction {
+	return &ValueTransaction{
+		MetaTransaction: metaTransaction,
+		trits: metaTransaction.GetData(),
+	}
+}
+
+func FromBytes(bytes []byte) (result *ValueTransaction) {
+	result = &ValueTransaction{
+		MetaTransaction: meta_transaction.FromTrits(ternary.BytesToTrits(bytes)[:meta_transaction.MARSHALLED_TOTAL_SIZE]),
+	}
+
+	result.trits = result.MetaTransaction.GetData()
+
+	return
+}
+
+// getter for the address (supports concurrency)
+func (this *ValueTransaction) GetAddress() (result ternary.Trinary) {
+	this.addressMutex.RLock()
+	if this.address == nil {
+		this.addressMutex.RUnlock()
+		this.addressMutex.Lock()
+		defer this.addressMutex.Unlock()
+		if this.address == nil {
+			address := this.trits[ADDRESS_OFFSET:ADDRESS_END].ToTrinary()
+
+			this.address = &address
+		}
+	} else {
+		defer this.addressMutex.RUnlock()
+	}
+
+	result = *this.address
+
+	return
+}
+
+// setter for the address (supports concurrency)
+func (this *ValueTransaction) SetAddress(address ternary.Trinary) bool {
+	this.addressMutex.RLock()
+	if this.address == nil || *this.address != address {
+		this.addressMutex.RUnlock()
+		this.addressMutex.Lock()
+		defer this.addressMutex.Unlock()
+		if this.address == nil || *this.address != address {
+			this.address = &address
+
+			this.BlockHasher()
+			copy(this.trits[ADDRESS_OFFSET:ADDRESS_END], address.ToTrits()[:ADDRESS_SIZE])
+			this.UnblockHasher()
+
+			this.SetModified(true)
+			this.ReHash()
+
+			return true
+		}
+	} else {
+		this.addressMutex.RUnlock()
+	}
+
+	return false
+}
+
+// getter for the value (supports concurrency)
+func (this *ValueTransaction) GetValue() (result int64) {
+	this.valueMutex.RLock()
+	if this.value == nil {
+		this.valueMutex.RUnlock()
+		this.valueMutex.Lock()
+		defer this.valueMutex.Unlock()
+		if this.value == nil {
+			value := this.trits[VALUE_OFFSET:VALUE_END].ToInt64()
+
+			this.value = &value
+		}
+	} else {
+		defer this.valueMutex.RUnlock()
+	}
+
+	result = *this.value
+
+	return
+}
+
+// setter for the value (supports concurrency)
+func (this *ValueTransaction) SetValue(value int64) bool {
+	this.valueMutex.RLock()
+	if this.value == nil || *this.value != value {
+		this.valueMutex.RUnlock()
+		this.valueMutex.Lock()
+		defer this.valueMutex.Unlock()
+		if this.value == nil || *this.value != value {
+			this.value = &value
+
+			this.BlockHasher()
+			copy(this.trits[VALUE_OFFSET:VALUE_END], ternary.Int64ToTrits(value)[:VALUE_SIZE])
+			this.UnblockHasher()
+
+			this.SetModified(true)
+			this.ReHash()
+
+			return true
+		}
+	} else {
+		this.valueMutex.RUnlock()
+	}
+
+	return false
+}
+
+// getter for the timestamp (supports concurrency)
+func (this *ValueTransaction) GetTimestamp() (result uint) {
+	this.timestampMutex.RLock()
+	if this.timestamp == nil {
+		this.timestampMutex.RUnlock()
+		this.timestampMutex.Lock()
+		defer this.timestampMutex.Unlock()
+		if this.timestamp == nil {
+			timestamp := this.trits[TIMESTAMP_OFFSET:TIMESTAMP_END].ToUint()
+
+			this.timestamp = &timestamp
+		}
+	} else {
+		defer this.timestampMutex.RUnlock()
+	}
+
+	result = *this.timestamp
+
+	return
+}
+
+// setter for the timestamp (supports concurrency)
+func (this *ValueTransaction) SetTimestamp(timestamp uint) bool {
+	this.timestampMutex.RLock()
+	if this.timestamp == nil || *this.timestamp != timestamp {
+		this.timestampMutex.RUnlock()
+		this.timestampMutex.Lock()
+		defer this.timestampMutex.Unlock()
+		if this.timestamp == nil || *this.timestamp != timestamp {
+			this.timestamp = &timestamp
+
+			this.BlockHasher()
+			copy(this.trits[TIMESTAMP_OFFSET:TIMESTAMP_END], ternary.UintToTrits(timestamp)[:TIMESTAMP_SIZE])
+			this.UnblockHasher()
+
+			this.SetModified(true)
+			this.ReHash()
+
+			return true
+		}
+	} else {
+		this.timestampMutex.RUnlock()
+	}
+
+	return false
+}
+
+// getter for the nonce (supports concurrency)
+func (this *ValueTransaction) GetNonce() (result ternary.Trinary) {
+	this.nonceMutex.RLock()
+	if this.nonce == nil {
+		this.nonceMutex.RUnlock()
+		this.nonceMutex.Lock()
+		defer this.nonceMutex.Unlock()
+		if this.nonce == nil {
+			nonce := this.trits[NONCE_OFFSET:NONCE_END].ToTrinary()
+
+			this.nonce = &nonce
+		}
+	} else {
+		defer this.nonceMutex.RUnlock()
+	}
+
+	result = *this.nonce
+
+	return
+}
+
+// setter for the nonce (supports concurrency)
+func (this *ValueTransaction) SetNonce(nonce ternary.Trinary) bool {
+	this.nonceMutex.RLock()
+	if this.nonce == nil || *this.nonce != nonce {
+		this.nonceMutex.RUnlock()
+		this.nonceMutex.Lock()
+		defer this.nonceMutex.Unlock()
+		if this.nonce == nil || *this.nonce != nonce {
+			this.nonce = &nonce
+
+			this.BlockHasher()
+			copy(this.trits[NONCE_OFFSET:NONCE_END], nonce.ToTrits()[:NONCE_SIZE])
+			this.UnblockHasher()
+
+			this.SetModified(true)
+			this.ReHash()
+
+			return true
+		}
+	} else {
+		this.nonceMutex.RUnlock()
+	}
+
+	return false
+}
+
+// getter for the signatureMessageFragmetn (supports concurrency)
+func (this *ValueTransaction) GetSignatureMessageFragment() (result ternary.Trinary) {
+	this.signatureMessageFragmentMutex.RLock()
+	if this.signatureMessageFragment == nil {
+		this.signatureMessageFragmentMutex.RUnlock()
+		this.signatureMessageFragmentMutex.Lock()
+		defer this.signatureMessageFragmentMutex.Unlock()
+		if this.signatureMessageFragment == nil {
+			signatureMessageFragment := this.trits[SIGNATURE_MESSAGE_FRAGMENT_OFFSET:SIGNATURE_MESSAGE_FRAGMENT_END].ToTrinary()
+
+			this.signatureMessageFragment = &signatureMessageFragment
+		}
+	} else {
+		defer this.signatureMessageFragmentMutex.RUnlock()
+	}
+
+	result = *this.signatureMessageFragment
+
+	return
+}
+
+// setter for the nonce (supports concurrency)
+func (this *ValueTransaction) SetSignatureMessageFragment(signatureMessageFragment ternary.Trinary) bool {
+	this.signatureMessageFragmentMutex.RLock()
+	if this.signatureMessageFragment == nil || *this.signatureMessageFragment != signatureMessageFragment {
+		this.signatureMessageFragmentMutex.RUnlock()
+		this.signatureMessageFragmentMutex.Lock()
+		defer this.signatureMessageFragmentMutex.Unlock()
+		if this.signatureMessageFragment == nil || *this.signatureMessageFragment != signatureMessageFragment {
+			this.signatureMessageFragment = &signatureMessageFragment
+
+			this.BlockHasher()
+			copy(this.trits[SIGNATURE_MESSAGE_FRAGMENT_OFFSET:SIGNATURE_MESSAGE_FRAGMENT_END], signatureMessageFragment.ToTrits()[:SIGNATURE_MESSAGE_FRAGMENT_SIZE])
+			this.UnblockHasher()
+
+			this.SetModified(true)
+			this.ReHash()
+
+			return true
+		}
+	} else {
+		this.signatureMessageFragmentMutex.RUnlock()
+	}
+
+	return false
+}
diff --git a/packages/model/value_transaction/value_transaction_test.go b/packages/model/value_transaction/value_transaction_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..35d3197f57e4d422dd4a528686d808cbadc2ce8c
--- /dev/null
+++ b/packages/model/value_transaction/value_transaction_test.go
@@ -0,0 +1,25 @@
+package value_transaction
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/iotaledger/goshimmer/packages/ternary"
+	"github.com/magiconair/properties/assert"
+)
+
+func TestValueTransaction_SettersGetters(t *testing.T) {
+	address := ternary.Trinary("A9999999999999999999999999999999999999999999999999999999999999999999999999999999F")
+
+	transaction := New()
+	transaction.SetAddress(address)
+
+	transactionCopy := FromMetaTransaction(transaction.MetaTransaction)
+	fmt.Println(transactionCopy.GetAddress())
+
+	assert.Equal(t, transaction.GetAddress(), address)
+	//assert.Equal(t, transaction.GetHash(), FromBytes(transaction.GetBytes()).GetHash())
+
+	fmt.Println(transaction.GetHash())
+	fmt.Println(transaction.GetAddress())
+}
diff --git a/packages/ternary/conversion.go b/packages/ternary/conversion.go
index afb96cf790d4f97d15a465aac25df8cfc03f804a..7cc01646ce33e7aa9059ff5fec43e4a9e925c9fb 100644
--- a/packages/ternary/conversion.go
+++ b/packages/ternary/conversion.go
@@ -1,6 +1,8 @@
 package ternary
 
-import "bytes"
+import (
+	"bytes"
+)
 
 const (
 	NUMBER_OF_TRITS_IN_A_BYTE  = 5
@@ -111,6 +113,58 @@ func BytesToTrits(bytes []byte) Trits {
 	return trits
 }
 
+func Int64ToTrits(value int64) (result Trits) {
+	negative := value < 0
+	shiftedValue := value >> 63
+	valueAbs := (value ^ shiftedValue) - shiftedValue
+
+	for valueAbs != 0 {
+		trit := Trit((valueAbs+1)%3 - 1)
+		if negative {
+			trit = -trit
+		}
+		result = append(result, trit)
+		valueAbs++
+		valueAbs /= 3
+	}
+
+	for i := len(result); i < 81; i++ {
+		result = append(result, 0)
+	}
+
+	return
+}
+
+func UintToTrits(value uint) (result Trits) {
+	for value != 0 {
+		trit := Trit((value+1)%3 - 1)
+		result = append(result, trit)
+		value++
+		value /= 3
+	}
+
+	for i := len(result); i < 27; i++ {
+		result = append(result, 0)
+	}
+
+	return
+}
+
+func Uint64ToTrits(value uint64) (result Trits) {
+	for value != 0 {
+		trit := Trit((value+1)%3 - 1)
+		result = append(result, trit)
+		value++
+		value /= 3
+	}
+
+	for i := len(result); i < 81; i++ {
+		result = append(result, 0)
+	}
+
+	return
+}
+
 func TritsToString(trits Trits, offset int, size int) string {
 	var buffer bytes.Buffer
 	for i := 0; i < (size+NUMBER_OF_TRITS_IN_A_TRYTE-1)/NUMBER_OF_TRITS_IN_A_TRYTE; i++ {
diff --git a/packages/ternary/conversion_test.go b/packages/ternary/conversion_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..d7d1665545cf142505afd9936048cc05dd3dfa3c
--- /dev/null
+++ b/packages/ternary/conversion_test.go
@@ -0,0 +1,21 @@
+package ternary
+
+import (
+	"testing"
+
+	"github.com/magiconair/properties/assert"
+)
+
+func TestInt64Conversion(t *testing.T) {
+	assert.Equal(t, Int64ToTrits(9223372036854775807).ToInt64(), int64(9223372036854775807))
+	assert.Equal(t, Int64ToTrits(1337).ToInt64(), int64(1337))
+	assert.Equal(t, Int64ToTrits(0).ToInt64(), int64(0))
+	assert.Equal(t, Int64ToTrits(-1337).ToInt64(), int64(-1337))
+	assert.Equal(t, Int64ToTrits(-9223372036854775808).ToInt64(), int64(-9223372036854775808))
+}
+
+func TestUInt64Conversion(t *testing.T) {
+	assert.Equal(t, Uint64ToTrits(18446744073709551615).ToUint64(), uint64(18446744073709551615))
+	assert.Equal(t, Uint64ToTrits(1337).ToUint64(), uint64(1337))
+	assert.Equal(t, Uint64ToTrits(0).ToUint64(), uint64(0))
+}
diff --git a/packages/ternary/ternary.go b/packages/ternary/ternary.go
index 1e4ba027a57cbf2217ab7ed5d4346384b8cd30e2..745ca3542b18c9f8b0bb61ab2a804d18f7f036dd 100644
--- a/packages/ternary/ternary.go
+++ b/packages/ternary/ternary.go
@@ -66,6 +66,14 @@ func (this Trits) TrailingZeroes() int {
 	return zeros
 }
 
+func (this Trits) ToUint() (result uint) {
+	for i := len(this) - 1; i >= 0; i-- {
+		result = result*3 + uint(this[i])
+	}
+
+	return
+}
+
 func (this Trits) ToInt64() int64 {
 	var val int64
 	for i := len(this) - 1; i >= 0; i-- {
diff --git a/packages/transaction/constants.go b/packages/transaction/constants.go
deleted file mode 100644
index 0b821f5e6b998270843334086e001efa5af5ce8f..0000000000000000000000000000000000000000
--- a/packages/transaction/constants.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package transaction
-
-const (
-	// sizes of the transaction fields
-	SIGNATURE_MESSAGE_FRAGMENT_SIZE = 6561
-	ADDRESS_SIZE                    = 243
-	VALUE_SIZE                      = 81
-	TIMESTAMP_SIZE                  = 27
-	CURRENT_INDEX_SIZE              = 27
-	LATEST_INDEX_SIZE               = 27
-	BUNDLE_HASH_SIZE                = 243
-	TRUNK_TRANSACTION_HASH_SIZE     = 243
-	BRANCH_TRANSACTION_HASH_SIZE    = 243
-	TAG_SIZE                        = 81
-	NONCE_SIZE                      = 81
-
-	// offsets of the transaction fields
-	SIGNATURE_MESSAGE_FRAGMENT_OFFSET = 0
-	ADDRESS_OFFSET                    = SIGNATURE_MESSAGE_FRAGMENT_END
-	VALUE_OFFSET                      = ADDRESS_END
-	TIMESTAMP_OFFSET                  = VALUE_END
-	CURRENT_INDEX_OFFSET              = TIMESTAMP_END
-	LATEST_INDEX_OFFSET               = CURRENT_INDEX_END
-	BUNDLE_HASH_OFFSET                = LATEST_INDEX_END
-	TRUNK_TRANSACTION_HASH_OFFSET     = BUNDLE_HASH_END
-	BRANCH_TRANSACTION_HASH_OFFSET    = TRUNK_TRANSACTION_HASH_END
-	TAG_OFFSET                        = BRANCH_TRANSACTION_HASH_END
-	NONCE_OFFSET                      = TAG_END
-
-	// ends of the transaction fields
-	SIGNATURE_MESSAGE_FRAGMENT_END = SIGNATURE_MESSAGE_FRAGMENT_OFFSET + SIGNATURE_MESSAGE_FRAGMENT_SIZE
-	ADDRESS_END                    = ADDRESS_OFFSET + ADDRESS_SIZE
-	VALUE_END                      = VALUE_OFFSET + VALUE_SIZE
-	TIMESTAMP_END                  = TIMESTAMP_OFFSET + TIMESTAMP_SIZE
-	CURRENT_INDEX_END              = CURRENT_INDEX_OFFSET + CURRENT_INDEX_SIZE
-	LATEST_INDEX_END               = LATEST_INDEX_OFFSET + LATEST_INDEX_SIZE
-	BUNDLE_HASH_END                = BUNDLE_HASH_OFFSET + BUNDLE_HASH_SIZE
-	TRUNK_TRANSACTION_HASH_END     = TRUNK_TRANSACTION_HASH_OFFSET + TRUNK_TRANSACTION_HASH_SIZE
-	BRANCH_TRANSACTION_HASH_END    = BRANCH_TRANSACTION_HASH_OFFSET + BRANCH_TRANSACTION_HASH_SIZE
-	TAG_END                        = TAG_OFFSET + TAG_SIZE
-	NONCE_END                      = NONCE_OFFSET + NONCE_SIZE
-
-	// the full size of a transaction
-	MARSHALED_TOTAL_SIZE = NONCE_END
-)
diff --git a/packages/transaction/transaction.go b/packages/transaction/transaction.go
deleted file mode 100644
index 0c606d8a8989c26cc86e6758431b8bf7de7700da..0000000000000000000000000000000000000000
--- a/packages/transaction/transaction.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package transaction
-
-import (
-	"github.com/iotaledger/goshimmer/packages/curl"
-	"github.com/iotaledger/goshimmer/packages/ternary"
-)
-
-type Transaction struct {
-	SignatureMessageFragment ternary.Trits
-	Address                  ternary.Trits
-	Value                    ternary.Trits
-	Timestamp                ternary.Trits
-	CurrentIndex             ternary.Trits
-	LatestIndex              ternary.Trits
-	BundleHash               ternary.Trits
-	TrunkTransactionHash     ternary.Trits
-	BranchTransactionHash    ternary.Trits
-	Tag                      ternary.Trits
-	Nonce                    ternary.Trits
-
-	Hash            ternary.Trits
-	WeightMagnitude int
-	Bytes           []byte
-	Trits           ternary.Trits
-}
-
-func FromTrits(trits ternary.Trits, optionalHash ...ternary.Trits) *Transaction {
-	hash := <-curl.CURLP81.Hash(trits)
-
-	transaction := &Transaction{
-		SignatureMessageFragment: trits[SIGNATURE_MESSAGE_FRAGMENT_OFFSET:SIGNATURE_MESSAGE_FRAGMENT_END],
-		Address:                  trits[ADDRESS_OFFSET:ADDRESS_END],
-		Value:                    trits[VALUE_OFFSET:VALUE_END],
-		Timestamp:                trits[TIMESTAMP_OFFSET:TIMESTAMP_END],
-		CurrentIndex:             trits[CURRENT_INDEX_OFFSET:CURRENT_INDEX_END],
-		LatestIndex:              trits[LATEST_INDEX_OFFSET:LATEST_INDEX_END],
-		BundleHash:               trits[BUNDLE_HASH_OFFSET:BUNDLE_HASH_END],
-		TrunkTransactionHash:     trits[TRUNK_TRANSACTION_HASH_OFFSET:TRUNK_TRANSACTION_HASH_END],
-		BranchTransactionHash:    trits[BRANCH_TRANSACTION_HASH_OFFSET:BRANCH_TRANSACTION_HASH_END],
-		Tag:                      trits[TAG_OFFSET:TAG_END],
-		Nonce:                    trits[NONCE_OFFSET:NONCE_END],
-
-		Hash:            hash,
-		WeightMagnitude: hash.TrailingZeroes(),
-		Trits:           trits,
-	}
-
-	return transaction
-}
-
-func FromBytes(bytes []byte) *Transaction {
-	transaction := FromTrits(ternary.BytesToTrits(bytes)[:MARSHALED_TOTAL_SIZE])
-	transaction.Bytes = bytes
-
-	return transaction
-}
diff --git a/packages/transactionspammer/transactionspammer.go b/packages/transactionspammer/transactionspammer.go
new file mode 100644
index 0000000000000000000000000000000000000000..503a0f5af72c6f3120b0749ebb30bf5778ba3cd5
--- /dev/null
+++ b/packages/transactionspammer/transactionspammer.go
@@ -0,0 +1,83 @@
+package transactionspammer
+
+import (
+	"sync"
+	"time"
+
+	"github.com/iotaledger/goshimmer/packages/daemon"
+	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
+	"github.com/iotaledger/goshimmer/plugins/gossip"
+	"github.com/iotaledger/goshimmer/plugins/tipselection"
+)
+
+var spamming = false
+
+var startMutex sync.Mutex
+
+var shutdownSignal chan int
+
+func Start(tps int64) {
+	startMutex.Lock()
+
+	if !spamming {
+		shutdownSignal = make(chan int, 1)
+
+		func(shutdownSignal chan int) {
+			daemon.BackgroundWorker(func() {
+				for {
+					start := time.Now()
+					sentCounter := int64(0)
+					totalSentCounter := int64(0)
+
+					for {
+						select {
+						case <-daemon.ShutdownSignal:
+							return
+
+						case <-shutdownSignal:
+							return
+
+						default:
+							sentCounter++
+							totalSentCounter++
+
+							tx := value_transaction.New()
+							tx.SetValue(totalSentCounter)
+							tx.SetBranchTransactionHash(tipselection.GetRandomTip())
+							tx.SetTrunkTransactionHash(tipselection.GetRandomTip())
+
+							gossip.Events.ReceiveTransaction.Trigger(tx.MetaTransaction)
+
+							if sentCounter >= tps {
+								duration := time.Since(start)
+								if duration < time.Second {
+									time.Sleep(time.Second - duration)
+
+									start = time.Now()
+								}
+
+								sentCounter = 0
+							}
+						}
+					}
+				}
+			})
+		}(shutdownSignal)
+
+		spamming = true
+	}
+
+	startMutex.Unlock()
+}
+
+func Stop() {
+	startMutex.Lock()
+
+	if spamming {
+		close(shutdownSignal)
+
+		spamming = false
+	}
+
+	startMutex.Unlock()
+}
diff --git a/packages/typeconversion/typeconversion.go b/packages/typeutils/typeutils.go
similarity index 74%
rename from packages/typeconversion/typeconversion.go
rename to packages/typeutils/typeutils.go
index 4ed9a5073dd7e14f5677ed19f8f71e3acc2a9fa6..eed90cf95478febc1fd3248a2d3ce5c90b7007bf 100644
--- a/packages/typeconversion/typeconversion.go
+++ b/packages/typeutils/typeutils.go
@@ -1,4 +1,4 @@
-package typeconversion
+package typeutils
 
 import (
 	"reflect"
@@ -16,3 +16,7 @@ func StringToBytes(str string) []byte {
 
 	return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{Data: hdr.Data, Len: hdr.Len, Cap: hdr.Len}))
 }
+
+func IsInterfaceNil(param interface{}) bool {
+	return param == nil || (*[2]uintptr)(unsafe.Pointer(&param))[1] == 0
+}
diff --git a/plugins/gossip-on-solidification/plugin.go b/plugins/gossip-on-solidification/plugin.go
new file mode 100644
index 0000000000000000000000000000000000000000..1c2268007bd1336b3643f294d3572953c38fa60a
--- /dev/null
+++ b/plugins/gossip-on-solidification/plugin.go
@@ -0,0 +1,15 @@
+package gossip_on_solidification
+
+import (
+	"github.com/iotaledger/goshimmer/packages/events"
+	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
+	"github.com/iotaledger/goshimmer/packages/node"
+	"github.com/iotaledger/goshimmer/plugins/gossip"
+	"github.com/iotaledger/goshimmer/plugins/tangle"
+)
+
+var PLUGIN = node.NewPlugin("Gossip On Solidification", func(plugin *node.Plugin) {
+	tangle.Events.TransactionSolid.Attach(events.NewClosure(func(tx *value_transaction.ValueTransaction) {
+		gossip.SendTransaction(tx.MetaTransaction)
+	}))
+})
diff --git a/plugins/gossip/events.go b/plugins/gossip/events.go
index 765e106f0509a7856685c04b3f96d02d28fe4366..6d3183820d2f8c5986751e13e20896c3cc3f1e8b 100644
--- a/plugins/gossip/events.go
+++ b/plugins/gossip/events.go
@@ -4,8 +4,8 @@ import (
 	"github.com/iotaledger/goshimmer/packages/errors"
 	"github.com/iotaledger/goshimmer/packages/events"
 	"github.com/iotaledger/goshimmer/packages/identity"
+	"github.com/iotaledger/goshimmer/packages/model/meta_transaction"
 	"github.com/iotaledger/goshimmer/packages/network"
-	"github.com/iotaledger/goshimmer/packages/transaction"
 )
 
 var Events = pluginEvents{
@@ -93,5 +93,5 @@ func dataCaller(handler interface{}, params ...interface{}) {
 }
 
 func transactionCaller(handler interface{}, params ...interface{}) {
-	handler.(func(*transaction.Transaction))(params[0].(*transaction.Transaction))
+	handler.(func(*meta_transaction.MetaTransaction))(params[0].(*meta_transaction.MetaTransaction))
 }
diff --git a/plugins/gossip/neighbors.go b/plugins/gossip/neighbors.go
index dd03c22a161369ec919e4a22dfb9001dc3c2fe89..f61e08d86a6d0eac60eff86fe65df56acb75105c 100644
--- a/plugins/gossip/neighbors.go
+++ b/plugins/gossip/neighbors.go
@@ -199,7 +199,7 @@ func AddNeighbor(newNeighbor *Neighbor) {
 			neighbor.Port = newNeighbor.Port
 			neighbor.Address = newNeighbor.Address
 
-			Events.UpdateNeighbor.Trigger(newNeighbor)
+			Events.UpdateNeighbor.Trigger(neighbor)
 		}
 	}
 }
diff --git a/plugins/gossip/plugin.go b/plugins/gossip/plugin.go
index d647a90686f3108ad7b1d6bac86617281ec68779..0f02bd1404f577c1d265e239493aeec712e97ead 100644
--- a/plugins/gossip/plugin.go
+++ b/plugins/gossip/plugin.go
@@ -1,9 +1,7 @@
 package gossip
 
 import (
-	"github.com/iotaledger/goshimmer/packages/events"
 	"github.com/iotaledger/goshimmer/packages/node"
-	"github.com/iotaledger/goshimmer/packages/transaction"
 )
 
 var PLUGIN = node.NewPlugin("Gossip", configure, run)
@@ -12,10 +10,6 @@ func configure(plugin *node.Plugin) {
 	configureNeighbors(plugin)
 	configureServer(plugin)
 	configureSendQueue(plugin)
-
-	Events.ReceiveTransaction.Attach(events.NewClosure(func(transaction *transaction.Transaction) {
-
-	}))
 }
 
 func run(plugin *node.Plugin) {
diff --git a/plugins/gossip/protocol_v1.go b/plugins/gossip/protocol_v1.go
index e177271f4b096ff6553abbb30925926c1da4afbd..b0adc6addc6ce15fd4029e9acad0009fca7b805e 100644
--- a/plugins/gossip/protocol_v1.go
+++ b/plugins/gossip/protocol_v1.go
@@ -9,8 +9,8 @@ import (
 	"github.com/iotaledger/goshimmer/packages/errors"
 	"github.com/iotaledger/goshimmer/packages/events"
 	"github.com/iotaledger/goshimmer/packages/identity"
+	"github.com/iotaledger/goshimmer/packages/model/meta_transaction"
 	"github.com/iotaledger/goshimmer/packages/ternary"
-	"github.com/iotaledger/goshimmer/packages/transaction"
 )
 
 // region protocolV1 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -45,7 +45,7 @@ func protocolV1(protocol *protocol) errors.IdentifiableError {
 	return nil
 }
 
-func sendTransactionV1(protocol *protocol, tx *transaction.Transaction) {
+func sendTransactionV1(protocol *protocol, tx *meta_transaction.MetaTransaction) {
 	if _, ok := protocol.SendState.(*dispatchStateV1); ok {
 		protocol.sendMutex.Lock()
 		defer protocol.sendMutex.Unlock()
@@ -303,7 +303,7 @@ type transactionStateV1 struct {
 func newTransactionStateV1(protocol *protocol) *transactionStateV1 {
 	return &transactionStateV1{
 		protocol: protocol,
-		buffer:   make([]byte, transaction.MARSHALED_TOTAL_SIZE/ternary.NUMBER_OF_TRITS_IN_A_BYTE),
+		buffer:   make([]byte, meta_transaction.MARSHALLED_TOTAL_SIZE/ternary.NUMBER_OF_TRITS_IN_A_BYTE),
 		offset:   0,
 	}
 }
@@ -312,10 +312,10 @@ func (state *transactionStateV1) Receive(data []byte, offset int, length int) (i
 	bytesRead := byteutils.ReadAvailableBytesToBuffer(state.buffer, state.offset, data, offset, length)
 
 	state.offset += bytesRead
-	if state.offset == transaction.MARSHALED_TOTAL_SIZE/ternary.NUMBER_OF_TRITS_IN_A_BYTE {
+	if state.offset == meta_transaction.MARSHALLED_TOTAL_SIZE/ternary.NUMBER_OF_TRITS_IN_A_BYTE {
 		protocol := state.protocol
 
-		transactionData := make([]byte, transaction.MARSHALED_TOTAL_SIZE/ternary.NUMBER_OF_TRITS_IN_A_BYTE)
+		transactionData := make([]byte, meta_transaction.MARSHALLED_TOTAL_SIZE/ternary.NUMBER_OF_TRITS_IN_A_BYTE)
 		copy(transactionData, state.buffer)
 
 		protocol.Events.ReceiveTransactionData.Trigger(transactionData)
@@ -330,10 +330,10 @@ func (state *transactionStateV1) Receive(data []byte, offset int, length int) (i
 }
 
 func (state *transactionStateV1) Send(param interface{}) errors.IdentifiableError {
-	if tx, ok := param.(*transaction.Transaction); ok {
+	if tx, ok := param.(*meta_transaction.MetaTransaction); ok {
 		protocol := state.protocol
 
-		if _, err := protocol.Conn.Write(tx.Bytes); err != nil {
+		if _, err := protocol.Conn.Write(tx.GetBytes()); err != nil {
 			return ErrSendFailed.Derive(err, "failed to send transaction")
 		}
 
diff --git a/plugins/gossip/send_queue.go b/plugins/gossip/send_queue.go
index 337095271bf49fa1d7d1eb705307ac9e11418368..354c0c3bf0557265e7806d249a20b38e294ef667 100644
--- a/plugins/gossip/send_queue.go
+++ b/plugins/gossip/send_queue.go
@@ -5,8 +5,8 @@ import (
 
 	"github.com/iotaledger/goshimmer/packages/daemon"
 	"github.com/iotaledger/goshimmer/packages/events"
+	"github.com/iotaledger/goshimmer/packages/model/meta_transaction"
 	"github.com/iotaledger/goshimmer/packages/node"
-	"github.com/iotaledger/goshimmer/packages/transaction"
 )
 
 // region plugin module setup //////////////////////////////////////////////////////////////////////////////////////////
@@ -63,11 +63,11 @@ func runSendQueue(plugin *node.Plugin) {
 
 // region public api ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-func SendTransaction(transaction *transaction.Transaction) {
+func SendTransaction(transaction *meta_transaction.MetaTransaction) {
 	sendQueue <- transaction
 }
 
-func (neighbor *Neighbor) SendTransaction(transaction *transaction.Transaction) {
+func (neighbor *Neighbor) SendTransaction(transaction *meta_transaction.MetaTransaction) {
 	if queue, exists := neighborQueues[neighbor.Identity.StringIdentifier]; exists {
 		select {
 		case queue.queue <- transaction:
@@ -87,7 +87,7 @@ func setupEventHandlers(neighbor *Neighbor) {
 	neighbor.Events.ProtocolConnectionEstablished.Attach(events.NewClosure(func(protocol *protocol) {
 		queue := &neighborQueue{
 			protocol:       protocol,
-			queue:          make(chan *transaction.Transaction, SEND_QUEUE_SIZE),
+			queue:          make(chan *meta_transaction.MetaTransaction, SEND_QUEUE_SIZE),
 			disconnectChan: make(chan int, 1),
 		}
 
@@ -135,7 +135,7 @@ func startNeighborSendQueue(neighborQueue *neighborQueue) {
 
 type neighborQueue struct {
 	protocol       *protocol
-	queue          chan *transaction.Transaction
+	queue          chan *meta_transaction.MetaTransaction
 	disconnectChan chan int
 }
 
@@ -147,7 +147,7 @@ var neighborQueues = make(map[string]*neighborQueue)
 
 var connectedNeighborsMutex sync.RWMutex
 
-var sendQueue = make(chan *transaction.Transaction, SEND_QUEUE_SIZE)
+var sendQueue = make(chan *meta_transaction.MetaTransaction, SEND_QUEUE_SIZE)
 
 const (
 	SEND_QUEUE_SIZE = 500
diff --git a/plugins/gossip/transaction_processor.go b/plugins/gossip/transaction_processor.go
index 9a96fdb25f475b11b64b77c74da22f215de03843..742ac36929dfabd2d64b293c8906f397b02575a1 100644
--- a/plugins/gossip/transaction_processor.go
+++ b/plugins/gossip/transaction_processor.go
@@ -2,14 +2,14 @@ package gossip
 
 import (
 	"github.com/iotaledger/goshimmer/packages/filter"
-	"github.com/iotaledger/goshimmer/packages/transaction"
+	"github.com/iotaledger/goshimmer/packages/model/meta_transaction"
 )
 
 // region public api ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 func ProcessReceivedTransactionData(transactionData []byte) {
 	if transactionFilter.Add(transactionData) {
-		Events.ReceiveTransaction.Trigger(transaction.FromBytes(transactionData))
+		Events.ReceiveTransaction.Trigger(meta_transaction.FromBytes(transactionData))
 	}
 }
 
@@ -20,7 +20,7 @@ func ProcessReceivedTransactionData(transactionData []byte) {
 var transactionFilter = filter.NewByteArrayFilter(TRANSACTION_FILTER_SIZE)
 
 const (
-	TRANSACTION_FILTER_SIZE = 5000
+	TRANSACTION_FILTER_SIZE = 500
 )
 
 // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/plugins/gossip/transaction_processor_test.go b/plugins/gossip/transaction_processor_test.go
index b970119aef82076c098d3bfdf56ae49c5971af5e..86b6349a9f3b32d7b3c10d07331647929500d2bb 100644
--- a/plugins/gossip/transaction_processor_test.go
+++ b/plugins/gossip/transaction_processor_test.go
@@ -4,12 +4,16 @@ import (
 	"sync"
 	"testing"
 
+	"github.com/iotaledger/goshimmer/packages/model/meta_transaction"
 	"github.com/iotaledger/goshimmer/packages/ternary"
-	"github.com/iotaledger/goshimmer/packages/transaction"
 )
 
 func BenchmarkProcessSimilarTransactionsFiltered(b *testing.B) {
+<<<<<<< HEAD
 	byteArray := setupTransaction(transaction.MARSHALED_TOTAL_SIZE / ternary.NUMBER_OF_TRITS_IN_A_BYTE)
+=======
+	byteArray := setupTransaction(meta_transaction.MARSHALLED_TOTAL_SIZE / ternary.NUMBER_OF_TRITS_IN_A_BYTE)
+>>>>>>> master
 
 	b.ResetTimer()
 
@@ -19,7 +23,11 @@ func BenchmarkProcessSimilarTransactionsFiltered(b *testing.B) {
 }
 
 func BenchmarkProcessSimilarTransactionsUnfiltered(b *testing.B) {
+<<<<<<< HEAD
 	byteArray := setupTransaction(transaction.MARSHALED_TOTAL_SIZE / ternary.NUMBER_OF_TRITS_IN_A_BYTE)
+=======
+	byteArray := setupTransaction(meta_transaction.MARSHALLED_TOTAL_SIZE / ternary.NUMBER_OF_TRITS_IN_A_BYTE)
+>>>>>>> master
 
 	b.ResetTimer()
 
@@ -29,7 +37,7 @@ func BenchmarkProcessSimilarTransactionsUnfiltered(b *testing.B) {
 		wg.Add(1)
 
 		go func() {
-			Events.ReceiveTransaction.Trigger(transaction.FromBytes(byteArray))
+			Events.ReceiveTransaction.Trigger(meta_transaction.FromBytes(byteArray))
 
 			wg.Done()
 		}()
diff --git a/plugins/statusscreen-tps/plugin.go b/plugins/statusscreen-tps/plugin.go
new file mode 100644
index 0000000000000000000000000000000000000000..eabb868f15e786ecea795ceac8173f2984d4a31c
--- /dev/null
+++ b/plugins/statusscreen-tps/plugin.go
@@ -0,0 +1,56 @@
+package statusscreen_tps
+
+import (
+	"strconv"
+	"sync/atomic"
+	"time"
+
+	"github.com/iotaledger/goshimmer/packages/daemon"
+	"github.com/iotaledger/goshimmer/packages/events"
+	"github.com/iotaledger/goshimmer/packages/model/meta_transaction"
+	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
+	"github.com/iotaledger/goshimmer/packages/node"
+	"github.com/iotaledger/goshimmer/plugins/gossip"
+	"github.com/iotaledger/goshimmer/plugins/statusscreen"
+	"github.com/iotaledger/goshimmer/plugins/tangle"
+)
+
+var receivedTpsCounter uint64
+
+var solidTpsCounter uint64
+
+var receivedTps uint64
+
+var solidTps uint64
+
+var PLUGIN = node.NewPlugin("Statusscreen TPS", func(plugin *node.Plugin) {
+	gossip.Events.ReceiveTransaction.Attach(events.NewClosure(func(_ *meta_transaction.MetaTransaction) {
+		atomic.AddUint64(&receivedTpsCounter, 1)
+	}))
+
+	tangle.Events.TransactionSolid.Attach(events.NewClosure(func(_ *value_transaction.ValueTransaction) {
+		atomic.AddUint64(&solidTpsCounter, 1)
+	}))
+
+	statusscreen.AddHeaderInfo(func() (s string, s2 string) {
+		return "TPS", strconv.FormatUint(atomic.LoadUint64(&receivedTps), 10) + " received / " + strconv.FormatUint(atomic.LoadUint64(&solidTps), 10) + " new"
+	})
+}, func(plugin *node.Plugin) {
+	daemon.BackgroundWorker(func() {
+		ticker := time.NewTicker(time.Second)
+
+		for {
+			select {
+			case <-daemon.ShutdownSignal:
+				return
+
+			case <-ticker.C:
+				atomic.StoreUint64(&receivedTps, atomic.LoadUint64(&receivedTpsCounter))
+				atomic.StoreUint64(&solidTps, atomic.LoadUint64(&solidTpsCounter))
+
+				atomic.StoreUint64(&receivedTpsCounter, 0)
+				atomic.StoreUint64(&solidTpsCounter, 0)
+			}
+		}
+	})
+})
diff --git a/plugins/statusscreen/ui_header_bar.go b/plugins/statusscreen/ui_header_bar.go
index 8ea81c0614c3e07a3ac42d83451d92759d0dc2a5..66ab397c5c45f1f24c868611f6f966cf023fe7de 100644
--- a/plugins/statusscreen/ui_header_bar.go
+++ b/plugins/statusscreen/ui_header_bar.go
@@ -17,6 +17,12 @@ import (
 
 var start = time.Now()
 
+var headerInfos = make([]func() (string, string), 0)
+
+func AddHeaderInfo(generator func() (string, string)) {
+	headerInfos = append(headerInfos, generator)
+}
+
 type UIHeaderBar struct {
 	Primitive     *tview.Grid
 	LogoContainer *tview.TextView
@@ -62,9 +68,16 @@ func (headerBar *UIHeaderBar) Update() {
 
 	fmt.Fprintln(headerBar.InfoContainer)
 	fmt.Fprintln(headerBar.InfoContainer, "[::d]COO-LESS IOTA PROTOTYPE  -  [::b]Status: [green::b]SYNCED  ")
-	fmt.Fprintln(headerBar.InfoContainer)
-	fmt.Fprintln(headerBar.InfoContainer)
-	fmt.Fprintln(headerBar.InfoContainer)
+	for i := 0; i < 3-len(headerInfos); i++ {
+		fmt.Fprintln(headerBar.InfoContainer)
+	}
+
+	for _, infoGenerator := range headerInfos {
+		fieldName, fieldValue := infoGenerator()
+		fmt.Fprintf(headerBar.InfoContainer, "[::b]%v: [::d]%40v  ", fieldName, fieldValue)
+		fmt.Fprintln(headerBar.InfoContainer)
+	}
+
 	fmt.Fprintf(headerBar.InfoContainer, "[::b]Node ID: [::d]%40v  ", accountability.OwnId().StringIdentifier)
 	fmt.Fprintln(headerBar.InfoContainer)
 	fmt.Fprintf(headerBar.InfoContainer, "[::b]Neighbors: [::d]%40v  ", strconv.Itoa(len(chosenneighbors.INSTANCE.Peers))+" chosen / "+strconv.Itoa(len(acceptedneighbors.INSTANCE.Peers))+" accepted")
diff --git a/plugins/tangle/api.go b/plugins/tangle/api.go
index 2a69fcc5db54efb08920798c2da4381cce64b8ac..3e40d0caa2ca91f45ff0d617d7ba178182b6963f 100644
--- a/plugins/tangle/api.go
+++ b/plugins/tangle/api.go
@@ -3,14 +3,27 @@ package tangle
 import (
 	"github.com/iotaledger/goshimmer/packages/datastructure"
 	"github.com/iotaledger/goshimmer/packages/errors"
+	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
 	"github.com/iotaledger/goshimmer/packages/ternary"
 )
 
 // region transaction api //////////////////////////////////////////////////////////////////////////////////////////////
 
-var transactionCache = datastructure.NewLRUCache(TRANSACTION_CACHE_SIZE)
+var transactionCache = datastructure.NewLRUCache(TRANSACTION_CACHE_SIZE, &datastructure.LRUCacheOptions{
+	EvictionCallback: func(key interface{}, value interface{}) {
+		go func(evictedTransaction *value_transaction.ValueTransaction) {
+			if err := storeTransactionInDatabase(evictedTransaction); err != nil {
+				panic(err)
+			}
+		}(value.(*value_transaction.ValueTransaction))
+	},
+})
+
+func StoreTransaction(transaction *value_transaction.ValueTransaction) {
+	transactionCache.Set(transaction.GetHash(), transaction)
+}
 
-func GetTransaction(transactionHash ternary.Trinary, computeIfAbsent ...func(ternary.Trinary) *Transaction) (result *Transaction, err errors.IdentifiableError) {
+func GetTransaction(transactionHash ternary.Trinary, computeIfAbsent ...func(ternary.Trinary) *value_transaction.ValueTransaction) (result *value_transaction.ValueTransaction, err errors.IdentifiableError) {
 	if cacheResult := transactionCache.ComputeIfAbsent(transactionHash, func() interface{} {
 		if transaction, dbErr := getTransactionFromDatabase(transactionHash); dbErr != nil {
 			err = dbErr
@@ -26,7 +39,7 @@ func GetTransaction(transactionHash ternary.Trinary, computeIfAbsent ...func(ter
 			return nil
 		}
 	}); cacheResult != nil {
-		result = cacheResult.(*Transaction)
+		result = cacheResult.(*value_transaction.ValueTransaction)
 	}
 
 	return
@@ -46,20 +59,26 @@ func ContainsTransaction(transactionHash ternary.Trinary) (result bool, err erro
 
 // region transactionmetadata api //////////////////////////////////////////////////////////////////////////////////////
 
-var metadataCache = datastructure.NewLRUCache(METADATA_CACHE_SIZE)
-
-func GetTransactionMetadata(transactionHash ternary.Trinary) (result *TransactionMetadata, err errors.IdentifiableError) {
-	result = metadataCache.ComputeIfAbsent(transactionHash, func() interface{} {
-		if metadata, dbErr := getTransactionMetadataFromDatabase(transactionHash); dbErr != nil {
-			err = dbErr
-
-			return nil
-		} else if metadata != nil {
-			return metadata
+var metadataCache = datastructure.NewLRUCache(METADATA_CACHE_SIZE, &datastructure.LRUCacheOptions{
+	EvictionCallback: func(key interface{}, value interface{}) {
+		go func(evictedMetadata *TransactionMetadata) {
+			if err := storeTransactionMetadataInDatabase(evictedMetadata); err != nil {
+				panic(err)
+			}
+		}(value.(*TransactionMetadata))
+	},
+})
+
+func GetTransactionMetadata(transactionHash ternary.Trinary, computeIfAbsent ...func(ternary.Trinary) *TransactionMetadata) (result *TransactionMetadata, err errors.IdentifiableError) {
+	if transactionMetadata := metadataCache.ComputeIfAbsent(transactionHash, func() interface{} {
+		if result, err = getTransactionMetadataFromDatabase(transactionHash); err == nil && result == nil && len(computeIfAbsent) >= 1 {
+			result = computeIfAbsent[0](transactionHash)
 		}
 
-		return nil
-	}).(*TransactionMetadata)
+		return result
+	}); transactionMetadata != nil && transactionMetadata.(*TransactionMetadata) != nil {
+		result = transactionMetadata.(*TransactionMetadata)
+	}
 
 	return
 }
@@ -77,6 +96,6 @@ func ContainsTransactionMetadata(transactionHash ternary.Trinary) (result bool,
 // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 const (
-	TRANSACTION_CACHE_SIZE = 1000
-	METADATA_CACHE_SIZE    = 1000
+	TRANSACTION_CACHE_SIZE = 10000
+	METADATA_CACHE_SIZE    = 10000
 )
diff --git a/plugins/tangle/approvers.go b/plugins/tangle/approvers.go
index 1fa2f0fbf9d3fc720b9c55b6de8ca77f571e59c1..6b2f03d9b3a209a36064ace7eb914f608b17e0f2 100644
--- a/plugins/tangle/approvers.go
+++ b/plugins/tangle/approvers.go
@@ -9,7 +9,7 @@ import (
 	"github.com/iotaledger/goshimmer/packages/datastructure"
 	"github.com/iotaledger/goshimmer/packages/errors"
 	"github.com/iotaledger/goshimmer/packages/ternary"
-	"github.com/iotaledger/goshimmer/packages/typeconversion"
+	"github.com/iotaledger/goshimmer/packages/typeutils"
 )
 
 // region global public api ////////////////////////////////////////////////////////////////////////////////////////////
@@ -23,12 +23,12 @@ func StoreApprovers(approvers *Approvers) {
 }
 
 func GetApprovers(transactionHash ternary.Trinary, computeIfAbsent ...func(ternary.Trinary) *Approvers) (result *Approvers, err errors.IdentifiableError) {
-	if approvers := approversCache.ComputeIfAbsent(transactionHash, func() (result interface{}) {
-		if result, err = getApproversFromDatabase(transactionHash); err == nil && (result.(*Approvers) == nil) && len(computeIfAbsent) >= 1 {
+	if approvers := approversCache.ComputeIfAbsent(transactionHash, func() interface{} {
+		if result, err = getApproversFromDatabase(transactionHash); err == nil && result == nil && len(computeIfAbsent) >= 1 {
 			result = computeIfAbsent[0](transactionHash)
 		}
 
-		return
+		return result
 	}); approvers != nil && approvers.(*Approvers) != nil {
 		result = approvers.(*Approvers)
 	}
@@ -132,13 +132,13 @@ func (approvers *Approvers) Unmarshal(data []byte) (err errors.IdentifiableError
 
 	approvers.hashesMutex.Lock()
 
-	approvers.hash = ternary.Trinary(typeconversion.BytesToString(data[MARSHALED_APPROVERS_HASH_START:MARSHALED_APPROVERS_HASH_END]))
+	approvers.hash = ternary.Trinary(typeutils.BytesToString(data[MARSHALED_APPROVERS_HASH_START:MARSHALED_APPROVERS_HASH_END]))
 	approvers.hashes = make(map[ternary.Trinary]bool, hashesCount)
 	for i := uint64(0); i < hashesCount; i++ {
 		var HASH_START = MARSHALED_APPROVERS_HASHES_START + i*(MARSHALED_APPROVERS_HASH_SIZE)
 		var HASH_END = HASH_START * MARSHALED_APPROVERS_HASH_SIZE
 
-		approvers.hashes[ternary.Trinary(typeconversion.BytesToString(data[HASH_START:HASH_END]))] = true
+		approvers.hashes[ternary.Trinary(typeutils.BytesToString(data[HASH_START:HASH_END]))] = true
 	}
 
 	approvers.hashesMutex.Unlock()
@@ -201,9 +201,7 @@ func (approvers *Approvers) Store(approverHash ternary.Trinary) {
 func getApproversFromDatabase(transactionHash ternary.Trinary) (result *Approvers, err errors.IdentifiableError) {
 	approversData, dbErr := approversDatabase.Get(transactionHash.CastToBytes())
 	if dbErr != nil {
-		if dbErr == badger.ErrKeyNotFound {
-			err = nil
-		} else {
+		if dbErr != badger.ErrKeyNotFound {
 			err = ErrDatabaseError.Derive(err, "failed to retrieve transaction")
 		}
 
diff --git a/plugins/tangle/approvers_test.go b/plugins/tangle/approvers_test.go
index b7e4b684e65b947bc14a1df4a4a4203434bb2baa..d5f7cfccb0db544d44c45a20205658952bcc0f66 100644
--- a/plugins/tangle/approvers_test.go
+++ b/plugins/tangle/approvers_test.go
@@ -5,6 +5,7 @@ import (
 	"testing"
 
 	"github.com/iotaledger/goshimmer/packages/events"
+	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
 	"github.com/iotaledger/goshimmer/packages/ternary"
 	"github.com/iotaledger/goshimmer/plugins/gossip"
 )
@@ -15,27 +16,27 @@ func TestSolidifier(t *testing.T) {
 	configureSolidifier(nil)
 
 	// create transactions and chain them together
-	transaction1 := NewTransaction(nil)
+	transaction1 := value_transaction.New()
 	transaction1.SetNonce(ternary.Trinary("99999999999999999999999999A"))
-	transaction2 := NewTransaction(nil)
+	transaction2 := value_transaction.New()
 	transaction2.SetBranchTransactionHash(transaction1.GetHash())
-	transaction3 := NewTransaction(nil)
+	transaction3 := value_transaction.New()
 	transaction3.SetBranchTransactionHash(transaction2.GetHash())
-	transaction4 := NewTransaction(nil)
+	transaction4 := value_transaction.New()
 	transaction4.SetBranchTransactionHash(transaction3.GetHash())
 
 	// setup event handlers
 	var wg sync.WaitGroup
-	Events.TransactionSolid.Attach(events.NewClosure(func(transaction *Transaction) {
+	Events.TransactionSolid.Attach(events.NewClosure(func(transaction *value_transaction.ValueTransaction) {
 		wg.Done()
 	}))
 
 	// issue transactions
 	wg.Add(4)
-	gossip.Events.ReceiveTransaction.Trigger(transaction1.Flush())
-	gossip.Events.ReceiveTransaction.Trigger(transaction2.Flush())
-	gossip.Events.ReceiveTransaction.Trigger(transaction3.Flush())
-	gossip.Events.ReceiveTransaction.Trigger(transaction4.Flush())
+	gossip.Events.ReceiveTransaction.Trigger(transaction1.MetaTransaction)
+	gossip.Events.ReceiveTransaction.Trigger(transaction2.MetaTransaction)
+	gossip.Events.ReceiveTransaction.Trigger(transaction3.MetaTransaction)
+	gossip.Events.ReceiveTransaction.Trigger(transaction4.MetaTransaction)
 
 	// wait until all are solid
 	wg.Wait()
diff --git a/plugins/tangle/database.go b/plugins/tangle/database.go
index fbfdc548c346587d7f8a0c2d6009c4c148b3cc2c..511d52d2cb5bc3d053a5ca96c11cfd6841c33a6a 100644
--- a/plugins/tangle/database.go
+++ b/plugins/tangle/database.go
@@ -1,14 +1,12 @@
 package tangle
 
 import (
-	"fmt"
-
 	"github.com/dgraph-io/badger"
 	"github.com/iotaledger/goshimmer/packages/database"
 	"github.com/iotaledger/goshimmer/packages/errors"
+	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
 	"github.com/iotaledger/goshimmer/packages/node"
 	"github.com/iotaledger/goshimmer/packages/ternary"
-	"github.com/iotaledger/goshimmer/packages/transaction"
 )
 
 // region plugin module setup //////////////////////////////////////////////////////////////////////////////////////////
@@ -37,7 +35,19 @@ func configureDatabase(plugin *node.Plugin) {
 
 // region internal utility functions ///////////////////////////////////////////////////////////////////////////////////
 
-func getTransactionFromDatabase(transactionHash ternary.Trinary) (*Transaction, errors.IdentifiableError) {
+func storeTransactionInDatabase(transaction *value_transaction.ValueTransaction) errors.IdentifiableError {
+	if transaction.GetModified() {
+		if err := transactionDatabase.Set(transaction.GetHash().CastToBytes(), transaction.MetaTransaction.GetBytes()); err != nil {
+			return ErrDatabaseError.Derive(err, "failed to store transaction")
+		}
+
+		transaction.SetModified(false)
+	}
+
+	return nil
+}
+
+func getTransactionFromDatabase(transactionHash ternary.Trinary) (*value_transaction.ValueTransaction, errors.IdentifiableError) {
 	txData, err := transactionDatabase.Get(transactionHash.CastToBytes())
 	if err != nil {
 		if err == badger.ErrKeyNotFound {
@@ -47,9 +57,7 @@ func getTransactionFromDatabase(transactionHash ternary.Trinary) (*Transaction,
 		}
 	}
 
-	return &Transaction{
-		rawTransaction: transaction.FromBytes(txData),
-	}, nil
+	return value_transaction.FromBytes(txData), nil
 }
 
 func databaseContainsTransaction(transactionHash ternary.Trinary) (bool, errors.IdentifiableError) {
@@ -60,6 +68,23 @@ func databaseContainsTransaction(transactionHash ternary.Trinary) (bool, errors.
 	}
 }
 
+func storeTransactionMetadataInDatabase(metadata *TransactionMetadata) errors.IdentifiableError {
+	if metadata.GetModified() {
+		marshalledMetadata, err := metadata.Marshal()
+		if err != nil {
+			return err
+		}
+
+		if err := transactionMetadataDatabase.Set(metadata.GetHash().CastToBytes(), marshalledMetadata); err != nil {
+			return ErrDatabaseError.Derive(err, "failed to store transaction metadata")
+		}
+
+		metadata.SetModified(false)
+	}
+
+	return nil
+}
+
 func getTransactionMetadataFromDatabase(transactionHash ternary.Trinary) (*TransactionMetadata, errors.IdentifiableError) {
 	txMetadata, err := transactionMetadataDatabase.Get(transactionHash.CastToBytes())
 	if err != nil {
@@ -70,11 +95,12 @@ func getTransactionMetadataFromDatabase(transactionHash ternary.Trinary) (*Trans
 		}
 	}
 
-	if false {
-		fmt.Println(txMetadata)
+	var result TransactionMetadata
+	if err := result.Unmarshal(txMetadata); err != nil {
+		panic(err)
 	}
 
-	return &TransactionMetadata{}, nil
+	return &result, nil
 }
 
 func databaseContainsTransactionMetadata(transactionHash ternary.Trinary) (bool, errors.IdentifiableError) {
diff --git a/plugins/tangle/events.go b/plugins/tangle/events.go
index bb8883a58a14f6fada96135e0a5cc24d36a29afc..e29ecd20c31dc13dbf3638cf5e880ae328411d37 100644
--- a/plugins/tangle/events.go
+++ b/plugins/tangle/events.go
@@ -2,6 +2,7 @@ package tangle
 
 import (
 	"github.com/iotaledger/goshimmer/packages/events"
+	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
 )
 
 var Events = pluginEvents{
@@ -15,5 +16,5 @@ type pluginEvents struct {
 }
 
 func transactionCaller(handler interface{}, params ...interface{}) {
-	handler.(func(*Transaction))(params[0].(*Transaction))
+	handler.(func(*value_transaction.ValueTransaction))(params[0].(*value_transaction.ValueTransaction))
 }
diff --git a/plugins/tangle/solidifier.go b/plugins/tangle/solidifier.go
index d662d7cc7bd44e204c9cfd95740d7946c5836000..c5b0d38d90e949415adba6cfc095fbe7e572a978 100644
--- a/plugins/tangle/solidifier.go
+++ b/plugins/tangle/solidifier.go
@@ -3,26 +3,64 @@ package tangle
 import (
 	"github.com/iotaledger/goshimmer/packages/errors"
 	"github.com/iotaledger/goshimmer/packages/events"
+	"github.com/iotaledger/goshimmer/packages/model/meta_transaction"
+	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
 	"github.com/iotaledger/goshimmer/packages/node"
 	"github.com/iotaledger/goshimmer/packages/ternary"
-	"github.com/iotaledger/goshimmer/packages/transaction"
 	"github.com/iotaledger/goshimmer/plugins/gossip"
 )
 
 // region plugin module setup //////////////////////////////////////////////////////////////////////////////////////////
 
+//var solidifierChan = make(chan *value_transaction.ValueTransaction, 1000)
+
+const NUMBER_OF_WORKERS = 300
+
+var tasksChan = make(chan *meta_transaction.MetaTransaction, NUMBER_OF_WORKERS)
+
 func configureSolidifier(plugin *node.Plugin) {
-	gossip.Events.ReceiveTransaction.Attach(events.NewClosure(func(rawTransaction *transaction.Transaction) {
-		go processRawTransaction(plugin, rawTransaction)
+	for i := 0; i < NUMBER_OF_WORKERS; i++ {
+		go func() {
+			for {
+				rawTransaction := <-tasksChan
+
+				processMetaTransaction(plugin, rawTransaction)
+			}
+		}()
+	}
+
+	gossip.Events.ReceiveTransaction.Attach(events.NewClosure(func(rawTransaction *meta_transaction.MetaTransaction) {
+		tasksChan <- rawTransaction
+
+		//go processMetaTransaction(plugin, rawTransaction)
 	}))
+	/*
+		for i := 0; i < NUMBER_OF_WORKERS; i++ {
+			go func() {
+				for transaction := range solidifierChan {
+					select {
+					case <-daemon.ShutdownSignal:
+						return
+
+					default:
+						// update the solidity flags of this transaction and its approvers
+						if _, err := IsSolid(transaction); err != nil {
+							plugin.LogFailure(err.Error())
+
+							return
+						}
+					}
+				}
+			}()
+		}*/
 }
 
 // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 // Checks and updates the solid flag of a single transaction.
-func checkSolidity(transaction *Transaction) (result bool, err errors.IdentifiableError) {
+func checkSolidity(transaction *value_transaction.ValueTransaction) (result bool, err errors.IdentifiableError) {
 	// abort if transaction is solid already
-	txMetadata, metaDataErr := transaction.GetMetaData()
+	txMetadata, metaDataErr := GetTransactionMetadata(transaction.GetHash(), NewTransactionMetadata)
 	if metaDataErr != nil {
 		err = metaDataErr
 
@@ -34,7 +72,7 @@ func checkSolidity(transaction *Transaction) (result bool, err errors.Identifiab
 	}
 
 	// check solidity of branch transaction if it is not genesis
-	if branchTransactionHash := transaction.GetBranchTransactionHash(); branchTransactionHash != TRANSACTION_NULL_HASH {
+	if branchTransactionHash := transaction.GetBranchTransactionHash(); branchTransactionHash != meta_transaction.BRANCH_NULL_HASH {
 		// abort if branch transaction is missing
 		if branchTransaction, branchErr := GetTransaction(branchTransactionHash); branchErr != nil {
 			err = branchErr
@@ -42,7 +80,7 @@ func checkSolidity(transaction *Transaction) (result bool, err errors.Identifiab
 			return
 		} else if branchTransaction == nil {
 			return
-		} else if branchTransactionMetadata, branchErr := branchTransaction.GetMetaData(); branchErr != nil {
+		} else if branchTransactionMetadata, branchErr := GetTransactionMetadata(branchTransaction.GetHash(), NewTransactionMetadata); branchErr != nil {
 			err = branchErr
 
 			return
@@ -52,14 +90,14 @@ func checkSolidity(transaction *Transaction) (result bool, err errors.Identifiab
 	}
 
 	// check solidity of branch transaction if it is not genesis
-	if trunkTransactionHash := transaction.GetBranchTransactionHash(); trunkTransactionHash != TRANSACTION_NULL_HASH {
+	if trunkTransactionHash := transaction.GetBranchTransactionHash(); trunkTransactionHash != meta_transaction.BRANCH_NULL_HASH {
 		if trunkTransaction, trunkErr := GetTransaction(trunkTransactionHash); trunkErr != nil {
 			err = trunkErr
 
 			return
 		} else if trunkTransaction == nil {
 			return
-		} else if trunkTransactionMetadata, trunkErr := trunkTransaction.GetMetaData(); trunkErr != nil {
+		} else if trunkTransactionMetadata, trunkErr := GetTransactionMetadata(trunkTransaction.GetHash(), NewTransactionMetadata); trunkErr != nil {
 			err = trunkErr
 
 			return
@@ -79,7 +117,7 @@ func checkSolidity(transaction *Transaction) (result bool, err errors.Identifiab
 }
 
 // Checks and updates the solid flag of a transaction and its approvers (future cone).
-func IsSolid(transaction *Transaction) (bool, errors.IdentifiableError) {
+func IsSolid(transaction *value_transaction.ValueTransaction) (bool, errors.IdentifiableError) {
 	if isSolid, err := checkSolidity(transaction); err != nil {
 		return false, err
 	} else if isSolid {
@@ -113,20 +151,20 @@ func propagateSolidity(transactionHash ternary.Trinary) errors.IdentifiableError
 	return nil
 }
 
-func processRawTransaction(plugin *node.Plugin, rawTransaction *transaction.Transaction) {
+func processMetaTransaction(plugin *node.Plugin, metaTransaction *meta_transaction.MetaTransaction) {
 	var newTransaction bool
-	if tx, err := GetTransaction(rawTransaction.Hash.ToTrinary(), func(transactionHash ternary.Trinary) *Transaction {
+	if tx, err := GetTransaction(metaTransaction.GetHash(), func(transactionHash ternary.Trinary) *value_transaction.ValueTransaction {
 		newTransaction = true
 
-		return &Transaction{rawTransaction: rawTransaction}
+		return value_transaction.FromMetaTransaction(metaTransaction)
 	}); err != nil {
 		plugin.LogFailure(err.Error())
 	} else if newTransaction {
-		go processTransaction(plugin, tx)
+		processTransaction(plugin, tx)
 	}
 }
 
-func processTransaction(plugin *node.Plugin, transaction *Transaction) {
+func processTransaction(plugin *node.Plugin, transaction *value_transaction.ValueTransaction) {
 	transactionHash := transaction.GetHash()
 
 	// register tx as approver for trunk
@@ -153,4 +191,5 @@ func processTransaction(plugin *node.Plugin, transaction *Transaction) {
 
 		return
 	}
+	//solidifierChan <- transaction
 }
diff --git a/plugins/tangle/transaction.go b/plugins/tangle/transaction.go
deleted file mode 100644
index daa166c4d4ec8072faa451081ddf91e3e05d586c..0000000000000000000000000000000000000000
--- a/plugins/tangle/transaction.go
+++ /dev/null
@@ -1,683 +0,0 @@
-package tangle
-
-import (
-	"math"
-	"sync"
-
-	"github.com/iotaledger/goshimmer/packages/curl"
-	"github.com/iotaledger/goshimmer/packages/errors"
-	"github.com/iotaledger/goshimmer/packages/ternary"
-	"github.com/iotaledger/goshimmer/packages/transaction"
-)
-
-// region type definition and constructor //////////////////////////////////////////////////////////////////////////////
-
-type Transaction struct {
-	// wrapped objects
-	rawTransaction   *transaction.Transaction
-	rawMetaData      *TransactionMetadata
-	rawMetaDataMutex sync.RWMutex
-
-	// mapped raw transaction properties
-	hash                       *ternary.Trinary
-	hashMutex                  sync.RWMutex
-	address                    *ternary.Trinary
-	addressMutex               sync.RWMutex
-	value                      *int64
-	valueMutex                 sync.RWMutex
-	timestamp                  *uint64
-	timestampMutex             sync.RWMutex
-	currentIndex               *uint64
-	currentIndexMutex          sync.RWMutex
-	latestIndex                *uint64
-	latestIndexMutex           sync.RWMutex
-	bundleHash                 *ternary.Trinary
-	bundleHashMutex            sync.RWMutex
-	trunkTransactionHash       *ternary.Trinary
-	trunkTransactionHashMutex  sync.RWMutex
-	branchTransactionHash      *ternary.Trinary
-	branchTransactionHashMutex sync.RWMutex
-	tag                        *ternary.Trinary
-	tagMutex                   sync.RWMutex
-	nonce                      *ternary.Trinary
-	nonceMutex                 sync.RWMutex
-
-	// additional runtime specific metadata
-	modified      bool
-	modifiedMutex sync.RWMutex
-}
-
-func NewTransaction(rawTransaction *transaction.Transaction) *Transaction {
-	if rawTransaction == nil {
-		rawTransaction = transaction.FromBytes(make([]byte, int(math.Ceil(float64(transaction.MARSHALED_TOTAL_SIZE)/ternary.NUMBER_OF_TRITS_IN_A_BYTE))))
-	}
-
-	return &Transaction{rawTransaction: rawTransaction}
-}
-
-// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-// region getters and setters //////////////////////////////////////////////////////////////////////////////////////////
-
-func (transaction *Transaction) GetMetaData() (*TransactionMetadata, errors.IdentifiableError) {
-	transaction.rawMetaDataMutex.RLock()
-	if transaction.rawMetaData == nil {
-		transaction.rawMetaDataMutex.RUnlock()
-		transaction.rawMetaDataMutex.Lock()
-		defer transaction.rawMetaDataMutex.Unlock()
-		if transaction.rawMetaData == nil {
-			if metaData, err := getTransactionMetadataFromDatabase(transaction.GetHash()); err != nil {
-				return nil, err
-			} else if metaData == nil {
-				transaction.rawMetaData = NewTransactionMetadata(transaction.GetHash())
-			} else {
-				transaction.rawMetaData = metaData
-			}
-
-			return transaction.rawMetaData, nil
-		}
-	}
-
-	defer transaction.rawMetaDataMutex.RUnlock()
-
-	return transaction.rawMetaData, nil
-}
-
-// getter for the hash (supports concurrency)
-func (transaction *Transaction) GetHash() ternary.Trinary {
-	transaction.hashMutex.RLock()
-	if transaction.hash == nil {
-		transaction.hashMutex.RUnlock()
-		transaction.hashMutex.Lock()
-		defer transaction.hashMutex.Unlock()
-		if transaction.hash == nil {
-			return transaction.parseHash()
-		}
-	}
-
-	defer transaction.hashMutex.RUnlock()
-
-	return *transaction.hash
-}
-
-// setter for the hash (supports concurrency)
-func (transaction *Transaction) SetHash(hash ternary.Trinary) {
-	transaction.hashMutex.RLock()
-	if transaction.hash == nil || *transaction.hash != hash {
-		transaction.hashMutex.RUnlock()
-		transaction.hashMutex.Lock()
-		defer transaction.hashMutex.Unlock()
-		if transaction.hash == nil || *transaction.hash != hash {
-			*transaction.hash = hash
-
-			transaction.SetModified(true)
-		}
-	} else {
-		transaction.hashMutex.RUnlock()
-	}
-}
-
-// restores the hash from the underlying raw transaction (supports concurrency)
-func (transaction *Transaction) ParseHash() ternary.Trinary {
-	transaction.hashMutex.Lock()
-	defer transaction.hashMutex.Unlock()
-
-	return transaction.parseHash()
-}
-
-// parses the hash from the underlying raw transaction (without locking - internal usage)
-func (transaction *Transaction) parseHash() (result ternary.Trinary) {
-	if transaction.modified {
-		transaction.Flush()
-	}
-
-	result = transaction.rawTransaction.Hash.ToTrinary()
-
-	transaction.hash = &result
-
-	return
-}
-
-// getter for the address (supports concurrency)
-func (transaction *Transaction) GetAddress() ternary.Trinary {
-	transaction.addressMutex.RLock()
-	if transaction.address == nil {
-		transaction.addressMutex.RUnlock()
-		transaction.addressMutex.Lock()
-		defer transaction.addressMutex.Unlock()
-		if transaction.address == nil {
-			return transaction.parseAddress()
-		}
-	}
-
-	defer transaction.addressMutex.RUnlock()
-
-	return *transaction.address
-}
-
-// setter for the address (supports concurrency)
-func (transaction *Transaction) SetAddress(address ternary.Trinary) {
-	transaction.addressMutex.RLock()
-	if transaction.address == nil || *transaction.address != address {
-		transaction.addressMutex.RUnlock()
-		transaction.addressMutex.Lock()
-		defer transaction.addressMutex.Unlock()
-		if transaction.address == nil || *transaction.address != address {
-			*transaction.address = address
-
-			transaction.SetModified(true)
-		}
-	} else {
-		transaction.addressMutex.RUnlock()
-	}
-}
-
-// restores the address from the underlying raw transaction (supports concurrency)
-func (transaction *Transaction) ParseAddress() ternary.Trinary {
-	transaction.addressMutex.Lock()
-	defer transaction.addressMutex.Unlock()
-
-	return transaction.parseAddress()
-}
-
-// parses the address from the underlying raw transaction (without locking - internal usage)
-func (transaction *Transaction) parseAddress() ternary.Trinary {
-	*transaction.address = transaction.rawTransaction.Hash.ToTrinary()
-
-	return *transaction.address
-}
-
-// getter for the value (supports concurrency)
-func (transaction *Transaction) GetValue() int64 {
-	transaction.valueMutex.RLock()
-	if transaction.value == nil {
-		transaction.valueMutex.RUnlock()
-		transaction.valueMutex.Lock()
-		defer transaction.valueMutex.Unlock()
-		if transaction.value == nil {
-			return transaction.parseValue()
-		}
-	}
-
-	defer transaction.valueMutex.RUnlock()
-
-	return *transaction.value
-}
-
-// setter for the value (supports concurrency)
-func (transaction *Transaction) SetValue(value int64) {
-	transaction.valueMutex.RLock()
-	if transaction.value == nil || *transaction.value != value {
-		transaction.valueMutex.RUnlock()
-		transaction.valueMutex.Lock()
-		defer transaction.valueMutex.Unlock()
-		if transaction.value == nil || *transaction.value != value {
-			*transaction.value = value
-
-			transaction.SetModified(true)
-		}
-	} else {
-		transaction.valueMutex.RUnlock()
-	}
-}
-
-// restores the value from the underlying raw transaction (supports concurrency)
-func (transaction *Transaction) ParseValue() int64 {
-	transaction.valueMutex.Lock()
-	defer transaction.valueMutex.Unlock()
-
-	return transaction.parseValue()
-}
-
-// parses the value from the underlying raw transaction (without locking - internal usage)
-func (transaction *Transaction) parseValue() int64 {
-	*transaction.value = transaction.rawTransaction.Value.ToInt64()
-
-	return *transaction.value
-}
-
-// getter for the timestamp (supports concurrency)
-func (transaction *Transaction) GetTimestamp() uint64 {
-	transaction.timestampMutex.RLock()
-	if transaction.timestamp == nil {
-		transaction.timestampMutex.RUnlock()
-		transaction.timestampMutex.Lock()
-		defer transaction.timestampMutex.Unlock()
-		if transaction.timestamp == nil {
-			return transaction.parseTimestamp()
-		}
-	}
-
-	defer transaction.timestampMutex.RUnlock()
-
-	return *transaction.timestamp
-}
-
-// setter for the timestamp (supports concurrency)
-func (transaction *Transaction) SetTimestamp(timestamp uint64) {
-	transaction.timestampMutex.RLock()
-	if transaction.timestamp == nil || *transaction.timestamp != timestamp {
-		transaction.timestampMutex.RUnlock()
-		transaction.timestampMutex.Lock()
-		defer transaction.timestampMutex.Unlock()
-		if transaction.timestamp == nil || *transaction.timestamp != timestamp {
-			*transaction.timestamp = timestamp
-
-			transaction.SetModified(true)
-		}
-	} else {
-		transaction.timestampMutex.RUnlock()
-	}
-}
-
-// restores the timestamp from the underlying raw transaction (supports concurrency)
-func (transaction *Transaction) ParseTimestamp() uint64 {
-	transaction.timestampMutex.Lock()
-	defer transaction.timestampMutex.Unlock()
-
-	return transaction.parseTimestamp()
-}
-
-// parses the timestamp from the underlying raw transaction (without locking - internal usage)
-func (transaction *Transaction) parseTimestamp() uint64 {
-	*transaction.timestamp = transaction.rawTransaction.Timestamp.ToUint64()
-
-	return *transaction.timestamp
-}
-
-// getter for the currentIndex (supports concurrency)
-func (transaction *Transaction) GetCurrentIndex() uint64 {
-	transaction.currentIndexMutex.RLock()
-	if transaction.currentIndex == nil {
-		transaction.currentIndexMutex.RUnlock()
-		transaction.currentIndexMutex.Lock()
-		defer transaction.currentIndexMutex.Unlock()
-		if transaction.currentIndex == nil {
-			return transaction.parseCurrentIndex()
-		}
-	}
-
-	defer transaction.currentIndexMutex.RUnlock()
-
-	return *transaction.currentIndex
-}
-
-// setter for the currentIndex (supports concurrency)
-func (transaction *Transaction) SetCurrentIndex(currentIndex uint64) {
-	transaction.currentIndexMutex.RLock()
-	if transaction.currentIndex == nil || *transaction.currentIndex != currentIndex {
-		transaction.currentIndexMutex.RUnlock()
-		transaction.currentIndexMutex.Lock()
-		defer transaction.currentIndexMutex.Unlock()
-		if transaction.currentIndex == nil || *transaction.currentIndex != currentIndex {
-			*transaction.currentIndex = currentIndex
-
-			transaction.SetModified(true)
-		}
-	} else {
-		transaction.currentIndexMutex.RUnlock()
-	}
-}
-
-// restores the currentIndex from the underlying raw transaction (supports concurrency)
-func (transaction *Transaction) ParseCurrentIndex() uint64 {
-	transaction.currentIndexMutex.Lock()
-	defer transaction.currentIndexMutex.Unlock()
-
-	return transaction.parseCurrentIndex()
-}
-
-// parses the currentIndex from the underlying raw transaction (without locking - internal usage)
-func (transaction *Transaction) parseCurrentIndex() uint64 {
-	*transaction.currentIndex = transaction.rawTransaction.CurrentIndex.ToUint64()
-
-	return *transaction.currentIndex
-}
-
-// getter for the latestIndex (supports concurrency)
-func (transaction *Transaction) GetLatestIndex() uint64 {
-	transaction.latestIndexMutex.RLock()
-	if transaction.latestIndex == nil {
-		transaction.latestIndexMutex.RUnlock()
-		transaction.latestIndexMutex.Lock()
-		defer transaction.latestIndexMutex.Unlock()
-		if transaction.latestIndex == nil {
-			return transaction.parseLatestIndex()
-		}
-	}
-
-	defer transaction.latestIndexMutex.RUnlock()
-
-	return *transaction.latestIndex
-}
-
-// setter for the latestIndex (supports concurrency)
-func (transaction *Transaction) SetLatestIndex(latestIndex uint64) {
-	transaction.latestIndexMutex.RLock()
-	if transaction.latestIndex == nil || *transaction.latestIndex != latestIndex {
-		transaction.latestIndexMutex.RUnlock()
-		transaction.latestIndexMutex.Lock()
-		defer transaction.latestIndexMutex.Unlock()
-		if transaction.latestIndex == nil || *transaction.latestIndex != latestIndex {
-			*transaction.latestIndex = latestIndex
-
-			transaction.SetModified(true)
-		}
-	} else {
-		transaction.latestIndexMutex.RUnlock()
-	}
-}
-
-// restores the latestIndex from the underlying raw transaction (supports concurrency)
-func (transaction *Transaction) ParseLatestIndex() uint64 {
-	transaction.latestIndexMutex.Lock()
-	defer transaction.latestIndexMutex.Unlock()
-
-	return transaction.parseLatestIndex()
-}
-
-// parses the latestIndex from the underlying raw transaction (without locking - internal usage)
-func (transaction *Transaction) parseLatestIndex() uint64 {
-	*transaction.latestIndex = transaction.rawTransaction.LatestIndex.ToUint64()
-
-	return *transaction.latestIndex
-}
-
-// getter for the bundleHash (supports concurrency)
-func (transaction *Transaction) GetBundleHash() ternary.Trinary {
-	transaction.bundleHashMutex.RLock()
-	if transaction.bundleHash == nil {
-		transaction.bundleHashMutex.RUnlock()
-		transaction.bundleHashMutex.Lock()
-		defer transaction.bundleHashMutex.Unlock()
-		if transaction.bundleHash == nil {
-			return transaction.parseBundleHash()
-		}
-	}
-
-	defer transaction.bundleHashMutex.RUnlock()
-
-	return *transaction.bundleHash
-}
-
-// setter for the bundleHash (supports concurrency)
-func (transaction *Transaction) SetBundleHash(bundleHash ternary.Trinary) {
-	transaction.bundleHashMutex.RLock()
-	if transaction.bundleHash == nil || *transaction.bundleHash != bundleHash {
-		transaction.bundleHashMutex.RUnlock()
-		transaction.bundleHashMutex.Lock()
-		defer transaction.bundleHashMutex.Unlock()
-		if transaction.bundleHash == nil || *transaction.bundleHash != bundleHash {
-			*transaction.bundleHash = bundleHash
-
-			transaction.SetModified(true)
-		}
-	} else {
-		transaction.bundleHashMutex.RUnlock()
-	}
-}
-
-// restores the bundleHash from the underlying raw transaction (supports concurrency)
-func (transaction *Transaction) ParseBundleHash() ternary.Trinary {
-	transaction.bundleHashMutex.Lock()
-	defer transaction.bundleHashMutex.Unlock()
-
-	return transaction.parseBundleHash()
-}
-
-// parses the bundleHash from the underlying raw transaction (without locking - internal usage)
-func (transaction *Transaction) parseBundleHash() ternary.Trinary {
-	*transaction.bundleHash = transaction.rawTransaction.BundleHash.ToTrinary()
-
-	return *transaction.bundleHash
-}
-
-// getter for the trunkTransactionHash (supports concurrency)
-func (transaction *Transaction) GetTrunkTransactionHash() ternary.Trinary {
-	transaction.trunkTransactionHashMutex.RLock()
-	if transaction.trunkTransactionHash == nil {
-		transaction.trunkTransactionHashMutex.RUnlock()
-		transaction.trunkTransactionHashMutex.Lock()
-		defer transaction.trunkTransactionHashMutex.Unlock()
-		if transaction.trunkTransactionHash == nil {
-			return transaction.parseTrunkTransactionHash()
-		}
-	}
-
-	defer transaction.trunkTransactionHashMutex.RUnlock()
-
-	return *transaction.trunkTransactionHash
-}
-
-// setter for the trunkTransactionHash (supports concurrency)
-func (transaction *Transaction) SetTrunkTransactionHash(trunkTransactionHash ternary.Trinary) {
-	transaction.trunkTransactionHashMutex.RLock()
-	if transaction.trunkTransactionHash == nil || *transaction.trunkTransactionHash != trunkTransactionHash {
-		transaction.trunkTransactionHashMutex.RUnlock()
-		transaction.trunkTransactionHashMutex.Lock()
-		defer transaction.trunkTransactionHashMutex.Unlock()
-		if transaction.trunkTransactionHash == nil || *transaction.trunkTransactionHash != trunkTransactionHash {
-			*transaction.trunkTransactionHash = trunkTransactionHash
-
-			transaction.SetModified(true)
-		}
-	} else {
-		transaction.trunkTransactionHashMutex.RUnlock()
-	}
-}
-
-// restores the trunkTransactionHash from the underlying raw transaction (supports concurrency)
-func (transaction *Transaction) ParseTrunkTransactionHash() ternary.Trinary {
-	transaction.trunkTransactionHashMutex.Lock()
-	defer transaction.trunkTransactionHashMutex.Unlock()
-
-	return transaction.parseTrunkTransactionHash()
-}
-
-// parses the trunkTransactionHash from the underlying raw transaction (without locking - internal usage)
-func (transaction *Transaction) parseTrunkTransactionHash() (result ternary.Trinary) {
-	result = transaction.rawTransaction.TrunkTransactionHash.ToTrinary()
-
-	transaction.trunkTransactionHash = &result
-
-	return
-}
-
-// getter for the branchTransactionHash (supports concurrency)
-func (transaction *Transaction) GetBranchTransactionHash() ternary.Trinary {
-	transaction.branchTransactionHashMutex.RLock()
-	if transaction.branchTransactionHash == nil {
-		transaction.branchTransactionHashMutex.RUnlock()
-		transaction.branchTransactionHashMutex.Lock()
-		defer transaction.branchTransactionHashMutex.Unlock()
-		if transaction.branchTransactionHash == nil {
-			return transaction.parseBranchTransactionHash()
-		}
-	}
-
-	defer transaction.branchTransactionHashMutex.RUnlock()
-
-	return *transaction.branchTransactionHash
-}
-
-// setter for the branchTransactionHash (supports concurrency)
-func (transaction *Transaction) SetBranchTransactionHash(branchTransactionHash ternary.Trinary) {
-	transaction.branchTransactionHashMutex.RLock()
-	if transaction.branchTransactionHash == nil || *transaction.branchTransactionHash != branchTransactionHash {
-		transaction.branchTransactionHashMutex.RUnlock()
-		transaction.branchTransactionHashMutex.Lock()
-		defer transaction.branchTransactionHashMutex.Unlock()
-		if transaction.branchTransactionHash == nil || *transaction.branchTransactionHash != branchTransactionHash {
-			transaction.branchTransactionHash = &branchTransactionHash
-
-			transaction.SetModified(true)
-		}
-	} else {
-		transaction.branchTransactionHashMutex.RUnlock()
-	}
-}
-
-// restores the branchTransactionHash from the underlying raw transaction (supports concurrency)
-func (transaction *Transaction) ParseBranchTransactionHash() ternary.Trinary {
-	transaction.branchTransactionHashMutex.Lock()
-	defer transaction.branchTransactionHashMutex.Unlock()
-
-	return transaction.parseBranchTransactionHash()
-}
-
-// parses the branchTransactionHash from the underlying raw transaction (without locking - internal usage)
-func (transaction *Transaction) parseBranchTransactionHash() (result ternary.Trinary) {
-	result = transaction.rawTransaction.BranchTransactionHash.ToTrinary()
-
-	transaction.branchTransactionHash = &result
-
-	return
-}
-
-// getter for the tag (supports concurrency)
-func (transaction *Transaction) GetTag() ternary.Trinary {
-	transaction.tagMutex.RLock()
-	if transaction.tag == nil {
-		transaction.tagMutex.RUnlock()
-		transaction.tagMutex.Lock()
-		defer transaction.tagMutex.Unlock()
-		if transaction.tag == nil {
-			return transaction.parseTag()
-		}
-	}
-
-	defer transaction.tagMutex.RUnlock()
-
-	return *transaction.tag
-}
-
-// setter for the tag (supports concurrency)
-func (transaction *Transaction) SetTag(tag ternary.Trinary) {
-	transaction.tagMutex.RLock()
-	if transaction.tag == nil || *transaction.tag != tag {
-		transaction.tagMutex.RUnlock()
-		transaction.tagMutex.Lock()
-		defer transaction.tagMutex.Unlock()
-		if transaction.tag == nil || *transaction.tag != tag {
-			*transaction.tag = tag
-
-			transaction.SetModified(true)
-		}
-	} else {
-		transaction.tagMutex.RUnlock()
-	}
-}
-
-// restores the tag from the underlying raw transaction (supports concurrency)
-func (transaction *Transaction) ParseTag() ternary.Trinary {
-	transaction.tagMutex.Lock()
-	defer transaction.tagMutex.Unlock()
-
-	return transaction.parseTag()
-}
-
-// parses the tag from the underlying raw transaction (without locking - internal usage)
-func (transaction *Transaction) parseTag() ternary.Trinary {
-	*transaction.tag = transaction.rawTransaction.Tag.ToTrinary()
-
-	return *transaction.tag
-}
-
-// getter for the nonce (supports concurrency)
-func (transaction *Transaction) GetNonce() ternary.Trinary {
-	transaction.nonceMutex.RLock()
-	if transaction.nonce == nil {
-		transaction.nonceMutex.RUnlock()
-		transaction.nonceMutex.Lock()
-		defer transaction.nonceMutex.Unlock()
-		if transaction.nonce == nil {
-			return transaction.parseNonce()
-		}
-	}
-
-	defer transaction.nonceMutex.RUnlock()
-
-	return *transaction.nonce
-}
-
-// setter for the nonce (supports concurrency)
-func (transaction *Transaction) SetNonce(nonce ternary.Trinary) {
-	transaction.nonceMutex.RLock()
-	if transaction.nonce == nil || *transaction.nonce != nonce {
-		transaction.nonceMutex.RUnlock()
-		transaction.nonceMutex.Lock()
-		defer transaction.nonceMutex.Unlock()
-		if transaction.nonce == nil || *transaction.nonce != nonce {
-			transaction.nonce = &nonce
-
-			transaction.SetModified(true)
-		}
-	} else {
-		transaction.nonceMutex.RUnlock()
-	}
-}
-
-// restores the nonce from the underlying raw transaction (supports concurrency)
-func (transaction *Transaction) ParseNonce() ternary.Trinary {
-	transaction.nonceMutex.Lock()
-	defer transaction.nonceMutex.Unlock()
-
-	return transaction.parseNonce()
-}
-
-// parses the nonce from the underlying raw transaction (without locking - internal usage)
-func (transaction *Transaction) parseNonce() (result ternary.Trinary) {
-	result = transaction.rawTransaction.Nonce.ToTrinary()
-
-	transaction.nonce = &result
-
-	return *transaction.nonce
-}
-
-// returns true if the transaction contains unsaved changes (supports concurrency)
-func (transaction *Transaction) GetModified() bool {
-	transaction.modifiedMutex.RLock()
-	defer transaction.modifiedMutex.RUnlock()
-
-	return transaction.modified
-}
-
-// sets the modified flag which controls if a transaction is going to be saved (supports concurrency)
-func (transaction *Transaction) SetModified(modified bool) {
-	transaction.modifiedMutex.Lock()
-	defer transaction.modifiedMutex.Unlock()
-
-	transaction.modified = modified
-}
-
-// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-// region database functions ///////////////////////////////////////////////////////////////////////////////////////////
-
-// Applies the current values to the
-func (this *Transaction) Flush() *transaction.Transaction {
-	if this.branchTransactionHash != nil {
-		copy(this.rawTransaction.Trits[transaction.BRANCH_TRANSACTION_HASH_OFFSET:transaction.BRANCH_TRANSACTION_HASH_END], this.branchTransactionHash.ToTrits()[:transaction.BRANCH_TRANSACTION_HASH_SIZE])
-	}
-	if this.nonce != nil {
-		copy(this.rawTransaction.Trits[transaction.NONCE_OFFSET:transaction.NONCE_END], this.nonce.ToTrits()[:transaction.NONCE_SIZE])
-	}
-
-	this.rawTransaction.Hash = <-curl.CURLP81.Hash(this.rawTransaction.Trits)
-
-	return this.rawTransaction
-}
-
-func (transaction *Transaction) Store() errors.IdentifiableError {
-	if err := transactionDatabase.Set(transaction.rawTransaction.Hash.ToBytes(), transaction.rawTransaction.Bytes); err != nil {
-		return ErrDatabaseError.Derive(err, "failed to store the transaction")
-	}
-
-	return nil
-}
-
-// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-const (
-	TRANSACTION_NULL_HASH = ternary.Trinary("999999999999999999999999999999999999999999999999999999999999999999999999999999999")
-)
diff --git a/plugins/tangle/transaction_metadata.go b/plugins/tangle/transaction_metadata.go
index d21b5ef8516adec1bb9d307dab29ac4a74e32663..7798e0396857691537b9423f7fa2faad25053cad 100644
--- a/plugins/tangle/transaction_metadata.go
+++ b/plugins/tangle/transaction_metadata.go
@@ -7,7 +7,7 @@ import (
 	"github.com/iotaledger/goshimmer/packages/bitutils"
 	"github.com/iotaledger/goshimmer/packages/errors"
 	"github.com/iotaledger/goshimmer/packages/ternary"
-	"github.com/iotaledger/goshimmer/packages/typeconversion"
+	"github.com/iotaledger/goshimmer/packages/typeutils"
 )
 
 // region type definition and constructor //////////////////////////////////////////////////////////////////////////////
@@ -228,7 +228,7 @@ func (metadata *TransactionMetadata) Unmarshal(data []byte) errors.IdentifiableE
 	metadata.finalizedMutex.Lock()
 	defer metadata.finalizedMutex.Unlock()
 
-	metadata.hash = ternary.Trinary(typeconversion.BytesToString(data[MARSHALED_HASH_START:MARSHALED_HASH_END]))
+	metadata.hash = ternary.Trinary(typeutils.BytesToString(data[MARSHALED_HASH_START:MARSHALED_HASH_END]))
 
 	if err := metadata.receivedTime.UnmarshalBinary(data[MARSHALED_RECEIVED_TIME_START:MARSHALED_RECEIVED_TIME_END]); err != nil {
 		return ErrUnmarshalFailed.Derive(err, "could not unmarshal the received time")
@@ -252,23 +252,6 @@ func (metadata *TransactionMetadata) Unmarshal(data []byte) errors.IdentifiableE
 
 // region database functions ///////////////////////////////////////////////////////////////////////////////////////////
 
-func (metadata *TransactionMetadata) Store() errors.IdentifiableError {
-	if metadata.GetModified() {
-		marshaledMetadata, err := metadata.Marshal()
-		if err != nil {
-			return err
-		}
-
-		if err := transactionMetadataDatabase.Set(metadata.GetHash().CastToBytes(), marshaledMetadata); err != nil {
-			return ErrDatabaseError.Derive(err, "failed to store the transaction")
-		}
-
-		metadata.SetModified(false)
-	}
-
-	return nil
-}
-
 // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 // region constants and variables //////////////////////////////////////////////////////////////////////////////////////
diff --git a/plugins/tipselection/plugin.go b/plugins/tipselection/plugin.go
new file mode 100644
index 0000000000000000000000000000000000000000..7980a59557a1db7c66006c1ebd8a1e582a6d9016
--- /dev/null
+++ b/plugins/tipselection/plugin.go
@@ -0,0 +1,23 @@
+package tipselection
+
+import (
+	"github.com/iotaledger/goshimmer/packages/events"
+	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
+	"github.com/iotaledger/goshimmer/packages/node"
+	"github.com/iotaledger/goshimmer/plugins/tangle"
+)
+
+var PLUGIN = node.NewPlugin("Tipselection", configure, run)
+
+func configure(node *node.Plugin) {
+	tangle.Events.TransactionSolid.Attach(events.NewClosure(func(transaction *value_transaction.ValueTransaction) {
+		go func() {
+			tips.Delete(transaction.GetBranchTransactionHash())
+			tips.Delete(transaction.GetTrunkTransactionHash())
+			tips.Set(transaction.GetHash(), transaction.GetHash())
+		}()
+	}))
+}
+
+func run(run *node.Plugin) {
+}
diff --git a/plugins/tipselection/tipselection.go b/plugins/tipselection/tipselection.go
new file mode 100644
index 0000000000000000000000000000000000000000..4457ddc026b922a3802e844d6b416677ef2af345
--- /dev/null
+++ b/plugins/tipselection/tipselection.go
@@ -0,0 +1,23 @@
+package tipselection
+
+import (
+	"github.com/iotaledger/goshimmer/packages/datastructure"
+	"github.com/iotaledger/goshimmer/packages/model/meta_transaction"
+	"github.com/iotaledger/goshimmer/packages/ternary"
+)
+
+var tips = datastructure.NewRandomMap()
+
+func GetRandomTip() (result ternary.Trinary) {
+	if randomTipHash := tips.RandomEntry(); randomTipHash != nil {
+		result = randomTipHash.(ternary.Trinary)
+	} else {
+		result = meta_transaction.BRANCH_NULL_HASH
+	}
+
+	return
+}
+
+func GetTipsCount() int {
+	return tips.Size()
+}
diff --git a/plugins/tipselection/tipselection_test.go b/plugins/tipselection/tipselection_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..cb8274bfed54cab78ce985ab7ecd001795b52f2e
--- /dev/null
+++ b/plugins/tipselection/tipselection_test.go
@@ -0,0 +1,24 @@
+package tipselection
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
+	"github.com/iotaledger/goshimmer/plugins/tangle"
+)
+
+func Test(t *testing.T) {
+	configure(nil)
+
+	for i := 0; i < 1000; i++ {
+		tx := value_transaction.New()
+		tx.SetValue(int64(i + 1))
+		tx.SetBranchTransactionHash(GetRandomTip())
+		tx.SetTrunkTransactionHash(GetRandomTip())
+
+		tangle.Events.TransactionSolid.Trigger(tx)
+
+		fmt.Println(GetTipsCount())
+	}
+}
diff --git a/plugins/webapi-gtta/plugin.go b/plugins/webapi-gtta/plugin.go
new file mode 100644
index 0000000000000000000000000000000000000000..3a97085736a984f78ea8df9528ba8d53b68d9721
--- /dev/null
+++ b/plugins/webapi-gtta/plugin.go
@@ -0,0 +1,35 @@
+package webapi_gtta
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/iotaledger/goshimmer/packages/node"
+	"github.com/iotaledger/goshimmer/packages/ternary"
+	"github.com/iotaledger/goshimmer/plugins/tipselection"
+	"github.com/iotaledger/goshimmer/plugins/webapi"
+	"github.com/labstack/echo"
+)
+
+var PLUGIN = node.NewPlugin("WebAPI GTTA Endpoint", func(plugin *node.Plugin) {
+	webapi.AddEndpoint("getTransactionsToApprove", Handler)
+})
+
+func Handler(c echo.Context) error {
+	start := time.Now()
+
+	branchTransactionHash := tipselection.GetRandomTip()
+	trunkTransactionHash := tipselection.GetRandomTip()
+
+	return c.JSON(http.StatusOK, webResponse{
+		Duration:          time.Since(start).Nanoseconds() / 1e6,
+		BranchTransaction: branchTransactionHash,
+		TrunkTransaction:  trunkTransactionHash,
+	})
+}
+
+type webResponse struct {
+	Duration          int64           `json:"duration"`
+	BranchTransaction ternary.Trinary `json:"branchTransaction"`
+	TrunkTransaction  ternary.Trinary `json:"trunkTransaction"`
+}
diff --git a/plugins/webapi-spammer/plugin.go b/plugins/webapi-spammer/plugin.go
new file mode 100644
index 0000000000000000000000000000000000000000..b216aca5e0f9d3e905eb30b898b6066f4dd42c72
--- /dev/null
+++ b/plugins/webapi-spammer/plugin.go
@@ -0,0 +1,73 @@
+package webapi_spammer
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/iotaledger/goshimmer/packages/node"
+	"github.com/iotaledger/goshimmer/packages/transactionspammer"
+	"github.com/iotaledger/goshimmer/plugins/webapi"
+	"github.com/labstack/echo"
+)
+
+var PLUGIN = node.NewPlugin("Spammer", configure)
+
+func configure(plugin *node.Plugin) {
+	webapi.AddEndpoint("spammer", WebApiHandler)
+}
+
+func WebApiHandler(c echo.Context) error {
+	c.Set("requestStartTime", time.Now())
+
+	var request webRequest
+	if err := c.Bind(&request); err != nil {
+		return requestFailed(c, err.Error())
+	}
+
+	switch request.Cmd {
+	case "start":
+		if request.Tps == 0 {
+			request.Tps = 1000
+		}
+
+		transactionspammer.Stop()
+		transactionspammer.Start(request.Tps)
+
+		return requestSuccessful(c, "started spamming transactions")
+
+	case "stop":
+		transactionspammer.Stop()
+
+		return requestSuccessful(c, "stopped spamming transactions")
+
+	default:
+		return requestFailed(c, "invalid cmd in request")
+	}
+}
+
+func requestSuccessful(c echo.Context, message string) error {
+	return c.JSON(http.StatusOK, webResponse{
+		Duration: time.Since(c.Get("requestStartTime").(time.Time)).Nanoseconds() / 1e6,
+		Status:   "success",
+		Message:  message,
+	})
+}
+
+func requestFailed(c echo.Context, message string) error {
+	return c.JSON(http.StatusOK, webResponse{
+		Duration: time.Since(c.Get("requestStartTime").(time.Time)).Nanoseconds() / 1e6,
+		Status:   "failed",
+		Message:  message,
+	})
+}
+
+type webResponse struct {
+	Duration int64  `json:"duration"`
+	Status   string `json:"status"`
+	Message  string `json:"message"`
+}
+
+type webRequest struct {
+	Cmd string `json:"cmd"`
+	Tps int64  `json:"tps"`
+}
diff --git a/plugins/webapi/api.go b/plugins/webapi/api.go
new file mode 100644
index 0000000000000000000000000000000000000000..5c50d71bc463fc56775777fe675a8f8ce1283fab
--- /dev/null
+++ b/plugins/webapi/api.go
@@ -0,0 +1,9 @@
+package webapi
+
+import (
+	"github.com/labstack/echo"
+)
+
+func AddEndpoint(url string, handler func(c echo.Context) error) {
+	Server.GET(url, handler)
+}
diff --git a/plugins/webapi/endpoints.go b/plugins/webapi/endpoints.go
new file mode 100644
index 0000000000000000000000000000000000000000..c01bd84cca2f270568f5762d65fdf1d94d540d37
--- /dev/null
+++ b/plugins/webapi/endpoints.go
@@ -0,0 +1,11 @@
+package webapi
+
+import (
+	"net/http"
+
+	"github.com/labstack/echo"
+)
+
+func IndexRequest(c echo.Context) error {
+	return c.String(http.StatusOK, "INDEX")
+}
diff --git a/plugins/webapi/plugin.go b/plugins/webapi/plugin.go
new file mode 100644
index 0000000000000000000000000000000000000000..ee2010c4de024d622b2da51705db47604c581e4c
--- /dev/null
+++ b/plugins/webapi/plugin.go
@@ -0,0 +1,43 @@
+package webapi
+
+import (
+	"context"
+	"time"
+
+	"github.com/iotaledger/goshimmer/packages/daemon"
+	"github.com/iotaledger/goshimmer/packages/events"
+	"github.com/iotaledger/goshimmer/packages/node"
+	"github.com/labstack/echo"
+)
+
+var PLUGIN = node.NewPlugin("WebAPI", configure, run)
+
+var Server = echo.New()
+
+func configure(plugin *node.Plugin) {
+	Server.HideBanner = true
+	Server.GET("/", IndexRequest)
+
+	daemon.Events.Shutdown.Attach(events.NewClosure(func() {
+		plugin.LogInfo("Stopping Web Server ...")
+
+		ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
+		defer cancel()
+
+		if err := Server.Shutdown(ctx); err != nil {
+			plugin.LogFailure(err.Error())
+		}
+	}))
+}
+
+func run(plugin *node.Plugin) {
+	plugin.LogInfo("Starting Web Server ...")
+
+	daemon.BackgroundWorker(func() {
+		plugin.LogSuccess("Starting Web Server ... done")
+
+		if err := Server.Start(":8080"); err != nil {
+			plugin.LogSuccess("Stopping Web Server ... done")
+		}
+	})
+}
diff --git a/plugins/webapi/routes.go b/plugins/webapi/routes.go
new file mode 100644
index 0000000000000000000000000000000000000000..2f5e375418c36e6690474c5d1490b63db0d6f465
--- /dev/null
+++ b/plugins/webapi/routes.go
@@ -0,0 +1,9 @@
+package webapi
+
+import (
+	"github.com/labstack/echo"
+)
+
+func setupRoutes(e *echo.Echo) {
+
+}