diff --git a/main.go b/main.go
index 514f031a620ef1fd5af3b65c3178aa0f4c8a0300..7e8099a447f7a779398c03b0049175744d8920b0 100644
--- a/main.go
+++ b/main.go
@@ -7,8 +7,12 @@ import (
 	"github.com/iotaledger/goshimmer/plugins/cli"
 	"github.com/iotaledger/goshimmer/plugins/gossip"
 	"github.com/iotaledger/goshimmer/plugins/gracefulshutdown"
+	"github.com/iotaledger/goshimmer/plugins/spammer"
 	"github.com/iotaledger/goshimmer/plugins/statusscreen"
 	"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"
 )
 
 func main() {
@@ -20,5 +24,10 @@ func main() {
 		analysis.PLUGIN,
 		statusscreen.PLUGIN,
 		gracefulshutdown.PLUGIN,
+		tipselection.PLUGIN,
+		spammer.PLUGIN,
+
+		webapi.PLUGIN,
+		webapi_gtta.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 9ac44a31685a017dd62785b16996f089540b15c8..d1fe569f7ed5a6012b9a396cd3ac8c76fdb069a7 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..c07da3ba485bce91765004d20091a7247546d7f7 100644
--- a/packages/datastructure/lru_cache.go
+++ b/packages/datastructure/lru_cache.go
@@ -14,14 +14,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 +58,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 +101,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); result != nil {
+			result = callbackResult
+
+			cache.set(key, callbackResult)
 		} else {
 			if err := cache.doublyLinkedList.removeEntry(entry); err != nil {
 				panic(err)
@@ -94,6 +112,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 +188,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/model/meta_transaction/constants.go b/packages/model/meta_transaction/constants.go
index 3db3cb053683b7958a0d491fb92b8cd3990416db..498b5798160d59feb6b1bc0690404078675428ba 100644
--- a/packages/model/meta_transaction/constants.go
+++ b/packages/model/meta_transaction/constants.go
@@ -1,5 +1,9 @@
 package meta_transaction
 
+import (
+	"github.com/iotaledger/goshimmer/packages/ternary"
+)
+
 const (
 	SHARD_MARKER_OFFSET            = 0
 	TRUNK_TRANSACTION_HASH_OFFSET  = SHARD_MARKER_END
@@ -9,13 +13,13 @@ const (
 	TRANSACTION_TYPE_OFFSET        = TAIL_END
 	DATA_OFFSET                    = TRANSACTION_TYPE_END
 
-	SHARD_MARKER_SIZE            = 12
+	SHARD_MARKER_SIZE            = 11
 	TRUNK_TRANSACTION_HASH_SIZE  = 243
 	BRANCH_TRANSACTION_HASH_SIZE = 243
 	HEAD_SIZE                    = 1
 	TAIL_SIZE                    = 1
-	TRANSACTION_TYPE_SIZE        = 22
-	DATA_SIZE                    = 5000
+	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
@@ -26,4 +30,6 @@ const (
 	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
index ea8e83b8abca89924fb9bd09b8f96e76a1e33ef9..456e7e36f57dd58278ba81f8354671caacd9a69e 100644
--- a/packages/model/meta_transaction/meta_transaction.go
+++ b/packages/model/meta_transaction/meta_transaction.go
@@ -53,11 +53,11 @@ func FromBytes(bytes []byte) (result *MetaTransaction) {
 	return
 }
 
-func (this *MetaTransaction) LockHasher() {
+func (this *MetaTransaction) BlockHasher() {
 	this.hasherMutex.RLock()
 }
 
-func (this *MetaTransaction) UnlockHasher() {
+func (this *MetaTransaction) UnblockHasher() {
 	this.hasherMutex.RUnlock()
 }
 
@@ -120,8 +120,6 @@ func (this *MetaTransaction) parseHashRelatedDetails() {
 
 	this.hash = &hashTrinary
 	this.weightMagnitude = hashTrits.TrailingZeroes()
-
-	return
 }
 
 // getter for the shard marker (supports concurrency)
@@ -454,7 +452,7 @@ func (this *MetaTransaction) GetBytes() (result []byte) {
 		this.bytes = this.trits.ToBytes()
 		this.hasherMutex.Unlock()
 	} else {
-		this.hasherMutex.RUnlock()
+		this.bytesMutex.RUnlock()
 	}
 
 	result = make([]byte, len(this.bytes))
diff --git a/packages/model/meta_transaction/meta_transaction_test.go b/packages/model/meta_transaction/meta_transaction_test.go
index dd54c2b2245cf96c0bf88bc17da799fb1c9c1def..1c73e4b4b03d97a61fe717fdd01c6ab01d9e66ba 100644
--- a/packages/model/meta_transaction/meta_transaction_test.go
+++ b/packages/model/meta_transaction/meta_transaction_test.go
@@ -41,9 +41,9 @@ func BenchmarkMetaTransaction_GetHash(b *testing.B) {
 	var waitGroup sync.WaitGroup
 
 	for i := 0; i < b.N; i++ {
-		go func() {
-			waitGroup.Add(1)
+		waitGroup.Add(1)
 
+		go func() {
 			New().GetHash()
 
 			waitGroup.Done()
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
index 337f003c2c1f5ad525d794305c12dbe10abae1a9..fe1246798e9413e578490599fad8fb2eed13bd0d 100644
--- a/packages/model/value_transaction/value_transaction.go
+++ b/packages/model/value_transaction/value_transaction.go
@@ -1,6 +1,8 @@
 package value_transaction
 
 import (
+	"sync"
+
 	"github.com/iotaledger/goshimmer/packages/model/meta_transaction"
 	"github.com/iotaledger/goshimmer/packages/ternary"
 )
@@ -8,7 +10,18 @@ import (
 type ValueTransaction struct {
 	*meta_transaction.MetaTransaction
 
-	data ternary.Trits
+	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) {
@@ -16,7 +29,256 @@ func New() (result *ValueTransaction) {
 		MetaTransaction: meta_transaction.New(),
 	}
 
-	result.data = result.MetaTransaction.GetData()
+	result.trits = result.MetaTransaction.GetData()
+
+	return
+}
+
+func FromMetaTransaction(metaTransaction *meta_transaction.MetaTransaction) *ValueTransaction {
+	return &ValueTransaction{
+		MetaTransaction: metaTransaction,
+	}
+}
+
+func FromBytes(bytes []byte) (result *ValueTransaction) {
+	result = &ValueTransaction{
+		MetaTransaction: meta_transaction.FromTrits(ternary.BytesToTrits(bytes)[:meta_transaction.MARSHALLED_TOTAL_SIZE]),
+	}
 
 	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
index f81aa1ab02c1e79d988577c480c5d077f38bd1b3..eb8310bedc1bbf71b0ae3ade869a1f83cbd9b606 100644
--- a/packages/model/value_transaction/value_transaction_test.go
+++ b/packages/model/value_transaction/value_transaction_test.go
@@ -8,27 +8,15 @@ import (
 	"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
+func TestValueTransaction_SettersGetters(t *testing.T) {
+	address := ternary.Trinary("A9999999999999999999999999999999999999999999999999999999999999999999999999999999F")
 
 	transaction := New()
-	transaction.SetShardMarker(shardMarker)
-	transaction.SetTrunkTransactionHash(trunkTransactionHash)
-	transaction.SetBranchTransactionHash(branchTransactionHash)
-	transaction.SetHead(head)
-	transaction.SetTail(tail)
+	transaction.SetAddress(address)
 
-	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.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 dd329015491c5beafd5d43b57b88760fca05dca1..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
-	MARSHALLED_TOTAL_SIZE = NONCE_END
-)
diff --git a/packages/transaction/transaction.go b/packages/transaction/transaction.go
deleted file mode 100644
index 9d7033099776a812cb7aded48dc3345fc9c9f841..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)[:MARSHALLED_TOTAL_SIZE])
-	transaction.Bytes = bytes
-
-	return transaction
-}
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 47aacbbdb1d2451fabc810330ab5bd3c0f44eeb2..f268cf4c6cae22cbd0dde4b61ddc4f4013758533 100644
--- a/plugins/gossip/neighbors.go
+++ b/plugins/gossip/neighbors.go
@@ -181,7 +181,7 @@ func (neighbor *Neighbor) Marshal() []byte {
 }
 
 func (neighbor *Neighbor) Equals(other *Neighbor) bool {
-	return neighbor.Identity.StringIdentifier == neighbor.Identity.StringIdentifier &&
+	return neighbor.Identity.StringIdentifier == other.Identity.StringIdentifier &&
 		neighbor.Port == other.Port && neighbor.Address.String() == other.Address.String()
 }
 
@@ -195,11 +195,11 @@ func AddNeighbor(newNeighbor *Neighbor) {
 		Events.AddNeighbor.Trigger(newNeighbor)
 	} else {
 		if !newNeighbor.Equals(neighbor) {
-			neighbor.Identity = neighbor.Identity
-			neighbor.Port = neighbor.Port
-			neighbor.Address = neighbor.Address
+			neighbor.Identity = newNeighbor.Identity
+			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 9b7677b3b8df0e73286ffcc1ad8fafa4edf6a0b7..628492973a1c35c4914f1e470468f8cd1d062c5b 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.MARSHALLED_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.MARSHALLED_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.MARSHALLED_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 7686214081166a086ce050385460c22a399af20a..c07602df5f71f7b93168bdd8f01271a994a50697 100644
--- a/plugins/gossip/transaction_processor_test.go
+++ b/plugins/gossip/transaction_processor_test.go
@@ -4,12 +4,12 @@ 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) {
-	byteArray := setupTransaction(transaction.MARSHALLED_TOTAL_SIZE / ternary.NUMBER_OF_TRITS_IN_A_BYTE)
+	byteArray := setupTransaction(meta_transaction.MARSHALLED_TOTAL_SIZE / ternary.NUMBER_OF_TRITS_IN_A_BYTE)
 
 	b.ResetTimer()
 
@@ -19,7 +19,7 @@ func BenchmarkProcessSimilarTransactionsFiltered(b *testing.B) {
 }
 
 func BenchmarkProcessSimilarTransactionsUnfiltered(b *testing.B) {
-	byteArray := setupTransaction(transaction.MARSHALLED_TOTAL_SIZE / ternary.NUMBER_OF_TRITS_IN_A_BYTE)
+	byteArray := setupTransaction(meta_transaction.MARSHALLED_TOTAL_SIZE / ternary.NUMBER_OF_TRITS_IN_A_BYTE)
 
 	b.ResetTimer()
 
@@ -29,7 +29,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/spammer/spammer.go b/plugins/spammer/spammer.go
new file mode 100644
index 0000000000000000000000000000000000000000..44985dea31b0032028a941c71b4d621ad8db4b51
--- /dev/null
+++ b/plugins/spammer/spammer.go
@@ -0,0 +1,86 @@
+package spammer
+
+import (
+	"fmt"
+	"runtime"
+	"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/tangle"
+	"github.com/iotaledger/goshimmer/plugins/tipselection"
+)
+
+var PLUGIN = node.NewPlugin("Spammer", configure, run)
+
+func bToMb(b uint64) uint64 {
+	return b / 1024 / 1024
+}
+
+func configure(plugin *node.Plugin) {
+	tpsCounter := 0
+	solidCounter := 0
+	var receivedCounter uint64
+
+	gossip.Events.ReceiveTransaction.Attach(events.NewClosure(func(transaction *meta_transaction.MetaTransaction) {
+		atomic.AddUint64(&receivedCounter, 1)
+	}))
+
+	go func() {
+		for {
+			select {
+			case <-daemon.ShutdownSignal:
+				return
+
+			case <-time.After(1 * time.Second):
+				fmt.Println("RECEIVED", receivedCounter, " / TPS "+strconv.Itoa(tpsCounter)+" / SOLID "+strconv.Itoa(solidCounter), " / TIPS ", tipselection.GetTipsCount())
+				fmt.Println(runtime.NumGoroutine())
+
+				var m runtime.MemStats
+				runtime.ReadMemStats(&m)
+				// For info on each, see: https://golang.org/pkg/runtime/#MemStats
+				fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc))
+				fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc))
+				fmt.Printf("\tSys = %v MiB", bToMb(m.Sys))
+				fmt.Printf("\tNumGC = %v\n", m.NumGC)
+
+				tpsCounter = 0
+			}
+		}
+	}()
+
+	tangle.Events.TransactionSolid.Attach(events.NewClosure(func(transaction *value_transaction.ValueTransaction) {
+		solidCounter++
+		tpsCounter++
+	}))
+}
+
+func run(plugin *node.Plugin) {
+	daemon.BackgroundWorker(func() {
+		for {
+			transactionCount := 100000
+
+			for i := 0; i < transactionCount; i++ {
+				select {
+				case <-daemon.ShutdownSignal:
+					return
+				default:
+					tx := value_transaction.New()
+					tx.SetValue(int64(i + 1))
+					tx.SetBranchTransactionHash(tipselection.GetRandomTip())
+					tx.SetTrunkTransactionHash(tipselection.GetRandomTip())
+
+					gossip.Events.ReceiveTransaction.Trigger(tx.MetaTransaction)
+				}
+			}
+
+			//time.Sleep(5 * time.Second)
+		}
+	})
+}
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 b7480dce8e03bb1a1a776d5fecf5a518187f0019..cdf3c7b4af96827c351f0f209b403d7cc0a9fdca 100644
--- a/plugins/tangle/approvers.go
+++ b/plugins/tangle/approvers.go
@@ -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 == 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)
 	}
@@ -103,7 +103,7 @@ func (approvers *Approvers) Marshal() (result []byte) {
 	copy(result[MARSHALLED_APPROVERS_HASH_START:MARSHALLED_APPROVERS_HASH_END], approvers.hash.CastToBytes())
 
 	i := 0
-	for hash, _ := range approvers.hashes {
+	for hash := range approvers.hashes {
 		var HASH_START = MARSHALLED_APPROVERS_HASHES_START + i*(MARSHALLED_APPROVERS_HASH_SIZE)
 		var HASH_END = HASH_START * MARSHALLED_APPROVERS_HASH_SIZE
 
@@ -181,7 +181,7 @@ func (approvers *Approvers) getHashes() (result []ternary.Trinary) {
 	result = make([]ternary.Trinary, len(approvers.hashes))
 
 	counter := 0
-	for hash, _ := range approvers.hashes {
+	for hash := range approvers.hashes {
 		result[counter] = hash
 
 		counter++
@@ -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 8f7033cb04123b5a3ff8bdd7f5b67640c3544f3d..c5b0d38d90e949415adba6cfc095fbe7e572a978 100644
--- a/plugins/tangle/solidifier.go
+++ b/plugins/tangle/solidifier.go
@@ -3,27 +3,65 @@ 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()
-	if err != nil {
+	txMetadata, metaDataErr := GetTransactionMetadata(transaction.GetHash(), NewTransactionMetadata)
+	if metaDataErr != nil {
 		err = metaDataErr
 
 		return
@@ -34,15 +72,15 @@ 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); err != nil {
+		if branchTransaction, branchErr := GetTransaction(branchTransactionHash); branchErr != nil {
 			err = branchErr
 
 			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 6ee98b52d8a3597f9e25e34b990f13eeeac32ffd..0000000000000000000000000000000000000000
--- a/plugins/tangle/transaction.go
+++ /dev/null
@@ -1,685 +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
-	signatureMessageFragment      *ternary.Trinary
-	signatureMessageFragmentMutex sync.RWMutex
-	address                       *ternary.Trinary
-	addressMutex                  sync.RWMutex
-	value                         *int64
-	valueMutex                    sync.RWMutex
-	timestamp                     *uint64
-	timestampMutex                sync.RWMutex
-	currentIndex                  *uint64
-	currentIndexMutex             sync.RWMutex
-	latestIndex                   *uint64
-	latestIndexMutex              sync.RWMutex
-	bundleHash                    *ternary.Trinary
-	bundleHashMutex               sync.RWMutex
-	trunkTransactionHash          *ternary.Trinary
-	trunkTransactionHashMutex     sync.RWMutex
-	branchTransactionHash         *ternary.Trinary
-	branchTransactionHashMutex    sync.RWMutex
-	tag                           *ternary.Trinary
-	tagMutex                      sync.RWMutex
-	nonce                         *ternary.Trinary
-	nonceMutex                    sync.RWMutex
-
-	// additional runtime specific metadata
-	modified      bool
-	modifiedMutex sync.RWMutex
-}
-
-func NewTransaction(rawTransaction *transaction.Transaction) *Transaction {
-	if rawTransaction == nil {
-		rawTransaction = transaction.FromBytes(make([]byte, int(math.Ceil(float64(transaction.MARSHALLED_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 97869f8802d82c637aad45d8ba678179ed60551c..c617f0c97a02a2f4e64864e62e3fe113a7ac9b56 100644
--- a/plugins/tangle/transaction_metadata.go
+++ b/plugins/tangle/transaction_metadata.go
@@ -252,23 +252,6 @@ func (metadata *TransactionMetadata) Unmarshal(data []byte) errors.IdentifiableE
 
 // region database functions ///////////////////////////////////////////////////////////////////////////////////////////
 
-func (metadata *TransactionMetadata) Store() errors.IdentifiableError {
-	if metadata.GetModified() {
-		marshalledMetadata, err := metadata.Marshal()
-		if err != nil {
-			return err
-		}
-
-		if err := transactionMetadataDatabase.Set(metadata.GetHash().CastToBytes(), marshalledMetadata); err != nil {
-			return ErrDatabaseError.Derive(err, "failed to store the transaction")
-		}
-
-		metadata.SetModified(false)
-	}
-
-	return nil
-}
-
 // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 // region constants and variables //////////////////////////////////////////////////////////////////////////////////////
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..b174e7ec57650af8a2d4b89cc3da7cd164c7c6fa
--- /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, response{
+		Duration:          time.Since(start).Nanoseconds() / 1e6,
+		BranchTransaction: branchTransactionHash,
+		TrunkTransaction:  trunkTransactionHash,
+	})
+}
+
+type response struct {
+	Duration          int64           `json:"duration"`
+	BranchTransaction ternary.Trinary `json:"branchTransaction"`
+	TrunkTransaction  ternary.Trinary `json:"trunkTransaction"`
+}
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) {
+
+}