From 1134f3fd403b7ef7fe6229f0fa07670cb039be22 Mon Sep 17 00:00:00 2001
From: Luca Moser <moser.luca@gmail.com>
Date: Mon, 24 Feb 2020 15:27:41 +0100
Subject: [PATCH] Adds changes for v0.1.2 (#266)

* New binary tangle using atomic transactions (#239)

* Feat: started porting the new binary stuff

* Refactor: removed unnecessary folder

* Refactor: cleaned up go.mod files

* Fix: removed objectsdb files

* Feat: added transactionrequester package

* Adds the transactionParser as a fliter and pre-processing mechanism of the tangle. (#242)

* Feat: started porting the new binary stuff

* Refactor: removed unnecessary folder

* Refactor: cleaned up go.mod files

* Fix: removed objectsdb files

* Feat: added transactionrequester package

* Feat: added new transactionparser as the filter for the tangle

* Feat: Use hive.go autopeering (#250)

* use autopeering from hive.go
* update hive.go

* update hive.go

* Adds the TransactionRequester and some refactors (#256)

* Feat: started porting the new binary stuff

* Refactor: removed unnecessary folder

* Refactor: cleaned up go.mod files

* Fix: removed objectsdb files

* Feat: added transactionrequester package

* Feat: added new transactionparser as the filter for the tangle

* Refactor: removed duplicate code

* Fix: Log dropping packets every 1000 drops (#255)

* Fix: Log dropping packets every 1000 drops

* use an atomic counter for dropped message because Write() could be called concurrently

* removes redundant zero

* Add external check in test

Co-authored-by: Luca Moser <moser.luca@gmail.com>

* Fix: Update pprof port (#244)

Since both Hornet and Goshimmer might be running on the same machine, update the port so that we can get debug information for both.

* Remove docker specific config (#245)

* :arrow_up: upgrades hive.go

* :bug: checks meta_tx size

* :heavy_minus_sign: removes dependencies

* :sparkles: enables local testing

* :sparkles: adds config plugin

* Extend remote log message (#260)

* Bump up Logstash and ElasticSearch memory #251

* Add version and if available GIT information to remote log message #251

* :bug: fixes flag parsing before loading config file

* Feat: Add --version to cli (#264)

* Adds changelog entry for v0.1.2 and bumps version number (#265)

* updates changelog for v0.1.2 release

* bumps version number to v0.1.2

Co-authored-by: Hans Moog <hm@mkjc.net>
Co-authored-by: Wolfgang Welz <welzwo@gmail.com>
Co-authored-by: jkrvivian <jkrvivian@gmail.com>
Co-authored-by: Dave <44786846+centercirclesolutions@users.noreply.github.com>
Co-authored-by: Angelo Capossele <angelocapossele@gmail.com>
Co-authored-by: Jonas Theis <mail@jonastheis.de>
---
 .gitignore                                    |   1 +
 CHANGELOG.md                                  |  13 +
 Dockerfile                                    |   3 +-
 docker.config.json                            |  34 --
 go.mod                                        |  17 +-
 go.sum                                        |  59 ++-
 main.go                                       |   3 +-
 packages/autopeering/discover/common.go       |  65 ---
 packages/autopeering/discover/events.go       |  35 --
 packages/autopeering/discover/manager.go      | 336 ------------
 packages/autopeering/discover/manager_test.go | 168 ------
 packages/autopeering/discover/mpeer.go        |  95 ----
 packages/autopeering/discover/mpeer_test.go   | 189 -------
 .../autopeering/discover/proto/message.go     |  39 --
 .../autopeering/discover/proto/message.pb.go  | 280 ----------
 .../autopeering/discover/proto/message.proto  |  42 --
 packages/autopeering/discover/protocol.go     | 492 ------------------
 .../autopeering/discover/protocol_test.go     | 293 -----------
 packages/autopeering/discover/query_strat.go  |  94 ----
 packages/autopeering/distance/consts.go       |   5 -
 packages/autopeering/distance/distance.go     |  33 --
 .../autopeering/distance/distance_test.go     |  38 --
 packages/autopeering/peer/id.go               |  40 --
 packages/autopeering/peer/local.go            | 126 -----
 packages/autopeering/peer/local_test.go       |  72 ---
 packages/autopeering/peer/peer.go             | 143 -----
 packages/autopeering/peer/peer_test.go        |  82 ---
 packages/autopeering/peer/peerdb.go           | 246 ---------
 packages/autopeering/peer/peerdb_test.go      |  90 ----
 .../autopeering/peer/peertest/peertest.go     |  35 --
 packages/autopeering/peer/proto/peer.pb.go    |  94 ----
 packages/autopeering/peer/proto/peer.proto    |  15 -
 .../peer/service/proto/service.pb.go          | 137 -----
 .../peer/service/proto/service.proto          |  17 -
 packages/autopeering/peer/service/record.go   | 118 -----
 packages/autopeering/peer/service/service.go  |  26 -
 packages/autopeering/peer/sort.go             |  38 --
 packages/autopeering/peer/sort_test.go        |  45 --
 packages/autopeering/salt/proto/salt.pb.go    |  89 ----
 packages/autopeering/salt/proto/salt.proto    |  12 -
 packages/autopeering/salt/salt.go             |  86 ---
 packages/autopeering/salt/salt_test.go        |  73 ---
 packages/autopeering/selection/common.go      |  86 ---
 packages/autopeering/selection/events.go      |  55 --
 packages/autopeering/selection/manager.go     | 371 -------------
 .../autopeering/selection/manager_test.go     | 216 --------
 .../autopeering/selection/neighborhood.go     | 132 -----
 .../selection/neighborhood_test.go            | 254 ---------
 .../autopeering/selection/proto/message.go    |  35 --
 .../autopeering/selection/proto/message.pb.go | 207 --------
 .../autopeering/selection/proto/message.proto |  30 --
 packages/autopeering/selection/protocol.go    | 370 -------------
 .../autopeering/selection/protocol_test.go    | 185 -------
 packages/autopeering/selection/selection.go   |  72 ---
 .../autopeering/selection/selection_test.go   | 165 ------
 packages/autopeering/server/common.go         |  38 --
 packages/autopeering/server/errors.go         |  17 -
 .../autopeering/server/proto/packet.pb.go     |  97 ----
 .../autopeering/server/proto/packet.proto     |  11 -
 packages/autopeering/server/protocol.go       |  32 --
 packages/autopeering/server/server.go         | 315 -----------
 packages/autopeering/server/server_test.go    | 216 --------
 packages/autopeering/transport/chan.go        | 116 -----
 packages/autopeering/transport/chan_test.go   |  78 ---
 packages/autopeering/transport/conn.go        |  58 ---
 packages/autopeering/transport/conn_test.go   |  41 --
 packages/autopeering/transport/const.go       |   5 -
 packages/autopeering/transport/errors.go      |   8 -
 packages/autopeering/transport/p2p.go         |  93 ----
 packages/autopeering/transport/p2p_test.go    |  34 --
 packages/autopeering/transport/transport.go   |  37 --
 packages/binary/identity/constants.go         |   7 +
 packages/binary/identity/identity.go          |  48 ++
 packages/binary/identity/identity_test.go     |  41 ++
 packages/binary/identity/type.go              |   8 +
 packages/binary/signature/ed25119/ed25119.go  |  18 +
 packages/binary/signature/ed25119/key_pair.go |   6 +
 .../binary/signature/ed25119/private_key.go   |  15 +
 .../binary/signature/ed25119/public_key.go    |  25 +
 .../binary/signature/ed25119/signature.go     |  19 +
 .../binary/storageprefix/storageprefix.go     |  17 +
 packages/binary/tangle/events.go              |  39 ++
 .../binary/tangle/model/approver/approver.go  |  59 +++
 .../tangle/model/approver/cached_approver.go  |  33 ++
 .../cached_missingtransaction.go              |  21 +
 .../missingtransaction/missingtransaction.go  |  53 ++
 .../model/transaction/cached_transaction.go   |  31 ++
 .../binary/tangle/model/transaction/id.go     |  34 ++
 .../binary/tangle/model/transaction/init.go   |  10 +
 .../model/transaction/payload/data/data.go    |  52 ++
 .../model/transaction/payload/data/init.go    |   9 +
 .../tangle/model/transaction/payload/id.go    |   5 +
 .../model/transaction/payload/payload.go      |  12 +
 .../tangle/model/transaction/payload/type.go  |   3 +
 .../transaction/payload/type_register.go      |  36 ++
 .../transaction/test/transaction_test.go      |  77 +++
 .../tangle/model/transaction/transaction.go   | 277 ++++++++++
 .../cached_transactionmetadata.go             |  25 +
 .../transactionmetadata.go                    |  94 ++++
 packages/binary/tangle/tangle.go              | 323 ++++++++++++
 packages/binary/tangle/tangle_test.go         |  95 ++++
 .../recently_seen_bytes_filter.go             |  68 +++
 .../transaction_signature_filter.go           |  66 +++
 .../tangle/transactionparser/bytes_filter.go  |   8 +
 .../binary/tangle/transactionparser/events.go |   9 +
 .../transactionparser/transaction_filter.go   |  12 +
 .../transactionparser/transactionparser.go    | 137 +++++
 .../transactionparser_test.go                 |  56 ++
 .../tangle/transactionrequester/constants.go  |  10 +
 .../tangle/transactionrequester/events.go     |   9 +
 .../tangle/transactionrequester/options.go    |  37 ++
 .../transactionrequester.go                   |  74 +++
 packages/gossip/common.go                     |   4 +-
 packages/gossip/events.go                     |   2 +-
 packages/gossip/manager.go                    |   2 +-
 packages/gossip/manager_test.go               |   4 +-
 packages/gossip/neighbor.go                   |  19 +-
 packages/gossip/neighbor_test.go              |  12 +-
 packages/gossip/server/handshake.go           |   2 +-
 packages/gossip/server/server.go              |   6 +-
 packages/gossip/server/server_test.go         |   4 +-
 .../meta_transaction/meta_transaction.go      |   5 +-
 .../meta_transaction/meta_transaction_test.go |   4 +-
 plugins/analysis/client/plugin.go             |   4 +-
 plugins/autopeering/autopeering.go            |  12 +-
 plugins/autopeering/local/local.go            |   6 +-
 plugins/autopeering/plugin.go                 |   6 +-
 plugins/cli/plugin.go                         |  13 +-
 plugins/config/config.go                      |  64 +++
 plugins/config/plugin.go                      |  12 +
 plugins/gossip/gossip.go                      |   4 +-
 plugins/gossip/plugin.go                      |   4 +-
 plugins/remotelog/plugin.go                   |  72 ++-
 plugins/remotelog/server/docker-compose.yml   |   4 +-
 plugins/spa/plugin.go                         |   2 +-
 plugins/tangle/solidifier.go                  |   8 +-
 plugins/tangle/solidifier_test.go             |   6 +-
 plugins/webapi/getNeighbors/plugin.go         |   4 +-
 138 files changed, 2289 insertions(+), 7266 deletions(-)
 delete mode 100644 docker.config.json
 delete mode 100644 packages/autopeering/discover/common.go
 delete mode 100644 packages/autopeering/discover/events.go
 delete mode 100644 packages/autopeering/discover/manager.go
 delete mode 100644 packages/autopeering/discover/manager_test.go
 delete mode 100644 packages/autopeering/discover/mpeer.go
 delete mode 100644 packages/autopeering/discover/mpeer_test.go
 delete mode 100644 packages/autopeering/discover/proto/message.go
 delete mode 100644 packages/autopeering/discover/proto/message.pb.go
 delete mode 100644 packages/autopeering/discover/proto/message.proto
 delete mode 100644 packages/autopeering/discover/protocol.go
 delete mode 100644 packages/autopeering/discover/protocol_test.go
 delete mode 100644 packages/autopeering/discover/query_strat.go
 delete mode 100644 packages/autopeering/distance/consts.go
 delete mode 100644 packages/autopeering/distance/distance.go
 delete mode 100644 packages/autopeering/distance/distance_test.go
 delete mode 100644 packages/autopeering/peer/id.go
 delete mode 100644 packages/autopeering/peer/local.go
 delete mode 100644 packages/autopeering/peer/local_test.go
 delete mode 100644 packages/autopeering/peer/peer.go
 delete mode 100644 packages/autopeering/peer/peer_test.go
 delete mode 100644 packages/autopeering/peer/peerdb.go
 delete mode 100644 packages/autopeering/peer/peerdb_test.go
 delete mode 100644 packages/autopeering/peer/peertest/peertest.go
 delete mode 100644 packages/autopeering/peer/proto/peer.pb.go
 delete mode 100644 packages/autopeering/peer/proto/peer.proto
 delete mode 100644 packages/autopeering/peer/service/proto/service.pb.go
 delete mode 100644 packages/autopeering/peer/service/proto/service.proto
 delete mode 100644 packages/autopeering/peer/service/record.go
 delete mode 100644 packages/autopeering/peer/service/service.go
 delete mode 100644 packages/autopeering/peer/sort.go
 delete mode 100644 packages/autopeering/peer/sort_test.go
 delete mode 100644 packages/autopeering/salt/proto/salt.pb.go
 delete mode 100644 packages/autopeering/salt/proto/salt.proto
 delete mode 100644 packages/autopeering/salt/salt.go
 delete mode 100644 packages/autopeering/salt/salt_test.go
 delete mode 100644 packages/autopeering/selection/common.go
 delete mode 100644 packages/autopeering/selection/events.go
 delete mode 100644 packages/autopeering/selection/manager.go
 delete mode 100644 packages/autopeering/selection/manager_test.go
 delete mode 100644 packages/autopeering/selection/neighborhood.go
 delete mode 100644 packages/autopeering/selection/neighborhood_test.go
 delete mode 100644 packages/autopeering/selection/proto/message.go
 delete mode 100644 packages/autopeering/selection/proto/message.pb.go
 delete mode 100644 packages/autopeering/selection/proto/message.proto
 delete mode 100644 packages/autopeering/selection/protocol.go
 delete mode 100644 packages/autopeering/selection/protocol_test.go
 delete mode 100644 packages/autopeering/selection/selection.go
 delete mode 100644 packages/autopeering/selection/selection_test.go
 delete mode 100644 packages/autopeering/server/common.go
 delete mode 100644 packages/autopeering/server/errors.go
 delete mode 100644 packages/autopeering/server/proto/packet.pb.go
 delete mode 100644 packages/autopeering/server/proto/packet.proto
 delete mode 100644 packages/autopeering/server/protocol.go
 delete mode 100644 packages/autopeering/server/server.go
 delete mode 100644 packages/autopeering/server/server_test.go
 delete mode 100644 packages/autopeering/transport/chan.go
 delete mode 100644 packages/autopeering/transport/chan_test.go
 delete mode 100644 packages/autopeering/transport/conn.go
 delete mode 100644 packages/autopeering/transport/conn_test.go
 delete mode 100644 packages/autopeering/transport/const.go
 delete mode 100644 packages/autopeering/transport/errors.go
 delete mode 100644 packages/autopeering/transport/p2p.go
 delete mode 100644 packages/autopeering/transport/p2p_test.go
 delete mode 100644 packages/autopeering/transport/transport.go
 create mode 100644 packages/binary/identity/constants.go
 create mode 100644 packages/binary/identity/identity.go
 create mode 100644 packages/binary/identity/identity_test.go
 create mode 100644 packages/binary/identity/type.go
 create mode 100644 packages/binary/signature/ed25119/ed25119.go
 create mode 100644 packages/binary/signature/ed25119/key_pair.go
 create mode 100644 packages/binary/signature/ed25119/private_key.go
 create mode 100644 packages/binary/signature/ed25119/public_key.go
 create mode 100644 packages/binary/signature/ed25119/signature.go
 create mode 100644 packages/binary/storageprefix/storageprefix.go
 create mode 100644 packages/binary/tangle/events.go
 create mode 100644 packages/binary/tangle/model/approver/approver.go
 create mode 100644 packages/binary/tangle/model/approver/cached_approver.go
 create mode 100644 packages/binary/tangle/model/missingtransaction/cached_missingtransaction.go
 create mode 100644 packages/binary/tangle/model/missingtransaction/missingtransaction.go
 create mode 100644 packages/binary/tangle/model/transaction/cached_transaction.go
 create mode 100644 packages/binary/tangle/model/transaction/id.go
 create mode 100644 packages/binary/tangle/model/transaction/init.go
 create mode 100644 packages/binary/tangle/model/transaction/payload/data/data.go
 create mode 100644 packages/binary/tangle/model/transaction/payload/data/init.go
 create mode 100644 packages/binary/tangle/model/transaction/payload/id.go
 create mode 100644 packages/binary/tangle/model/transaction/payload/payload.go
 create mode 100644 packages/binary/tangle/model/transaction/payload/type.go
 create mode 100644 packages/binary/tangle/model/transaction/payload/type_register.go
 create mode 100644 packages/binary/tangle/model/transaction/test/transaction_test.go
 create mode 100644 packages/binary/tangle/model/transaction/transaction.go
 create mode 100644 packages/binary/tangle/model/transactionmetadata/cached_transactionmetadata.go
 create mode 100644 packages/binary/tangle/model/transactionmetadata/transactionmetadata.go
 create mode 100644 packages/binary/tangle/tangle.go
 create mode 100644 packages/binary/tangle/tangle_test.go
 create mode 100644 packages/binary/tangle/transactionparser/builtinfilters/recently_seen_bytes_filter.go
 create mode 100644 packages/binary/tangle/transactionparser/builtinfilters/transaction_signature_filter.go
 create mode 100644 packages/binary/tangle/transactionparser/bytes_filter.go
 create mode 100644 packages/binary/tangle/transactionparser/events.go
 create mode 100644 packages/binary/tangle/transactionparser/transaction_filter.go
 create mode 100644 packages/binary/tangle/transactionparser/transactionparser.go
 create mode 100644 packages/binary/tangle/transactionparser/transactionparser_test.go
 create mode 100644 packages/binary/tangle/transactionrequester/constants.go
 create mode 100644 packages/binary/tangle/transactionrequester/events.go
 create mode 100644 packages/binary/tangle/transactionrequester/options.go
 create mode 100644 packages/binary/tangle/transactionrequester/transactionrequester.go
 create mode 100644 plugins/config/config.go
 create mode 100644 plugins/config/plugin.go

diff --git a/.gitignore b/.gitignore
index 52422ce9..b376e693 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,7 @@ testNodes/*
 
 # Database directory
 mainnetdb/
+objectsdb/
 
 # OSX related files
 .DS_Store
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b47ac3d5..cff14c1a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,16 @@
+# v0.1.2 - 2020-02-24
+
+* Adds `--version` flag to retrieve the GoShimmer version
+* Adds the version and commit hash to the remote log logging
+* Replaces the autopeering module with the one from hive.go 
+* Changed the pprof listen port to `6061` to avoid conflict with Hornet
+* Fixes `invalid stored peer` messages
+* Fixes masternodes getting removed if they were offline
+* Fixes `-c` and `-d` to define config file/dir
+* Fixes drop messages about full queues appearing too many times
+* Fixes crash due to incopatible transaction size
+* Changed the salt lifetime to 2 hours from 30 minutes
+
 # v0.1.1 - 2020-02-07
 
 This release contains a series of fixes:
diff --git a/Dockerfile b/Dockerfile
index 381f8824..fda2f888 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -27,11 +27,10 @@ VOLUME /app/mainnetdb
 
 EXPOSE 14666/tcp
 EXPOSE 14626/udp
-EXPOSE 14626/tcp
 
 # Copy the Pre-built binary file from the previous stage
 COPY --from=build /go/bin/goshimmer .
 # Copy the docker config
-COPY docker.config.json config.json
+COPY config.json config.json
 
 ENTRYPOINT ["./goshimmer"] 
diff --git a/docker.config.json b/docker.config.json
deleted file mode 100644
index ff931575..00000000
--- a/docker.config.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
-  "analysis": {
-    "serveraddress": "ressims.iota.cafe:188",
-    "serverport": 0
-  },
-  "autopeering": {
-    "address": "0.0.0.0",
-    "entrynodes": [
-      "V8LYtWWcPYYDTTXLeIEFjJEuWlsjDiI0+Pq/Cx9ai6g=@116.202.49.178:14626"
-    ],
-    "port": 14626
-  },
-  "database": {
-    "directory": "mainnetdb"
-  },
-  "gossip": {
-    "port": 14666
-  },
-  "logger": {
-    "Level": "info",
-    "DisableCaller": true,
-    "DisableStacktrace": false,
-    "Encoding": "console",
-    "OutputPaths": [
-      "stdout",
-      "goshimmer.log"
-    ],
-    "DisableEvents": true
-  },
-  "node": {
-    "disablePlugins": [],
-    "enablePlugins": []
-  }
-}
diff --git a/go.mod b/go.mod
index af0a116b..88641721 100644
--- a/go.mod
+++ b/go.mod
@@ -13,31 +13,36 @@ require (
 	github.com/googollee/go-engine.io v1.4.3-0.20190924125625-798118fc0dd2
 	github.com/googollee/go-socket.io v1.4.3-0.20191204093753-683f8725b6d0
 	github.com/gorilla/websocket v1.4.1
-	github.com/iotaledger/hive.go v0.0.0-20200207144536-27b18f10f09e
+	github.com/iotaledger/hive.go v0.0.0-20200219224037-2d5f5238c0de
 	github.com/iotaledger/iota.go v1.0.0-beta.14
+	github.com/kr/pretty v0.2.0 // indirect
+	github.com/kr/text v0.2.0 // indirect
 	github.com/labstack/echo v3.3.10+incompatible
 	github.com/labstack/gommon v0.3.0 // indirect
 	github.com/magiconair/properties v1.8.1
 	github.com/mattn/go-colorable v0.1.4 // indirect
 	github.com/mattn/go-isatty v0.0.11 // indirect
+	github.com/mr-tron/base58 v1.1.3
+	github.com/oasislabs/ed25519 v0.0.0-20200206134218-2893bee822a3
+	github.com/panjf2000/ants/v2 v2.2.2
 	github.com/pelletier/go-toml v1.6.0 // indirect
 	github.com/pkg/errors v0.9.1
 	github.com/rogpeppe/go-internal v1.5.2 // indirect
+	github.com/sergi/go-diff v1.1.0 // indirect
 	github.com/spf13/afero v1.2.2 // indirect
 	github.com/spf13/cast v1.3.1 // indirect
 	github.com/spf13/jwalterweatherman v1.1.0 // indirect
 	github.com/spf13/pflag v1.0.5
 	github.com/spf13/viper v1.6.1
-	github.com/stretchr/objx v0.2.0 // indirect
 	github.com/stretchr/testify v1.4.0
 	github.com/valyala/fasttemplate v1.1.0 // indirect
 	go.uber.org/atomic v1.5.1
 	go.uber.org/zap v1.13.0
-	golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d // indirect
-	golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553
-	golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 // indirect
-	golang.org/x/text v0.3.2 // indirect
+	golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6
+	golang.org/x/net v0.0.0-20200202094626-16171245cfb2
+	golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 // indirect
 	golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7 // indirect
 	gopkg.in/ini.v1 v1.51.1 // indirect
+	gopkg.in/src-d/go-git.v4 v4.13.1
 	gopkg.in/yaml.v2 v2.2.7 // indirect
 )
diff --git a/go.sum b/go.sum
index a943eb06..c1a5c4ac 100644
--- a/go.sum
+++ b/go.sum
@@ -13,10 +13,13 @@ github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
 github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
 github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
+github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
 github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -32,6 +35,8 @@ github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7
 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
 github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -50,11 +55,14 @@ github.com/dgryski/go-farm v0.0.0-20191112170834-c2139c5d712b/go.mod h1:SqUrOPUn
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
+github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
 github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
 github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
+github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
@@ -90,6 +98,7 @@ github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
 github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@@ -123,18 +132,24 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/iotaledger/hive.go v0.0.0-20200207144536-27b18f10f09e h1:eM0/mEG3ZPflZRJxOn0cc+/8ZZIpirEAyhzF4rzTKjM=
-github.com/iotaledger/hive.go v0.0.0-20200207144536-27b18f10f09e/go.mod h1:wj3bFHlcX0NiEOWu5+WOg/MI/5N7PKCFnyaziaylB64=
+github.com/iotaledger/hive.go v0.0.0-20200219224037-2d5f5238c0de h1:J9G9YWM5q7r3DObMIx/Qc8CUjrpD+c90EPVKjsBrR+E=
+github.com/iotaledger/hive.go v0.0.0-20200219224037-2d5f5238c0de/go.mod h1:wj3bFHlcX0NiEOWu5+WOg/MI/5N7PKCFnyaziaylB64=
 github.com/iotaledger/iota.go v1.0.0-beta.9/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8=
 github.com/iotaledger/iota.go v1.0.0-beta.14 h1:Oeb28MfBuJEeXcGrLhTCJFtbsnc8y1u7xidsAmiOD5A=
 github.com/iotaledger/iota.go v1.0.0-beta.14/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
 github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
+github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
 github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
 github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
+github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -143,10 +158,15 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
 github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
 github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
 github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
@@ -163,13 +183,18 @@ github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGe
 github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
+github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc=
+github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
 github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
 github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
+github.com/oasislabs/ed25519 v0.0.0-20200206134218-2893bee822a3 h1:xhsvlWpWPdHXHt8i5eaXf2WbAxHLciGqrfup6zAPjVQ=
+github.com/oasislabs/ed25519 v0.0.0-20200206134218-2893bee822a3/go.mod h1:xIpCyrK2ouGA4QBGbiNbkoONrvJ00u9P3QOkXSOAC0c=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
@@ -177,7 +202,9 @@ github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
 github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
 github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
+github.com/panjf2000/ants/v2 v2.2.2 h1:TWzusBjq/IflXhy+/S6u5wmMLCBdJnB9tPIx9Zmhvok=
 github.com/panjf2000/ants/v2 v2.2.2/go.mod h1:1GFm8bV8nyCQvU5K4WvBCTG1/YBFOD2VzjffD8fV55A=
+github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
 github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
@@ -213,7 +240,10 @@ github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE
 github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 github.com/sasha-s/go-deadlock v0.2.0 h1:lMqc+fUb7RrFS3gQLtoQsJ7/6TV/pAIFvBsqX73DK8Y=
 github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZqiDbRupzT10=
+github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
 github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
+github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
 github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
 github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
@@ -268,6 +298,8 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM
 github.com/spf13/viper v1.5.0/go.mod h1:AkYRkVJF8TkSG/xet6PzXX+l39KhhXa2pdqVSxnTcn4=
 github.com/spf13/viper v1.6.1 h1:VPZzIkznI1YhVMRi6vNFLHSwhnhReBfgTxIPccpfdZk=
 github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
+github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
+github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
@@ -288,6 +320,8 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC
 github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
 github.com/valyala/fasttemplate v1.1.0 h1:RZqt0yGBsps8NGvLSGW804QQqCUYYLsaOjTVHy1Ocw4=
 github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
+github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
+github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
 github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
 github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
@@ -314,14 +348,19 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
 golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U=
 golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6 h1:Sy5bstxEqwwbYs6n0/pBuxKENqOeZUgD45Gp3Q3pqLg=
+golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -343,8 +382,11 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
 golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -363,16 +405,20 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h
 golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSfrPzImPoVxuomtbT2nk=
 golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 h1:sfkvUWPNGwSV+8/fNqctR5lS2AqCSqYwXdrjCxp/dXo=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
@@ -389,6 +435,7 @@ golang.org/x/tools v0.0.0-20190214204934-8dcb7bc8c7fe/go.mod h1:E6PF97AdD6v0s+fP
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
 golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -431,8 +478,16 @@ gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.51.1 h1:GyboHr4UqMiLUybYjd22ZjQIKEJEpgtLXtuGbR21Oho=
 gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg=
+gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
+gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg=
+gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
+gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE=
+gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
+gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
 gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/main.go b/main.go
index 2f947172..b45501ba 100644
--- a/main.go
+++ b/main.go
@@ -29,9 +29,10 @@ import (
 )
 
 func main() {
+	cli.PrintVersion()
 	cli.LoadConfig()
 
-	go http.ListenAndServe("localhost:6060", nil) // pprof Server for Debbuging Mutexes
+	go http.ListenAndServe("localhost:6061", nil) // pprof Server for Debbuging Mutexes
 
 	node.Run(
 		node.Plugins(
diff --git a/packages/autopeering/discover/common.go b/packages/autopeering/discover/common.go
deleted file mode 100644
index 99b092ea..00000000
--- a/packages/autopeering/discover/common.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package discover
-
-import (
-	"time"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/hive.go/logger"
-)
-
-// Default values for the global parameters
-const (
-	DefaultReverifyInterval = 10 * time.Second
-	DefaultQueryInterval    = 60 * time.Second
-	DefaultMaxManaged       = 1000
-	DefaultMaxReplacements  = 10
-)
-
-var (
-	reverifyInterval = DefaultReverifyInterval // time interval after which the next peer is reverified
-	queryInterval    = DefaultQueryInterval    // time interval after which peers are queried for new peers
-	maxManaged       = DefaultMaxManaged       // maximum number of peers that can be managed
-	maxReplacements  = DefaultMaxReplacements  // maximum number of peers kept in the replacement list
-)
-
-// Config holds discovery related settings.
-type Config struct {
-	// These settings are required and configure the listener:
-	Log *logger.Logger
-
-	// These settings are optional:
-	MasterPeers []*peer.Peer // list of master peers used for bootstrapping
-}
-
-// Parameters holds the parameters that can be configured.
-type Parameters struct {
-	ReverifyInterval time.Duration // time interval after which the next peer is reverified
-	QueryInterval    time.Duration // time interval after which peers are queried for new peers
-	MaxManaged       int           // maximum number of peers that can be managed
-	MaxReplacements  int           // maximum number of peers kept in the replacement list
-}
-
-// SetParameters sets the global parameters for this package.
-// This function cannot be used concurrently.
-func SetParameter(param Parameters) {
-	if param.ReverifyInterval > 0 {
-		reverifyInterval = param.ReverifyInterval
-	} else {
-		reverifyInterval = DefaultReverifyInterval
-	}
-	if param.QueryInterval > 0 {
-		queryInterval = param.QueryInterval
-	} else {
-		queryInterval = DefaultQueryInterval
-	}
-	if param.MaxManaged > 0 {
-		maxManaged = param.MaxManaged
-	} else {
-		maxManaged = DefaultMaxManaged
-	}
-	if param.MaxReplacements > 0 {
-		maxReplacements = param.MaxReplacements
-	} else {
-		maxReplacements = DefaultMaxReplacements
-	}
-}
diff --git a/packages/autopeering/discover/events.go b/packages/autopeering/discover/events.go
deleted file mode 100644
index 177c6be8..00000000
--- a/packages/autopeering/discover/events.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package discover
-
-import (
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/hive.go/events"
-)
-
-// Events contains all the events that are triggered during the peer discovery.
-var Events = struct {
-	// A PeerDiscovered event is triggered, when a new peer has been discovered and verified.
-	PeerDiscovered *events.Event
-	// A PeerDeleted event is triggered, when a discovered and verified peer could not be reverified.
-	PeerDeleted *events.Event
-}{
-	PeerDiscovered: events.NewEvent(peerDiscovered),
-	PeerDeleted:    events.NewEvent(peerDeleted),
-}
-
-// DiscoveredEvent bundles the information of the discovered peer.
-type DiscoveredEvent struct {
-	Peer *peer.Peer // discovered peer
-}
-
-// DeletedEvent bundles the information of the deleted peer.
-type DeletedEvent struct {
-	Peer *peer.Peer // deleted peer
-}
-
-func peerDiscovered(handler interface{}, params ...interface{}) {
-	handler.(func(*DiscoveredEvent))(params[0].(*DiscoveredEvent))
-}
-
-func peerDeleted(handler interface{}, params ...interface{}) {
-	handler.(func(*DeletedEvent))(params[0].(*DeletedEvent))
-}
diff --git a/packages/autopeering/discover/manager.go b/packages/autopeering/discover/manager.go
deleted file mode 100644
index 3bd36f06..00000000
--- a/packages/autopeering/discover/manager.go
+++ /dev/null
@@ -1,336 +0,0 @@
-package discover
-
-import (
-	"math/rand"
-	"sync"
-	"time"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/server"
-	"github.com/iotaledger/hive.go/logger"
-)
-
-const (
-	// PingExpiration is the time until a peer verification expires.
-	PingExpiration = 12 * time.Hour
-	// MaxPeersInResponse is the maximum number of peers returned in DiscoveryResponse.
-	MaxPeersInResponse = 6
-	// MaxServices is the maximum number of services a peer can support.
-	MaxServices = 5
-
-	// VersionNum specifies the expected version number for this Protocol.
-	VersionNum = 0
-)
-
-type network interface {
-	local() *peer.Local
-
-	Ping(*peer.Peer) error
-	DiscoveryRequest(*peer.Peer) ([]*peer.Peer, error)
-}
-
-type manager struct {
-	mutex        sync.Mutex // protects active and replacement
-	active       []*mpeer
-	replacements []*mpeer
-
-	net network
-	log *logger.Logger
-
-	wg      sync.WaitGroup
-	closing chan struct{}
-}
-
-func newManager(net network, masters []*peer.Peer, log *logger.Logger) *manager {
-	m := &manager{
-		active:       make([]*mpeer, 0, maxManaged),
-		replacements: make([]*mpeer, 0, maxReplacements),
-		net:          net,
-		log:          log,
-		closing:      make(chan struct{}),
-	}
-	m.loadInitialPeers(masters)
-
-	return m
-}
-
-func (m *manager) start() {
-	m.wg.Add(1)
-	go m.loop()
-}
-
-func (m *manager) self() peer.ID {
-	return m.net.local().ID()
-}
-
-func (m *manager) close() {
-	close(m.closing)
-	m.wg.Wait()
-}
-
-func (m *manager) loop() {
-	defer m.wg.Done()
-
-	var (
-		reverify     = time.NewTimer(0) // setting this to 0 will cause a trigger right away
-		reverifyDone chan struct{}
-
-		query     = time.NewTimer(server.ResponseTimeout) // trigger the first query after the reverify
-		queryNext chan time.Duration
-	)
-	defer reverify.Stop()
-	defer query.Stop()
-
-Loop:
-	for {
-		select {
-		// start verification, if not yet running
-		case <-reverify.C:
-			// if there is no reverifyDone, this means doReverify is not running
-			if reverifyDone == nil {
-				reverifyDone = make(chan struct{})
-				go m.doReverify(reverifyDone)
-			}
-
-		// reset verification
-		case <-reverifyDone:
-			reverifyDone = nil
-			reverify.Reset(reverifyInterval) // reverify again after the given interval
-
-		// start requesting new peers, if no yet running
-		case <-query.C:
-			if queryNext == nil {
-				queryNext = make(chan time.Duration)
-				go m.doQuery(queryNext)
-			}
-
-		// on query done, reset time to given duration
-		case d := <-queryNext:
-			queryNext = nil
-			query.Reset(d)
-
-		// on close, exit the loop
-		case <-m.closing:
-			break Loop
-		}
-	}
-
-	// wait for spawned goroutines to finish
-	if reverifyDone != nil {
-		<-reverifyDone
-	}
-	if queryNext != nil {
-		<-queryNext
-	}
-}
-
-// doReverify pings the oldest active peer.
-func (m *manager) doReverify(done chan<- struct{}) {
-	defer close(done)
-
-	p := m.peerToReverify()
-	if p == nil {
-		return // nothing can be reverified
-	}
-	m.log.Debugw("reverifying",
-		"id", p.ID(),
-		"addr", p.Address(),
-	)
-
-	// could not verify the peer
-	if m.net.Ping(unwrapPeer(p)) != nil {
-		m.mutex.Lock()
-		defer m.mutex.Unlock()
-
-		m.active, _ = deletePeerByID(m.active, p.ID())
-		m.log.Debugw("remove dead",
-			"peer", p,
-		)
-		Events.PeerDeleted.Trigger(&DeletedEvent{Peer: unwrapPeer(p)})
-
-		// add a random replacement, if available
-		if len(m.replacements) > 0 {
-			var r *mpeer
-			m.replacements, r = deletePeer(m.replacements, rand.Intn(len(m.replacements)))
-			m.active = pushPeer(m.active, r, maxManaged)
-		}
-		return
-	}
-
-	// no need to do anything here, as the peer is bumped when handling the pong
-}
-
-// peerToReverify returns the oldest peer, or nil if empty.
-func (m *manager) peerToReverify() *mpeer {
-	m.mutex.Lock()
-	defer m.mutex.Unlock()
-
-	if len(m.active) == 0 {
-		return nil
-	}
-	// the last peer is the oldest
-	return m.active[len(m.active)-1]
-}
-
-// updatePeer moves the peer with the given ID to the front of the list of managed peers.
-// It returns 0 if there was no peer with that id, otherwise the verifiedCount of the updated peer is returned.
-func (m *manager) updatePeer(update *peer.Peer) uint {
-	id := update.ID()
-	for i, p := range m.active {
-		if p.ID() == id {
-			if i > 0 {
-				//  move i-th peer to the front
-				copy(m.active[1:], m.active[:i])
-			}
-			// replace first mpeer with a wrap of the updated peer
-			m.active[0] = &mpeer{
-				Peer:          *update,
-				verifiedCount: p.verifiedCount + 1,
-				lastNewPeers:  p.lastNewPeers,
-			}
-			return p.verifiedCount + 1
-		}
-	}
-	return 0
-}
-
-func (m *manager) addReplacement(p *mpeer) bool {
-	if containsPeer(m.replacements, p.ID()) {
-		return false // already in the list
-	}
-	m.replacements = unshiftPeer(m.replacements, p, maxReplacements)
-	return true
-}
-
-func (m *manager) loadInitialPeers(masters []*peer.Peer) {
-	var peers []*peer.Peer
-
-	db := m.net.local().Database()
-	if db != nil {
-		peers = db.SeedPeers()
-	}
-
-	peers = append(peers, masters...)
-	for _, p := range peers {
-		m.addDiscoveredPeer(p)
-	}
-}
-
-// addDiscoveredPeer adds a newly discovered peer that has never been verified or pinged yet.
-// It returns true, if the given peer was new and added, false otherwise.
-func (m *manager) addDiscoveredPeer(p *peer.Peer) bool {
-	// never add the local peer
-	if p.ID() == m.self() {
-		return false
-	}
-
-	m.mutex.Lock()
-	defer m.mutex.Unlock()
-
-	if containsPeer(m.active, p.ID()) {
-		return false
-	}
-	m.log.Debugw("discovered",
-		"peer", p,
-	)
-
-	mp := wrapPeer(p)
-	if len(m.active) >= maxManaged {
-		return m.addReplacement(mp)
-	}
-
-	m.active = pushPeer(m.active, mp, maxManaged)
-	return true
-}
-
-// addVerifiedPeer adds a new peer that has just been successfully pinged.
-// It returns true, if the given peer was new and added, false otherwise.
-func (m *manager) addVerifiedPeer(p *peer.Peer) bool {
-	// never add the local peer
-	if p.ID() == m.self() {
-		return false
-	}
-
-	m.log.Debugw("verified",
-		"peer", p,
-		"services", p.Services(),
-	)
-
-	m.mutex.Lock()
-	defer m.mutex.Unlock()
-
-	// if already in the list, move it to the front
-	if v := m.updatePeer(p); v > 0 {
-		// trigger the event only for the first time the peer is updated
-		if v == 1 {
-			Events.PeerDiscovered.Trigger(&DiscoveredEvent{Peer: p})
-		}
-		return false
-	}
-
-	mp := wrapPeer(p)
-	mp.verifiedCount = 1
-
-	if len(m.active) >= maxManaged {
-		return m.addReplacement(mp)
-	}
-	// trigger the event only when the peer is added to active
-	Events.PeerDiscovered.Trigger(&DiscoveredEvent{Peer: p})
-
-	// new nodes are added to the front
-	m.active = unshiftPeer(m.active, mp, maxManaged)
-	return true
-}
-
-// getRandomPeers returns a list of randomly selected peers.
-func (m *manager) getRandomPeers(n int, minVerified uint) []*peer.Peer {
-	m.mutex.Lock()
-	defer m.mutex.Unlock()
-
-	if n > len(m.active) {
-		n = len(m.active)
-	}
-
-	peers := make([]*peer.Peer, 0, n)
-	for _, i := range rand.Perm(len(m.active)) {
-		if len(peers) == n {
-			break
-		}
-
-		mp := m.active[i]
-		if mp.verifiedCount < minVerified {
-			continue
-		}
-		peers = append(peers, unwrapPeer(mp))
-	}
-
-	return peers
-}
-
-// getVerifiedPeers returns all the currently managed peers that have been verified at least once.
-func (m *manager) getVerifiedPeers() []*mpeer {
-	m.mutex.Lock()
-	defer m.mutex.Unlock()
-
-	peers := make([]*mpeer, 0, len(m.active))
-	for _, mp := range m.active {
-		if mp.verifiedCount == 0 {
-			continue
-		}
-		peers = append(peers, mp)
-	}
-
-	return peers
-}
-
-// isKnown returns true if the manager is keeping track of that peer.
-func (m *manager) isKnown(id peer.ID) bool {
-	if id == m.self() {
-		return true
-	}
-
-	m.mutex.Lock()
-	defer m.mutex.Unlock()
-
-	return containsPeer(m.active, id) || containsPeer(m.replacements, id)
-}
diff --git a/packages/autopeering/discover/manager_test.go b/packages/autopeering/discover/manager_test.go
deleted file mode 100644
index 1ae1494d..00000000
--- a/packages/autopeering/discover/manager_test.go
+++ /dev/null
@@ -1,168 +0,0 @@
-package discover
-
-import (
-	"fmt"
-	"testing"
-	"time"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/peertest"
-	"github.com/iotaledger/goshimmer/packages/autopeering/server"
-	"github.com/iotaledger/goshimmer/packages/database/mapdb"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/mock"
-	"github.com/stretchr/testify/require"
-)
-
-func TestMgrClose(t *testing.T) {
-	_, _, teardown := newManagerTest(t)
-	defer teardown()
-
-	time.Sleep(graceTime)
-}
-
-func TestMgrVerifyDiscoveredPeer(t *testing.T) {
-	mgr, m, teardown := newManagerTest(t)
-	defer teardown()
-
-	p := peertest.NewPeer(testNetwork, "p")
-
-	// expect Ping of peer p
-	m.On("Ping", p).Return(nil).Once()
-	// ignore DiscoveryRequest calls
-	m.On("DiscoveryRequest", mock.Anything).Return([]*peer.Peer{}, nil).Maybe()
-
-	// let the manager initialize
-	time.Sleep(graceTime)
-
-	mgr.addDiscoveredPeer(p)
-
-	mgr.doReverify(make(chan struct{})) // manually trigger a verify
-	m.AssertExpectations(t)
-}
-
-func TestMgrReverifyPeer(t *testing.T) {
-	mgr, m, teardown := newManagerTest(t)
-	defer teardown()
-
-	p := peertest.NewPeer(testNetwork, "p")
-
-	// expect Ping of peer p
-	m.On("Ping", p).Return(nil).Once()
-	// ignore DiscoveryRequest calls
-	m.On("DiscoveryRequest", mock.Anything).Return([]*peer.Peer{}, nil).Maybe()
-
-	// let the manager initialize
-	time.Sleep(graceTime)
-
-	mgr.addVerifiedPeer(p)
-
-	mgr.doReverify(make(chan struct{})) // manually trigger a verify
-	m.AssertExpectations(t)
-}
-
-func TestMgrRequestDiscoveredPeer(t *testing.T) {
-	mgr, m, teardown := newManagerTest(t)
-	defer teardown()
-
-	p1 := peertest.NewPeer(testNetwork, "verified")
-	p2 := peertest.NewPeer(testNetwork, "discovered")
-
-	// expect DiscoveryRequest on the discovered peer
-	m.On("DiscoveryRequest", p1).Return([]*peer.Peer{p2}, nil).Once()
-	// ignore any Ping
-	m.On("Ping", mock.Anything).Return(nil).Maybe()
-
-	mgr.addVerifiedPeer(p1)
-	mgr.addDiscoveredPeer(p2)
-
-	mgr.doQuery(make(chan time.Duration, 1)) // manually trigger a query
-	m.AssertExpectations(t)
-}
-
-func TestMgrAddManyVerifiedPeers(t *testing.T) {
-	mgr, m, teardown := newManagerTest(t)
-	defer teardown()
-
-	p := peertest.NewPeer(testNetwork, "p")
-
-	// expect Ping of peer p
-	m.On("Ping", p).Return(nil).Once()
-	// ignore DiscoveryRequest calls
-	m.On("DiscoveryRequest", mock.Anything).Return([]*peer.Peer{}, nil).Maybe()
-
-	// let the manager initialize
-	time.Sleep(graceTime)
-
-	mgr.addVerifiedPeer(p)
-	for i := 0; i < maxManaged+maxReplacements; i++ {
-		mgr.addVerifiedPeer(peertest.NewPeer(testNetwork, fmt.Sprintf("p%d", i)))
-	}
-
-	mgr.doReverify(make(chan struct{})) // manually trigger a verify
-	ps := unwrapPeers(mgr.getVerifiedPeers())
-
-	assert.Equal(t, maxManaged, len(ps))
-	assert.Contains(t, ps, p)
-
-	m.AssertExpectations(t)
-}
-
-func TestMgrDeleteUnreachablePeer(t *testing.T) {
-	mgr, m, teardown := newManagerTest(t)
-	defer teardown()
-
-	p := peertest.NewPeer(testNetwork, "p")
-
-	// expect Ping of peer p, but return error
-	m.On("Ping", p).Return(server.ErrTimeout).Times(1)
-	// ignore DiscoveryRequest calls
-	m.On("DiscoveryRequest", mock.Anything).Return([]*peer.Peer{}, nil).Maybe()
-
-	// let the manager initialize
-	time.Sleep(graceTime)
-
-	mgr.addVerifiedPeer(p)
-	for i := 0; i < maxManaged; i++ {
-		mgr.addVerifiedPeer(peertest.NewPeer(testNetwork, fmt.Sprintf("p%d", i)))
-	}
-
-	mgr.doReverify(make(chan struct{})) // manually trigger a verify
-	ps := unwrapPeers(mgr.getVerifiedPeers())
-
-	assert.Equal(t, maxManaged, len(ps))
-	assert.NotContains(t, ps, p)
-
-	m.AssertExpectations(t)
-}
-
-type NetworkMock struct {
-	mock.Mock
-
-	loc *peer.Local
-}
-
-func newManagerTest(t require.TestingT) (*manager, *NetworkMock, func()) {
-	db, err := peer.NewDB(mapdb.NewMapDB())
-	require.NoError(t, err)
-	local := peertest.NewLocal(testNetwork, testAddress, db)
-	networkMock := &NetworkMock{
-		loc: local,
-	}
-	mgr := newManager(networkMock, nil, log)
-	return mgr, networkMock, mgr.close
-}
-
-func (m *NetworkMock) local() *peer.Local {
-	return m.loc
-}
-
-func (m *NetworkMock) Ping(p *peer.Peer) error {
-	args := m.Called(p)
-	return args.Error(0)
-}
-
-func (m *NetworkMock) DiscoveryRequest(p *peer.Peer) ([]*peer.Peer, error) {
-	args := m.Called(p)
-	return args.Get(0).([]*peer.Peer), args.Error(1)
-}
diff --git a/packages/autopeering/discover/mpeer.go b/packages/autopeering/discover/mpeer.go
deleted file mode 100644
index 7116ad85..00000000
--- a/packages/autopeering/discover/mpeer.go
+++ /dev/null
@@ -1,95 +0,0 @@
-package discover
-
-import (
-	"fmt"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-)
-
-// mpeer represents a discovered peer with additional data.
-// The fields of Peer may not be modified.
-type mpeer struct {
-	peer.Peer
-
-	verifiedCount uint // how often that peer has been reverified
-	lastNewPeers  uint // number of returned new peers when queried the last time
-}
-
-func wrapPeer(p *peer.Peer) *mpeer {
-	return &mpeer{Peer: *p}
-}
-
-func unwrapPeer(p *mpeer) *peer.Peer {
-	return &p.Peer
-}
-
-func unwrapPeers(ps []*mpeer) []*peer.Peer {
-	result := make([]*peer.Peer, len(ps))
-	for i, n := range ps {
-		result[i] = unwrapPeer(n)
-	}
-	return result
-}
-
-// containsPeer returns true if a peer with the given ID is in the list.
-func containsPeer(list []*mpeer, id peer.ID) bool {
-	for _, p := range list {
-		if p.ID() == id {
-			return true
-		}
-	}
-	return false
-}
-
-// unshiftPeer adds a new peer to the front of the list.
-// If the list already contains max peers, the last is discarded.
-func unshiftPeer(list []*mpeer, p *mpeer, max int) []*mpeer {
-	if len(list) > max {
-		panic(fmt.Sprintf("mpeer: invalid max value %d", max))
-	}
-	if len(list) < max {
-		list = append(list, nil)
-	}
-	copy(list[1:], list)
-	list[0] = p
-
-	return list
-}
-
-// deletePeer is a helper that deletes the peer with the given index from the list.
-func deletePeer(list []*mpeer, i int) ([]*mpeer, *mpeer) {
-	if i >= len(list) {
-		panic("mpeer: invalid index or empty mpeer list")
-	}
-	p := list[i]
-
-	copy(list[i:], list[i+1:])
-	list[len(list)-1] = nil
-
-	return list[:len(list)-1], p
-}
-
-// deletePeerByID deletes the peer with the given ID from the list.
-func deletePeerByID(list []*mpeer, id peer.ID) ([]*mpeer, *mpeer) {
-	for i, p := range list {
-		if p.ID() == id {
-			return deletePeer(list, i)
-		}
-	}
-	panic("mpeer: id not contained in list")
-}
-
-// pushPeer adds the given peer to the pack of the list.
-// If the list already contains max peers, the first is discarded.
-func pushPeer(list []*mpeer, p *mpeer, max int) []*mpeer {
-	if len(list) > max {
-		panic(fmt.Sprintf("mpeer: invalid max value %d", max))
-	}
-	if len(list) == max {
-		copy(list, list[1:])
-		list[len(list)-1] = p
-		return list
-	}
-
-	return append(list, p)
-}
diff --git a/packages/autopeering/discover/mpeer_test.go b/packages/autopeering/discover/mpeer_test.go
deleted file mode 100644
index f917382d..00000000
--- a/packages/autopeering/discover/mpeer_test.go
+++ /dev/null
@@ -1,189 +0,0 @@
-package discover
-
-import (
-	"fmt"
-	"testing"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/peertest"
-	"github.com/stretchr/testify/assert"
-)
-
-func TestUnwrapPeers(t *testing.T) {
-	m := make([]*mpeer, 5)
-	p := make([]*peer.Peer, 5)
-	for i := range m {
-		p[i] = peertest.NewPeer(testNetwork, fmt.Sprintf("%d", i))
-		m[i] = &mpeer{Peer: *p[i]}
-	}
-
-	unwrapP := unwrapPeers(m)
-	assert.Equal(t, p, unwrapP, "unwrapPeers")
-}
-
-func TestContainsPeer(t *testing.T) {
-	m := make([]*mpeer, 5)
-	p := make([]*peer.Peer, 5)
-	k := peertest.NewPeer(testNetwork, "k")
-	for i := range m {
-		p[i] = peertest.NewPeer(testNetwork, fmt.Sprintf("%d", i))
-		m[i] = &mpeer{Peer: *p[i]}
-	}
-
-	for i := range m {
-		assert.Equal(t, true, containsPeer(m, p[i].ID()), "Contains")
-	}
-	assert.Equal(t, false, containsPeer(m, k.ID()), "Contains")
-}
-
-func TestUnshiftPeer(t *testing.T) {
-	m := make([]*mpeer, 5)
-	for i := range m {
-		m[i] = &mpeer{Peer: *peertest.NewPeer(testNetwork, fmt.Sprintf("%d", i))}
-	}
-
-	type testCase struct {
-		input    []*mpeer
-		toAdd    *mpeer
-		expected []*mpeer
-	}
-
-	tests := []testCase{
-		{
-			input:    []*mpeer{},
-			toAdd:    m[0],
-			expected: []*mpeer{m[0]},
-		},
-		{
-			input:    []*mpeer{m[0]},
-			toAdd:    m[1],
-			expected: []*mpeer{m[1], m[0]},
-		},
-		{
-			input:    []*mpeer{m[0], m[1]},
-			toAdd:    m[2],
-			expected: []*mpeer{m[2], m[0], m[1]},
-		},
-		{
-			input:    []*mpeer{m[0], m[1], m[2], m[3]},
-			toAdd:    m[4],
-			expected: []*mpeer{m[4], m[0], m[1], m[2]},
-		},
-	}
-
-	for _, test := range tests {
-		test.input = unshiftPeer(test.input, test.toAdd, len(m)-1)
-		assert.Equal(t, test.expected, test.input, "unshiftPeer")
-	}
-}
-
-func TestDeletePeer(t *testing.T) {
-	m := make([]*mpeer, 5)
-	for i := range m {
-		m[i] = &mpeer{Peer: *peertest.NewPeer(testNetwork, fmt.Sprintf("%d", i))}
-	}
-
-	type testCase struct {
-		input    []*mpeer
-		toRemove int
-		expected []*mpeer
-		deleted  *mpeer
-	}
-
-	tests := []testCase{
-		{
-			input:    []*mpeer{m[0]},
-			toRemove: 0,
-			expected: []*mpeer{},
-			deleted:  m[0],
-		},
-		{
-			input:    []*mpeer{m[0], m[1], m[2], m[3]},
-			toRemove: 2,
-			expected: []*mpeer{m[0], m[1], m[3]},
-			deleted:  m[2],
-		},
-	}
-
-	for _, test := range tests {
-		var deleted *mpeer
-		test.input, deleted = deletePeer(test.input, test.toRemove)
-		assert.Equal(t, test.expected, test.input, "deletePeer_list")
-		assert.Equal(t, test.deleted, deleted, "deletePeer_peer")
-	}
-}
-
-func TestDeletePeerByID(t *testing.T) {
-	m := make([]*mpeer, 5)
-	p := make([]*peer.Peer, 5)
-	for i := range m {
-		p[i] = peertest.NewPeer(testNetwork, fmt.Sprintf("%d", i))
-		m[i] = &mpeer{Peer: *p[i]}
-	}
-
-	type testCase struct {
-		input    []*mpeer
-		toRemove peer.ID
-		expected []*mpeer
-		deleted  *mpeer
-	}
-
-	tests := []testCase{
-		{
-			input:    []*mpeer{m[0]},
-			toRemove: p[0].ID(),
-			expected: []*mpeer{},
-			deleted:  m[0],
-		},
-		{
-			input:    []*mpeer{m[0], m[1], m[2], m[3]},
-			toRemove: p[2].ID(),
-			expected: []*mpeer{m[0], m[1], m[3]},
-			deleted:  m[2],
-		},
-	}
-
-	for _, test := range tests {
-		var deleted *mpeer
-		test.input, deleted = deletePeerByID(test.input, test.toRemove)
-		assert.Equal(t, test.expected, test.input, "deletePeerByID_list")
-		assert.Equal(t, test.deleted, deleted, "deletePeerByID_peer")
-	}
-}
-
-func TestPushPeer(t *testing.T) {
-	m := make([]*mpeer, 5)
-	max := len(m) - 1
-	for i := range m {
-		m[i] = &mpeer{Peer: *peertest.NewPeer(testNetwork, fmt.Sprintf("%d", i))}
-	}
-
-	type testCase struct {
-		input    []*mpeer
-		toPush   *mpeer
-		expected []*mpeer
-	}
-
-	tests := []testCase{
-		{
-			input:    []*mpeer{},
-			toPush:   m[0],
-			expected: []*mpeer{m[0]},
-		},
-		{
-			input:    []*mpeer{m[0], m[1]},
-			toPush:   m[2],
-			expected: []*mpeer{m[0], m[1], m[2]},
-		},
-		{
-			input:    []*mpeer{m[0], m[1], m[2], m[3]},
-			toPush:   m[4],
-			expected: []*mpeer{m[1], m[2], m[3], m[4]},
-		},
-	}
-
-	for _, test := range tests {
-		test.input = pushPeer(test.input, test.toPush, max)
-		assert.Equal(t, test.expected, test.input, "pushPeer")
-	}
-}
diff --git a/packages/autopeering/discover/proto/message.go b/packages/autopeering/discover/proto/message.go
deleted file mode 100644
index d7516862..00000000
--- a/packages/autopeering/discover/proto/message.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package proto
-
-import (
-	"github.com/golang/protobuf/proto"
-	"github.com/iotaledger/goshimmer/packages/autopeering/server"
-)
-
-// MType is the type of message type enum.
-type MType = server.MType
-
-// An enum for the different message types.
-const (
-	MPing MType = 10 + iota
-	MPong
-	MDiscoveryRequest
-	MDiscoveryResponse
-)
-
-// Message extends the proto.Message interface with additional util functions.
-type Message interface {
-	proto.Message
-
-	// Name returns the name of the corresponding message type for debugging.
-	Name() string
-	// Type returns the type of the corresponding message as an enum.
-	Type() MType
-}
-
-func (m *Ping) Name() string { return "PING" }
-func (m *Ping) Type() MType  { return MPing }
-
-func (m *Pong) Name() string { return "PONG" }
-func (m *Pong) Type() MType  { return MPong }
-
-func (m *DiscoveryRequest) Name() string { return "DISCOVERY_REQUEST" }
-func (m *DiscoveryRequest) Type() MType  { return MDiscoveryRequest }
-
-func (m *DiscoveryResponse) Name() string { return "DISCOVERY_RESPONSE" }
-func (m *DiscoveryResponse) Type() MType  { return MDiscoveryResponse }
diff --git a/packages/autopeering/discover/proto/message.pb.go b/packages/autopeering/discover/proto/message.pb.go
deleted file mode 100644
index f130a59e..00000000
--- a/packages/autopeering/discover/proto/message.pb.go
+++ /dev/null
@@ -1,280 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// source: discover/proto/message.proto
-
-package proto
-
-import (
-	fmt "fmt"
-	math "math"
-
-	proto "github.com/golang/protobuf/proto"
-	proto2 "github.com/iotaledger/goshimmer/packages/autopeering/peer/proto"
-	proto1 "github.com/iotaledger/goshimmer/packages/autopeering/peer/service/proto"
-)
-
-// Reference imports to suppress errors if they are not otherwise used.
-var _ = proto.Marshal
-var _ = fmt.Errorf
-var _ = math.Inf
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the proto package it is being compiled against.
-// A compilation error at this line likely means your copy of the
-// proto package needs to be updated.
-const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
-
-type Ping struct {
-	// protocol version number
-	Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
-	// string form of the return address (e.g. "192.0.2.1:25", "[2001:db8::1]:80")
-	From string `protobuf:"bytes,2,opt,name=from,proto3" json:"from,omitempty"`
-	// string form of the recipient address
-	To string `protobuf:"bytes,3,opt,name=to,proto3" json:"to,omitempty"`
-	// unix time
-	Timestamp            int64    `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
-
-func (m *Ping) Reset()         { *m = Ping{} }
-func (m *Ping) String() string { return proto.CompactTextString(m) }
-func (*Ping) ProtoMessage()    {}
-func (*Ping) Descriptor() ([]byte, []int) {
-	return fileDescriptor_43f14146485f66eb, []int{0}
-}
-
-func (m *Ping) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_Ping.Unmarshal(m, b)
-}
-func (m *Ping) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_Ping.Marshal(b, m, deterministic)
-}
-func (m *Ping) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_Ping.Merge(m, src)
-}
-func (m *Ping) XXX_Size() int {
-	return xxx_messageInfo_Ping.Size(m)
-}
-func (m *Ping) XXX_DiscardUnknown() {
-	xxx_messageInfo_Ping.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_Ping proto.InternalMessageInfo
-
-func (m *Ping) GetVersion() uint32 {
-	if m != nil {
-		return m.Version
-	}
-	return 0
-}
-
-func (m *Ping) GetFrom() string {
-	if m != nil {
-		return m.From
-	}
-	return ""
-}
-
-func (m *Ping) GetTo() string {
-	if m != nil {
-		return m.To
-	}
-	return ""
-}
-
-func (m *Ping) GetTimestamp() int64 {
-	if m != nil {
-		return m.Timestamp
-	}
-	return 0
-}
-
-type Pong struct {
-	// hash of the ping packet
-	PingHash []byte `protobuf:"bytes,1,opt,name=ping_hash,json=pingHash,proto3" json:"ping_hash,omitempty"`
-	// string form of the recipient address
-	To string `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"`
-	// services supported by the sender
-	Services             *proto1.ServiceMap `protobuf:"bytes,3,opt,name=services,proto3" json:"services,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}           `json:"-"`
-	XXX_unrecognized     []byte             `json:"-"`
-	XXX_sizecache        int32              `json:"-"`
-}
-
-func (m *Pong) Reset()         { *m = Pong{} }
-func (m *Pong) String() string { return proto.CompactTextString(m) }
-func (*Pong) ProtoMessage()    {}
-func (*Pong) Descriptor() ([]byte, []int) {
-	return fileDescriptor_43f14146485f66eb, []int{1}
-}
-
-func (m *Pong) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_Pong.Unmarshal(m, b)
-}
-func (m *Pong) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_Pong.Marshal(b, m, deterministic)
-}
-func (m *Pong) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_Pong.Merge(m, src)
-}
-func (m *Pong) XXX_Size() int {
-	return xxx_messageInfo_Pong.Size(m)
-}
-func (m *Pong) XXX_DiscardUnknown() {
-	xxx_messageInfo_Pong.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_Pong proto.InternalMessageInfo
-
-func (m *Pong) GetPingHash() []byte {
-	if m != nil {
-		return m.PingHash
-	}
-	return nil
-}
-
-func (m *Pong) GetTo() string {
-	if m != nil {
-		return m.To
-	}
-	return ""
-}
-
-func (m *Pong) GetServices() *proto1.ServiceMap {
-	if m != nil {
-		return m.Services
-	}
-	return nil
-}
-
-type DiscoveryRequest struct {
-	// string form of the recipient address
-	To string `protobuf:"bytes,1,opt,name=to,proto3" json:"to,omitempty"`
-	// unix time
-	Timestamp            int64    `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
-
-func (m *DiscoveryRequest) Reset()         { *m = DiscoveryRequest{} }
-func (m *DiscoveryRequest) String() string { return proto.CompactTextString(m) }
-func (*DiscoveryRequest) ProtoMessage()    {}
-func (*DiscoveryRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_43f14146485f66eb, []int{2}
-}
-
-func (m *DiscoveryRequest) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_DiscoveryRequest.Unmarshal(m, b)
-}
-func (m *DiscoveryRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_DiscoveryRequest.Marshal(b, m, deterministic)
-}
-func (m *DiscoveryRequest) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_DiscoveryRequest.Merge(m, src)
-}
-func (m *DiscoveryRequest) XXX_Size() int {
-	return xxx_messageInfo_DiscoveryRequest.Size(m)
-}
-func (m *DiscoveryRequest) XXX_DiscardUnknown() {
-	xxx_messageInfo_DiscoveryRequest.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_DiscoveryRequest proto.InternalMessageInfo
-
-func (m *DiscoveryRequest) GetTo() string {
-	if m != nil {
-		return m.To
-	}
-	return ""
-}
-
-func (m *DiscoveryRequest) GetTimestamp() int64 {
-	if m != nil {
-		return m.Timestamp
-	}
-	return 0
-}
-
-type DiscoveryResponse struct {
-	// hash of the corresponding request
-	ReqHash []byte `protobuf:"bytes,1,opt,name=req_hash,json=reqHash,proto3" json:"req_hash,omitempty"`
-	// list of peers
-	Peers                []*proto2.Peer `protobuf:"bytes,2,rep,name=peers,proto3" json:"peers,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}       `json:"-"`
-	XXX_unrecognized     []byte         `json:"-"`
-	XXX_sizecache        int32          `json:"-"`
-}
-
-func (m *DiscoveryResponse) Reset()         { *m = DiscoveryResponse{} }
-func (m *DiscoveryResponse) String() string { return proto.CompactTextString(m) }
-func (*DiscoveryResponse) ProtoMessage()    {}
-func (*DiscoveryResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_43f14146485f66eb, []int{3}
-}
-
-func (m *DiscoveryResponse) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_DiscoveryResponse.Unmarshal(m, b)
-}
-func (m *DiscoveryResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_DiscoveryResponse.Marshal(b, m, deterministic)
-}
-func (m *DiscoveryResponse) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_DiscoveryResponse.Merge(m, src)
-}
-func (m *DiscoveryResponse) XXX_Size() int {
-	return xxx_messageInfo_DiscoveryResponse.Size(m)
-}
-func (m *DiscoveryResponse) XXX_DiscardUnknown() {
-	xxx_messageInfo_DiscoveryResponse.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_DiscoveryResponse proto.InternalMessageInfo
-
-func (m *DiscoveryResponse) GetReqHash() []byte {
-	if m != nil {
-		return m.ReqHash
-	}
-	return nil
-}
-
-func (m *DiscoveryResponse) GetPeers() []*proto2.Peer {
-	if m != nil {
-		return m.Peers
-	}
-	return nil
-}
-
-func init() {
-	proto.RegisterType((*Ping)(nil), "proto.Ping")
-	proto.RegisterType((*Pong)(nil), "proto.Pong")
-	proto.RegisterType((*DiscoveryRequest)(nil), "proto.DiscoveryRequest")
-	proto.RegisterType((*DiscoveryResponse)(nil), "proto.DiscoveryResponse")
-}
-
-func init() { proto.RegisterFile("discover/proto/message.proto", fileDescriptor_43f14146485f66eb) }
-
-var fileDescriptor_43f14146485f66eb = []byte{
-	// 309 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x91, 0xc1, 0x4b, 0xc3, 0x30,
-	0x14, 0xc6, 0x59, 0xd7, 0xb9, 0xf6, 0x4d, 0xc5, 0x05, 0x84, 0x3a, 0x77, 0x98, 0x3b, 0x79, 0x59,
-	0x0b, 0x2a, 0x9e, 0x45, 0x3c, 0x78, 0x11, 0x66, 0xbc, 0x79, 0x91, 0xb4, 0x8b, 0x6d, 0xc0, 0x36,
-	0x59, 0x93, 0x0e, 0xfc, 0xef, 0x7d, 0x4d, 0x63, 0x9d, 0xe2, 0x29, 0xef, 0x7d, 0xef, 0xf1, 0x7d,
-	0xbf, 0x24, 0x30, 0xdf, 0x08, 0x9d, 0xc9, 0x1d, 0xaf, 0x13, 0x55, 0x4b, 0x23, 0x93, 0x92, 0x6b,
-	0xcd, 0x72, 0x1e, 0xdb, 0x8e, 0x8c, 0xec, 0x31, 0x3b, 0x55, 0xbc, 0x5f, 0x68, 0xcb, 0x6e, 0x3a,
-	0x5b, 0x58, 0x59, 0xf3, 0x7a, 0x27, 0x32, 0xee, 0xc6, 0xae, 0xeb, 0x36, 0x96, 0x29, 0xf8, 0x6b,
-	0x51, 0xe5, 0x24, 0x82, 0x31, 0x46, 0x68, 0x21, 0xab, 0x68, 0xb0, 0x18, 0x5c, 0x1e, 0xd1, 0xef,
-	0x96, 0x10, 0xf0, 0xdf, 0x6b, 0x59, 0x46, 0x1e, 0xca, 0x21, 0xb5, 0x35, 0x39, 0x06, 0xcf, 0xc8,
-	0x68, 0x68, 0x15, 0xac, 0xc8, 0x1c, 0x42, 0x23, 0x10, 0xcc, 0xb0, 0x52, 0x45, 0x3e, 0xca, 0x43,
-	0xfa, 0x23, 0xd8, 0x0c, 0x89, 0x19, 0xe7, 0x10, 0x2a, 0xcc, 0x7a, 0x2b, 0x98, 0x2e, 0x6c, 0xca,
-	0x21, 0x0d, 0x5a, 0xe1, 0x11, 0x7b, 0x67, 0xe9, 0xf5, 0x96, 0x2b, 0x08, 0x1c, 0xa9, 0xb6, 0x41,
-	0x93, 0xab, 0x69, 0x87, 0x1c, 0xbf, 0x74, 0xf2, 0x13, 0x53, 0xb4, 0x5f, 0x59, 0xde, 0xc1, 0xc9,
-	0x83, 0x7b, 0xa7, 0x4f, 0xca, 0xb7, 0x0d, 0x46, 0x3b, 0xcb, 0xc1, 0xff, 0x94, 0xde, 0x5f, 0xca,
-	0x67, 0x98, 0xee, 0x39, 0x68, 0x25, 0x2b, 0xcd, 0xc9, 0x19, 0x04, 0x35, 0xdf, 0xee, 0x13, 0x8f,
-	0xb1, 0xb7, 0xc0, 0x17, 0x30, 0x6a, 0x5f, 0x57, 0xa3, 0xd3, 0x10, 0xe9, 0x26, 0x8e, 0x6e, 0x8d,
-	0x1a, 0xed, 0x26, 0xf7, 0xb7, 0xaf, 0x37, 0xb9, 0x30, 0x45, 0x93, 0xc6, 0x99, 0x2c, 0x13, 0x21,
-	0x0d, 0xfb, 0xe0, 0x9b, 0x1c, 0x7f, 0x84, 0x35, 0x46, 0xb6, 0x2b, 0x78, 0xf9, 0x95, 0x16, 0x65,
-	0xf2, 0xfb, 0x8b, 0xd3, 0x03, 0x7b, 0x5c, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0x4d, 0xa6, 0x1f,
-	0xce, 0xfb, 0x01, 0x00, 0x00,
-}
diff --git a/packages/autopeering/discover/proto/message.proto b/packages/autopeering/discover/proto/message.proto
deleted file mode 100644
index e76db4ea..00000000
--- a/packages/autopeering/discover/proto/message.proto
+++ /dev/null
@@ -1,42 +0,0 @@
-syntax = "proto3";
-
-option go_package = "github.com/iotaledger/goshimmer/packages/autopeering/discover/proto";
-
-package proto;
-
-import "peer/proto/peer.proto";
-import "peer/service/proto/service.proto";
-
-message Ping {
-  // protocol version number
-  uint32 version = 1;
-  // string form of the return address (e.g. "192.0.2.1:25", "[2001:db8::1]:80")
-  string from = 2;
-  // string form of the recipient address
-  string to = 3;
-  // unix time
-  int64 timestamp = 4;
-}
-
-message Pong {
-  // hash of the ping packet
-  bytes ping_hash = 1;
-  // string form of the recipient address
-  string to = 2;
-  // services supported by the sender
-  ServiceMap services = 3;
-}
-
-message DiscoveryRequest {
-  // string form of the recipient address
-  string to = 1;
-  // unix time
-  int64 timestamp = 2;
-}
-
-message DiscoveryResponse {
-  // hash of the corresponding request
-  bytes req_hash = 1;
-  // list of peers
-  repeated Peer peers = 2;
-}
diff --git a/packages/autopeering/discover/protocol.go b/packages/autopeering/discover/protocol.go
deleted file mode 100644
index 4b4ccb2e..00000000
--- a/packages/autopeering/discover/protocol.go
+++ /dev/null
@@ -1,492 +0,0 @@
-package discover
-
-import (
-	"bytes"
-	"errors"
-	"fmt"
-	"sync"
-	"time"
-
-	"github.com/golang/protobuf/proto"
-	pb "github.com/iotaledger/goshimmer/packages/autopeering/discover/proto"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	peerpb "github.com/iotaledger/goshimmer/packages/autopeering/peer/proto"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
-	"github.com/iotaledger/goshimmer/packages/autopeering/server"
-	"github.com/iotaledger/hive.go/backoff"
-	"github.com/iotaledger/hive.go/logger"
-	"github.com/iotaledger/hive.go/typeutils"
-)
-
-const (
-	maxRetries = 2
-	logSends   = true
-)
-
-//  policy for retrying failed network calls
-var retryPolicy = backoff.ExponentialBackOff(500*time.Millisecond, 1.5).With(
-	backoff.Jitter(0.5), backoff.MaxRetries(maxRetries))
-
-// The Protocol handles the peer discovery.
-// It responds to incoming messages and sends own requests when needed.
-type Protocol struct {
-	server.Protocol
-
-	loc *peer.Local    // local peer that runs the protocol
-	log *logger.Logger // logging
-
-	mgr       *manager // the manager handles the actual peer discovery and re-verification
-	running   *typeutils.AtomicBool
-	closeOnce sync.Once
-}
-
-// New creates a new discovery protocol.
-func New(local *peer.Local, cfg Config) *Protocol {
-	p := &Protocol{
-		Protocol: server.Protocol{},
-		loc:      local,
-		log:      cfg.Log,
-		running:  typeutils.NewAtomicBool(),
-	}
-	p.mgr = newManager(p, cfg.MasterPeers, cfg.Log.Named("mgr"))
-
-	return p
-}
-
-// Start starts the actual peer discovery over the provided Sender.
-func (p *Protocol) Start(s server.Sender) {
-	p.Protocol.Sender = s
-	p.mgr.start()
-	p.log.Debug("discover started")
-	p.running.Set()
-}
-
-// Close finalizes the protocol.
-func (p *Protocol) Close() {
-	p.closeOnce.Do(func() {
-		p.running.UnSet()
-		p.mgr.close()
-	})
-}
-
-// IsVerified checks whether the given peer has recently been verified a recent enough endpoint proof.
-func (p *Protocol) IsVerified(id peer.ID, addr string) bool {
-	return time.Since(p.loc.Database().LastPong(id, addr)) < PingExpiration
-}
-
-// EnsureVerified checks if the given peer has recently sent a Ping;
-// if not, we send a Ping to trigger a verification.
-func (p *Protocol) EnsureVerified(peer *peer.Peer) error {
-	if !p.hasVerified(peer.ID(), peer.Address()) {
-		if err := p.Ping(peer); err != nil {
-			return err
-		}
-		// Wait for them to Ping back and process our pong
-		time.Sleep(server.ResponseTimeout)
-	}
-	return nil
-}
-
-// GetVerifiedPeer returns the verified peer with the given ID, or nil if no such peer exists.
-func (p *Protocol) GetVerifiedPeer(id peer.ID, addr string) *peer.Peer {
-	for _, verified := range p.mgr.getVerifiedPeers() {
-		if verified.ID() == id && verified.Address() == addr {
-			return unwrapPeer(verified)
-		}
-	}
-	return nil
-}
-
-// GetVerifiedPeers returns all the currently managed peers that have been verified at least once.
-func (p *Protocol) GetVerifiedPeers() []*peer.Peer {
-	return unwrapPeers(p.mgr.getVerifiedPeers())
-}
-
-// HandleMessage responds to incoming peer discovery messages.
-func (p *Protocol) HandleMessage(s *server.Server, fromAddr string, fromID peer.ID, fromKey peer.PublicKey, data []byte) (bool, error) {
-	if !p.running.IsSet() {
-		return false, nil
-	}
-
-	switch pb.MType(data[0]) {
-	// Ping
-	case pb.MPing:
-		m := new(pb.Ping)
-		if err := proto.Unmarshal(data[1:], m); err != nil {
-			return true, fmt.Errorf("invalid message: %w", err)
-		}
-		if p.validatePing(fromAddr, m) {
-			p.handlePing(s, fromAddr, fromID, fromKey, data)
-		}
-
-	// Pong
-	case pb.MPong:
-		m := new(pb.Pong)
-		if err := proto.Unmarshal(data[1:], m); err != nil {
-			return true, fmt.Errorf("invalid message: %w", err)
-		}
-		if p.validatePong(s, fromAddr, fromID, m) {
-			p.handlePong(fromAddr, fromID, fromKey, m)
-		}
-
-	// DiscoveryRequest
-	case pb.MDiscoveryRequest:
-		m := new(pb.DiscoveryRequest)
-		if err := proto.Unmarshal(data[1:], m); err != nil {
-			return true, fmt.Errorf("invalid message: %w", err)
-		}
-		if p.validateDiscoveryRequest(fromAddr, fromID, m) {
-			p.handleDiscoveryRequest(s, fromAddr, data)
-		}
-
-	// DiscoveryResponse
-	case pb.MDiscoveryResponse:
-		m := new(pb.DiscoveryResponse)
-		if err := proto.Unmarshal(data[1:], m); err != nil {
-			return true, fmt.Errorf("invalid message: %w", err)
-		}
-		p.validateDiscoveryResponse(s, fromAddr, fromID, m)
-		// DiscoveryResponse messages are handled in the handleReply function of the validation
-
-	default:
-		return false, nil
-	}
-
-	return true, nil
-}
-
-// local returns the associated local peer of the neighbor selection.
-func (p *Protocol) local() *peer.Local {
-	return p.loc
-}
-
-// publicAddr returns the public address of the peering service in string representation.
-func (p *Protocol) publicAddr() string {
-	return p.loc.Services().Get(service.PeeringKey).String()
-}
-
-// ------ message senders ------
-
-// Ping sends a Ping to the specified peer and blocks until a reply is received or timeout.
-func (p *Protocol) Ping(to *peer.Peer) error {
-	return backoff.Retry(retryPolicy, func() error {
-		err := <-p.sendPing(to.Address(), to.ID())
-		if err != nil && !errors.Is(err, server.ErrTimeout) {
-			return backoff.Permanent(err)
-		}
-		return err
-	})
-}
-
-// sendPing sends a Ping to the specified address and expects a matching reply.
-// This method is non-blocking, but it returns a channel that can be used to query potential errors.
-func (p *Protocol) sendPing(toAddr string, toID peer.ID) <-chan error {
-	ping := newPing(p.publicAddr(), toAddr)
-	data := marshal(ping)
-
-	// compute the message hash
-	hash := server.PacketHash(data)
-	hashEqual := func(m interface{}) bool {
-		return bytes.Equal(m.(*pb.Pong).GetPingHash(), hash)
-	}
-
-	p.logSend(toAddr, ping)
-	return p.Protocol.SendExpectingReply(toAddr, toID, data, pb.MPong, hashEqual)
-}
-
-// DiscoveryRequest request known peers from the given target. This method blocks
-// until a response is received and the provided peers are returned.
-func (p *Protocol) DiscoveryRequest(to *peer.Peer) ([]*peer.Peer, error) {
-	if err := p.EnsureVerified(to); err != nil {
-		return nil, err
-	}
-
-	req := newDiscoveryRequest(to.Address())
-	data := marshal(req)
-
-	// compute the message hash
-	hash := server.PacketHash(data)
-
-	peers := make([]*peer.Peer, 0, MaxPeersInResponse)
-	callback := func(m interface{}) bool {
-		res := m.(*pb.DiscoveryResponse)
-		if !bytes.Equal(res.GetReqHash(), hash) {
-			return false
-		}
-
-		peers = peers[:0]
-		for _, protoPeer := range res.GetPeers() {
-			if p, _ := peer.FromProto(protoPeer); p != nil {
-				peers = append(peers, p)
-			}
-		}
-		return true
-	}
-
-	err := backoff.Retry(retryPolicy, func() error {
-		p.logSend(to.Address(), req)
-		err := <-p.Protocol.SendExpectingReply(to.Address(), to.ID(), data, pb.MDiscoveryResponse, callback)
-		if err != nil && !errors.Is(err, server.ErrTimeout) {
-			return backoff.Permanent(err)
-		}
-		return err
-	})
-	return peers, err
-}
-
-// ------ helper functions ------
-
-// hasVerified returns whether the given peer has recently verified the local peer.
-func (p *Protocol) hasVerified(id peer.ID, addr string) bool {
-	return time.Since(p.loc.Database().LastPing(id, addr)) < PingExpiration
-}
-
-func (p *Protocol) logSend(toAddr string, msg pb.Message) {
-	if logSends {
-		p.log.Debugw("send message", "type", msg.Name(), "addr", toAddr)
-	}
-}
-
-func marshal(msg pb.Message) []byte {
-	mType := msg.Type()
-	if mType > 0xFF {
-		panic("invalid message")
-	}
-
-	data, err := proto.Marshal(msg)
-	if err != nil {
-		panic("invalid message")
-	}
-	return append([]byte{byte(mType)}, data...)
-}
-
-// newPeer creates a new peer that only has a peering service at the given address.
-func newPeer(key peer.PublicKey, network string, address string) *peer.Peer {
-	services := service.New()
-	services.Update(service.PeeringKey, network, address)
-
-	return peer.NewPeer(key, services)
-}
-
-// ------ Message Constructors ------
-
-func newPing(fromAddr string, toAddr string) *pb.Ping {
-	return &pb.Ping{
-		Version:   VersionNum,
-		From:      fromAddr,
-		To:        toAddr,
-		Timestamp: time.Now().Unix(),
-	}
-}
-
-func newPong(toAddr string, reqData []byte, services *service.Record) *pb.Pong {
-	return &pb.Pong{
-		PingHash: server.PacketHash(reqData),
-		To:       toAddr,
-		Services: services.ToProto(),
-	}
-}
-
-func newDiscoveryRequest(toAddr string) *pb.DiscoveryRequest {
-	return &pb.DiscoveryRequest{
-		To:        toAddr,
-		Timestamp: time.Now().Unix(),
-	}
-}
-
-func newDiscoveryResponse(reqData []byte, list []*peer.Peer) *pb.DiscoveryResponse {
-	peers := make([]*peerpb.Peer, 0, len(list))
-	for _, p := range list {
-		peers = append(peers, p.ToProto())
-	}
-	return &pb.DiscoveryResponse{
-		ReqHash: server.PacketHash(reqData),
-		Peers:   peers,
-	}
-}
-
-// ------ Message Handlers ------
-
-func (p *Protocol) validatePing(fromAddr string, m *pb.Ping) bool {
-	// check version number
-	if m.GetVersion() != VersionNum {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"version", m.GetVersion(),
-			"want", VersionNum,
-		)
-		return false
-	}
-	// check that From matches the package sender address
-	if m.GetFrom() != fromAddr {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"from", m.GetFrom(),
-			"want", fromAddr,
-		)
-		return false
-	}
-	// check that To matches the local address
-	if m.GetTo() != p.publicAddr() {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"to", m.GetTo(),
-			"want", p.publicAddr(),
-		)
-		return false
-	}
-	// check Timestamp
-	if p.Protocol.IsExpired(m.GetTimestamp()) {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"timestamp", time.Unix(m.GetTimestamp(), 0),
-		)
-		return false
-	}
-
-	p.log.Debugw("valid message",
-		"type", m.Name(),
-		"addr", fromAddr,
-	)
-	return true
-}
-
-func (p *Protocol) handlePing(s *server.Server, fromAddr string, fromID peer.ID, fromKey peer.PublicKey, rawData []byte) {
-	// create and send the pong response
-	pong := newPong(fromAddr, rawData, p.loc.Services().CreateRecord())
-
-	p.logSend(fromAddr, pong)
-	s.Send(fromAddr, marshal(pong))
-
-	// if the peer is new or expired, send a Ping to verify
-	if !p.IsVerified(fromID, fromAddr) {
-		p.sendPing(fromAddr, fromID)
-	} else if !p.mgr.isKnown(fromID) { // add a discovered peer to the manager if it is new
-		p.mgr.addDiscoveredPeer(newPeer(fromKey, s.LocalAddr().Network(), fromAddr))
-	}
-
-	_ = p.loc.Database().UpdateLastPing(fromID, fromAddr, time.Now())
-}
-
-func (p *Protocol) validatePong(s *server.Server, fromAddr string, fromID peer.ID, m *pb.Pong) bool {
-	// check that To matches the local address
-	if m.GetTo() != p.publicAddr() {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"to", m.GetTo(),
-			"want", p.publicAddr(),
-		)
-		return false
-	}
-	// there must be a Ping waiting for this pong as a reply
-	if !s.IsExpectedReply(fromAddr, fromID, m.Type(), m) {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"unexpected", fromAddr,
-		)
-		return false
-	}
-	// there must a valid number of services
-	numServices := len(m.GetServices().GetMap())
-	if numServices <= 0 || numServices > MaxServices {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"#peers", numServices,
-		)
-		return false
-	}
-
-	p.log.Debugw("valid message",
-		"type", m.Name(),
-		"addr", fromAddr,
-	)
-	return true
-}
-
-func (p *Protocol) handlePong(fromAddr string, fromID peer.ID, fromKey peer.PublicKey, m *pb.Pong) {
-	services, _ := service.FromProto(m.GetServices())
-	peering := services.Get(service.PeeringKey)
-	if peering == nil || peering.String() != fromAddr {
-		p.log.Warn("invalid services")
-		return
-	}
-
-	// create a proper key with these services
-	from := peer.NewPeer(fromKey, services)
-
-	// a valid pong verifies the peer
-	p.mgr.addVerifiedPeer(from)
-
-	// update peer database
-	db := p.loc.Database()
-	_ = db.UpdateLastPong(fromID, fromAddr, time.Now())
-	_ = db.UpdatePeer(from)
-}
-
-func (p *Protocol) validateDiscoveryRequest(fromAddr string, fromID peer.ID, m *pb.DiscoveryRequest) bool {
-	// check that To matches the local address
-	if m.GetTo() != p.publicAddr() {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"to", m.GetTo(),
-			"want", p.publicAddr(),
-		)
-		return false
-	}
-	// check Timestamp
-	if p.Protocol.IsExpired(m.GetTimestamp()) {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"timestamp", time.Unix(m.GetTimestamp(), 0),
-		)
-		return false
-	}
-	// check whether the sender is verified
-	if !p.IsVerified(fromID, fromAddr) {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"unverified", fromAddr,
-		)
-		return false
-	}
-
-	p.log.Debugw("valid message",
-		"type", m.Name(),
-		"addr", fromAddr,
-	)
-	return true
-}
-
-func (p *Protocol) handleDiscoveryRequest(s *server.Server, fromAddr string, rawData []byte) {
-	// get a random list of verified peers
-	peers := p.mgr.getRandomPeers(MaxPeersInResponse, 1)
-	res := newDiscoveryResponse(rawData, peers)
-
-	p.logSend(fromAddr, res)
-	s.Send(fromAddr, marshal(res))
-}
-
-func (p *Protocol) validateDiscoveryResponse(s *server.Server, fromAddr string, fromID peer.ID, m *pb.DiscoveryResponse) bool {
-	// there must not be too many peers
-	if len(m.GetPeers()) > MaxPeersInResponse {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"#peers", len(m.GetPeers()),
-		)
-		return false
-	}
-	// there must be a request waiting for this response
-	if !s.IsExpectedReply(fromAddr, fromID, m.Type(), m) {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"unexpected", fromAddr,
-		)
-		return false
-	}
-
-	p.log.Debugw("valid message",
-		"type", m.Name(),
-		"addr", fromAddr,
-	)
-	return true
-}
diff --git a/packages/autopeering/discover/protocol_test.go b/packages/autopeering/discover/protocol_test.go
deleted file mode 100644
index 2a584280..00000000
--- a/packages/autopeering/discover/protocol_test.go
+++ /dev/null
@@ -1,293 +0,0 @@
-package discover
-
-import (
-	"testing"
-	"time"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/peertest"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
-	"github.com/iotaledger/goshimmer/packages/autopeering/server"
-	"github.com/iotaledger/goshimmer/packages/autopeering/transport"
-	"github.com/iotaledger/goshimmer/packages/database/mapdb"
-	"github.com/iotaledger/hive.go/logger"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-	"go.uber.org/zap"
-)
-
-const (
-	testNetwork = "test"
-	testAddress = "test"
-	graceTime   = 100 * time.Millisecond
-)
-
-var log = logger.NewExampleLogger("discover")
-
-func init() {
-	// decrease parameters to simplify and speed up tests
-	SetParameter(Parameters{
-		ReverifyInterval: 500 * time.Millisecond,
-		QueryInterval:    1000 * time.Millisecond,
-		MaxManaged:       10,
-		MaxReplacements:  2,
-	})
-}
-
-func TestProtVerifyMaster(t *testing.T) {
-	p2p := transport.P2P()
-	defer p2p.Close()
-
-	protA, closeA := newTestProtocol(p2p.A, log)
-	defer closeA()
-
-	peerA := getPeer(protA)
-
-	// use peerA as masters peer
-	protB, closeB := newTestProtocol(p2p.B, log, peerA)
-
-	time.Sleep(graceTime) // wait for the packages to ripple through the network
-	closeB()              // close srvB to avoid race conditions, when asserting
-
-	if assert.EqualValues(t, 1, len(protB.mgr.active)) {
-		assert.EqualValues(t, peerA, &protB.mgr.active[0].Peer)
-		assert.EqualValues(t, 1, protB.mgr.active[0].verifiedCount)
-	}
-}
-
-func TestProtPingPong(t *testing.T) {
-	p2p := transport.P2P()
-	defer p2p.Close()
-
-	protA, closeA := newTestProtocol(p2p.A, log)
-	defer closeA()
-	protB, closeB := newTestProtocol(p2p.B, log)
-	defer closeB()
-
-	peerA := getPeer(protA)
-	peerB := getPeer(protB)
-
-	// send a Ping from node A to B
-	t.Run("A->B", func(t *testing.T) { assert.NoError(t, protA.Ping(peerB)) })
-	time.Sleep(graceTime)
-
-	// send a Ping from node B to A
-	t.Run("B->A", func(t *testing.T) { assert.NoError(t, protB.Ping(peerA)) })
-	time.Sleep(graceTime)
-}
-
-func TestProtPingTimeout(t *testing.T) {
-	p2p := transport.P2P()
-	defer p2p.Close()
-
-	protA, closeA := newTestProtocol(p2p.A, log)
-	defer closeA()
-	protB, closeB := newTestProtocol(p2p.B, log)
-	closeB() // close the connection right away to prevent any replies
-
-	// send a Ping from node A to B
-	err := protA.Ping(getPeer(protB))
-	assert.EqualError(t, err, server.ErrTimeout.Error())
-}
-
-func TestProtVerifiedPeers(t *testing.T) {
-	p2p := transport.P2P()
-	defer p2p.Close()
-
-	protA, closeA := newTestProtocol(p2p.A, log)
-	defer closeA()
-	protB, closeB := newTestProtocol(p2p.B, log)
-	defer closeB()
-
-	peerB := getPeer(protB)
-
-	// send a Ping from node A to B
-	assert.NoError(t, protA.Ping(peerB))
-	time.Sleep(graceTime)
-
-	// protA should have peerB as the single verified peer
-	assert.ElementsMatch(t, []*peer.Peer{peerB}, protA.GetVerifiedPeers())
-	for _, p := range protA.GetVerifiedPeers() {
-		assert.Equal(t, p, protA.GetVerifiedPeer(p.ID(), p.Address()))
-	}
-}
-
-func TestProtVerifiedPeer(t *testing.T) {
-	p2p := transport.P2P()
-	defer p2p.Close()
-
-	protA, closeA := newTestProtocol(p2p.A, log)
-	defer closeA()
-	protB, closeB := newTestProtocol(p2p.B, log)
-	defer closeB()
-
-	peerA := getPeer(protA)
-	peerB := getPeer(protB)
-
-	// send a Ping from node A to B
-	assert.NoError(t, protA.Ping(peerB))
-	time.Sleep(graceTime)
-
-	// we should have peerB as a verified peer
-	assert.Equal(t, peerB, protA.GetVerifiedPeer(peerB.ID(), peerB.Address()))
-	// we should not have ourselves as a verified peer
-	assert.Nil(t, protA.GetVerifiedPeer(peerA.ID(), peerA.Address()))
-	// the address of peerB should match
-	assert.Nil(t, protA.GetVerifiedPeer(peerB.ID(), ""))
-}
-
-func TestProtDiscoveryRequest(t *testing.T) {
-	p2p := transport.P2P()
-	defer p2p.Close()
-
-	protA, closeA := newTestProtocol(p2p.A, log)
-	defer closeA()
-	protB, closeB := newTestProtocol(p2p.B, log)
-	defer closeB()
-
-	peerA := getPeer(protA)
-	peerB := getPeer(protB)
-
-	// request peers from node A
-	t.Run("A->B", func(t *testing.T) {
-		if ps, err := protA.DiscoveryRequest(peerB); assert.NoError(t, err) {
-			assert.ElementsMatch(t, []*peer.Peer{peerA}, ps)
-		}
-	})
-	// request peers from node B
-	t.Run("B->A", func(t *testing.T) {
-		if ps, err := protB.DiscoveryRequest(peerA); assert.NoError(t, err) {
-			assert.ElementsMatch(t, []*peer.Peer{peerB}, ps)
-		}
-	})
-}
-
-func TestProtServices(t *testing.T) {
-	p2p := transport.P2P()
-	defer p2p.Close()
-
-	protA, closeA := newTestProtocol(p2p.A, log)
-	defer closeA()
-
-	err := protA.local().UpdateService(service.FPCKey, "fpc", p2p.A.LocalAddr().String())
-	require.NoError(t, err)
-
-	peerA := getPeer(protA)
-
-	// use peerA as masters peer
-	protB, closeB := newTestProtocol(p2p.B, log, peerA)
-	defer closeB()
-
-	time.Sleep(graceTime) // wait for the packages to ripple through the network
-	ps := protB.GetVerifiedPeers()
-
-	if assert.ElementsMatch(t, []*peer.Peer{peerA}, ps) {
-		assert.Equal(t, protA.local().Services(), ps[0].Services())
-	}
-}
-
-func TestProtDiscovery(t *testing.T) {
-	net := transport.NewNetwork("M", "A", "B", "C")
-	defer net.Close()
-
-	protM, closeM := newTestProtocol(net.GetTransport("M"), log)
-	defer closeM()
-	time.Sleep(graceTime) // wait for the master to initialize
-
-	protA, closeA := newTestProtocol(net.GetTransport("A"), log, getPeer(protM))
-	defer closeA()
-	protB, closeB := newTestProtocol(net.GetTransport("B"), log, getPeer(protM))
-	defer closeB()
-	protC, closeC := newTestProtocol(net.GetTransport("C"), log, getPeer(protM))
-	defer closeC()
-
-	time.Sleep(queryInterval + graceTime)    // wait for the next discovery cycle
-	time.Sleep(reverifyInterval + graceTime) // wait for the next verification cycle
-
-	// now the full network should be discovered
-	assert.ElementsMatch(t, []*peer.Peer{getPeer(protA), getPeer(protB), getPeer(protC)}, protM.GetVerifiedPeers())
-	assert.ElementsMatch(t, []*peer.Peer{getPeer(protM), getPeer(protB), getPeer(protC)}, protA.GetVerifiedPeers())
-	assert.ElementsMatch(t, []*peer.Peer{getPeer(protM), getPeer(protA), getPeer(protC)}, protB.GetVerifiedPeers())
-	assert.ElementsMatch(t, []*peer.Peer{getPeer(protM), getPeer(protA), getPeer(protB)}, protC.GetVerifiedPeers())
-}
-
-func BenchmarkPingPong(b *testing.B) {
-	p2p := transport.P2P()
-	defer p2p.Close()
-	log := zap.NewNop().Sugar() // disable logging
-
-	// disable query/reverify
-	reverifyInterval = time.Hour
-	queryInterval = time.Hour
-
-	protA, closeA := newTestProtocol(p2p.A, log)
-	defer closeA()
-	protB, closeB := newTestProtocol(p2p.B, log)
-	defer closeB()
-
-	peerB := getPeer(protB)
-
-	// send initial Ping to ensure that every peer is verified
-	err := protA.Ping(peerB)
-	require.NoError(b, err)
-	time.Sleep(graceTime)
-
-	b.ResetTimer()
-	for n := 0; n < b.N; n++ {
-		// send a Ping from node A to B
-		_ = protA.Ping(peerB)
-	}
-
-	b.StopTimer()
-}
-
-func BenchmarkDiscoveryRequest(b *testing.B) {
-	p2p := transport.P2P()
-	defer p2p.Close()
-	log := zap.NewNop().Sugar() // disable logging
-
-	// disable query/reverify
-	reverifyInterval = time.Hour
-	queryInterval = time.Hour
-
-	protA, closeA := newTestProtocol(p2p.A, log)
-	defer closeA()
-	protB, closeB := newTestProtocol(p2p.B, log)
-	defer closeB()
-
-	peerB := getPeer(protB)
-
-	// send initial DiscoveryRequest to ensure that every peer is verified
-	_, err := protA.DiscoveryRequest(peerB)
-	require.NoError(b, err)
-	time.Sleep(graceTime)
-
-	b.ResetTimer()
-	for n := 0; n < b.N; n++ {
-		_, _ = protA.DiscoveryRequest(peerB)
-	}
-
-	b.StopTimer()
-}
-
-// newTestProtocol creates a new discovery server and also returns the teardown.
-func newTestProtocol(trans transport.Transport, logger *logger.Logger, masters ...*peer.Peer) (*Protocol, func()) {
-	db, _ := peer.NewDB(mapdb.NewMapDB())
-	local := peertest.NewLocal(trans.LocalAddr().Network(), trans.LocalAddr().String(), db)
-	log := logger.Named(trans.LocalAddr().String())
-
-	prot := New(local, Config{Log: log, MasterPeers: masters})
-
-	srv := server.Serve(local, trans, log, prot)
-	prot.Start(srv)
-
-	teardown := func() {
-		srv.Close()
-		prot.Close()
-	}
-	return prot, teardown
-}
-
-func getPeer(p *Protocol) *peer.Peer {
-	return &p.local().Peer
-}
diff --git a/packages/autopeering/discover/query_strat.go b/packages/autopeering/discover/query_strat.go
deleted file mode 100644
index 0f70a6ba..00000000
--- a/packages/autopeering/discover/query_strat.go
+++ /dev/null
@@ -1,94 +0,0 @@
-package discover
-
-import (
-	"container/ring"
-	"math/rand"
-	"sync"
-	"time"
-)
-
-// doQuery is the main method of the query strategy.
-// It writes the next time this function should be called by the manager to next.
-// The current strategy is to always select the latest verified peer and one of
-// the peers that returned the most number of peers the last time it was queried.
-func (m *manager) doQuery(next chan<- time.Duration) {
-	defer func() { next <- queryInterval }()
-
-	ps := m.peersToQuery()
-	if len(ps) == 0 {
-		return
-	}
-	m.log.Debugw("querying",
-		"#peers", len(ps),
-	)
-
-	// request from peers in parallel
-	var wg sync.WaitGroup
-	wg.Add(len(ps))
-	for _, p := range ps {
-		go m.requestWorker(p, &wg)
-	}
-	wg.Wait()
-}
-
-func (m *manager) requestWorker(p *mpeer, wg *sync.WaitGroup) {
-	defer wg.Done()
-
-	peers, err := m.net.DiscoveryRequest(unwrapPeer(p))
-	if err != nil || len(peers) == 0 {
-		p.lastNewPeers = 0
-
-		m.log.Debugw("query failed",
-			"id", p.ID(),
-			"addr", p.Address(),
-			"err", err,
-		)
-		return
-	}
-
-	var added uint
-	for _, rp := range peers {
-		if m.addDiscoveredPeer(rp) {
-			added++
-		}
-	}
-	p.lastNewPeers = added
-
-	m.log.Debugw("queried",
-		"id", p.ID(),
-		"addr", p.Address(),
-		"#added", added,
-	)
-}
-
-// peersToQuery selects the peers that should be queried.
-func (m *manager) peersToQuery() []*mpeer {
-	ps := m.getVerifiedPeers()
-	if len(ps) == 0 {
-		return nil
-	}
-
-	latest := ps[0]
-	if len(ps) == 1 {
-		return []*mpeer{latest}
-	}
-
-	// find the 3 heaviest peers
-	r := ring.New(3)
-	for i, p := range ps {
-		if i == 0 {
-			continue // the latest peer is already included
-		}
-		if r.Value == nil {
-			r.Value = p
-		} else if p.lastNewPeers >= r.Value.(*mpeer).lastNewPeers {
-			r = r.Next()
-			r.Value = p
-		}
-	}
-
-	// select a random peer from the heaviest ones
-	r.Move(rand.Intn(r.Len()))
-
-	return []*mpeer{latest, r.Value.(*mpeer)}
-}
diff --git a/packages/autopeering/distance/consts.go b/packages/autopeering/distance/consts.go
deleted file mode 100644
index b51f994b..00000000
--- a/packages/autopeering/distance/consts.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package distance
-
-const (
-	Max = 4294967295
-)
diff --git a/packages/autopeering/distance/distance.go b/packages/autopeering/distance/distance.go
deleted file mode 100644
index 6a943b17..00000000
--- a/packages/autopeering/distance/distance.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package distance
-
-import (
-	"crypto/sha256"
-	"encoding/binary"
-)
-
-// BySalt returns the distance (uint32) between x and y
-// by xoring the hash of x and y + salt
-// xor(hash(x), hash(y+salt))[:4]
-func BySalt(x, y, salt []byte) uint32 {
-	return xorSHA32(x, joinBytes(y, salt))
-}
-
-func joinBytes(a, b []byte) (out []byte) {
-	out = make([]byte, len(a)+len(b))
-	copy(out[0:], a)
-	copy(out[len(a):], b)
-	return out
-}
-
-func xorSHA32(a, b []byte) uint32 {
-	return binary.LittleEndian.Uint32(
-		xorSHA(sha256.Sum256(a), sha256.Sum256(b))[:4])
-}
-
-func xorSHA(a, b [sha256.Size]byte) (out []byte) {
-	out = make([]byte, sha256.Size)
-	for i := 0; i < sha256.Size; i++ {
-		out[i] = a[i] ^ b[i]
-	}
-	return out
-}
diff --git a/packages/autopeering/distance/distance_test.go b/packages/autopeering/distance/distance_test.go
deleted file mode 100644
index 1f922748..00000000
--- a/packages/autopeering/distance/distance_test.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package distance
-
-import (
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-)
-
-func TestBySalt(t *testing.T) {
-	type testCase struct {
-		x            []byte
-		y            []byte
-		salt         []byte
-		zeroDistance bool
-	}
-
-	tests := []testCase{
-		{
-			x:            []byte("X"),
-			y:            []byte("Y"),
-			salt:         []byte("salt"),
-			zeroDistance: false,
-		},
-		{
-			x:            []byte("X"),
-			y:            []byte("X"),
-			salt:         []byte{},
-			zeroDistance: true,
-		},
-	}
-
-	for _, test := range tests {
-		d := BySalt(test.x, test.y, test.salt)
-		got := d == 0
-		assert.Equal(t, test.zeroDistance, got, "Zero Distance")
-	}
-
-}
diff --git a/packages/autopeering/peer/id.go b/packages/autopeering/peer/id.go
deleted file mode 100644
index 7365c433..00000000
--- a/packages/autopeering/peer/id.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package peer
-
-import (
-	"crypto/sha256"
-	"encoding/hex"
-	"fmt"
-	"strings"
-)
-
-// ID is a unique identifier for each peer.
-type ID [sha256.Size]byte
-
-// Bytes returns the byte slice representation of the ID
-func (id ID) Bytes() []byte {
-	return id[:]
-}
-
-// String returns a shortened version of the ID as a hex encoded string.
-func (id ID) String() string {
-	return hex.EncodeToString(id[:8])
-}
-
-// ParseID parses a hex encoded ID.
-func ParseID(s string) (ID, error) {
-	var id ID
-	b, err := hex.DecodeString(strings.TrimPrefix(s, "0x"))
-	if err != nil {
-		return id, err
-	}
-	if len(b) != len(ID{}) {
-		return id, fmt.Errorf("invalid length: need %d hex chars", hex.EncodedLen(len(ID{})))
-	}
-	copy(id[:], b)
-	return id, nil
-}
-
-// ID computes the ID corresponding to the given public key.
-func (k PublicKey) ID() ID {
-	return sha256.Sum256(k)
-}
diff --git a/packages/autopeering/peer/local.go b/packages/autopeering/peer/local.go
deleted file mode 100644
index e4a8861e..00000000
--- a/packages/autopeering/peer/local.go
+++ /dev/null
@@ -1,126 +0,0 @@
-package peer
-
-import (
-	"crypto/ed25519"
-	"fmt"
-	"sync"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
-	"github.com/iotaledger/goshimmer/packages/autopeering/salt"
-)
-
-// Local defines the struct of a local peer
-type Local struct {
-	Peer
-	key PrivateKey
-	db  *DB
-
-	// everything below is protected by a lock
-	mu            sync.RWMutex
-	serviceRecord *service.Record
-	publicSalt    *salt.Salt
-	privateSalt   *salt.Salt
-}
-
-// PrivateKey is the type of Ed25519 private keys used for the local peer.
-type PrivateKey ed25519.PrivateKey
-
-// Public returns the PublicKey corresponding to priv.
-func (priv PrivateKey) Public() PublicKey {
-	publicKey := ed25519.PrivateKey(priv).Public()
-	return PublicKey(publicKey.(ed25519.PublicKey))
-}
-
-// newLocal creates a new local peer.
-func newLocal(key PrivateKey, serviceRecord *service.Record, db *DB) *Local {
-	return &Local{
-		Peer:          *NewPeer(key.Public(), serviceRecord),
-		key:           key,
-		db:            db,
-		serviceRecord: serviceRecord,
-	}
-}
-
-// NewLocal creates a new local peer linked to the provided db.
-// If an optional seed is provided, the seed is used to generate the private key. Without a seed,
-// the provided key is loaded from the provided database and generated if not stored there.
-func NewLocal(serviceRecord *service.Record, db *DB, seed ...[]byte) (*Local, error) {
-	var key PrivateKey
-	if len(seed) > 0 {
-		key = PrivateKey(ed25519.NewKeyFromSeed(seed[0]))
-		if db != nil {
-			if err := db.UpdateLocalPrivateKey(key); err != nil {
-				return nil, err
-			}
-		}
-	} else {
-		var err error
-		key, err = db.LocalPrivateKey()
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	if l := len(key); l != ed25519.PrivateKeySize {
-		return nil, fmt.Errorf("invalid key length: %d, need %d", l, ed25519.PrivateKeySize)
-	}
-	return newLocal(key, serviceRecord, db), nil
-}
-
-// Database returns the node database associated with the local peer.
-func (l *Local) Database() *DB {
-	return l.db
-}
-
-// Sign signs the message with the local peer's private key and returns a signature.
-func (l *Local) Sign(message []byte) []byte {
-	return ed25519.Sign(ed25519.PrivateKey(l.key), message)
-}
-
-// UpdateService updates the endpoint address of the given local service.
-func (l *Local) UpdateService(key service.Key, network string, address string) error {
-	l.mu.Lock()
-	defer l.mu.Unlock()
-
-	// update the service in the read protected map
-	l.serviceRecord.Update(key, network, address)
-
-	// create a new peer with the corresponding services
-	l.Peer = *NewPeer(l.key.Public(), l.serviceRecord)
-
-	return nil
-}
-
-// GetPublicSalt returns the public salt
-func (l *Local) GetPublicSalt() *salt.Salt {
-	l.mu.RLock()
-	defer l.mu.RUnlock()
-	return l.publicSalt
-}
-
-// SetPublicSalt sets the public salt
-func (l *Local) SetPublicSalt(salt *salt.Salt) {
-	l.mu.Lock()
-	defer l.mu.Unlock()
-	l.publicSalt = salt
-}
-
-// GetPrivateSalt returns the private salt
-func (l *Local) GetPrivateSalt() *salt.Salt {
-	l.mu.RLock()
-	defer l.mu.RUnlock()
-	return l.privateSalt
-}
-
-// SetPrivateSalt sets the private salt
-func (l *Local) SetPrivateSalt(salt *salt.Salt) {
-	l.mu.Lock()
-	defer l.mu.Unlock()
-	l.privateSalt = salt
-}
-
-// generatePrivateKey generates a private key that can be used for Local.
-func generatePrivateKey() (PrivateKey, error) {
-	_, priv, err := ed25519.GenerateKey(nil)
-	return PrivateKey(priv), err
-}
diff --git a/packages/autopeering/peer/local_test.go b/packages/autopeering/peer/local_test.go
deleted file mode 100644
index 5d61bfd4..00000000
--- a/packages/autopeering/peer/local_test.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package peer
-
-import (
-	"crypto/ed25519"
-	"testing"
-	"time"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
-	"github.com/iotaledger/goshimmer/packages/autopeering/salt"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-func TestID(t *testing.T) {
-	pub, priv, err := ed25519.GenerateKey(nil)
-	require.NoError(t, err)
-
-	local := newLocal(PrivateKey(priv), newTestServiceRecord(), nil)
-	id := PublicKey(pub).ID()
-	assert.Equal(t, id, local.ID())
-}
-
-func TestPublicKey(t *testing.T) {
-	pub, priv, err := ed25519.GenerateKey(nil)
-	require.NoError(t, err)
-
-	local := newLocal(PrivateKey(priv), newTestServiceRecord(), nil)
-	assert.EqualValues(t, pub, local.PublicKey())
-}
-
-func TestAddress(t *testing.T) {
-	local := newTestLocal(t, nil)
-
-	address := local.Services().Get(service.PeeringKey).String()
-	assert.EqualValues(t, address, local.Address())
-}
-
-func TestPrivateSalt(t *testing.T) {
-	p := newTestLocal(t, nil)
-
-	s, _ := salt.NewSalt(time.Second * 10)
-	p.SetPrivateSalt(s)
-
-	got := p.GetPrivateSalt()
-	assert.Equal(t, s, got, "Private salt")
-}
-
-func TestPublicSalt(t *testing.T) {
-	p := newTestLocal(t, nil)
-
-	s, _ := salt.NewSalt(time.Second * 10)
-	p.SetPublicSalt(s)
-
-	got := p.GetPublicSalt()
-
-	assert.Equal(t, s, got, "Public salt")
-}
-
-func newTestLocal(t require.TestingT, db *DB) *Local {
-	var priv PrivateKey
-	var err error
-	if db == nil {
-		priv, err = generatePrivateKey()
-		require.NoError(t, err)
-	} else {
-		priv, err = db.LocalPrivateKey()
-		require.NoError(t, err)
-	}
-	services := service.New()
-	services.Update(service.PeeringKey, testNetwork, testAddress)
-	return newLocal(priv, services, db)
-}
diff --git a/packages/autopeering/peer/peer.go b/packages/autopeering/peer/peer.go
deleted file mode 100644
index cea34433..00000000
--- a/packages/autopeering/peer/peer.go
+++ /dev/null
@@ -1,143 +0,0 @@
-package peer
-
-import (
-	"crypto/ed25519"
-	"encoding/base64"
-	"errors"
-	"fmt"
-	"net/url"
-
-	"github.com/golang/protobuf/proto"
-	pb "github.com/iotaledger/goshimmer/packages/autopeering/peer/proto"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
-)
-
-// Errors in the peer package.
-var (
-	ErrNeedsPeeringService = errors.New("needs peering service")
-	ErrInvalidSignature    = errors.New("invalid signature")
-)
-
-// PublicKey is the type of Ed25519 public keys used for peers.
-type PublicKey ed25519.PublicKey
-
-// Peer defines the immutable data of a peer.
-type Peer struct {
-	id        ID              // comparable node identifier
-	publicKey PublicKey       // public key used to verify signatures
-	services  *service.Record // unmodifiable services supported by the peer
-}
-
-// ID returns the identifier of the peer.
-func (p *Peer) ID() ID {
-	return p.id
-}
-
-// PublicKey returns the public key of the peer.
-func (p *Peer) PublicKey() PublicKey {
-	return p.publicKey
-}
-
-// Network returns the autopeering network of the peer.
-func (p *Peer) Network() string {
-	return p.services.Get(service.PeeringKey).Network()
-}
-
-// Address returns the autopeering address of a peer.
-func (p *Peer) Address() string {
-	return p.services.Get(service.PeeringKey).String()
-}
-
-// Services returns the supported services of the peer.
-func (p *Peer) Services() service.Service {
-	return p.services
-}
-
-// String returns a string representation of the peer.
-func (p *Peer) String() string {
-	u := url.URL{
-		Scheme: "peer",
-		User:   url.User(base64.StdEncoding.EncodeToString(p.PublicKey())),
-		Host:   p.Address(),
-	}
-	return u.String()
-}
-
-// SignedData is an interface wrapper around data with key and signature.
-type SignedData interface {
-	GetData() []byte
-	GetPublicKey() []byte
-	GetSignature() []byte
-}
-
-// RecoverKeyFromSignedData validates and returns the key that was used to sign the data.
-func RecoverKeyFromSignedData(m SignedData) (PublicKey, error) {
-	return recoverKey(m.GetPublicKey(), m.GetData(), m.GetSignature())
-}
-
-// NewPeer creates a new unmodifiable peer.
-func NewPeer(publicKey PublicKey, services service.Service) *Peer {
-	if services.Get(service.PeeringKey) == nil {
-		panic("need peering service")
-	}
-
-	return &Peer{
-		id:        publicKey.ID(),
-		publicKey: publicKey,
-		services:  services.CreateRecord(),
-	}
-}
-
-// ToProto encodes a given peer into a proto buffer Peer message
-func (p *Peer) ToProto() *pb.Peer {
-	return &pb.Peer{
-		PublicKey: p.publicKey,
-		Services:  p.services.ToProto(),
-	}
-}
-
-// FromProto decodes a given proto buffer Peer message (in) and returns the corresponding Peer.
-func FromProto(in *pb.Peer) (*Peer, error) {
-	if l := len(in.GetPublicKey()); l != ed25519.PublicKeySize {
-		return nil, fmt.Errorf("invalid key length: %d, need %d", l, ed25519.PublicKeySize)
-	}
-	services, err := service.FromProto(in.GetServices())
-	if err != nil {
-		return nil, err
-	}
-	if services.Get(service.PeeringKey) == nil {
-		return nil, ErrNeedsPeeringService
-	}
-
-	return NewPeer(in.GetPublicKey(), services), nil
-}
-
-// Marshal serializes a given Peer (p) into a slice of bytes.
-func (p *Peer) Marshal() ([]byte, error) {
-	return proto.Marshal(p.ToProto())
-}
-
-// Unmarshal de-serializes a given slice of bytes (data) into a Peer.
-func Unmarshal(data []byte) (*Peer, error) {
-	s := &pb.Peer{}
-	if err := proto.Unmarshal(data, s); err != nil {
-		return nil, err
-	}
-	return FromProto(s)
-}
-
-func recoverKey(key, data, sig []byte) (PublicKey, error) {
-	if l := len(key); l != ed25519.PublicKeySize {
-		return nil, fmt.Errorf("%w: invalid key length: %d, need %d", ErrInvalidSignature, l, ed25519.PublicKeySize)
-	}
-	if l := len(sig); l != ed25519.SignatureSize {
-		return nil, fmt.Errorf("%w: invalid signature length: %d, need %d", ErrInvalidSignature, l, ed25519.SignatureSize)
-	}
-	if !ed25519.Verify(key, data, sig) {
-		return nil, ErrInvalidSignature
-	}
-
-	publicKey := make([]byte, ed25519.PublicKeySize)
-	copy(publicKey, key)
-	return publicKey, nil
-}
diff --git a/packages/autopeering/peer/peer_test.go b/packages/autopeering/peer/peer_test.go
deleted file mode 100644
index a3375684..00000000
--- a/packages/autopeering/peer/peer_test.go
+++ /dev/null
@@ -1,82 +0,0 @@
-package peer
-
-import (
-	"crypto/ed25519"
-	"testing"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-const (
-	testNetwork = "udp"
-	testAddress = "127.0.0.1:8000"
-	testMessage = "Hello World!"
-)
-
-func newTestServiceRecord() *service.Record {
-	services := service.New()
-	services.Update(service.PeeringKey, testNetwork, testAddress)
-
-	return services
-}
-
-func newTestPeer(name string) *Peer {
-	key := make([]byte, ed25519.PublicKeySize)
-	copy(key, name)
-	return NewPeer(key, newTestServiceRecord())
-}
-
-func TestNoServicePeer(t *testing.T) {
-	key := make([]byte, ed25519.PublicKeySize)
-	services := service.New()
-
-	assert.Panics(t, func() {
-		_ = NewPeer(key, services)
-	})
-}
-
-func TestInvalidServicePeer(t *testing.T) {
-	key := make([]byte, ed25519.PublicKeySize)
-	services := service.New()
-	services.Update(service.FPCKey, "network", "address")
-
-	assert.Panics(t, func() {
-		_ = NewPeer(key, services)
-	})
-}
-
-func TestMarshalUnmarshal(t *testing.T) {
-	p := newTestPeer("test")
-	data, err := p.Marshal()
-	require.NoError(t, err)
-
-	got, err := Unmarshal(data)
-	require.NoError(t, err)
-
-	assert.Equal(t, p, got)
-}
-
-func TestRecoverKeyFromSignedData(t *testing.T) {
-	msg := []byte(testMessage)
-
-	pub, priv, err := ed25519.GenerateKey(nil)
-	require.NoError(t, err)
-
-	sig := ed25519.Sign(priv, msg)
-
-	d := signedData{pub: pub, msg: msg, sig: sig}
-	key, err := RecoverKeyFromSignedData(d)
-	require.NoError(t, err)
-
-	assert.Equal(t, PublicKey(pub).ID(), key.ID())
-}
-
-type signedData struct {
-	pub, msg, sig []byte
-}
-
-func (d signedData) GetPublicKey() []byte { return d.pub }
-func (d signedData) GetData() []byte      { return d.msg }
-func (d signedData) GetSignature() []byte { return d.sig }
diff --git a/packages/autopeering/peer/peerdb.go b/packages/autopeering/peer/peerdb.go
deleted file mode 100644
index d0972c77..00000000
--- a/packages/autopeering/peer/peerdb.go
+++ /dev/null
@@ -1,246 +0,0 @@
-package peer
-
-import (
-	"bytes"
-	"encoding/binary"
-	"math/rand"
-	"time"
-
-	"github.com/iotaledger/goshimmer/packages/database"
-)
-
-const (
-	// remove peers from DB, when the last received ping was older than this
-	peerExpiration = 24 * time.Hour
-	// interval in which expired peers are checked
-	cleanupInterval = time.Hour
-
-	// number of peers used for bootstrapping
-	seedCount = 10
-	// time after which potential seed peers should expire
-	seedExpiration = 5 * 24 * time.Hour
-)
-
-// Database defines the database functionality required by DB.
-type Database interface {
-	Get(database.Key) (database.Entry, error)
-	Set(database.Entry) error
-	ForEachPrefix(database.KeyPrefix, func(database.Entry) bool) error
-}
-
-// DB is the peer database, storing previously seen peers and any collected properties of them.
-type DB struct {
-	db Database
-}
-
-// Keys in the node database.
-const (
-	dbNodePrefix  = "n:"     // Identifier to prefix node entries with
-	dbLocalPrefix = "local:" // Identifier to prefix local entries
-
-	// These fields are stored per ID and address. Use nodeFieldKey to create those keys.
-	dbNodePing = "lastping"
-	dbNodePong = "lastpong"
-
-	// Local information is keyed by ID only. Use localFieldKey to create those keys.
-	dbLocalKey = "key"
-)
-
-// NewDB creates a new peer database.
-func NewDB(db Database) (*DB, error) {
-	pDB := &DB{
-		db: db,
-	}
-	err := pDB.init()
-	if err != nil {
-		return nil, err
-	}
-	return pDB, nil
-}
-
-func (db *DB) init() error {
-	// get all peers in the DB
-	peers := db.getPeers(0)
-
-	for _, p := range peers {
-		// if they dont have an associated pong, give them a grace period
-		if db.LastPong(p.ID(), p.Address()).Unix() == 0 {
-			if err := db.setPeerWithTTL(p, cleanupInterval); err != nil {
-				return err
-			}
-		}
-	}
-	return nil
-}
-
-// nodeKey returns the database key for a node record.
-func nodeKey(id ID) []byte {
-	return append([]byte(dbNodePrefix), id.Bytes()...)
-}
-
-// nodeFieldKey returns the database key for a node metadata field.
-func nodeFieldKey(id ID, address string, field string) []byte {
-	return bytes.Join([][]byte{nodeKey(id), []byte(address), []byte(field)}, []byte{':'})
-}
-
-func localFieldKey(field string) []byte {
-	return append([]byte(dbLocalPrefix), []byte(field)...)
-}
-
-func parseInt64(blob []byte) int64 {
-	val, read := binary.Varint(blob)
-	if read <= 0 {
-		return 0
-	}
-	return val
-}
-
-// getInt64 retrieves an integer associated with a particular key.
-func (db *DB) getInt64(key []byte) int64 {
-	entry, err := db.db.Get(key)
-	if err != nil {
-		return 0
-	}
-	return parseInt64(entry.Value)
-}
-
-// setInt64 stores an integer in the given key.
-func (db *DB) setInt64(key []byte, n int64) error {
-	blob := make([]byte, binary.MaxVarintLen64)
-	blob = blob[:binary.PutVarint(blob, n)]
-	return db.db.Set(database.Entry{Key: key, Value: blob, TTL: peerExpiration})
-}
-
-// LocalPrivateKey returns the private key stored in the database or creates a new one.
-func (db *DB) LocalPrivateKey() (PrivateKey, error) {
-	entry, err := db.db.Get(localFieldKey(dbLocalKey))
-	if err == database.ErrKeyNotFound {
-		key, genErr := generatePrivateKey()
-		if genErr == nil {
-			err = db.UpdateLocalPrivateKey(key)
-		}
-		return key, err
-	}
-	if err != nil {
-		return nil, err
-	}
-	return PrivateKey(entry.Value), nil
-}
-
-// UpdateLocalPrivateKey stores the provided key in the database.
-func (db *DB) UpdateLocalPrivateKey(key PrivateKey) error {
-	return db.db.Set(database.Entry{Key: localFieldKey(dbLocalKey), Value: []byte(key)})
-}
-
-// LastPing returns that property for the given peer ID and address.
-func (db *DB) LastPing(id ID, address string) time.Time {
-	return time.Unix(db.getInt64(nodeFieldKey(id, address, dbNodePing)), 0)
-}
-
-// UpdateLastPing updates that property for the given peer ID and address.
-func (db *DB) UpdateLastPing(id ID, address string, t time.Time) error {
-	return db.setInt64(nodeFieldKey(id, address, dbNodePing), t.Unix())
-}
-
-// LastPong returns that property for the given peer ID and address.
-func (db *DB) LastPong(id ID, address string) time.Time {
-	return time.Unix(db.getInt64(nodeFieldKey(id, address, dbNodePong)), 0)
-}
-
-// UpdateLastPong updates that property for the given peer ID and address.
-func (db *DB) UpdateLastPong(id ID, address string, t time.Time) error {
-	return db.setInt64(nodeFieldKey(id, address, dbNodePong), t.Unix())
-}
-
-func (db *DB) setPeerWithTTL(p *Peer, ttl time.Duration) error {
-	data, err := p.Marshal()
-	if err != nil {
-		return err
-	}
-	return db.db.Set(database.Entry{Key: nodeKey(p.ID()), Value: data, TTL: ttl})
-}
-
-// UpdatePeer updates a peer in the database.
-func (db *DB) UpdatePeer(p *Peer) error {
-	return db.setPeerWithTTL(p, peerExpiration)
-}
-
-func parsePeer(data []byte) *Peer {
-	p, err := Unmarshal(data)
-	if err != nil {
-		return nil
-	}
-	return p
-}
-
-// Peer retrieves a peer from the database.
-func (db *DB) Peer(id ID) *Peer {
-	data, err := db.db.Get(nodeKey(id))
-	if err != nil {
-		return nil
-	}
-	return parsePeer(data.Value)
-}
-
-func randomSubset(peers []*Peer, m int) []*Peer {
-	if len(peers) <= m {
-		return peers
-	}
-
-	result := make([]*Peer, 0, m)
-	for i, p := range peers {
-		if rand.Intn(len(peers)-i) < m-len(result) {
-			result = append(result, p)
-		}
-	}
-	return result
-}
-
-func (db *DB) getPeers(maxAge time.Duration) (peers []*Peer) {
-	now := time.Now()
-	err := db.db.ForEachPrefix([]byte(dbNodePrefix), func(entry database.Entry) bool {
-		var id ID
-		if len(entry.Key) != len(id) {
-			return false
-		}
-		copy(id[:], entry.Key)
-
-		p := parsePeer(entry.Value)
-		if p == nil || p.ID() != id {
-			return false
-		}
-		if maxAge > 0 && now.Sub(db.LastPong(p.ID(), p.Address())) > maxAge {
-			return false
-		}
-
-		peers = append(peers, p)
-		return false
-	})
-	if err != nil {
-		return nil
-	}
-	return peers
-}
-
-// SeedPeers retrieves random nodes to be used as potential bootstrap peers.
-func (db *DB) SeedPeers() []*Peer {
-	// get all stored peers and select subset
-	peers := db.getPeers(0)
-
-	return randomSubset(peers, seedCount)
-}
-
-// PersistSeeds assures that potential bootstrap peers are not garbage collected.
-// It returns the number of peers that have been persisted.
-func (db *DB) PersistSeeds() int {
-	// randomly select potential bootstrap peers
-	peers := randomSubset(db.getPeers(peerExpiration), seedCount)
-
-	for i, p := range peers {
-		err := db.setPeerWithTTL(p, seedExpiration)
-		if err != nil {
-			return i
-		}
-	}
-	return len(peers)
-}
diff --git a/packages/autopeering/peer/peerdb_test.go b/packages/autopeering/peer/peerdb_test.go
deleted file mode 100644
index f52f45c9..00000000
--- a/packages/autopeering/peer/peerdb_test.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package peer
-
-import (
-	"crypto/ed25519"
-	"fmt"
-	"testing"
-	"time"
-
-	"github.com/iotaledger/goshimmer/packages/database/mapdb"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-func TestPeerDB(t *testing.T) {
-	db, err := NewDB(mapdb.NewMapDB())
-	require.NoError(t, err)
-	p := newTestPeer("test")
-
-	t.Run("LocalPrivateKey", func(t *testing.T) {
-		key, err := db.LocalPrivateKey()
-		require.NoError(t, err)
-
-		assert.EqualValues(t, ed25519.PrivateKeySize, len(key))
-		assert.EqualValues(t, ed25519.PublicKeySize, len(key.Public()))
-
-		err = db.UpdateLocalPrivateKey(key)
-		require.NoError(t, err)
-
-		key2, err := db.LocalPrivateKey()
-		require.NoError(t, err)
-
-		assert.Equal(t, key, key2)
-	})
-
-	t.Run("Peer", func(t *testing.T) {
-		err := db.UpdatePeer(p)
-		require.NoError(t, err)
-
-		assert.Equal(t, p, db.Peer(p.ID()))
-	})
-
-	t.Run("LastPing", func(t *testing.T) {
-		now := time.Now()
-		err := db.UpdateLastPing(p.ID(), p.Address(), now)
-		require.NoError(t, err)
-
-		assert.Equal(t, now.Unix(), db.LastPing(p.ID(), p.Address()).Unix())
-	})
-
-	t.Run("LastPong", func(t *testing.T) {
-		now := time.Now()
-		err := db.UpdateLastPong(p.ID(), p.Address(), now)
-		require.NoError(t, err)
-
-		assert.Equal(t, now.Unix(), db.LastPong(p.ID(), p.Address()).Unix())
-	})
-
-	t.Run("getPeers", func(t *testing.T) {
-		time.Sleep(time.Second) // let the old peers expire
-
-		newPeer := newTestPeer("new")
-		assert.NoError(t, db.UpdatePeer(newPeer))
-		assert.NoError(t, db.UpdateLastPong(newPeer.ID(), newPeer.Address(), time.Now()))
-
-		peers := db.getPeers(time.Second)
-		assert.ElementsMatch(t, []*Peer{newPeer}, peers)
-	})
-
-	t.Run("SeedPeers", func(t *testing.T) {
-		for i := 0; i < seedCount+1; i++ {
-			p := newTestPeer(fmt.Sprintf("SeedPeers%0d", i))
-			assert.NoError(t, db.UpdatePeer(p))
-			assert.NoError(t, db.UpdateLastPong(p.ID(), p.Address(), time.Now()))
-		}
-
-		peers := db.SeedPeers()
-		assert.EqualValues(t, seedCount, len(peers))
-	})
-
-	t.Run("PersistSeeds", func(t *testing.T) {
-		for i := 0; i < seedCount+1; i++ {
-			p := newTestPeer(fmt.Sprintf("PersistSeeds%0d", i))
-			assert.NoError(t, db.UpdatePeer(p))
-			assert.NoError(t, db.UpdateLastPong(p.ID(), p.Address(), time.Now()))
-		}
-
-		count := db.PersistSeeds()
-		assert.EqualValues(t, seedCount, count)
-	})
-}
diff --git a/packages/autopeering/peer/peertest/peertest.go b/packages/autopeering/peer/peertest/peertest.go
deleted file mode 100644
index e1c0fb8f..00000000
--- a/packages/autopeering/peer/peertest/peertest.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Package peertest provides utilities for writing tests with the peer package.
-package peertest
-
-import (
-	"crypto/ed25519"
-	"log"
-	"math/rand"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
-)
-
-func NewPeer(network, address string) *peer.Peer {
-	services := service.New()
-	services.Update(service.PeeringKey, network, address)
-	key := make([]byte, ed25519.PublicKeySize)
-	copy(key, address)
-	return peer.NewPeer(key, services)
-}
-
-func NewLocal(network, address string, db *peer.DB) *peer.Local {
-	services := service.New()
-	services.Update(service.PeeringKey, network, address)
-	local, err := peer.NewLocal(services, db, randomSeed())
-	if err != nil {
-		log.Panic(err)
-	}
-	return local
-}
-
-func randomSeed() []byte {
-	seed := make([]byte, ed25519.SeedSize)
-	rand.Read(seed)
-	return seed
-}
diff --git a/packages/autopeering/peer/proto/peer.pb.go b/packages/autopeering/peer/proto/peer.pb.go
deleted file mode 100644
index 471070ff..00000000
--- a/packages/autopeering/peer/proto/peer.pb.go
+++ /dev/null
@@ -1,94 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// source: peer/proto/peer.proto
-
-package proto
-
-import (
-	fmt "fmt"
-	math "math"
-
-	proto "github.com/golang/protobuf/proto"
-	proto1 "github.com/iotaledger/goshimmer/packages/autopeering/peer/service/proto"
-)
-
-// Reference imports to suppress errors if they are not otherwise used.
-var _ = proto.Marshal
-var _ = fmt.Errorf
-var _ = math.Inf
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the proto package it is being compiled against.
-// A compilation error at this line likely means your copy of the
-// proto package needs to be updated.
-const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
-
-// Minimal encoding of a peer
-type Peer struct {
-	// public key used for signing
-	PublicKey []byte `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
-	// services supported by the peer
-	Services             *proto1.ServiceMap `protobuf:"bytes,2,opt,name=services,proto3" json:"services,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}           `json:"-"`
-	XXX_unrecognized     []byte             `json:"-"`
-	XXX_sizecache        int32              `json:"-"`
-}
-
-func (m *Peer) Reset()         { *m = Peer{} }
-func (m *Peer) String() string { return proto.CompactTextString(m) }
-func (*Peer) ProtoMessage()    {}
-func (*Peer) Descriptor() ([]byte, []int) {
-	return fileDescriptor_155860cd2f47eba7, []int{0}
-}
-
-func (m *Peer) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_Peer.Unmarshal(m, b)
-}
-func (m *Peer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_Peer.Marshal(b, m, deterministic)
-}
-func (m *Peer) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_Peer.Merge(m, src)
-}
-func (m *Peer) XXX_Size() int {
-	return xxx_messageInfo_Peer.Size(m)
-}
-func (m *Peer) XXX_DiscardUnknown() {
-	xxx_messageInfo_Peer.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_Peer proto.InternalMessageInfo
-
-func (m *Peer) GetPublicKey() []byte {
-	if m != nil {
-		return m.PublicKey
-	}
-	return nil
-}
-
-func (m *Peer) GetServices() *proto1.ServiceMap {
-	if m != nil {
-		return m.Services
-	}
-	return nil
-}
-
-func init() {
-	proto.RegisterType((*Peer)(nil), "proto.Peer")
-}
-
-func init() { proto.RegisterFile("peer/proto/peer.proto", fileDescriptor_155860cd2f47eba7) }
-
-var fileDescriptor_155860cd2f47eba7 = []byte{
-	// 168 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x12, 0x2d, 0x48, 0x4d, 0x2d,
-	0xd2, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0xd7, 0x07, 0x31, 0xf5, 0xc0, 0x4c, 0x21, 0x56, 0x30, 0x25,
-	0xa5, 0x00, 0x96, 0x2d, 0x4e, 0x2d, 0x2a, 0xcb, 0x4c, 0x4e, 0x85, 0xaa, 0x82, 0xf2, 0x20, 0x0a,
-	0x95, 0x42, 0xb8, 0x58, 0x02, 0x80, 0x6a, 0x84, 0x64, 0xb9, 0xb8, 0x0a, 0x4a, 0x93, 0x72, 0x32,
-	0x93, 0xe3, 0xb3, 0x53, 0x2b, 0x25, 0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0x38, 0x21, 0x22, 0xde,
-	0xa9, 0x95, 0x42, 0xba, 0x5c, 0x1c, 0x50, 0x7d, 0xc5, 0x12, 0x4c, 0x40, 0x49, 0x6e, 0x23, 0x41,
-	0x88, 0x01, 0x7a, 0xc1, 0x10, 0x61, 0xdf, 0xc4, 0x82, 0x20, 0xb8, 0x12, 0x27, 0xa3, 0x28, 0x83,
-	0xf4, 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0xfd, 0xcc, 0xfc, 0x92, 0xc4, 0x9c,
-	0xd4, 0x94, 0x74, 0xa0, 0x53, 0x12, 0x4b, 0x4b, 0xf2, 0x41, 0x6e, 0xca, 0xcc, 0x4b, 0xd7, 0x2d,
-	0xce, 0xcc, 0xd5, 0x47, 0xb8, 0x3e, 0x89, 0x0d, 0x4c, 0x19, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff,
-	0x8e, 0xb0, 0x04, 0x1f, 0xd2, 0x00, 0x00, 0x00,
-}
diff --git a/packages/autopeering/peer/proto/peer.proto b/packages/autopeering/peer/proto/peer.proto
deleted file mode 100644
index 16327b26..00000000
--- a/packages/autopeering/peer/proto/peer.proto
+++ /dev/null
@@ -1,15 +0,0 @@
-syntax = "proto3";
-
-option go_package = "github.com/iotaledger/goshimmer/packages/autopeering/peer/proto";
-
-package proto;
-
-import "peer/service/proto/service.proto";
-
-// Minimal encoding of a peer
-message Peer {
-  // public key used for signing
-  bytes public_key = 1;
-  // services supported by the peer
-  ServiceMap services = 2;
-}
diff --git a/packages/autopeering/peer/service/proto/service.pb.go b/packages/autopeering/peer/service/proto/service.pb.go
deleted file mode 100644
index 9da648b9..00000000
--- a/packages/autopeering/peer/service/proto/service.pb.go
+++ /dev/null
@@ -1,137 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// source: peer/service/proto/service.proto
-
-package proto
-
-import (
-	fmt "fmt"
-	proto "github.com/golang/protobuf/proto"
-	math "math"
-)
-
-// Reference imports to suppress errors if they are not otherwise used.
-var _ = proto.Marshal
-var _ = fmt.Errorf
-var _ = math.Inf
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the proto package it is being compiled against.
-// A compilation error at this line likely means your copy of the
-// proto package needs to be updated.
-const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
-
-// Mapping between a service ID and its tuple network_address
-// e.g., map[autopeering:&{tcp, 198.51.100.1:80}]
-type ServiceMap struct {
-	Map                  map[string]*NetworkAddress `protobuf:"bytes,1,rep,name=map,proto3" json:"map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
-	XXX_NoUnkeyedLiteral struct{}                   `json:"-"`
-	XXX_unrecognized     []byte                     `json:"-"`
-	XXX_sizecache        int32                      `json:"-"`
-}
-
-func (m *ServiceMap) Reset()         { *m = ServiceMap{} }
-func (m *ServiceMap) String() string { return proto.CompactTextString(m) }
-func (*ServiceMap) ProtoMessage()    {}
-func (*ServiceMap) Descriptor() ([]byte, []int) {
-	return fileDescriptor_8dd4c5b37d65f758, []int{0}
-}
-
-func (m *ServiceMap) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_ServiceMap.Unmarshal(m, b)
-}
-func (m *ServiceMap) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_ServiceMap.Marshal(b, m, deterministic)
-}
-func (m *ServiceMap) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_ServiceMap.Merge(m, src)
-}
-func (m *ServiceMap) XXX_Size() int {
-	return xxx_messageInfo_ServiceMap.Size(m)
-}
-func (m *ServiceMap) XXX_DiscardUnknown() {
-	xxx_messageInfo_ServiceMap.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_ServiceMap proto.InternalMessageInfo
-
-func (m *ServiceMap) GetMap() map[string]*NetworkAddress {
-	if m != nil {
-		return m.Map
-	}
-	return nil
-}
-
-// The service type (e.g., tcp, upd) and the address (e.g., 198.51.100.1:80)
-type NetworkAddress struct {
-	Network              string   `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"`
-	Address              string   `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
-
-func (m *NetworkAddress) Reset()         { *m = NetworkAddress{} }
-func (m *NetworkAddress) String() string { return proto.CompactTextString(m) }
-func (*NetworkAddress) ProtoMessage()    {}
-func (*NetworkAddress) Descriptor() ([]byte, []int) {
-	return fileDescriptor_8dd4c5b37d65f758, []int{1}
-}
-
-func (m *NetworkAddress) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_NetworkAddress.Unmarshal(m, b)
-}
-func (m *NetworkAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_NetworkAddress.Marshal(b, m, deterministic)
-}
-func (m *NetworkAddress) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_NetworkAddress.Merge(m, src)
-}
-func (m *NetworkAddress) XXX_Size() int {
-	return xxx_messageInfo_NetworkAddress.Size(m)
-}
-func (m *NetworkAddress) XXX_DiscardUnknown() {
-	xxx_messageInfo_NetworkAddress.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_NetworkAddress proto.InternalMessageInfo
-
-func (m *NetworkAddress) GetNetwork() string {
-	if m != nil {
-		return m.Network
-	}
-	return ""
-}
-
-func (m *NetworkAddress) GetAddress() string {
-	if m != nil {
-		return m.Address
-	}
-	return ""
-}
-
-func init() {
-	proto.RegisterType((*ServiceMap)(nil), "proto.ServiceMap")
-	proto.RegisterMapType((map[string]*NetworkAddress)(nil), "proto.ServiceMap.MapEntry")
-	proto.RegisterType((*NetworkAddress)(nil), "proto.NetworkAddress")
-}
-
-func init() { proto.RegisterFile("peer/service/proto/service.proto", fileDescriptor_8dd4c5b37d65f758) }
-
-var fileDescriptor_8dd4c5b37d65f758 = []byte{
-	// 227 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x52, 0x28, 0x48, 0x4d, 0x2d,
-	0xd2, 0x2f, 0x4e, 0x2d, 0x2a, 0xcb, 0x4c, 0x4e, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x87, 0xf1,
-	0xf4, 0xc0, 0x3c, 0x21, 0x56, 0x30, 0xa5, 0xd4, 0xc9, 0xc8, 0xc5, 0x15, 0x0c, 0x91, 0xf0, 0x4d,
-	0x2c, 0x10, 0xd2, 0xe1, 0x62, 0xce, 0x4d, 0x2c, 0x90, 0x60, 0x54, 0x60, 0xd6, 0xe0, 0x36, 0x92,
-	0x82, 0x28, 0xd5, 0x43, 0xc8, 0xeb, 0x01, 0xb1, 0x6b, 0x5e, 0x49, 0x51, 0x65, 0x10, 0x48, 0x99,
-	0x94, 0x2f, 0x17, 0x07, 0x4c, 0x40, 0x48, 0x80, 0x8b, 0x39, 0x3b, 0xb5, 0x12, 0xa8, 0x93, 0x51,
-	0x83, 0x33, 0x08, 0xc4, 0x14, 0xd2, 0xe6, 0x62, 0x2d, 0x4b, 0xcc, 0x29, 0x4d, 0x95, 0x60, 0x02,
-	0x8a, 0x71, 0x1b, 0x89, 0x42, 0x4d, 0xf3, 0x4b, 0x2d, 0x29, 0xcf, 0x2f, 0xca, 0x76, 0x4c, 0x49,
-	0x29, 0x4a, 0x2d, 0x2e, 0x0e, 0x82, 0xa8, 0xb1, 0x62, 0xb2, 0x60, 0x54, 0x72, 0xe1, 0xe2, 0x43,
-	0x95, 0x14, 0x92, 0xe0, 0x62, 0xcf, 0x83, 0x88, 0x40, 0x0d, 0x86, 0x71, 0x41, 0x32, 0x89, 0x10,
-	0x45, 0x60, 0xe3, 0x81, 0x32, 0x50, 0xae, 0x93, 0x55, 0x94, 0x45, 0x7a, 0x66, 0x49, 0x46, 0x69,
-	0x92, 0x5e, 0x72, 0x7e, 0xae, 0x7e, 0x66, 0x7e, 0x49, 0x62, 0x4e, 0x6a, 0x4a, 0x3a, 0x30, 0x34,
-	0x12, 0x4b, 0x4b, 0xf2, 0x41, 0xc1, 0x92, 0x99, 0x97, 0xae, 0x5b, 0x9c, 0x99, 0xab, 0x8f, 0x19,
-	0x44, 0x49, 0x6c, 0x60, 0xca, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x5f, 0xe9, 0x8e, 0x9d, 0x3f,
-	0x01, 0x00, 0x00,
-}
diff --git a/packages/autopeering/peer/service/proto/service.proto b/packages/autopeering/peer/service/proto/service.proto
deleted file mode 100644
index 28f04088..00000000
--- a/packages/autopeering/peer/service/proto/service.proto
+++ /dev/null
@@ -1,17 +0,0 @@
-syntax = "proto3";
-
-option go_package = "github.com/iotaledger/goshimmer/packages/autopeering/peer/service/proto";
-
-package proto;
-
-// Mapping between a service ID and its tuple network_address
-// e.g., map[autopeering:&{tcp, 198.51.100.1:80}]
-message ServiceMap {
-  map<string, NetworkAddress> map = 1;
-}
-  
-// The service type (e.g., tcp, upd) and the address (e.g., 198.51.100.1:80)
-message NetworkAddress {
-  string network = 1;
-  string address = 2;
-}
\ No newline at end of file
diff --git a/packages/autopeering/peer/service/record.go b/packages/autopeering/peer/service/record.go
deleted file mode 100644
index 7a6df07a..00000000
--- a/packages/autopeering/peer/service/record.go
+++ /dev/null
@@ -1,118 +0,0 @@
-package service
-
-import (
-	"fmt"
-	"net"
-
-	"github.com/golang/protobuf/proto"
-	pb "github.com/iotaledger/goshimmer/packages/autopeering/peer/service/proto"
-)
-
-// Record defines the mapping between a service ID and its tuple TypePort
-// e.g., map[autopeering:&{TCP, 8000}]
-type Record struct {
-	m map[string]*networkAddress
-}
-
-// networkAddress implements net.Addr
-type networkAddress struct {
-	network string
-	address string
-}
-
-// Network returns the service's network name.
-func (a *networkAddress) Network() string {
-	return a.network
-}
-
-// String returns the service's address in string form.
-func (a *networkAddress) String() string {
-	return a.address
-}
-
-// New initializes and returns an empty new Record
-func New() *Record {
-	return &Record{
-		m: make(map[string]*networkAddress),
-	}
-}
-
-// Get returns the network end point address of the service with the given name.
-func (s *Record) Get(key Key) net.Addr {
-	val, ok := s.m[string(key)]
-	if !ok {
-		return nil
-	}
-	return val
-}
-
-// CreateRecord creates a modifyable Record from the services.
-func (s *Record) CreateRecord() *Record {
-	result := New()
-	for k, v := range s.m {
-		result.m[k] = v
-	}
-	return result
-}
-
-// Update adds a new service to the map.
-func (s *Record) Update(key Key, network string, address string) {
-	s.m[string(key)] = &networkAddress{
-		network: network, address: address,
-	}
-}
-
-// String returns a string representation of the service record.
-func (s *Record) String() string {
-	return fmt.Sprintf("%v", s.m)
-}
-
-// FromProto creates a Record from the provided protobuf struct.
-func FromProto(in *pb.ServiceMap) (*Record, error) {
-	m := in.GetMap()
-	if m == nil {
-		return nil, nil
-	}
-
-	services := New()
-	for service, addr := range m {
-		services.m[service] = &networkAddress{
-			network: addr.GetNetwork(),
-			address: addr.GetAddress(),
-		}
-	}
-	return services, nil
-}
-
-// ToProto returns the corresponding protobuf struct.
-func (s *Record) ToProto() *pb.ServiceMap {
-	if len(s.m) == 0 {
-		return nil
-	}
-
-	services := make(map[string]*pb.NetworkAddress, len(s.m))
-	for service, addr := range s.m {
-		services[service] = &pb.NetworkAddress{
-			Network: addr.network,
-			Address: addr.address,
-		}
-	}
-
-	return &pb.ServiceMap{
-		Map: services,
-	}
-}
-
-// Marshal serializes a given Peer (p) into a slice of bytes.
-func (s *Record) Marshal() ([]byte, error) {
-	return proto.Marshal(s.ToProto())
-}
-
-// Unmarshal de-serializes a given slice of bytes (data) into a Peer.
-func Unmarshal(data []byte) (*Record, error) {
-	s := &pb.ServiceMap{}
-	if err := proto.Unmarshal(data, s); err != nil {
-		return nil, err
-	}
-	return FromProto(s)
-}
diff --git a/packages/autopeering/peer/service/service.go b/packages/autopeering/peer/service/service.go
deleted file mode 100644
index a201bce0..00000000
--- a/packages/autopeering/peer/service/service.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package service
-
-import (
-	"net"
-)
-
-// Service is a read-only interface to access services.
-type Service interface {
-	// Get returns the network end point address of the given service or nil if not supported.
-	Get(Key) net.Addr
-
-	// CreateRecord creates a modifyable Record from the services.
-	CreateRecord() *Record
-}
-
-// Key is the type of keys used to look-up a service.
-type Key string
-
-const (
-	// PeeringKey is the key for the auto peering service.
-	PeeringKey Key = "peering"
-	// FPCKey is the key for the FPC service.
-	FPCKey Key = "fpc"
-	// GossipKey is the key for the gossip service.
-	GossipKey Key = "gossip"
-)
diff --git a/packages/autopeering/peer/sort.go b/packages/autopeering/peer/sort.go
deleted file mode 100644
index a0dd3e9a..00000000
--- a/packages/autopeering/peer/sort.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package peer
-
-import (
-	"sort"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/distance"
-)
-
-// PeerDistance defines the relative distance wrt a remote peer
-type PeerDistance struct {
-	Remote   *Peer
-	Distance uint32
-}
-
-// byDistance is a slice of PeerDistance used to sort
-type byDistance []PeerDistance
-
-func (a byDistance) Len() int           { return len(a) }
-func (a byDistance) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
-func (a byDistance) Less(i, j int) bool { return a[i].Distance < a[j].Distance }
-
-// NewPeerDistance returns a new PeerDistance
-func NewPeerDistance(anchorID, salt []byte, remote *Peer) PeerDistance {
-	return PeerDistance{
-		Remote:   remote,
-		Distance: distance.BySalt(anchorID, remote.ID().Bytes(), salt),
-	}
-}
-
-// SortBySalt returns a slice of PeerDistance given a list of remote peers
-func SortBySalt(anchor, salt []byte, remotePeers []*Peer) (result []PeerDistance) {
-	result = make(byDistance, len(remotePeers))
-	for i, remote := range remotePeers {
-		result[i] = NewPeerDistance(anchor, salt, remote)
-	}
-	sort.Sort(byDistance(result))
-	return result
-}
diff --git a/packages/autopeering/peer/sort_test.go b/packages/autopeering/peer/sort_test.go
deleted file mode 100644
index 9357bb7a..00000000
--- a/packages/autopeering/peer/sort_test.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package peer
-
-import (
-	"crypto/ed25519"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-)
-
-func newTestPeerWithID(ID byte) *Peer {
-	key := make([]byte, ed25519.PublicKeySize)
-	key[0] = ID
-	return NewPeer(key, newTestServiceRecord())
-}
-
-func TestOrderedDistanceList(t *testing.T) {
-	type testCase struct {
-		anchor  []byte
-		salt    []byte
-		ordered bool
-	}
-
-	tests := []testCase{
-		{
-			anchor:  []byte("X"),
-			salt:    []byte("salt"),
-			ordered: true,
-		},
-	}
-
-	remotePeers := make([]*Peer, 10)
-	for i := range remotePeers {
-		remotePeers[i] = newTestPeerWithID(byte(i + 1))
-	}
-
-	for _, test := range tests {
-		d := SortBySalt(test.anchor, test.salt, remotePeers)
-		prev := d[0]
-		for _, next := range d[1:] {
-			got := prev.Distance < next.Distance
-			assert.Equal(t, test.ordered, got, "Ordered distance list")
-			prev = next
-		}
-	}
-}
diff --git a/packages/autopeering/salt/proto/salt.pb.go b/packages/autopeering/salt/proto/salt.pb.go
deleted file mode 100644
index cb7f27bf..00000000
--- a/packages/autopeering/salt/proto/salt.pb.go
+++ /dev/null
@@ -1,89 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// source: salt/proto/salt.proto
-
-package proto
-
-import (
-	fmt "fmt"
-	proto "github.com/golang/protobuf/proto"
-	math "math"
-)
-
-// Reference imports to suppress errors if they are not otherwise used.
-var _ = proto.Marshal
-var _ = fmt.Errorf
-var _ = math.Inf
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the proto package it is being compiled against.
-// A compilation error at this line likely means your copy of the
-// proto package needs to be updated.
-const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
-
-type Salt struct {
-	// value of the salt
-	Bytes []byte `protobuf:"bytes,1,opt,name=bytes,proto3" json:"bytes,omitempty"`
-	// expiration time of the salt
-	ExpTime              uint64   `protobuf:"fixed64,2,opt,name=exp_time,json=expTime,proto3" json:"exp_time,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
-
-func (m *Salt) Reset()         { *m = Salt{} }
-func (m *Salt) String() string { return proto.CompactTextString(m) }
-func (*Salt) ProtoMessage()    {}
-func (*Salt) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d46762658484b01f, []int{0}
-}
-
-func (m *Salt) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_Salt.Unmarshal(m, b)
-}
-func (m *Salt) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_Salt.Marshal(b, m, deterministic)
-}
-func (m *Salt) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_Salt.Merge(m, src)
-}
-func (m *Salt) XXX_Size() int {
-	return xxx_messageInfo_Salt.Size(m)
-}
-func (m *Salt) XXX_DiscardUnknown() {
-	xxx_messageInfo_Salt.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_Salt proto.InternalMessageInfo
-
-func (m *Salt) GetBytes() []byte {
-	if m != nil {
-		return m.Bytes
-	}
-	return nil
-}
-
-func (m *Salt) GetExpTime() uint64 {
-	if m != nil {
-		return m.ExpTime
-	}
-	return 0
-}
-
-func init() {
-	proto.RegisterType((*Salt)(nil), "proto.Salt")
-}
-
-func init() { proto.RegisterFile("salt/proto/salt.proto", fileDescriptor_d46762658484b01f) }
-
-var fileDescriptor_d46762658484b01f = []byte{
-	// 142 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x12, 0x2d, 0x4e, 0xcc, 0x29,
-	0xd1, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0xd7, 0x07, 0x31, 0xf5, 0xc0, 0x4c, 0x21, 0x56, 0x30, 0xa5,
-	0x64, 0xce, 0xc5, 0x12, 0x0c, 0x14, 0x14, 0x12, 0xe1, 0x62, 0x4d, 0xaa, 0x2c, 0x49, 0x2d, 0x96,
-	0x60, 0x54, 0x60, 0xd4, 0xe0, 0x09, 0x82, 0x70, 0x84, 0x24, 0xb9, 0x38, 0x52, 0x2b, 0x0a, 0xe2,
-	0x4b, 0x32, 0x73, 0x53, 0x25, 0x98, 0x80, 0x12, 0x6c, 0x41, 0xec, 0x40, 0x7e, 0x08, 0x90, 0xeb,
-	0x64, 0x14, 0x65, 0x90, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x9f, 0x99,
-	0x5f, 0x92, 0x98, 0x93, 0x9a, 0x92, 0x9e, 0x5a, 0xa4, 0x9f, 0x58, 0x5a, 0x92, 0x5f, 0x90, 0x9a,
-	0x5a, 0x94, 0x99, 0x97, 0xae, 0x5b, 0x9c, 0x99, 0xab, 0x8f, 0xb0, 0x3e, 0x89, 0x0d, 0x4c, 0x19,
-	0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x47, 0x07, 0x7d, 0x5f, 0x93, 0x00, 0x00, 0x00,
-}
diff --git a/packages/autopeering/salt/proto/salt.proto b/packages/autopeering/salt/proto/salt.proto
deleted file mode 100644
index e1b61df5..00000000
--- a/packages/autopeering/salt/proto/salt.proto
+++ /dev/null
@@ -1,12 +0,0 @@
-syntax = "proto3";
-
-option go_package = "github.com/iotaledger/goshimmer/packages/autopeering/salt/proto";
-
-package proto;
-
-message Salt {
-    // value of the salt
-    bytes bytes = 1;
-    // expiration time of the salt
-    fixed64 exp_time = 2;
-}
\ No newline at end of file
diff --git a/packages/autopeering/salt/salt.go b/packages/autopeering/salt/salt.go
deleted file mode 100644
index 07afb2ea..00000000
--- a/packages/autopeering/salt/salt.go
+++ /dev/null
@@ -1,86 +0,0 @@
-package salt
-
-import (
-	"crypto/rand"
-	"fmt"
-	"sync"
-	"time"
-
-	"github.com/golang/protobuf/proto"
-	pb "github.com/iotaledger/goshimmer/packages/autopeering/salt/proto"
-)
-
-// SaltByteSize specifies the number of bytes used for the salt.
-const SaltByteSize = 20
-
-// Salt encapsulates high level functions around salt management.
-type Salt struct {
-	bytes          []byte    // value of the salt
-	expirationTime time.Time // expiration time of the salt
-	mutex          sync.RWMutex
-}
-
-// NewSalt generates a new salt given a lifetime duration
-func NewSalt(lifetime time.Duration) (salt *Salt, err error) {
-	salt = &Salt{
-		bytes:          make([]byte, SaltByteSize),
-		expirationTime: time.Now().Add(lifetime),
-	}
-
-	if _, err = rand.Read(salt.bytes); err != nil {
-		return nil, err
-	}
-
-	return salt, err
-}
-
-func (s *Salt) GetBytes() []byte {
-	s.mutex.RLock()
-	defer s.mutex.RUnlock()
-	return append([]byte{}, s.bytes...)
-}
-
-func (s *Salt) GetExpiration() time.Time {
-	s.mutex.RLock()
-	defer s.mutex.RUnlock()
-	return s.expirationTime
-}
-
-// Expired returns true if the given salt expired
-func (s *Salt) Expired() bool {
-	return time.Now().After(s.GetExpiration())
-}
-
-// ToProto encodes the Salt into a proto buffer Salt message
-func (s *Salt) ToProto() *pb.Salt {
-	return &pb.Salt{
-		Bytes:   s.bytes,
-		ExpTime: uint64(s.expirationTime.Unix()),
-	}
-}
-
-// FromProto decodes a given proto buffer Salt message (in) and returns the corresponding Salt.
-func FromProto(in *pb.Salt) (*Salt, error) {
-	if l := len(in.GetBytes()); l != SaltByteSize {
-		return nil, fmt.Errorf("invalid salt length: %d, need %d", l, SaltByteSize)
-	}
-	out := &Salt{
-		bytes:          in.GetBytes(),
-		expirationTime: time.Unix(int64(in.GetExpTime()), 0),
-	}
-	return out, nil
-}
-
-// Marshal serializes a given salt (s) into a slice of bytes (data)
-func (s *Salt) Marshal() ([]byte, error) {
-	return proto.Marshal(s.ToProto())
-}
-
-// Unmarshal de-serializes a given slice of bytes (data) into a Salt.
-func Unmarshal(data []byte) (*Salt, error) {
-	s := &pb.Salt{}
-	if err := proto.Unmarshal(data, s); err != nil {
-		return nil, err
-	}
-	return FromProto(s)
-}
diff --git a/packages/autopeering/salt/salt_test.go b/packages/autopeering/salt/salt_test.go
deleted file mode 100644
index 3e5bbc3f..00000000
--- a/packages/autopeering/salt/salt_test.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package salt
-
-import (
-	"testing"
-	"time"
-
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-func TestNewSalt(t *testing.T) {
-	type testCase struct {
-		input time.Duration
-		want  error
-	}
-
-	tests := []testCase{
-		{input: 0, want: nil},
-		{input: 10, want: nil},
-		{input: -1, want: nil},
-	}
-
-	for _, test := range tests {
-		_, err := NewSalt(test.input)
-		assert.Equal(t, test.want, err, test)
-	}
-}
-
-func TestSaltExpired(t *testing.T) {
-	type testCase struct {
-		input time.Duration
-		want  bool
-	}
-
-	tests := []testCase{
-		{input: 0, want: true},
-		{input: time.Second * 10, want: false},
-		{input: -1, want: true},
-	}
-
-	for _, test := range tests {
-		salt, _ := NewSalt(test.input)
-		got := salt.Expired()
-		assert.Equal(t, test.want, got, test)
-	}
-}
-
-func TestMarshalUnmarshal(t *testing.T) {
-	type testCase struct {
-		input time.Duration
-	}
-
-	tests := []testCase{
-		{input: 0},
-		{input: time.Second * 10},
-		{input: -1},
-	}
-
-	for _, test := range tests {
-		salt, _ := NewSalt(test.input)
-
-		data, err := salt.Marshal()
-		require.Equal(t, nil, err, "NoErrorCheck")
-
-		got, err := Unmarshal(data)
-		require.Equal(t, nil, err, "NoErrorCheck")
-
-		assert.Equal(t, salt.GetBytes(), got.GetBytes(), "Salt")
-		assert.Equal(t, salt.GetExpiration().Unix(), got.GetExpiration().Unix(), "SameSaltExpirationTime")
-
-	}
-
-}
diff --git a/packages/autopeering/selection/common.go b/packages/autopeering/selection/common.go
deleted file mode 100644
index 60bff450..00000000
--- a/packages/autopeering/selection/common.go
+++ /dev/null
@@ -1,86 +0,0 @@
-package selection
-
-import (
-	"time"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/hive.go/logger"
-)
-
-// Default values for the global parameters
-const (
-	DefaultInboundNeighborSize        = 4
-	DefaultOutboundNeighborSize       = 4
-	DefaultSaltLifetime               = 30 * time.Minute
-	DefaultOutboundUpdateInterval     = 1 * time.Second
-	DefaultFullOutboundUpdateInterval = 1 * time.Minute
-)
-
-var (
-	inboundNeighborSize        = DefaultInboundNeighborSize        // number of inbound neighbors
-	outboundNeighborSize       = DefaultOutboundNeighborSize       // number of outbound neighbors
-	saltLifetime               = DefaultSaltLifetime               // lifetime of the private and public local salt
-	outboundUpdateInterval     = DefaultOutboundUpdateInterval     // time after which out neighbors are updated
-	fullOutboundUpdateInterval = DefaultFullOutboundUpdateInterval // time after which full out neighbors are updated
-)
-
-// Config holds settings for the peer selection.
-type Config struct {
-	// Logger
-	Log *logger.Logger
-
-	// These settings are optional:
-	DropOnUpdate      bool      // set true to drop all neighbors when the salt is updated
-	NeighborValidator Validator // potential neighbor validator
-}
-
-// A Validator checks whether a peer is a valid neighbor
-type Validator interface {
-	IsValid(*peer.Peer) bool
-}
-
-// The ValidatorFunc type is an adapter to allow the use of ordinary functions as neighbor validators.
-// If f is a function with the appropriate signature, ValidatorFunc(f) is a Validator that calls f.
-type ValidatorFunc func(p *peer.Peer) bool
-
-// IsValid calls f(p).
-func (f ValidatorFunc) IsValid(p *peer.Peer) bool { return f(p) }
-
-// Parameters holds the parameters that can be configured.
-type Parameters struct {
-	InboundNeighborSize        int           // number of inbound neighbors
-	OutboundNeighborSize       int           // number of outbound neighbors
-	SaltLifetime               time.Duration // lifetime of the private and public local salt
-	OutboundUpdateInterval     time.Duration // time interval after which the outbound neighbors are checked
-	FullOutboundUpdateInterval time.Duration // time after which the full outbound neighbors are updated
-}
-
-// SetParameters sets the global parameters for this package.
-// This function cannot be used concurrently.
-func SetParameters(param Parameters) {
-	if param.InboundNeighborSize > 0 {
-		inboundNeighborSize = param.InboundNeighborSize
-	} else {
-		inboundNeighborSize = DefaultInboundNeighborSize
-	}
-	if param.OutboundNeighborSize > 0 {
-		outboundNeighborSize = param.OutboundNeighborSize
-	} else {
-		outboundNeighborSize = DefaultOutboundNeighborSize
-	}
-	if param.SaltLifetime > 0 {
-		saltLifetime = param.SaltLifetime
-	} else {
-		saltLifetime = DefaultSaltLifetime
-	}
-	if param.OutboundUpdateInterval > 0 {
-		outboundUpdateInterval = param.OutboundUpdateInterval
-	} else {
-		outboundUpdateInterval = DefaultOutboundUpdateInterval
-	}
-	if param.FullOutboundUpdateInterval > 0 {
-		fullOutboundUpdateInterval = param.FullOutboundUpdateInterval
-	} else {
-		fullOutboundUpdateInterval = DefaultFullOutboundUpdateInterval
-	}
-}
diff --git a/packages/autopeering/selection/events.go b/packages/autopeering/selection/events.go
deleted file mode 100644
index bc927e91..00000000
--- a/packages/autopeering/selection/events.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package selection
-
-import (
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/salt"
-	"github.com/iotaledger/hive.go/events"
-)
-
-// Events contains all the events that are triggered during the neighbor selection.
-var Events = struct {
-	// A SaltUpdated event is triggered, when the private and public salt were updated.
-	SaltUpdated *events.Event
-	// An OutgoingPeering event is triggered, when a valid response of PeeringRequest has been received.
-	OutgoingPeering *events.Event
-	// An IncomingPeering event is triggered, when a valid PeerRequest has been received.
-	IncomingPeering *events.Event
-	// A Dropped event is triggered, when a neighbor is dropped or when a drop message is received.
-	Dropped *events.Event
-}{
-	SaltUpdated:     events.NewEvent(saltUpdatedCaller),
-	OutgoingPeering: events.NewEvent(peeringCaller),
-	IncomingPeering: events.NewEvent(peeringCaller),
-	Dropped:         events.NewEvent(droppedCaller),
-}
-
-// SaltUpdatedEvent bundles the information sent in the SaltUpdated event.
-type SaltUpdatedEvent struct {
-	Self            peer.ID    // ID of the peer triggering the event.
-	Public, Private *salt.Salt // the updated salt
-}
-
-// PeeringEvent bundles the information sent in the OutgoingPeering and IncomingPeering event.
-type PeeringEvent struct {
-	Self   peer.ID    // ID of the peer triggering the event.
-	Peer   *peer.Peer // peering partner
-	Status bool       // true, when the peering partner has accepted the request
-}
-
-// DroppedEvent bundles the information sent in Dropped events.
-type DroppedEvent struct {
-	Self      peer.ID // ID of the peer triggering the event.
-	DroppedID peer.ID // ID of the peer that gets dropped.
-}
-
-func saltUpdatedCaller(handler interface{}, params ...interface{}) {
-	handler.(func(*SaltUpdatedEvent))(params[0].(*SaltUpdatedEvent))
-}
-
-func peeringCaller(handler interface{}, params ...interface{}) {
-	handler.(func(*PeeringEvent))(params[0].(*PeeringEvent))
-}
-
-func droppedCaller(handler interface{}, params ...interface{}) {
-	handler.(func(*DroppedEvent))(params[0].(*DroppedEvent))
-}
diff --git a/packages/autopeering/selection/manager.go b/packages/autopeering/selection/manager.go
deleted file mode 100644
index 313d3c7c..00000000
--- a/packages/autopeering/selection/manager.go
+++ /dev/null
@@ -1,371 +0,0 @@
-package selection
-
-import (
-	"sync"
-	"time"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/salt"
-	"github.com/iotaledger/hive.go/logger"
-)
-
-const (
-	accept = true
-	reject = false
-
-	// buffer size of the channels handling inbound requests and drops.
-	queueSize = 10
-)
-
-// A network represents the communication layer for the manager.
-type network interface {
-	local() *peer.Local
-
-	PeeringRequest(*peer.Peer, *salt.Salt) (bool, error)
-	PeeringDrop(*peer.Peer)
-}
-
-type peeringRequest struct {
-	peer *peer.Peer
-	salt *salt.Salt
-}
-
-type manager struct {
-	net               network
-	getPeersToConnect func() []*peer.Peer
-	log               *logger.Logger
-	dropOnUpdate      bool      // set true to drop all neighbors when the salt is updated
-	neighborValidator Validator // potential neighbor validator
-
-	inbound  *Neighborhood
-	outbound *Neighborhood
-
-	rejectionFilter *Filter
-
-	dropChan    chan peer.ID
-	requestChan chan peeringRequest
-	replyChan   chan bool
-
-	wg      sync.WaitGroup
-	closing chan struct{}
-}
-
-func newManager(net network, peersFunc func() []*peer.Peer, log *logger.Logger, config Config) *manager {
-	return &manager{
-		net:               net,
-		getPeersToConnect: peersFunc,
-		log:               log,
-		dropOnUpdate:      config.DropOnUpdate,
-		neighborValidator: config.NeighborValidator,
-		inbound:           NewNeighborhood(inboundNeighborSize),
-		outbound:          NewNeighborhood(outboundNeighborSize),
-		rejectionFilter:   NewFilter(),
-		dropChan:          make(chan peer.ID, queueSize),
-		requestChan:       make(chan peeringRequest, queueSize),
-		replyChan:         make(chan bool, 1),
-		closing:           make(chan struct{}),
-	}
-}
-
-func (m *manager) start() {
-	if m.getPublicSalt() == nil || m.getPrivateSalt() == nil {
-		m.updateSalt()
-	}
-	m.wg.Add(1)
-	go m.loop()
-}
-
-func (m *manager) close() {
-	close(m.closing)
-	m.wg.Wait()
-}
-
-func (m *manager) getID() peer.ID {
-	return m.net.local().ID()
-}
-
-func (m *manager) getPublicSalt() *salt.Salt {
-	return m.net.local().GetPublicSalt()
-}
-
-func (m *manager) getPrivateSalt() *salt.Salt {
-	return m.net.local().GetPrivateSalt()
-}
-
-func (m *manager) getNeighbors() []*peer.Peer {
-	var neighbors []*peer.Peer
-	neighbors = append(neighbors, m.inbound.GetPeers()...)
-	neighbors = append(neighbors, m.outbound.GetPeers()...)
-
-	return neighbors
-}
-
-func (m *manager) getInNeighbors() []*peer.Peer {
-	return m.inbound.GetPeers()
-}
-
-func (m *manager) getOutNeighbors() []*peer.Peer {
-	return m.outbound.GetPeers()
-}
-
-func (m *manager) requestPeering(p *peer.Peer, s *salt.Salt) bool {
-	var status bool
-	select {
-	case m.requestChan <- peeringRequest{p, s}:
-		status = <-m.replyChan
-	default:
-		// a full queue should count as a failed request
-		status = false
-	}
-	return status
-}
-
-func (m *manager) removeNeighbor(id peer.ID) {
-	m.dropChan <- id
-}
-
-func (m *manager) loop() {
-	defer m.wg.Done()
-
-	var updateOutResultChan chan peer.PeerDistance
-	updateTimer := time.NewTimer(0) // setting this to 0 will cause a trigger right away
-	defer updateTimer.Stop()
-
-Loop:
-	for {
-		select {
-
-		// update the outbound neighbors
-		case <-updateTimer.C:
-			updateOutResultChan = make(chan peer.PeerDistance)
-			// check salt and update if necessary
-			if m.getPublicSalt().Expired() {
-				m.updateSalt()
-			}
-			// check for new peers to connect to in a separate go routine
-			go m.updateOutbound(updateOutResultChan)
-
-		// handle the result of updateOutbound
-		case req := <-updateOutResultChan:
-			if req.Remote != nil {
-				// if the peer is already in inbound, do not add it and remove it from inbound
-				if p := m.inbound.RemovePeer(req.Remote.ID()); p != nil {
-					m.triggerPeeringEvent(true, req.Remote, false)
-					m.dropPeering(p)
-				} else {
-					m.addNeighbor(m.outbound, req)
-					m.triggerPeeringEvent(true, req.Remote, true)
-				}
-			}
-			// call updateOutbound again after the given interval
-			updateOutResultChan = nil
-			updateTimer.Reset(m.getUpdateTimeout())
-
-		// handle a drop request
-		case id := <-m.dropChan:
-			droppedPeer := m.inbound.RemovePeer(id)
-			if p := m.outbound.RemovePeer(id); p != nil {
-				droppedPeer = p
-				m.rejectionFilter.AddPeer(id)
-				// if not yet updating, trigger an immediate update
-				if updateOutResultChan == nil && updateTimer.Stop() {
-					updateTimer.Reset(0)
-				}
-			}
-			if droppedPeer != nil {
-				m.dropPeering(droppedPeer)
-			}
-
-		// handle an inbound request
-		case req := <-m.requestChan:
-			status := m.handleInRequest(req)
-			// trigger in the main loop to guarantee order of events
-			m.triggerPeeringEvent(false, req.peer, status)
-
-		// on close, exit the loop
-		case <-m.closing:
-			break Loop
-		}
-	}
-
-	// wait for the updateOutbound to finish
-	if updateOutResultChan != nil {
-		<-updateOutResultChan
-	}
-}
-
-func (m *manager) getUpdateTimeout() time.Duration {
-	result := outboundUpdateInterval
-	if m.outbound.IsFull() {
-		result = fullOutboundUpdateInterval
-	}
-	saltExpiration := time.Until(m.getPublicSalt().GetExpiration())
-	if saltExpiration < result {
-		result = saltExpiration
-	}
-	return result
-}
-
-// updateOutbound updates outbound neighbors.
-func (m *manager) updateOutbound(resultChan chan<- peer.PeerDistance) {
-	var result peer.PeerDistance
-	defer func() { resultChan <- result }() // assure that a result is always sent to the channel
-
-	// sort verified peers by distance
-	distList := peer.SortBySalt(m.getID().Bytes(), m.getPublicSalt().GetBytes(), m.getPeersToConnect())
-
-	// filter out current neighbors
-	filter := m.getConnectedFilter()
-	if m.neighborValidator != nil {
-		filter.AddCondition(m.neighborValidator.IsValid)
-	}
-
-	// filter out previous rejections
-	filteredList := m.rejectionFilter.Apply(filter.Apply(distList))
-	if len(filteredList) == 0 {
-		return
-	}
-
-	// select new candidate
-	candidate := m.outbound.Select(filteredList)
-	if candidate.Remote == nil {
-		return
-	}
-
-	status, err := m.net.PeeringRequest(candidate.Remote, m.getPublicSalt())
-	if err != nil {
-		m.rejectionFilter.AddPeer(candidate.Remote.ID())
-		m.log.Debugw("error requesting peering",
-			"id", candidate.Remote.ID(),
-			"addr", candidate.Remote.Address(), "err", err,
-		)
-		return
-	}
-	if !status {
-		m.rejectionFilter.AddPeer(candidate.Remote.ID())
-		m.triggerPeeringEvent(true, candidate.Remote, false)
-		return
-	}
-
-	result = candidate
-}
-
-func (m *manager) handleInRequest(req peeringRequest) (resp bool) {
-	resp = reject
-	defer func() { m.replyChan <- resp }() // assure that a response is always issued
-
-	if !m.isValidNeighbor(req.peer) {
-		return
-	}
-
-	reqDistance := peer.NewPeerDistance(m.getID().Bytes(), m.getPrivateSalt().GetBytes(), req.peer)
-	filter := m.getConnectedFilter()
-	filteredList := filter.Apply([]peer.PeerDistance{reqDistance})
-	if len(filteredList) == 0 {
-		return
-	}
-
-	toAccept := m.inbound.Select(filteredList)
-	if toAccept.Remote == nil {
-		return
-	}
-
-	m.addNeighbor(m.inbound, toAccept)
-	resp = accept
-	return
-}
-
-func (m *manager) addNeighbor(nh *Neighborhood, toAdd peer.PeerDistance) {
-	// drop furthest neighbor if necessary
-	if furthest, _ := nh.getFurthest(); furthest.Remote != nil {
-		if p := nh.RemovePeer(furthest.Remote.ID()); p != nil {
-			m.dropPeering(p)
-		}
-	}
-	nh.Add(toAdd)
-}
-
-func (m *manager) updateSalt() {
-	public, _ := salt.NewSalt(saltLifetime)
-	m.net.local().SetPublicSalt(public)
-	private, _ := salt.NewSalt(saltLifetime)
-	m.net.local().SetPrivateSalt(private)
-
-	// clean the rejection filter
-	m.rejectionFilter.Clean()
-
-	if !m.dropOnUpdate { // update distance without dropping neighbors
-		m.outbound.UpdateDistance(m.getID().Bytes(), m.getPublicSalt().GetBytes())
-		m.inbound.UpdateDistance(m.getID().Bytes(), m.getPrivateSalt().GetBytes())
-	} else { // drop all the neighbors
-		m.dropNeighborhood(m.inbound)
-		m.dropNeighborhood(m.outbound)
-	}
-
-	m.log.Debugw("salt updated",
-		"public", saltLifetime,
-		"private", saltLifetime,
-	)
-	Events.SaltUpdated.Trigger(&SaltUpdatedEvent{Self: m.getID(), Public: public, Private: private})
-}
-
-func (m *manager) dropNeighborhood(nh *Neighborhood) {
-	for _, p := range nh.GetPeers() {
-		nh.RemovePeer(p.ID())
-		m.dropPeering(p)
-	}
-}
-
-// dropPeering sends the peering drop over the network and triggers the corresponding event.
-func (m *manager) dropPeering(p *peer.Peer) {
-	m.net.PeeringDrop(p)
-
-	m.log.Debugw("peering dropped",
-		"id", p.ID(),
-		"#out", m.outbound,
-		"#in", m.inbound,
-	)
-	Events.Dropped.Trigger(&DroppedEvent{Self: m.getID(), DroppedID: p.ID()})
-}
-
-func (m *manager) getConnectedFilter() *Filter {
-	filter := NewFilter()
-	filter.AddPeer(m.getID())              //set filter for oneself
-	filter.AddPeers(m.inbound.GetPeers())  // set filter for inbound neighbors
-	filter.AddPeers(m.outbound.GetPeers()) // set filter for outbound neighbors
-	return filter
-}
-
-// isValidNeighbor returns whether the given peer is a valid neighbor candidate.
-func (m *manager) isValidNeighbor(p *peer.Peer) bool {
-	// do not connect to oneself
-	if m.getID() == p.ID() {
-		return false
-	}
-	if m.neighborValidator == nil {
-		return true
-	}
-	return m.neighborValidator.IsValid(p)
-}
-
-func (m *manager) triggerPeeringEvent(isOut bool, p *peer.Peer, status bool) {
-	if isOut {
-		m.log.Debugw("peering requested",
-			"direction", "out",
-			"status", status,
-			"to", p.ID(),
-			"#out", m.outbound,
-			"#in", m.inbound,
-		)
-		Events.OutgoingPeering.Trigger(&PeeringEvent{Self: m.getID(), Peer: p, Status: status})
-	} else {
-		m.log.Debugw("peering requested",
-			"direction", "in",
-			"status", status,
-			"from", p.ID(),
-			"#out", m.outbound,
-			"#in", m.inbound,
-		)
-		Events.IncomingPeering.Trigger(&PeeringEvent{Self: m.getID(), Peer: p, Status: status})
-	}
-}
diff --git a/packages/autopeering/selection/manager_test.go b/packages/autopeering/selection/manager_test.go
deleted file mode 100644
index 5b9f746f..00000000
--- a/packages/autopeering/selection/manager_test.go
+++ /dev/null
@@ -1,216 +0,0 @@
-package selection
-
-import (
-	"fmt"
-	"sync"
-	"testing"
-	"time"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/peertest"
-	"github.com/iotaledger/goshimmer/packages/autopeering/salt"
-	"github.com/iotaledger/goshimmer/packages/database/mapdb"
-	"github.com/iotaledger/hive.go/events"
-	"github.com/stretchr/testify/assert"
-)
-
-const (
-	testSaltLifetime   = time.Hour     // disable salt updates
-	testUpdateInterval = 2 * graceTime // very short update interval to speed up tests
-)
-
-func TestMgrNoDuplicates(t *testing.T) {
-	const (
-		nNeighbors = 4
-		nNodes     = 2*nNeighbors + 1
-	)
-	SetParameters(Parameters{
-		OutboundNeighborSize:   nNeighbors,
-		InboundNeighborSize:    nNeighbors,
-		SaltLifetime:           testSaltLifetime,
-		OutboundUpdateInterval: testUpdateInterval,
-	})
-
-	mgrMap := make(map[peer.ID]*manager)
-	runTestNetwork(nNodes, mgrMap)
-
-	for _, mgr := range mgrMap {
-		assert.NotEmpty(t, mgr.getOutNeighbors())
-		assert.NotEmpty(t, mgr.getInNeighbors())
-		assert.Empty(t, getDuplicates(mgr.getNeighbors()))
-	}
-}
-
-func TestEvents(t *testing.T) {
-	// we want many drops/connects
-	const (
-		nNeighbors = 2
-		nNodes     = 10
-	)
-	SetParameters(Parameters{
-		OutboundNeighborSize:   nNeighbors,
-		InboundNeighborSize:    nNeighbors,
-		SaltLifetime:           3 * testUpdateInterval,
-		OutboundUpdateInterval: testUpdateInterval,
-	})
-
-	e, teardown := newEventMock(t)
-	defer teardown()
-	mgrMap := make(map[peer.ID]*manager)
-	runTestNetwork(nNodes, mgrMap)
-
-	// the events should lead to exactly the same neighbors
-	for _, mgr := range mgrMap {
-		nc := e.m[mgr.getID()]
-		assert.ElementsMatchf(t, mgr.getOutNeighbors(), getValues(nc.out),
-			"out neighbors of %s do not match", mgr.getID())
-		assert.ElementsMatch(t, mgr.getInNeighbors(), getValues(nc.in),
-			"in neighbors of %s do not match", mgr.getID())
-	}
-}
-
-func getValues(m map[peer.ID]*peer.Peer) []*peer.Peer {
-	result := make([]*peer.Peer, 0, len(m))
-	for _, p := range m {
-		result = append(result, p)
-	}
-	return result
-}
-
-func runTestNetwork(n int, mgrMap map[peer.ID]*manager) {
-	for i := 0; i < n; i++ {
-		_ = newTestManager(fmt.Sprintf("%d", i), mgrMap)
-	}
-	for _, mgr := range mgrMap {
-		mgr.start()
-	}
-
-	// give the managers time to potentially connect all other peers
-	time.Sleep((time.Duration(n) - 1) * (outboundUpdateInterval + graceTime))
-
-	// close all the managers
-	for _, mgr := range mgrMap {
-		mgr.close()
-	}
-}
-
-func getDuplicates(peers []*peer.Peer) []*peer.Peer {
-	seen := make(map[peer.ID]bool, len(peers))
-	result := make([]*peer.Peer, 0, len(peers))
-
-	for _, p := range peers {
-		if !seen[p.ID()] {
-			seen[p.ID()] = true
-		} else {
-			result = append(result, p)
-		}
-	}
-
-	return result
-}
-
-type neighbors struct {
-	out, in map[peer.ID]*peer.Peer
-}
-
-type eventMock struct {
-	t    *testing.T
-	lock sync.Mutex
-	m    map[peer.ID]neighbors
-}
-
-func newEventMock(t *testing.T) (*eventMock, func()) {
-	e := &eventMock{
-		t: t,
-		m: make(map[peer.ID]neighbors),
-	}
-
-	outgoingPeeringC := events.NewClosure(e.outgoingPeering)
-	incomingPeeringC := events.NewClosure(e.incomingPeering)
-	droppedC := events.NewClosure(e.dropped)
-
-	Events.OutgoingPeering.Attach(outgoingPeeringC)
-	Events.IncomingPeering.Attach(incomingPeeringC)
-	Events.Dropped.Attach(droppedC)
-
-	teardown := func() {
-		Events.OutgoingPeering.Detach(outgoingPeeringC)
-		Events.IncomingPeering.Detach(incomingPeeringC)
-		Events.Dropped.Detach(droppedC)
-	}
-	return e, teardown
-}
-
-func (e *eventMock) outgoingPeering(ev *PeeringEvent) {
-	if !ev.Status {
-		return
-	}
-	e.lock.Lock()
-	defer e.lock.Unlock()
-	s, ok := e.m[ev.Self]
-	if !ok {
-		s = neighbors{out: make(map[peer.ID]*peer.Peer), in: make(map[peer.ID]*peer.Peer)}
-		e.m[ev.Self] = s
-	}
-	assert.NotContains(e.t, s.out, ev.Peer)
-	s.out[ev.Peer.ID()] = ev.Peer
-}
-
-func (e *eventMock) incomingPeering(ev *PeeringEvent) {
-	if !ev.Status {
-		return
-	}
-	e.lock.Lock()
-	defer e.lock.Unlock()
-	s, ok := e.m[ev.Self]
-	if !ok {
-		s = neighbors{out: make(map[peer.ID]*peer.Peer), in: make(map[peer.ID]*peer.Peer)}
-		e.m[ev.Self] = s
-	}
-	assert.NotContains(e.t, s.in, ev.Peer)
-	s.in[ev.Peer.ID()] = ev.Peer
-}
-
-func (e *eventMock) dropped(ev *DroppedEvent) {
-	e.lock.Lock()
-	defer e.lock.Unlock()
-	if assert.Contains(e.t, e.m, ev.Self) {
-		s := e.m[ev.Self]
-		delete(s.out, ev.DroppedID)
-		delete(s.in, ev.DroppedID)
-	}
-}
-
-type networkMock struct {
-	loc *peer.Local
-	mgr map[peer.ID]*manager
-}
-
-func (n *networkMock) local() *peer.Local {
-	return n.loc
-}
-
-func (n *networkMock) PeeringDrop(p *peer.Peer) {
-	n.mgr[p.ID()].removeNeighbor(n.local().ID())
-}
-
-func (n *networkMock) PeeringRequest(p *peer.Peer, s *salt.Salt) (bool, error) {
-	return n.mgr[p.ID()].requestPeering(&n.local().Peer, s), nil
-}
-
-func (n *networkMock) GetKnownPeers() []*peer.Peer {
-	peers := make([]*peer.Peer, 0, len(n.mgr))
-	for _, m := range n.mgr {
-		peers = append(peers, &m.net.local().Peer)
-	}
-	return peers
-}
-
-func newTestManager(name string, mgrMap map[peer.ID]*manager) *manager {
-	db, _ := peer.NewDB(mapdb.NewMapDB())
-	local := peertest.NewLocal("mock", name, db)
-	networkMock := &networkMock{loc: local, mgr: mgrMap}
-	m := newManager(networkMock, networkMock.GetKnownPeers, log.Named(name), Config{})
-	mgrMap[m.getID()] = m
-	return m
-}
diff --git a/packages/autopeering/selection/neighborhood.go b/packages/autopeering/selection/neighborhood.go
deleted file mode 100644
index 638874b0..00000000
--- a/packages/autopeering/selection/neighborhood.go
+++ /dev/null
@@ -1,132 +0,0 @@
-package selection
-
-import (
-	"fmt"
-	"sync"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/distance"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-)
-
-type Neighborhood struct {
-	neighbors []peer.PeerDistance
-	size      int
-	mu        sync.RWMutex
-}
-
-func NewNeighborhood(size int) *Neighborhood {
-	return &Neighborhood{
-		neighbors: []peer.PeerDistance{},
-		size:      size,
-	}
-}
-
-func (nh *Neighborhood) String() string {
-	return fmt.Sprintf("%d/%d", nh.GetNumPeers(), nh.size)
-}
-
-func (nh *Neighborhood) getFurthest() (peer.PeerDistance, int) {
-	nh.mu.RLock()
-	defer nh.mu.RUnlock()
-	if len(nh.neighbors) < nh.size {
-		return peer.PeerDistance{
-			Remote:   nil,
-			Distance: distance.Max,
-		}, len(nh.neighbors)
-	}
-
-	index := 0
-	furthest := nh.neighbors[index]
-	for i, n := range nh.neighbors {
-		if n.Distance > furthest.Distance {
-			furthest = n
-			index = i
-		}
-	}
-	return furthest, index
-}
-
-func (nh *Neighborhood) Select(candidates []peer.PeerDistance) peer.PeerDistance {
-	if len(candidates) > 0 {
-		target, _ := nh.getFurthest()
-		for _, candidate := range candidates {
-			if candidate.Distance < target.Distance {
-				return candidate
-			}
-		}
-	}
-	return peer.PeerDistance{}
-}
-
-// Add tries to add a new peer with distance to the neighborhood.
-// It returns true, if the peer was added, or false if the neighborhood was full.
-func (nh *Neighborhood) Add(toAdd peer.PeerDistance) bool {
-	nh.mu.Lock()
-	defer nh.mu.Unlock()
-	if len(nh.neighbors) >= nh.size {
-		return false
-	}
-	nh.neighbors = append(nh.neighbors, toAdd)
-	return true
-}
-
-// RemovePeer removes the peer with the given ID from the neighborhood.
-// It returns the peer that was removed or nil of no such peer exists.
-func (nh *Neighborhood) RemovePeer(id peer.ID) *peer.Peer {
-	nh.mu.Lock()
-	defer nh.mu.Unlock()
-
-	index := nh.getPeerIndex(id)
-	if index < 0 {
-		return nil
-	}
-	n := nh.neighbors[index]
-
-	// remove index from slice
-	if index < len(nh.neighbors)-1 {
-		copy(nh.neighbors[index:], nh.neighbors[index+1:])
-	}
-	nh.neighbors[len(nh.neighbors)-1] = peer.PeerDistance{}
-	nh.neighbors = nh.neighbors[:len(nh.neighbors)-1]
-
-	return n.Remote
-}
-
-func (nh *Neighborhood) getPeerIndex(id peer.ID) int {
-	for i, p := range nh.neighbors {
-		if p.Remote.ID() == id {
-			return i
-		}
-	}
-	return -1
-}
-
-func (nh *Neighborhood) UpdateDistance(anchor, salt []byte) {
-	nh.mu.Lock()
-	defer nh.mu.Unlock()
-	for i, n := range nh.neighbors {
-		nh.neighbors[i].Distance = distance.BySalt(anchor, n.Remote.ID().Bytes(), salt)
-	}
-}
-
-func (nh *Neighborhood) IsFull() bool {
-	nh.mu.RLock()
-	defer nh.mu.RUnlock()
-	return len(nh.neighbors) >= nh.size
-}
-
-func (nh *Neighborhood) GetPeers() []*peer.Peer {
-	nh.mu.RLock()
-	defer nh.mu.RUnlock()
-	result := make([]*peer.Peer, len(nh.neighbors))
-	for i, n := range nh.neighbors {
-		result[i] = n.Remote
-	}
-	return result
-}
-
-func (nh *Neighborhood) GetNumPeers() int {
-	nh.mu.RLock()
-	defer nh.mu.RUnlock()
-	return len(nh.neighbors)
-}
diff --git a/packages/autopeering/selection/neighborhood_test.go b/packages/autopeering/selection/neighborhood_test.go
deleted file mode 100644
index 04891d91..00000000
--- a/packages/autopeering/selection/neighborhood_test.go
+++ /dev/null
@@ -1,254 +0,0 @@
-package selection
-
-import (
-	"fmt"
-	"testing"
-	"time"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/distance"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/peertest"
-	"github.com/iotaledger/goshimmer/packages/autopeering/salt"
-	"github.com/stretchr/testify/assert"
-)
-
-func TestGetFurthest(t *testing.T) {
-	d := make([]peer.PeerDistance, 5)
-	for i := range d {
-		d[i].Remote = peertest.NewPeer(testNetwork, fmt.Sprintf("%d", i))
-		d[i].Distance = uint32(i + 1)
-	}
-
-	type testCase struct {
-		input    *Neighborhood
-		expected peer.PeerDistance
-		index    int
-	}
-
-	tests := []testCase{
-		{
-			input: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0]},
-				size:      4},
-			expected: peer.PeerDistance{
-				Remote:   nil,
-				Distance: distance.Max},
-			index: 1,
-		},
-		{
-			input: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0], d[1], d[2], d[3]},
-				size:      4},
-			expected: d[3],
-			index:    3,
-		},
-		{
-			input: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0], d[1], d[4], d[2]},
-				size:      4},
-			expected: d[4],
-			index:    2,
-		},
-	}
-
-	for _, test := range tests {
-		p, l := test.input.getFurthest()
-		assert.Equal(t, test.expected, p, "Get furthest neighbor")
-		assert.Equal(t, test.index, l, "Get furthest neighbor")
-	}
-}
-
-func TestGetPeerIndex(t *testing.T) {
-	d := make([]peer.PeerDistance, 5)
-	for i := range d {
-		d[i].Remote = peertest.NewPeer(testNetwork, fmt.Sprintf("%d", i))
-		d[i].Distance = uint32(i + 1)
-	}
-
-	type testCase struct {
-		input  *Neighborhood
-		target *peer.Peer
-		index  int
-	}
-
-	tests := []testCase{
-		{
-			input: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0]},
-				size:      4},
-			target: d[0].Remote,
-			index:  0,
-		},
-		{
-			input: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0], d[1], d[2], d[3]},
-				size:      4},
-			target: d[3].Remote,
-			index:  3,
-		},
-		{
-			input: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0], d[1], d[4], d[2]},
-				size:      4},
-			target: d[3].Remote,
-			index:  -1,
-		},
-	}
-
-	for _, test := range tests {
-		i := test.input.getPeerIndex(test.target.ID())
-		assert.Equal(t, test.index, i, "Get Peer Index")
-	}
-}
-
-func TestRemove(t *testing.T) {
-	d := make([]peer.PeerDistance, 10)
-	for i := range d {
-		d[i].Remote = peertest.NewPeer(testNetwork, fmt.Sprintf("%d", i))
-		d[i].Distance = uint32(i + 1)
-	}
-
-	type testCase struct {
-		input    *Neighborhood
-		toRemove *peer.Peer
-		expected []peer.PeerDistance
-	}
-
-	tests := []testCase{
-		{
-			input: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0]},
-				size:      4},
-			toRemove: d[0].Remote,
-			expected: []peer.PeerDistance{},
-		},
-		{
-			input: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0], d[1], d[3]},
-				size:      4},
-			toRemove: d[1].Remote,
-			expected: []peer.PeerDistance{d[0], d[3]},
-		},
-		{
-			input: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0], d[1], d[4], d[2]},
-				size:      4},
-			toRemove: d[2].Remote,
-			expected: []peer.PeerDistance{d[0], d[1], d[4]},
-		},
-	}
-
-	for _, test := range tests {
-		test.input.RemovePeer(test.toRemove.ID())
-		assert.Equal(t, test.expected, test.input.neighbors, "Remove")
-	}
-}
-
-func TestAdd(t *testing.T) {
-	d := make([]peer.PeerDistance, 10)
-	for i := range d {
-		d[i].Remote = peertest.NewPeer(testNetwork, fmt.Sprintf("%d", i))
-		d[i].Distance = uint32(i + 1)
-	}
-
-	type testCase struct {
-		input    *Neighborhood
-		toAdd    peer.PeerDistance
-		expected []peer.PeerDistance
-	}
-
-	tests := []testCase{
-		{
-			input: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0]},
-				size:      4},
-			toAdd:    d[2],
-			expected: []peer.PeerDistance{d[0], d[2]},
-		},
-		{
-			input: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0], d[1], d[3]},
-				size:      4},
-			toAdd:    d[2],
-			expected: []peer.PeerDistance{d[0], d[1], d[3], d[2]},
-		},
-		{
-			input: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0], d[1], d[4], d[2]},
-				size:      4},
-			toAdd:    d[3],
-			expected: []peer.PeerDistance{d[0], d[1], d[4], d[2]},
-		},
-	}
-
-	for _, test := range tests {
-		test.input.Add(test.toAdd)
-		assert.Equal(t, test.expected, test.input.neighbors, "Add")
-	}
-}
-
-func TestUpdateDistance(t *testing.T) {
-	d := make([]peer.PeerDistance, 5)
-	for i := range d {
-		d[i].Remote = peertest.NewPeer(testNetwork, fmt.Sprintf("%d", i))
-		d[i].Distance = uint32(i + 1)
-	}
-
-	s, _ := salt.NewSalt(100 * time.Second)
-
-	d2 := make([]peer.PeerDistance, 4)
-	for i := range d2 {
-		d2[i].Remote = d[i+1].Remote
-		d2[i].Distance = distance.BySalt(d[0].Remote.ID().Bytes(), d2[i].Remote.ID().Bytes(), s.GetBytes())
-	}
-
-	neighborhood := Neighborhood{
-		neighbors: d[1:],
-		size:      4}
-
-	neighborhood.UpdateDistance(d[0].Remote.ID().Bytes(), s.GetBytes())
-
-	assert.Equal(t, d2, neighborhood.neighbors, "UpdateDistance")
-}
-
-func TestGetPeers(t *testing.T) {
-	d := make([]peer.PeerDistance, 4)
-	peers := make([]*peer.Peer, 4)
-
-	for i := range d {
-		d[i].Remote = peertest.NewPeer(testNetwork, fmt.Sprintf("%d", i))
-		d[i].Distance = uint32(i + 1)
-		peers[i] = d[i].Remote
-	}
-
-	type testCase struct {
-		input    *Neighborhood
-		expected []*peer.Peer
-	}
-
-	tests := []testCase{
-		{
-			input: &Neighborhood{
-				neighbors: []peer.PeerDistance{},
-				size:      4},
-			expected: []*peer.Peer{},
-		},
-		{
-			input: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0]},
-				size:      4},
-			expected: []*peer.Peer{peers[0]},
-		},
-		{
-			input: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0], d[1], d[3], d[2]},
-				size:      4},
-			expected: []*peer.Peer{peers[0], peers[1], peers[3], peers[2]},
-		},
-	}
-
-	for _, test := range tests {
-		got := test.input.GetPeers()
-		assert.Equal(t, test.expected, got, "GetPeers")
-	}
-}
diff --git a/packages/autopeering/selection/proto/message.go b/packages/autopeering/selection/proto/message.go
deleted file mode 100644
index 3e1516a6..00000000
--- a/packages/autopeering/selection/proto/message.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package proto
-
-import (
-	"github.com/golang/protobuf/proto"
-	"github.com/iotaledger/goshimmer/packages/autopeering/server"
-)
-
-// MType is the type of message type enum.
-type MType = server.MType
-
-// An enum for the different message types.
-const (
-	MPeeringRequest MType = 20 + iota
-	MPeeringResponse
-	MPeeringDrop
-)
-
-// Message extends the proto.Message interface with additional util functions.
-type Message interface {
-	proto.Message
-
-	// Name returns the name of the corresponding message type for debugging.
-	Name() string
-	// Type returns the type of the corresponding message as an enum.
-	Type() MType
-}
-
-func (m *PeeringRequest) Name() string { return "PEERING_REQUEST" }
-func (m *PeeringRequest) Type() MType  { return MPeeringRequest }
-
-func (m *PeeringResponse) Name() string { return "PEERING_RESPONSE" }
-func (m *PeeringResponse) Type() MType  { return MPeeringResponse }
-
-func (m *PeeringDrop) Name() string { return "PEERING_DROP" }
-func (m *PeeringDrop) Type() MType  { return MPeeringDrop }
diff --git a/packages/autopeering/selection/proto/message.pb.go b/packages/autopeering/selection/proto/message.pb.go
deleted file mode 100644
index 5ad61039..00000000
--- a/packages/autopeering/selection/proto/message.pb.go
+++ /dev/null
@@ -1,207 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// source: selection/proto/message.proto
-
-package proto
-
-import (
-	fmt "fmt"
-	math "math"
-
-	proto "github.com/golang/protobuf/proto"
-	proto1 "github.com/iotaledger/goshimmer/packages/autopeering/salt/proto"
-)
-
-// Reference imports to suppress errors if they are not otherwise used.
-var _ = proto.Marshal
-var _ = fmt.Errorf
-var _ = math.Inf
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the proto package it is being compiled against.
-// A compilation error at this line likely means your copy of the
-// proto package needs to be updated.
-const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
-
-type PeeringRequest struct {
-	// string form of the recipient address
-	To string `protobuf:"bytes,1,opt,name=to,proto3" json:"to,omitempty"`
-	// unix time
-	Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
-	// salt of the requester
-	Salt                 *proto1.Salt `protobuf:"bytes,3,opt,name=salt,proto3" json:"salt,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}     `json:"-"`
-	XXX_unrecognized     []byte       `json:"-"`
-	XXX_sizecache        int32        `json:"-"`
-}
-
-func (m *PeeringRequest) Reset()         { *m = PeeringRequest{} }
-func (m *PeeringRequest) String() string { return proto.CompactTextString(m) }
-func (*PeeringRequest) ProtoMessage()    {}
-func (*PeeringRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_e39e4329bafd72d5, []int{0}
-}
-
-func (m *PeeringRequest) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_PeeringRequest.Unmarshal(m, b)
-}
-func (m *PeeringRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_PeeringRequest.Marshal(b, m, deterministic)
-}
-func (m *PeeringRequest) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_PeeringRequest.Merge(m, src)
-}
-func (m *PeeringRequest) XXX_Size() int {
-	return xxx_messageInfo_PeeringRequest.Size(m)
-}
-func (m *PeeringRequest) XXX_DiscardUnknown() {
-	xxx_messageInfo_PeeringRequest.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_PeeringRequest proto.InternalMessageInfo
-
-func (m *PeeringRequest) GetTo() string {
-	if m != nil {
-		return m.To
-	}
-	return ""
-}
-
-func (m *PeeringRequest) GetTimestamp() int64 {
-	if m != nil {
-		return m.Timestamp
-	}
-	return 0
-}
-
-func (m *PeeringRequest) GetSalt() *proto1.Salt {
-	if m != nil {
-		return m.Salt
-	}
-	return nil
-}
-
-type PeeringResponse struct {
-	// hash of the corresponding request
-	ReqHash []byte `protobuf:"bytes,1,opt,name=req_hash,json=reqHash,proto3" json:"req_hash,omitempty"`
-	// response of a peering request
-	Status               bool     `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
-
-func (m *PeeringResponse) Reset()         { *m = PeeringResponse{} }
-func (m *PeeringResponse) String() string { return proto.CompactTextString(m) }
-func (*PeeringResponse) ProtoMessage()    {}
-func (*PeeringResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_e39e4329bafd72d5, []int{1}
-}
-
-func (m *PeeringResponse) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_PeeringResponse.Unmarshal(m, b)
-}
-func (m *PeeringResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_PeeringResponse.Marshal(b, m, deterministic)
-}
-func (m *PeeringResponse) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_PeeringResponse.Merge(m, src)
-}
-func (m *PeeringResponse) XXX_Size() int {
-	return xxx_messageInfo_PeeringResponse.Size(m)
-}
-func (m *PeeringResponse) XXX_DiscardUnknown() {
-	xxx_messageInfo_PeeringResponse.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_PeeringResponse proto.InternalMessageInfo
-
-func (m *PeeringResponse) GetReqHash() []byte {
-	if m != nil {
-		return m.ReqHash
-	}
-	return nil
-}
-
-func (m *PeeringResponse) GetStatus() bool {
-	if m != nil {
-		return m.Status
-	}
-	return false
-}
-
-type PeeringDrop struct {
-	// string form of the recipient address
-	To string `protobuf:"bytes,1,opt,name=to,proto3" json:"to,omitempty"`
-	// unix time
-	Timestamp            int64    `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
-
-func (m *PeeringDrop) Reset()         { *m = PeeringDrop{} }
-func (m *PeeringDrop) String() string { return proto.CompactTextString(m) }
-func (*PeeringDrop) ProtoMessage()    {}
-func (*PeeringDrop) Descriptor() ([]byte, []int) {
-	return fileDescriptor_e39e4329bafd72d5, []int{2}
-}
-
-func (m *PeeringDrop) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_PeeringDrop.Unmarshal(m, b)
-}
-func (m *PeeringDrop) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_PeeringDrop.Marshal(b, m, deterministic)
-}
-func (m *PeeringDrop) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_PeeringDrop.Merge(m, src)
-}
-func (m *PeeringDrop) XXX_Size() int {
-	return xxx_messageInfo_PeeringDrop.Size(m)
-}
-func (m *PeeringDrop) XXX_DiscardUnknown() {
-	xxx_messageInfo_PeeringDrop.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_PeeringDrop proto.InternalMessageInfo
-
-func (m *PeeringDrop) GetTo() string {
-	if m != nil {
-		return m.To
-	}
-	return ""
-}
-
-func (m *PeeringDrop) GetTimestamp() int64 {
-	if m != nil {
-		return m.Timestamp
-	}
-	return 0
-}
-
-func init() {
-	proto.RegisterType((*PeeringRequest)(nil), "proto.PeeringRequest")
-	proto.RegisterType((*PeeringResponse)(nil), "proto.PeeringResponse")
-	proto.RegisterType((*PeeringDrop)(nil), "proto.PeeringDrop")
-}
-
-func init() { proto.RegisterFile("selection/proto/message.proto", fileDescriptor_e39e4329bafd72d5) }
-
-var fileDescriptor_e39e4329bafd72d5 = []byte{
-	// 243 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x90, 0xc1, 0x4b, 0xf3, 0x40,
-	0x10, 0xc5, 0x69, 0xfb, 0x7d, 0xb5, 0x9d, 0x48, 0x85, 0x05, 0x25, 0x8a, 0xa2, 0xe4, 0xe4, 0xc5,
-	0x2c, 0x28, 0xe2, 0xc1, 0x9b, 0xf4, 0xe0, 0x51, 0xd6, 0x9b, 0x97, 0xb2, 0xad, 0x43, 0xb2, 0x90,
-	0x64, 0xb6, 0x3b, 0x93, 0xff, 0xdf, 0xed, 0x26, 0x28, 0x78, 0xf3, 0x34, 0xf3, 0xde, 0x5b, 0x7e,
-	0x6f, 0x19, 0xb8, 0x62, 0x6c, 0x70, 0x27, 0x8e, 0x3a, 0xed, 0x03, 0x09, 0xe9, 0x16, 0x99, 0x6d,
-	0x85, 0x65, 0x52, 0xea, 0x7f, 0x1a, 0x17, 0xa7, 0x6c, 0x1b, 0x19, 0x1f, 0x1c, 0xd6, 0x21, 0x2d,
-	0x36, 0xb0, 0x7a, 0x43, 0x0c, 0xae, 0xab, 0x0c, 0xee, 0x7b, 0x64, 0x51, 0x2b, 0x98, 0x0a, 0xe5,
-	0x93, 0x9b, 0xc9, 0xed, 0xd2, 0xc4, 0x4d, 0x5d, 0xc2, 0x52, 0x5c, 0x44, 0x8a, 0x6d, 0x7d, 0x3e,
-	0x8d, 0xf6, 0xcc, 0xfc, 0x18, 0xea, 0x1a, 0xfe, 0x1d, 0x68, 0xf9, 0x2c, 0x06, 0xd9, 0x7d, 0x36,
-	0x50, 0xcb, 0xf7, 0x68, 0x99, 0x14, 0x14, 0x6b, 0x38, 0xf9, 0x2e, 0x60, 0x4f, 0x1d, 0xa3, 0x3a,
-	0x87, 0x45, 0xc0, 0xfd, 0xa6, 0xb6, 0x5c, 0xa7, 0x9e, 0x63, 0x73, 0x14, 0xf5, 0x6b, 0x94, 0xea,
-	0x0c, 0xe6, 0x91, 0x2b, 0x3d, 0xa7, 0xa6, 0x85, 0x19, 0x55, 0xf1, 0x0c, 0xd9, 0x48, 0x59, 0x07,
-	0xf2, 0x7f, 0xfb, 0xe3, 0xcb, 0xd3, 0xc7, 0x63, 0xe5, 0xa4, 0xee, 0xb7, 0xe5, 0x8e, 0x5a, 0xed,
-	0x48, 0x6c, 0x83, 0x9f, 0x15, 0x06, 0x6d, 0x7b, 0x21, 0x3f, 0x60, 0xef, 0xd8, 0xb5, 0xfa, 0xd7,
-	0x21, 0xb7, 0xf3, 0x34, 0x1e, 0xbe, 0x02, 0x00, 0x00, 0xff, 0xff, 0x3e, 0x1b, 0x76, 0xbe, 0x62,
-	0x01, 0x00, 0x00,
-}
diff --git a/packages/autopeering/selection/proto/message.proto b/packages/autopeering/selection/proto/message.proto
deleted file mode 100644
index 0e070951..00000000
--- a/packages/autopeering/selection/proto/message.proto
+++ /dev/null
@@ -1,30 +0,0 @@
-syntax = "proto3";
-
-option go_package = "github.com/iotaledger/goshimmer/packages/autopeering/selection/proto";
-
-package proto;
-
-import "salt/proto/salt.proto";
-
-message PeeringRequest {
-  // string form of the recipient address
-  string to = 1;
-  // unix time
-  int64 timestamp = 2;
-  // salt of the requester
-  Salt salt = 3;
-}
-
-message PeeringResponse {
-  // hash of the corresponding request
-  bytes req_hash = 1;
-  // response of a peering request
-  bool status = 2;
-}
-
-message PeeringDrop {
-  // string form of the recipient address
-  string to = 1;
-  // unix time
-  int64 timestamp = 2;
-}
diff --git a/packages/autopeering/selection/protocol.go b/packages/autopeering/selection/protocol.go
deleted file mode 100644
index b0cf1cc1..00000000
--- a/packages/autopeering/selection/protocol.go
+++ /dev/null
@@ -1,370 +0,0 @@
-package selection
-
-import (
-	"bytes"
-	"errors"
-	"fmt"
-	"sync"
-	"time"
-
-	"github.com/golang/protobuf/proto"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
-	"github.com/iotaledger/goshimmer/packages/autopeering/salt"
-	pb "github.com/iotaledger/goshimmer/packages/autopeering/selection/proto"
-	"github.com/iotaledger/goshimmer/packages/autopeering/server"
-	"github.com/iotaledger/hive.go/backoff"
-	"github.com/iotaledger/hive.go/logger"
-	"github.com/iotaledger/hive.go/typeutils"
-)
-
-const (
-	maxRetries = 2
-	logSends   = true
-)
-
-//  policy for retrying failed network calls
-var retryPolicy = backoff.ExponentialBackOff(500*time.Millisecond, 1.5).With(
-	backoff.Jitter(0.5), backoff.MaxRetries(maxRetries))
-
-// DiscoverProtocol specifies the methods from the peer discovery that are required.
-type DiscoverProtocol interface {
-	IsVerified(id peer.ID, addr string) bool
-	EnsureVerified(*peer.Peer) error
-
-	GetVerifiedPeer(id peer.ID, addr string) *peer.Peer
-	GetVerifiedPeers() []*peer.Peer
-}
-
-// The Protocol handles the neighbor selection.
-// It responds to incoming messages and sends own requests when needed.
-type Protocol struct {
-	server.Protocol
-
-	disc DiscoverProtocol // reference to the peer discovery to query verified peers
-	loc  *peer.Local      // local peer that runs the protocol
-	log  *logger.Logger   // logging
-
-	mgr       *manager // the manager handles the actual neighbor selection
-	running   *typeutils.AtomicBool
-	closeOnce sync.Once
-}
-
-// New creates a new neighbor selection protocol.
-func New(local *peer.Local, disc DiscoverProtocol, cfg Config) *Protocol {
-	p := &Protocol{
-		Protocol: server.Protocol{},
-		loc:      local,
-		disc:     disc,
-		log:      cfg.Log,
-		running:  typeutils.NewAtomicBool(),
-	}
-	p.mgr = newManager(p, disc.GetVerifiedPeers, cfg.Log.Named("mgr"), cfg)
-
-	return p
-}
-
-// Start starts the actual neighbor selection over the provided Sender.
-func (p *Protocol) Start(s server.Sender) {
-	p.Protocol.Sender = s
-	p.mgr.start()
-	p.log.Debug("neighborhood started")
-	p.running.Set()
-}
-
-// Close finalizes the protocol.
-func (p *Protocol) Close() {
-	p.closeOnce.Do(func() {
-		p.running.UnSet()
-		p.mgr.close()
-	})
-}
-
-// GetNeighbors returns the current neighbors.
-func (p *Protocol) GetNeighbors() []*peer.Peer {
-	return p.mgr.getNeighbors()
-}
-
-// GetIncomingNeighbors returns the current incoming neighbors.
-func (p *Protocol) GetIncomingNeighbors() []*peer.Peer {
-	return p.mgr.getInNeighbors()
-}
-
-// GetOutgoingNeighbors returns the current outgoing neighbors.
-func (p *Protocol) GetOutgoingNeighbors() []*peer.Peer {
-	return p.mgr.getOutNeighbors()
-}
-
-// RemoveNeighbor removes the peer with the given id from the incoming and outgoing neighbors.
-// If such a peer was actually contained in anyone of the neighbor sets, the corresponding event is triggered
-// and the corresponding peering drop is sent. Otherwise the call is ignored.
-func (p *Protocol) RemoveNeighbor(id peer.ID) {
-	p.mgr.removeNeighbor(id)
-}
-
-// HandleMessage responds to incoming neighbor selection messages.
-func (p *Protocol) HandleMessage(s *server.Server, fromAddr string, fromID peer.ID, _ peer.PublicKey, data []byte) (bool, error) {
-	if !p.running.IsSet() {
-		return false, nil
-	}
-
-	switch pb.MType(data[0]) {
-	// PeeringRequest
-	case pb.MPeeringRequest:
-		m := new(pb.PeeringRequest)
-		if err := proto.Unmarshal(data[1:], m); err != nil {
-			return true, fmt.Errorf("invalid message: %w", err)
-		}
-		if p.validatePeeringRequest(fromAddr, fromID, m) {
-			p.handlePeeringRequest(s, fromAddr, fromID, data, m)
-		}
-
-	// PeeringResponse
-	case pb.MPeeringResponse:
-		m := new(pb.PeeringResponse)
-		if err := proto.Unmarshal(data[1:], m); err != nil {
-			return true, fmt.Errorf("invalid message: %w", err)
-		}
-		p.validatePeeringResponse(s, fromAddr, fromID, m)
-		// PeeringResponse messages are handled in the handleReply function of the validation
-
-	// PeeringDrop
-	case pb.MPeeringDrop:
-		m := new(pb.PeeringDrop)
-		if err := proto.Unmarshal(data[1:], m); err != nil {
-			return true, fmt.Errorf("invalid message: %w", err)
-		}
-		if p.validatePeeringDrop(fromAddr, m) {
-			p.handlePeeringDrop(fromID)
-		}
-
-	default:
-		return false, nil
-	}
-
-	return true, nil
-}
-
-// Local returns the associated local peer of the neighbor selection.
-func (p *Protocol) local() *peer.Local {
-	return p.loc
-}
-
-// publicAddr returns the public address of the peering service in string representation.
-func (p *Protocol) publicAddr() string {
-	return p.loc.Services().Get(service.PeeringKey).String()
-}
-
-// ------ message senders ------
-
-// PeeringRequest sends a PeeringRequest to the given peer. This method blocks
-// until a response is received and the status answer is returned.
-func (p *Protocol) PeeringRequest(to *peer.Peer, salt *salt.Salt) (bool, error) {
-	if err := p.disc.EnsureVerified(to); err != nil {
-		return false, err
-	}
-
-	// create the request package
-	toAddr := to.Address()
-	req := newPeeringRequest(toAddr, salt)
-	data := marshal(req)
-
-	// compute the message hash
-	hash := server.PacketHash(data)
-
-	var status bool
-	callback := func(m interface{}) bool {
-		res := m.(*pb.PeeringResponse)
-		if !bytes.Equal(res.GetReqHash(), hash) {
-			return false
-		}
-		status = res.GetStatus()
-		return true
-	}
-
-	err := backoff.Retry(retryPolicy, func() error {
-		p.logSend(toAddr, req)
-		err := <-p.Protocol.SendExpectingReply(toAddr, to.ID(), data, pb.MPeeringResponse, callback)
-		if err != nil && !errors.Is(err, server.ErrTimeout) {
-			return backoff.Permanent(err)
-		}
-		return err
-	})
-	return status, err
-}
-
-// PeeringDrop sends a peering drop message to the given peer, non-blocking and does not wait for any responses.
-func (p *Protocol) PeeringDrop(to *peer.Peer) {
-	drop := newPeeringDrop(to.Address())
-
-	p.logSend(to.Address(), drop)
-	p.Protocol.Send(to, marshal(drop))
-}
-
-// ------ helper functions ------
-
-func (p *Protocol) logSend(toAddr string, msg pb.Message) {
-	if logSends {
-		p.log.Debugw("send message", "type", msg.Name(), "addr", toAddr)
-	}
-}
-
-func marshal(msg pb.Message) []byte {
-	mType := msg.Type()
-	if mType > 0xFF {
-		panic("invalid message")
-	}
-
-	data, err := proto.Marshal(msg)
-	if err != nil {
-		panic("invalid message")
-	}
-	return append([]byte{byte(mType)}, data...)
-}
-
-// ------ Message Constructors ------
-
-func newPeeringRequest(toAddr string, salt *salt.Salt) *pb.PeeringRequest {
-	return &pb.PeeringRequest{
-		To:        toAddr,
-		Timestamp: time.Now().Unix(),
-		Salt:      salt.ToProto(),
-	}
-}
-
-func newPeeringResponse(reqData []byte, status bool) *pb.PeeringResponse {
-	return &pb.PeeringResponse{
-		ReqHash: server.PacketHash(reqData),
-		Status:  status,
-	}
-}
-
-func newPeeringDrop(toAddr string) *pb.PeeringDrop {
-	return &pb.PeeringDrop{
-		To:        toAddr,
-		Timestamp: time.Now().Unix(),
-	}
-}
-
-// ------ Packet Handlers ------
-
-func (p *Protocol) validatePeeringRequest(fromAddr string, fromID peer.ID, m *pb.PeeringRequest) bool {
-	// check that To matches the local address
-	if m.GetTo() != p.publicAddr() {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"to", m.GetTo(),
-			"want", p.publicAddr(),
-		)
-		return false
-	}
-	// check Timestamp
-	if p.Protocol.IsExpired(m.GetTimestamp()) {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"timestamp", time.Unix(m.GetTimestamp(), 0),
-		)
-		return false
-	}
-	// check whether the sender is verified
-	if !p.disc.IsVerified(fromID, fromAddr) {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"unverified", fromAddr,
-		)
-		return false
-	}
-	// check Salt
-	s, err := salt.FromProto(m.GetSalt())
-	if err != nil {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"salt", err,
-		)
-		return false
-	}
-	// check salt expiration
-	if s.Expired() {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"salt.expiration", s.GetExpiration(),
-		)
-		return false
-	}
-
-	p.log.Debugw("valid message",
-		"type", m.Name(),
-		"addr", fromAddr,
-	)
-	return true
-}
-
-func (p *Protocol) handlePeeringRequest(s *server.Server, fromAddr string, fromID peer.ID, rawData []byte, m *pb.PeeringRequest) {
-	salt, err := salt.FromProto(m.GetSalt())
-	if err != nil {
-		// this should not happen as it is checked in validation
-		p.log.Warnw("invalid salt", "err", err)
-		return
-	}
-
-	from := p.disc.GetVerifiedPeer(fromID, fromAddr)
-	if from == nil {
-		// this should not happen as it is checked in validation
-		p.log.Warnw("invalid stored peer",
-			"id", fromID,
-		)
-		return
-	}
-
-	res := newPeeringResponse(rawData, p.mgr.requestPeering(from, salt))
-
-	p.logSend(fromAddr, res)
-	s.Send(fromAddr, marshal(res))
-}
-
-func (p *Protocol) validatePeeringResponse(s *server.Server, fromAddr string, fromID peer.ID, m *pb.PeeringResponse) bool {
-	// there must be a request waiting for this response
-	if !s.IsExpectedReply(fromAddr, fromID, m.Type(), m) {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"unexpected", fromAddr,
-		)
-		return false
-	}
-
-	p.log.Debugw("valid message",
-		"type", m.Name(),
-		"addr", fromAddr,
-	)
-	return true
-}
-
-func (p *Protocol) validatePeeringDrop(fromAddr string, m *pb.PeeringDrop) bool {
-	// check that To matches the local address
-	if m.GetTo() != p.publicAddr() {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"to", m.GetTo(),
-			"want", p.publicAddr(),
-		)
-		return false
-	}
-	// check Timestamp
-	if p.Protocol.IsExpired(m.GetTimestamp()) {
-		p.log.Debugw("invalid message",
-			"type", m.Name(),
-			"timestamp", time.Unix(m.GetTimestamp(), 0),
-		)
-		return false
-	}
-
-	p.log.Debugw("valid message",
-		"type", m.Name(),
-		"addr", fromAddr,
-	)
-	return true
-}
-
-func (p *Protocol) handlePeeringDrop(fromID peer.ID) {
-	p.mgr.removeNeighbor(fromID)
-}
diff --git a/packages/autopeering/selection/protocol_test.go b/packages/autopeering/selection/protocol_test.go
deleted file mode 100644
index 4df4b46a..00000000
--- a/packages/autopeering/selection/protocol_test.go
+++ /dev/null
@@ -1,185 +0,0 @@
-package selection
-
-import (
-	"testing"
-	"time"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/discover"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/peertest"
-	"github.com/iotaledger/goshimmer/packages/autopeering/salt"
-	"github.com/iotaledger/goshimmer/packages/autopeering/server"
-	"github.com/iotaledger/goshimmer/packages/autopeering/transport"
-	"github.com/iotaledger/goshimmer/packages/database/mapdb"
-	"github.com/iotaledger/hive.go/logger"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-const (
-	testNetwork = "udp"
-	graceTime   = 100 * time.Millisecond
-)
-
-var (
-	log     = logger.NewExampleLogger("discover")
-	peerMap = make(map[peer.ID]*peer.Peer)
-)
-
-func TestProtocol(t *testing.T) {
-	// assure that the default test parameters are used for all protocol tests
-	SetParameters(Parameters{
-		SaltLifetime:           testSaltLifetime,
-		OutboundUpdateInterval: testUpdateInterval,
-	})
-
-	t.Run("PeeringRequest", func(t *testing.T) {
-		p2p := transport.P2P()
-		defer p2p.Close()
-
-		protA, closeA := newTestProtocol(p2p.A)
-		defer closeA()
-		protB, closeB := newTestProtocol(p2p.B)
-		defer closeB()
-
-		peerA := getPeer(protA)
-		saltA, _ := salt.NewSalt(100 * time.Second)
-		peerB := getPeer(protB)
-		saltB, _ := salt.NewSalt(100 * time.Second)
-
-		// request peering to peer B
-		t.Run("A->B", func(t *testing.T) {
-			if services, err := protA.PeeringRequest(peerB, saltA); assert.NoError(t, err) {
-				assert.NotEmpty(t, services)
-			}
-		})
-		// request peering to peer A
-		t.Run("B->A", func(t *testing.T) {
-			if services, err := protB.PeeringRequest(peerA, saltB); assert.NoError(t, err) {
-				assert.NotEmpty(t, services)
-			}
-		})
-	})
-
-	t.Run("ExpiredSalt", func(t *testing.T) {
-		p2p := transport.P2P()
-		defer p2p.Close()
-
-		protA, closeA := newTestProtocol(p2p.A)
-		defer closeA()
-		protB, closeB := newTestProtocol(p2p.B)
-		defer closeB()
-
-		saltA, _ := salt.NewSalt(-1 * time.Second)
-		peerB := getPeer(protB)
-
-		// request peering to peer B
-		_, err := protA.PeeringRequest(peerB, saltA)
-		assert.EqualError(t, err, server.ErrTimeout.Error())
-	})
-
-	t.Run("PeeringDrop", func(t *testing.T) {
-		p2p := transport.P2P()
-		defer p2p.Close()
-
-		protA, closeA := newTestProtocol(p2p.A)
-		defer closeA()
-		protB, closeB := newTestProtocol(p2p.B)
-		defer closeB()
-
-		peerA := getPeer(protA)
-		saltA, _ := salt.NewSalt(100 * time.Second)
-		peerB := getPeer(protB)
-
-		// request peering to peer B
-		status, err := protA.PeeringRequest(peerB, saltA)
-		require.NoError(t, err)
-		assert.True(t, status)
-
-		require.Contains(t, protB.GetNeighbors(), peerA)
-
-		// drop peer A
-		protA.PeeringDrop(peerB)
-		time.Sleep(graceTime)
-		require.NotContains(t, protB.GetNeighbors(), peerA)
-	})
-
-	t.Run("FullTest", func(t *testing.T) {
-		p2p := transport.P2P()
-		defer p2p.Close()
-
-		protA, closeA := newFullTestProtocol(p2p.A)
-		defer closeA()
-
-		time.Sleep(graceTime) // wait for the master to initialize
-
-		protB, closeB := newFullTestProtocol(p2p.B, getPeer(protA))
-		defer closeB()
-
-		time.Sleep(outboundUpdateInterval + graceTime) // wait for the next outbound cycle
-
-		// the two peers should be peered
-		assert.ElementsMatch(t, []*peer.Peer{getPeer(protB)}, protA.GetNeighbors())
-		assert.ElementsMatch(t, []*peer.Peer{getPeer(protA)}, protB.GetNeighbors())
-	})
-}
-
-// dummyDiscovery is a dummy implementation of DiscoveryProtocol never returning any verified peers.
-type dummyDiscovery struct{}
-
-func (d dummyDiscovery) IsVerified(peer.ID, string) bool                 { return true }
-func (d dummyDiscovery) EnsureVerified(*peer.Peer) error                 { return nil }
-func (d dummyDiscovery) GetVerifiedPeer(id peer.ID, _ string) *peer.Peer { return peerMap[id] }
-func (d dummyDiscovery) GetVerifiedPeers() []*peer.Peer                  { return []*peer.Peer{} }
-
-// newTestProtocol creates a new neighborhood server and also returns the teardown.
-func newTestProtocol(trans transport.Transport) (*Protocol, func()) {
-	db, _ := peer.NewDB(mapdb.NewMapDB())
-	local := peertest.NewLocal(trans.LocalAddr().Network(), trans.LocalAddr().String(), db)
-	// add the new peer to the global map for dummyDiscovery
-	peerMap[local.ID()] = &local.Peer
-	l := log.Named(trans.LocalAddr().String())
-
-	prot := New(local, dummyDiscovery{}, Config{Log: l.Named("disc")})
-	srv := server.Serve(local, trans, l.Named("srv"), prot)
-	prot.Start(srv)
-
-	teardown := func() {
-		srv.Close()
-		prot.Close()
-	}
-	return prot, teardown
-}
-
-// newTestProtocol creates a new server handling discover as well as neighborhood and also returns the teardown.
-func newFullTestProtocol(trans transport.Transport, masterPeers ...*peer.Peer) (*Protocol, func()) {
-	db, _ := peer.NewDB(mapdb.NewMapDB())
-	local := peertest.NewLocal(trans.LocalAddr().Network(), trans.LocalAddr().String(), db)
-	// add the new peer to the global map for dummyDiscovery
-	peerMap[local.ID()] = &local.Peer
-	l := log.Named(trans.LocalAddr().String())
-
-	discovery := discover.New(local, discover.Config{
-		Log:         l.Named("disc"),
-		MasterPeers: masterPeers,
-	})
-	selection := New(local, discovery, Config{
-		Log: l.Named("sel"),
-	})
-
-	srv := server.Serve(local, trans, l.Named("srv"), discovery, selection)
-
-	discovery.Start(srv)
-	selection.Start(srv)
-
-	teardown := func() {
-		srv.Close()
-		selection.Close()
-		discovery.Close()
-	}
-	return selection, teardown
-}
-
-func getPeer(p *Protocol) *peer.Peer {
-	return &p.local().Peer
-}
diff --git a/packages/autopeering/selection/selection.go b/packages/autopeering/selection/selection.go
deleted file mode 100644
index f27393ac..00000000
--- a/packages/autopeering/selection/selection.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package selection
-
-import (
-	"sync"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-)
-
-type Selector interface {
-	Select(candidates peer.PeerDistance) *peer.Peer
-}
-
-type Filter struct {
-	internal   map[peer.ID]bool
-	conditions []func(*peer.Peer) bool
-	lock       sync.RWMutex
-}
-
-func NewFilter() *Filter {
-	return &Filter{
-		internal: make(map[peer.ID]bool),
-	}
-}
-
-func (f *Filter) Apply(list []peer.PeerDistance) (filtered []peer.PeerDistance) {
-	f.lock.RLock()
-	defer f.lock.RUnlock()
-
-list:
-	for _, p := range list {
-		if _, contains := f.internal[p.Remote.ID()]; contains {
-			continue
-		}
-		for _, c := range f.conditions {
-			if !c(p.Remote) {
-				continue list
-			}
-		}
-		filtered = append(filtered, p)
-	}
-	return
-}
-
-func (f *Filter) AddPeers(n []*peer.Peer) {
-	f.lock.Lock()
-	for _, p := range n {
-		f.internal[p.ID()] = true
-	}
-	f.lock.Unlock()
-}
-
-func (f *Filter) AddPeer(peer peer.ID) {
-	f.lock.Lock()
-	f.internal[peer] = true
-	f.lock.Unlock()
-}
-
-func (f *Filter) RemovePeer(peer peer.ID) {
-	f.lock.Lock()
-	f.internal[peer] = false
-	f.lock.Unlock()
-}
-
-func (f *Filter) AddCondition(c func(p *peer.Peer) bool) {
-	f.conditions = append(f.conditions, c)
-}
-
-func (f *Filter) Clean() {
-	f.lock.Lock()
-	f.internal = make(map[peer.ID]bool)
-	f.lock.Unlock()
-}
diff --git a/packages/autopeering/selection/selection_test.go b/packages/autopeering/selection/selection_test.go
deleted file mode 100644
index 49d22c8d..00000000
--- a/packages/autopeering/selection/selection_test.go
+++ /dev/null
@@ -1,165 +0,0 @@
-package selection
-
-import (
-	"fmt"
-	"testing"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/peertest"
-	"github.com/stretchr/testify/assert"
-)
-
-func TestFilterAddPeers(t *testing.T) {
-	p := make([]*peer.Peer, 5)
-	for i := range p {
-		p[i] = peertest.NewPeer(testNetwork, fmt.Sprintf("%d", i))
-	}
-
-	type testCase struct {
-		input    []*peer.Peer
-		notExist []*peer.Peer
-	}
-
-	tests := []testCase{
-		{
-			input:    []*peer.Peer{p[0]},
-			notExist: []*peer.Peer{p[1]},
-		},
-		{
-			input:    []*peer.Peer{p[0], p[1], p[2]},
-			notExist: []*peer.Peer{p[3], p[4]},
-		},
-	}
-
-	for _, test := range tests {
-		f := NewFilter()
-		f.AddPeers(test.input)
-		for _, e := range test.input {
-			assert.Equal(t, true, f.internal[e.ID()], "Filter add peers")
-		}
-
-		for _, e := range test.notExist {
-			assert.Equal(t, false, f.internal[e.ID()], "Filter add peers")
-		}
-	}
-}
-
-func TestFilterRemovePeers(t *testing.T) {
-	p := make([]*peer.Peer, 5)
-	for i := range p {
-		p[i] = peertest.NewPeer(testNetwork, fmt.Sprintf("%d", i))
-	}
-
-	type testCase struct {
-		input    []*peer.Peer
-		toRemove *peer.Peer
-		left     []*peer.Peer
-	}
-
-	tests := []testCase{
-		{
-			input:    []*peer.Peer{p[0]},
-			toRemove: p[0],
-			left:     []*peer.Peer{},
-		},
-		{
-			input:    []*peer.Peer{p[0], p[1], p[2]},
-			toRemove: p[1],
-			left:     []*peer.Peer{p[0], p[2]},
-		},
-	}
-
-	for _, test := range tests {
-		f := NewFilter()
-		f.AddPeers(test.input)
-		f.RemovePeer(test.toRemove.ID())
-		for _, e := range test.left {
-			assert.Equal(t, true, f.internal[e.ID()], "Filter remove peers")
-		}
-		assert.Equal(t, false, f.internal[test.toRemove.ID()], "Filter remove peers")
-	}
-}
-
-func TestFilterApply(t *testing.T) {
-	d := make([]peer.PeerDistance, 5)
-	for i := range d {
-		d[i].Remote = peertest.NewPeer(testNetwork, fmt.Sprintf("%d", i))
-		d[i].Distance = uint32(i + 1)
-	}
-
-	type testCase struct {
-		input    []*peer.Peer
-		apply    []peer.PeerDistance
-		expected []peer.PeerDistance
-	}
-
-	tests := []testCase{
-		{
-			input:    []*peer.Peer{d[0].Remote},
-			apply:    []peer.PeerDistance{d[0], d[1], d[2]},
-			expected: []peer.PeerDistance{d[1], d[2]},
-		},
-		{
-			input:    []*peer.Peer{d[0].Remote, d[1].Remote},
-			apply:    []peer.PeerDistance{d[2], d[3], d[4]},
-			expected: []peer.PeerDistance{d[2], d[3], d[4]},
-		},
-	}
-
-	for _, test := range tests {
-		f := NewFilter()
-		f.AddPeers(test.input)
-		filteredList := f.Apply(test.apply)
-		assert.Equal(t, test.expected, filteredList, "Filter apply")
-	}
-}
-
-func TestSelection(t *testing.T) {
-	d := make([]peer.PeerDistance, 10)
-	for i := range d {
-		d[i].Remote = peertest.NewPeer(testNetwork, fmt.Sprintf("%d", i))
-		d[i].Distance = uint32(i + 1)
-	}
-
-	type testCase struct {
-		nh           *Neighborhood
-		expCandidate *peer.Peer
-	}
-
-	tests := []testCase{
-		{
-			nh: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0]},
-				size:      4},
-			expCandidate: d[1].Remote,
-		},
-		{
-			nh: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0], d[1], d[3]},
-				size:      4},
-			expCandidate: d[2].Remote,
-		},
-		{
-			nh: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0], d[1], d[4], d[2]},
-				size:      4},
-			expCandidate: d[3].Remote,
-		},
-		{
-			nh: &Neighborhood{
-				neighbors: []peer.PeerDistance{d[0], d[1], d[2], d[3]},
-				size:      4},
-			expCandidate: nil,
-		},
-	}
-
-	for _, test := range tests {
-		filter := NewFilter()
-		filter.AddPeers(test.nh.GetPeers())
-		fList := filter.Apply(d)
-
-		got := test.nh.Select(fList)
-
-		assert.Equal(t, test.expCandidate, got.Remote, "Next Candidate", test)
-	}
-}
diff --git a/packages/autopeering/server/common.go b/packages/autopeering/server/common.go
deleted file mode 100644
index 593d916b..00000000
--- a/packages/autopeering/server/common.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package server
-
-import (
-	"crypto/sha256"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-)
-
-// MType is the type of message type enum.
-type MType uint
-
-// The Sender interface specifies common method required to send requests.
-type Sender interface {
-	Send(toAddr string, data []byte)
-	SendExpectingReply(toAddr string, toID peer.ID, data []byte, replyType MType, callback func(interface{}) bool) <-chan error
-}
-
-// A Handler reacts to an incoming message.
-type Handler interface {
-	// HandleMessage is called for each incoming message.
-	// It returns true, if that particular message type can be processed by the current Handler.
-	HandleMessage(s *Server, fromAddr string, fromID peer.ID, fromKey peer.PublicKey, data []byte) (bool, error)
-}
-
-// The HandlerFunc type is an adapter to allow the use of ordinary functions as Server handlers.
-// If f is a function with the appropriate signature, HandlerFunc(f) is a Handler that calls f.
-type HandlerFunc func(*Server, string, peer.ID, peer.PublicKey, []byte) (bool, error)
-
-// HandleMessage returns f(s, from, data).
-func (f HandlerFunc) HandleMessage(s *Server, fromAddr string, fromID peer.ID, fromKey peer.PublicKey, data []byte) (bool, error) {
-	return f(s, fromAddr, fromID, fromKey, data)
-}
-
-// PacketHash returns the hash of a packet
-func PacketHash(data []byte) []byte {
-	sum := sha256.Sum256(data)
-	return sum[:]
-}
diff --git a/packages/autopeering/server/errors.go b/packages/autopeering/server/errors.go
deleted file mode 100644
index c278c2f5..00000000
--- a/packages/autopeering/server/errors.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package server
-
-import "errors"
-
-var (
-	// ErrTimeout is returned when an expected response was not received in time.
-	ErrTimeout = errors.New("response timeout")
-
-	// ErrClosed means that the server was shut down before a response could be received.
-	ErrClosed = errors.New("socket closed")
-
-	// ErrNoMessage is returned when the package did not contain any data.
-	ErrNoMessage = errors.New("packet does not contain a message")
-
-	// ErrInvalidMessage means that no handler could process the received message.
-	ErrInvalidMessage = errors.New("invalid message")
-)
diff --git a/packages/autopeering/server/proto/packet.pb.go b/packages/autopeering/server/proto/packet.pb.go
deleted file mode 100644
index 9c8dd1f5..00000000
--- a/packages/autopeering/server/proto/packet.pb.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// source: server/proto/packet.proto
-
-package proto
-
-import (
-	fmt "fmt"
-	proto "github.com/golang/protobuf/proto"
-	math "math"
-)
-
-// Reference imports to suppress errors if they are not otherwise used.
-var _ = proto.Marshal
-var _ = fmt.Errorf
-var _ = math.Inf
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the proto package it is being compiled against.
-// A compilation error at this line likely means your copy of the
-// proto package needs to be updated.
-const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
-
-type Packet struct {
-	PublicKey            []byte   `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
-	Signature            []byte   `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"`
-	Data                 []byte   `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
-
-func (m *Packet) Reset()         { *m = Packet{} }
-func (m *Packet) String() string { return proto.CompactTextString(m) }
-func (*Packet) ProtoMessage()    {}
-func (*Packet) Descriptor() ([]byte, []int) {
-	return fileDescriptor_c39379c1dd924f72, []int{0}
-}
-
-func (m *Packet) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_Packet.Unmarshal(m, b)
-}
-func (m *Packet) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_Packet.Marshal(b, m, deterministic)
-}
-func (m *Packet) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_Packet.Merge(m, src)
-}
-func (m *Packet) XXX_Size() int {
-	return xxx_messageInfo_Packet.Size(m)
-}
-func (m *Packet) XXX_DiscardUnknown() {
-	xxx_messageInfo_Packet.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_Packet proto.InternalMessageInfo
-
-func (m *Packet) GetPublicKey() []byte {
-	if m != nil {
-		return m.PublicKey
-	}
-	return nil
-}
-
-func (m *Packet) GetSignature() []byte {
-	if m != nil {
-		return m.Signature
-	}
-	return nil
-}
-
-func (m *Packet) GetData() []byte {
-	if m != nil {
-		return m.Data
-	}
-	return nil
-}
-
-func init() {
-	proto.RegisterType((*Packet)(nil), "proto.Packet")
-}
-
-func init() { proto.RegisterFile("server/proto/packet.proto", fileDescriptor_c39379c1dd924f72) }
-
-var fileDescriptor_c39379c1dd924f72 = []byte{
-	// 166 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x92, 0x2c, 0x4e, 0x2d, 0x2a,
-	0x4b, 0x2d, 0xd2, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0xd7, 0x2f, 0x48, 0x4c, 0xce, 0x4e, 0x2d, 0xd1,
-	0x03, 0x73, 0x84, 0x58, 0xc1, 0x94, 0x52, 0x24, 0x17, 0x5b, 0x00, 0x58, 0x58, 0x48, 0x96, 0x8b,
-	0xab, 0xa0, 0x34, 0x29, 0x27, 0x33, 0x39, 0x3e, 0x3b, 0xb5, 0x52, 0x82, 0x51, 0x81, 0x51, 0x83,
-	0x27, 0x88, 0x13, 0x22, 0xe2, 0x9d, 0x5a, 0x29, 0x24, 0xc3, 0xc5, 0x59, 0x9c, 0x99, 0x9e, 0x97,
-	0x58, 0x52, 0x5a, 0x94, 0x2a, 0xc1, 0x04, 0x91, 0x85, 0x0b, 0x08, 0x09, 0x71, 0xb1, 0xa4, 0x24,
-	0x96, 0x24, 0x4a, 0x30, 0x83, 0x25, 0xc0, 0x6c, 0x27, 0x93, 0x28, 0xa3, 0xf4, 0xcc, 0x92, 0x8c,
-	0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0xfd, 0xcc, 0xfc, 0x92, 0xc4, 0x9c, 0xd4, 0x94, 0x74, 0xa0,
-	0x6b, 0x12, 0x4b, 0x4b, 0xf2, 0x0b, 0x52, 0x53, 0x8b, 0x32, 0xf3, 0xd2, 0x75, 0x8b, 0x33, 0x73,
-	0xf5, 0x91, 0x1d, 0x99, 0xc4, 0x06, 0xa6, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x50, 0x6a,
-	0x7d, 0xb7, 0xbb, 0x00, 0x00, 0x00,
-}
diff --git a/packages/autopeering/server/proto/packet.proto b/packages/autopeering/server/proto/packet.proto
deleted file mode 100644
index 59da610d..00000000
--- a/packages/autopeering/server/proto/packet.proto
+++ /dev/null
@@ -1,11 +0,0 @@
-syntax = "proto3";
-
-option go_package = "github.com/iotaledger/goshimmer/packages/autopeering/server/proto";
-
-package proto;
-
-message Packet {
-  bytes public_key = 1;
-  bytes signature = 2;
-  bytes data = 3;
-}
diff --git a/packages/autopeering/server/protocol.go b/packages/autopeering/server/protocol.go
deleted file mode 100644
index e3ef6a62..00000000
--- a/packages/autopeering/server/protocol.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package server
-
-import (
-	"time"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-)
-
-const (
-	packetExpiration = 20 * time.Second
-)
-
-// Protocol provides a basis for server protocols handling incoming messages.
-type Protocol struct {
-	Sender Sender // interface to send own requests
-}
-
-// Send sends the data to the given peer.
-func (p *Protocol) Send(to *peer.Peer, data []byte) {
-	p.Sender.Send(to.Address(), data)
-}
-
-// SendExpectingReply sends request data to a peer and expects a response of the given type.
-// On an incoming matching request the callback is executed to perform additional verification steps.
-func (p *Protocol) SendExpectingReply(toAddr string, toID peer.ID, data []byte, replyType MType, callback func(interface{}) bool) <-chan error {
-	return p.Sender.SendExpectingReply(toAddr, toID, data, replyType, callback)
-}
-
-// IsExpired checks whether the given UNIX time stamp is too far in the past.
-func (p *Protocol) IsExpired(ts int64) bool {
-	return time.Since(time.Unix(ts, 0)) >= packetExpiration
-}
diff --git a/packages/autopeering/server/server.go b/packages/autopeering/server/server.go
deleted file mode 100644
index d1bca6aa..00000000
--- a/packages/autopeering/server/server.go
+++ /dev/null
@@ -1,315 +0,0 @@
-package server
-
-import (
-	"container/list"
-	"fmt"
-	"io"
-	"net"
-	"sync"
-	"time"
-
-	"github.com/golang/protobuf/proto"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	pb "github.com/iotaledger/goshimmer/packages/autopeering/server/proto"
-	"github.com/iotaledger/goshimmer/packages/autopeering/transport"
-	"github.com/iotaledger/goshimmer/packages/netutil"
-	"github.com/iotaledger/hive.go/logger"
-)
-
-const (
-	// ResponseTimeout specifies the time limit after which a response must have been received.
-	ResponseTimeout = 500 * time.Millisecond
-)
-
-// Server offers the functionality to start a server that handles requests and responses from peers.
-type Server struct {
-	local    *peer.Local
-	trans    transport.Transport
-	handlers []Handler
-	log      *logger.Logger
-	network  string
-	address  string
-
-	closeOnce sync.Once
-	wg        sync.WaitGroup
-
-	addReplyMatcher chan *replyMatcher
-	replyReceived   chan reply
-	closing         chan struct{} // if this channel gets closed all pending waits should terminate
-}
-
-// a replyMatcher stores the information required to identify and react to an expected replay.
-type replyMatcher struct {
-	// fromAddr must match the sender of the reply
-	fromAddr string
-	// fromID must match the sender ID
-	fromID peer.ID
-	// mtype must match the type of the reply
-	mtype MType
-
-	// deadline when the request must complete
-	deadline time.Time
-
-	// callback is called when a matching reply arrives
-	// If it returns true, the reply is acceptable.
-	callback func(msg interface{}) bool
-
-	// errc receives nil when the callback indicates completion or an
-	// error if no further reply is received within the timeout
-	errc chan error
-}
-
-// reply is a reply packet from a certain peer
-type reply struct {
-	fromAddr       string
-	fromID         peer.ID
-	mtype          MType
-	msg            interface{} // the actual reply message
-	matchedRequest chan<- bool // a matching request is indicated via this channel
-}
-
-// Serve starts a new peer server using the given transport layer for communication.
-// Sent data is signed using the identity of the local peer,
-// received data with a valid peer signature is handled according to the provided Handler.
-func Serve(local *peer.Local, t transport.Transport, log *logger.Logger, h ...Handler) *Server {
-	srv := &Server{
-		local:           local,
-		trans:           t,
-		handlers:        h,
-		log:             log,
-		network:         local.Network(),
-		address:         local.Address(),
-		addReplyMatcher: make(chan *replyMatcher),
-		replyReceived:   make(chan reply),
-		closing:         make(chan struct{}),
-	}
-
-	srv.wg.Add(2)
-	go srv.replyLoop()
-	go srv.readLoop()
-
-	log.Debugw("server started",
-		"network", srv.LocalAddr().Network(),
-		"address", srv.LocalAddr().String(),
-		"#handlers", len(h))
-
-	return srv
-}
-
-// Close shuts down the server.
-func (s *Server) Close() {
-	s.closeOnce.Do(func() {
-		close(s.closing)
-		s.trans.Close()
-		s.wg.Wait()
-	})
-}
-
-// Local returns the the local peer.
-func (s *Server) Local() *peer.Local {
-	return s.local
-}
-
-// LocalAddr returns the address of the local peer in string form.
-func (s *Server) LocalAddr() net.Addr {
-	return s.trans.LocalAddr()
-}
-
-// Send sends a message to the given address
-func (s *Server) Send(toAddr string, data []byte) {
-	pkt := s.encode(data)
-	s.write(toAddr, pkt)
-}
-
-// SendExpectingReply sends a message to the given address and tells the Server
-// to expect a reply message with the given specifications.
-// If eventually nil is returned, a matching message was received.
-func (s *Server) SendExpectingReply(toAddr string, toID peer.ID, data []byte, replyType MType, callback func(interface{}) bool) <-chan error {
-	errc := s.expectReply(toAddr, toID, replyType, callback)
-	s.Send(toAddr, data)
-
-	return errc
-}
-
-// expectReply tells the Server to expect a reply message with the given specifications.
-// If eventually nil is returned, a matching message was received.
-func (s *Server) expectReply(fromAddr string, fromID peer.ID, mtype MType, callback func(interface{}) bool) <-chan error {
-	ch := make(chan error, 1)
-	m := &replyMatcher{fromAddr: fromAddr, fromID: fromID, mtype: mtype, callback: callback, errc: ch}
-	select {
-	case s.addReplyMatcher <- m:
-	case <-s.closing:
-		ch <- ErrClosed
-	}
-	return ch
-}
-
-// IsExpectedReply checks whether the given Message matches an expected reply added with SendExpectingReply.
-func (s *Server) IsExpectedReply(fromAddr string, fromID peer.ID, mtype MType, msg interface{}) bool {
-	matched := make(chan bool, 1)
-	select {
-	case s.replyReceived <- reply{fromAddr, fromID, mtype, msg, matched}:
-		// wait for matcher and return whether a matching request was found
-		return <-matched
-	case <-s.closing:
-		return false
-	}
-}
-
-// Loop checking for matching replies.
-func (s *Server) replyLoop() {
-	defer s.wg.Done()
-
-	var (
-		matcherList = list.New()
-		timeout     = time.NewTimer(0)
-	)
-	defer timeout.Stop()
-
-	<-timeout.C // ignore first timeout
-
-	for {
-
-		// Set the timer so that it fires when the next reply expires
-		if e := matcherList.Front(); e != nil {
-			// the first element always has the closest deadline
-			m := e.Value.(*replyMatcher)
-			timeout.Reset(time.Until(m.deadline))
-		} else {
-			timeout.Stop()
-		}
-
-		select {
-
-		// add a new matcher to the list
-		case s := <-s.addReplyMatcher:
-			s.deadline = time.Now().Add(ResponseTimeout)
-			matcherList.PushBack(s)
-
-		// on reply received, check all matchers for fits
-		case r := <-s.replyReceived:
-			matched := false
-			for e := matcherList.Front(); e != nil; e = e.Next() {
-				m := e.Value.(*replyMatcher)
-				if m.mtype == r.mtype && m.fromID == r.fromID && m.fromAddr == r.fromAddr {
-					if m.callback(r.msg) {
-						// request has been matched
-						matched = true
-						m.errc <- nil
-						matcherList.Remove(e)
-					}
-				}
-			}
-			r.matchedRequest <- matched
-
-		// on timeout, check for expired matchers
-		case <-timeout.C:
-			now := time.Now()
-
-			// notify and remove any expired matchers
-			for e := matcherList.Front(); e != nil; e = e.Next() {
-				m := e.Value.(*replyMatcher)
-				if now.After(m.deadline) || now.Equal(m.deadline) {
-					m.errc <- ErrTimeout
-					matcherList.Remove(e)
-				}
-			}
-
-		// on close, notice all the matchers
-		case <-s.closing:
-			for e := matcherList.Front(); e != nil; e = e.Next() {
-				e.Value.(*replyMatcher).errc <- ErrClosed
-			}
-			return
-
-		}
-	}
-}
-
-func (s *Server) write(toAddr string, pkt *pb.Packet) {
-	b, err := proto.Marshal(pkt)
-	if err != nil {
-		s.log.Error("marshal error", "err", err)
-		return
-	}
-	if l := len(b); l > transport.MaxPacketSize {
-		s.log.Error("packet too large", "size", l, "max", transport.MaxPacketSize)
-		return
-	}
-
-	err = s.trans.WriteTo(b, toAddr)
-	if err != nil {
-		s.log.Debugw("failed to write packet", "addr", toAddr, "err", err)
-	}
-}
-
-// encodes a message as a data packet that can be written.
-func (s *Server) encode(data []byte) *pb.Packet {
-	if len(data) == 0 {
-		panic("server: no data")
-	}
-
-	return &pb.Packet{
-		PublicKey: s.local.PublicKey(),
-		Signature: s.local.Sign(data),
-		Data:      append([]byte(nil), data...),
-	}
-}
-
-func (s *Server) readLoop() {
-	defer s.wg.Done()
-
-	for {
-		b, fromAddr, err := s.trans.ReadFrom()
-		if netutil.IsTemporaryError(err) {
-			// ignore temporary read errors.
-			s.log.Debugw("temporary read error", "err", err)
-			continue
-		}
-		if err != nil {
-			// return from the loop on all other errors
-			if err != io.EOF {
-				s.log.Warnw("read error", "err", err)
-			}
-			s.log.Debug("reading stopped")
-			return
-		}
-
-		pkt := new(pb.Packet)
-		if err := proto.Unmarshal(b, pkt); err != nil {
-			s.log.Debugw("bad packet", "from", fromAddr, "err", err)
-			continue
-		}
-		if err := s.handlePacket(pkt, fromAddr); err != nil {
-			s.log.Debugw("failed to handle packet", "from", fromAddr, "err", err)
-		}
-	}
-}
-
-func (s *Server) handlePacket(pkt *pb.Packet, fromAddr string) error {
-	data, key, err := decode(pkt)
-	if err != nil {
-		return fmt.Errorf("invalid packet: %w", err)
-	}
-
-	fromID := key.ID()
-	for _, handler := range s.handlers {
-		ok, err := handler.HandleMessage(s, fromAddr, fromID, key, data)
-		if ok {
-			return err
-		}
-	}
-	return ErrInvalidMessage
-}
-
-func decode(pkt *pb.Packet) ([]byte, peer.PublicKey, error) {
-	if len(pkt.GetData()) == 0 {
-		return nil, nil, ErrNoMessage
-	}
-
-	key, err := peer.RecoverKeyFromSignedData(pkt)
-	if err != nil {
-		return nil, nil, err
-	}
-	return pkt.GetData(), key, nil
-}
diff --git a/packages/autopeering/server/server_test.go b/packages/autopeering/server/server_test.go
deleted file mode 100644
index 8fc6022f..00000000
--- a/packages/autopeering/server/server_test.go
+++ /dev/null
@@ -1,216 +0,0 @@
-package server
-
-import (
-	"testing"
-	"time"
-
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
-	"github.com/iotaledger/goshimmer/packages/autopeering/salt"
-	"github.com/iotaledger/goshimmer/packages/autopeering/transport"
-	"github.com/iotaledger/goshimmer/packages/database/mapdb"
-	"github.com/iotaledger/hive.go/logger"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/mock"
-	"github.com/stretchr/testify/require"
-)
-
-const graceTime = 5 * time.Millisecond
-
-var log = logger.NewExampleLogger("server")
-
-const (
-	MPing MType = iota
-	MPong
-)
-
-type Message interface {
-	Type() MType
-	Marshal() []byte
-}
-
-type Ping struct{}
-type Pong struct{}
-
-func (m *Ping) Type() MType     { return MPing }
-func (m *Ping) Marshal() []byte { return append([]byte{}, byte(MPing)) }
-
-func (m *Pong) Type() MType     { return MPong }
-func (m *Pong) Marshal() []byte { return append([]byte{}, byte(MPong)) }
-
-func sendPong(args mock.Arguments) {
-	srv := args.Get(0).(*Server)
-	addr := args.Get(1).(string)
-	srv.Send(addr, new(Pong).Marshal())
-}
-
-var (
-	pingMock *mock.Mock
-	pongMock *mock.Mock
-)
-
-func setupTest() func(t *testing.T) {
-	pingMock = new(mock.Mock)
-	pongMock = new(mock.Mock)
-
-	return func(t *testing.T) {
-		pingMock.AssertExpectations(t)
-		pingMock = nil
-		pongMock.AssertExpectations(t)
-		pongMock = nil
-	}
-}
-
-func handle(s *Server, fromAddr string, fromID peer.ID, fromKey peer.PublicKey, data []byte) (bool, error) {
-	msg, err := unmarshal(data)
-	if err != nil {
-		return false, err
-	}
-
-	switch msg.Type() {
-	case MPing:
-		pingMock.Called(s, fromAddr, fromID, fromKey, data)
-
-	case MPong:
-		if s.IsExpectedReply(fromAddr, fromID, MPong, msg) {
-			pongMock.Called(s, fromAddr, fromID, fromKey, data)
-		}
-
-	default:
-		panic("unknown message type")
-	}
-
-	return true, nil
-}
-
-func unmarshal(data []byte) (Message, error) {
-	if len(data) != 1 {
-		return nil, ErrInvalidMessage
-	}
-
-	switch MType(data[0]) {
-	case MPing:
-		return new(Ping), nil
-	case MPong:
-		return new(Pong), nil
-	}
-	return nil, ErrInvalidMessage
-}
-
-func newTestDB(t require.TestingT) *peer.DB {
-	db, err := peer.NewDB(mapdb.NewMapDB())
-	require.NoError(t, err)
-	return db
-}
-
-func TestSrvEncodeDecodePing(t *testing.T) {
-	services := service.New()
-	services.Update(service.PeeringKey, "dummy", "local")
-	local, err := peer.NewLocal(services, newTestDB(t))
-	require.NoError(t, err)
-	s := &Server{local: local}
-
-	ping := new(Ping)
-	packet := s.encode(ping.Marshal())
-
-	data, key, err := decode(packet)
-	require.NoError(t, err)
-
-	msg, _ := unmarshal(data)
-	assert.Equal(t, local.ID(), key.ID())
-	assert.Equal(t, msg, ping)
-}
-
-func newTestServer(t require.TestingT, name string, trans transport.Transport) (*Server, func()) {
-	l := log.Named(name)
-
-	services := service.New()
-	services.Update(service.PeeringKey, trans.LocalAddr().Network(), trans.LocalAddr().String())
-	local, err := peer.NewLocal(services, newTestDB(t))
-	require.NoError(t, err)
-
-	s, _ := salt.NewSalt(100 * time.Second)
-	local.SetPrivateSalt(s)
-	s, _ = salt.NewSalt(100 * time.Second)
-	local.SetPublicSalt(s)
-
-	srv := Serve(local, trans, l, HandlerFunc(handle))
-
-	return srv, srv.Close
-}
-
-func sendPing(s *Server, p *peer.Peer) error {
-	ping := new(Ping)
-	isPong := func(msg interface{}) bool {
-		_, ok := msg.(*Pong)
-		return ok
-	}
-
-	errc := s.SendExpectingReply(p.Address(), p.ID(), ping.Marshal(), MPong, isPong)
-	return <-errc
-}
-
-func TestPingPong(t *testing.T) {
-	p2p := transport.P2P()
-
-	srvA, closeA := newTestServer(t, "A", p2p.A)
-	defer closeA()
-	srvB, closeB := newTestServer(t, "B", p2p.B)
-	defer closeB()
-
-	peerA := &srvA.Local().Peer
-	peerB := &srvB.Local().Peer
-
-	t.Run("A->B", func(t *testing.T) {
-		defer setupTest()(t)
-
-		// B expects valid ping from A and sends pong back
-		pingMock.On("handle", srvB, peerA.Address(), peerA.ID(), peerA.PublicKey(), mock.Anything).Run(sendPong).Once()
-		// A expects valid pong from B
-		pongMock.On("handle", srvA, peerB.Address(), peerB.ID(), peerB.PublicKey(), mock.Anything).Once()
-
-		assert.NoError(t, sendPing(srvA, peerB))
-		time.Sleep(graceTime)
-
-	})
-
-	t.Run("B->A", func(t *testing.T) {
-		defer setupTest()(t)
-
-		pingMock.On("handle", srvA, peerB.Address(), peerB.ID(), peerB.PublicKey(), mock.Anything).Run(sendPong).Once() // A expects valid ping from B and sends pong back
-		pongMock.On("handle", srvB, peerA.Address(), peerA.ID(), peerA.PublicKey(), mock.Anything).Once()               // B expects valid pong from A
-
-		assert.NoError(t, sendPing(srvB, peerA))
-		time.Sleep(graceTime)
-	})
-}
-
-func TestSrvPingTimeout(t *testing.T) {
-	defer setupTest()(t)
-
-	p2p := transport.P2P()
-
-	srvA, closeA := newTestServer(t, "A", p2p.A)
-	defer closeA()
-	srvB, closeB := newTestServer(t, "B", p2p.B)
-	closeB()
-
-	peerB := &srvB.Local().Peer
-	assert.EqualError(t, sendPing(srvA, peerB), ErrTimeout.Error())
-}
-
-func TestUnexpectedPong(t *testing.T) {
-	defer setupTest()(t)
-
-	p2p := transport.P2P()
-
-	srvA, closeA := newTestServer(t, "A", p2p.A)
-	defer closeA()
-	srvB, closeB := newTestServer(t, "B", p2p.B)
-	defer closeB()
-
-	// there should never be a Ping.Handle
-	// there should never be a Pong.Handle
-
-	srvA.Send(srvB.LocalAddr().String(), new(Pong).Marshal())
-}
diff --git a/packages/autopeering/transport/chan.go b/packages/autopeering/transport/chan.go
deleted file mode 100644
index d26a8258..00000000
--- a/packages/autopeering/transport/chan.go
+++ /dev/null
@@ -1,116 +0,0 @@
-package transport
-
-import (
-	"io"
-	"net"
-	"sync"
-)
-
-// ChanNetwork offers in-memory transfers between an arbitrary number of clients.
-type ChanNetwork struct {
-	peers map[string]*chanPeer
-}
-
-type chanPeer struct {
-	network *ChanNetwork
-	addr    chanAddr
-
-	c         chan transfer
-	closeOnce sync.Once
-	closing   chan struct{}
-}
-
-// chanAddr represents the address of an end point in the in-memory transport network.
-type chanAddr struct {
-	address string
-}
-
-func (a chanAddr) Network() string { return "chan-network" }
-func (a chanAddr) String() string  { return a.address }
-
-// NewNetwork creates a new in-memory transport network.
-// For each provided address a corresponding client is created.
-func NewNetwork(addresses ...string) *ChanNetwork {
-	network := &ChanNetwork{
-		peers: make(map[string]*chanPeer, len(addresses)),
-	}
-
-	for _, addr := range addresses {
-		network.AddTransport(addr)
-	}
-
-	return network
-}
-
-// AddTransport adds a new client transport layer to the network.
-func (n *ChanNetwork) AddTransport(addr string) {
-	n.peers[addr] = newChanPeer(addr, n)
-}
-
-// GetTransport returns the corresponding client transport layer for the provided address.
-// This function will panic, if no transport layer for that address exists.
-func (n *ChanNetwork) GetTransport(addr string) Transport {
-	peer, ok := n.peers[addr]
-	if !ok {
-		panic(errPeer.Error())
-	}
-
-	return peer
-}
-
-// Close closes each of the peers' transport layers.
-func (n *ChanNetwork) Close() {
-	for _, peer := range n.peers {
-		peer.Close()
-	}
-}
-
-func newChanPeer(address string, network *ChanNetwork) *chanPeer {
-	return &chanPeer{
-		addr:    chanAddr{address: address},
-		network: network,
-		c:       make(chan transfer, queueSize),
-		closing: make(chan struct{}),
-	}
-}
-
-// ReadFrom implements the Transport ReadFrom method.
-func (p *chanPeer) ReadFrom() ([]byte, string, error) {
-	select {
-	case res := <-p.c:
-		return res.pkt, res.addr, nil
-	case <-p.closing:
-		return nil, "", io.EOF
-	}
-}
-
-// WriteTo implements the Transport WriteTo method.
-func (p *chanPeer) WriteTo(pkt []byte, address string) error {
-	// determine the receiving peer
-	peer, ok := p.network.peers[address]
-	if !ok {
-		return errPeer
-	}
-
-	// clone the packet before sending, just to make sure...
-	req := transfer{pkt: append([]byte{}, pkt...), addr: p.addr.address}
-
-	select {
-	case peer.c <- req:
-		return nil
-	case <-p.closing:
-		return errClosed
-	}
-}
-
-// Close closes the transport layer.
-func (p *chanPeer) Close() {
-	p.closeOnce.Do(func() {
-		close(p.closing)
-	})
-}
-
-// LocalAddr returns the local network address.
-func (p *chanPeer) LocalAddr() net.Addr {
-	return p.addr
-}
diff --git a/packages/autopeering/transport/chan_test.go b/packages/autopeering/transport/chan_test.go
deleted file mode 100644
index 09aa04dd..00000000
--- a/packages/autopeering/transport/chan_test.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package transport
-
-import (
-	"io"
-	"sync"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-func TestChanReadClosed(t *testing.T) {
-	network := NewNetwork("A")
-	defer network.Close()
-
-	a := network.GetTransport("A")
-	a.Close()
-	_, _, err := a.ReadFrom()
-	assert.EqualError(t, err, io.EOF.Error())
-}
-
-func TestChanPacket(t *testing.T) {
-	network := NewNetwork("A", "B")
-	defer network.Close()
-
-	a := network.GetTransport("A")
-	b := network.GetTransport("B")
-
-	err := a.WriteTo(testPacket, b.LocalAddr().String())
-	require.NoError(t, err)
-
-	pkt, addr, err := b.ReadFrom()
-	require.NoError(t, err)
-
-	assert.Equal(t, pkt, testPacket)
-	assert.Equal(t, addr, a.LocalAddr().String())
-}
-
-func TestChanConcurrentWrite(t *testing.T) {
-	network := NewNetwork("A", "B", "C", "D")
-	defer network.Close()
-
-	a := network.GetTransport("A")
-	b := network.GetTransport("B")
-	c := network.GetTransport("C")
-	d := network.GetTransport("D")
-
-	var wg sync.WaitGroup
-	numSender := 3
-
-	// reader
-	wg.Add(1)
-	go func() {
-		defer wg.Done()
-		for i := 0; i < numSender*1000; i++ {
-			_, _, err := d.ReadFrom()
-			assert.Equal(t, err, nil)
-		}
-	}()
-
-	wg.Add(numSender)
-	burstWriteTo(a, d.LocalAddr().String(), 1000, &wg)
-	burstWriteTo(b, d.LocalAddr().String(), 1000, &wg)
-	burstWriteTo(c, d.LocalAddr().String(), 1000, &wg)
-
-	// wait for everything to finish
-	wg.Wait()
-}
-
-func burstWriteTo(t Transport, addr string, numPackets int, wg *sync.WaitGroup) {
-	defer wg.Done()
-
-	go func() {
-		for i := 0; i < numPackets; i++ {
-			_ = t.WriteTo(testPacket, addr)
-		}
-	}()
-}
diff --git a/packages/autopeering/transport/conn.go b/packages/autopeering/transport/conn.go
deleted file mode 100644
index 1d67a76e..00000000
--- a/packages/autopeering/transport/conn.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package transport
-
-import (
-	"io"
-	"net"
-	"strings"
-)
-
-// ResolveFunc resolves a string address to the corresponding net.Addr.
-type ResolveFunc func(network, address string) (net.Addr, error)
-
-// TransportConn wraps a PacketConn my un-/marshaling the packets using protobuf.
-type TransportConn struct {
-	conn net.PacketConn
-	res  ResolveFunc
-}
-
-// Conn creates a new transport layer by using the underlying PacketConn.
-func Conn(conn net.PacketConn, res ResolveFunc) *TransportConn {
-	return &TransportConn{conn: conn, res: res}
-}
-
-// ReadFrom implements the Transport ReadFrom method.
-func (t *TransportConn) ReadFrom() ([]byte, string, error) {
-	b := make([]byte, MaxPacketSize)
-	n, addr, err := t.conn.ReadFrom(b)
-	if err != nil {
-		// make ErrNetClosing handled consistently
-		if strings.Contains(err.Error(), "use of closed network connection") {
-			err = io.EOF
-		}
-		return nil, "", err
-	}
-
-	return b[:n], addr.String(), nil
-}
-
-// WriteTo implements the Transport WriteTo method.
-func (t *TransportConn) WriteTo(pkt []byte, address string) error {
-	network := t.conn.LocalAddr().Network()
-	addr, err := t.res(network, address)
-	if err != nil {
-		return err
-	}
-
-	_, err = t.conn.WriteTo(pkt, addr)
-	return err
-}
-
-// Close closes the transport layer.
-func (t *TransportConn) Close() {
-	_ = t.conn.Close()
-}
-
-// LocalAddr returns the local network address.
-func (t *TransportConn) LocalAddr() net.Addr {
-	return t.conn.LocalAddr()
-}
diff --git a/packages/autopeering/transport/conn_test.go b/packages/autopeering/transport/conn_test.go
deleted file mode 100644
index 3066fae3..00000000
--- a/packages/autopeering/transport/conn_test.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package transport
-
-import (
-	"io"
-	"net"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-func TestConnUdpClosed(t *testing.T) {
-	conn := openUDP(t)
-
-	conn.Close()
-	_, _, err := conn.ReadFrom()
-	assert.EqualError(t, err, io.EOF.Error())
-}
-
-func TestConnUdpPacket(t *testing.T) {
-	a := openUDP(t)
-	defer a.Close()
-	b := openUDP(t)
-	defer b.Close()
-
-	err := a.WriteTo(testPacket, b.LocalAddr().String())
-	require.NoError(t, err)
-
-	pkt, addr, err := b.ReadFrom()
-	require.NoError(t, err)
-
-	assert.Equal(t, pkt, testPacket)
-	assert.Equal(t, addr, a.LocalAddr().String())
-}
-
-func openUDP(t *testing.T) *TransportConn {
-	c, err := net.ListenPacket("udp", "127.0.0.1:0")
-	require.NoError(t, err)
-
-	return Conn(c, func(network, address string) (net.Addr, error) { return net.ResolveUDPAddr(network, address) })
-}
diff --git a/packages/autopeering/transport/const.go b/packages/autopeering/transport/const.go
deleted file mode 100644
index afff55cb..00000000
--- a/packages/autopeering/transport/const.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package transport
-
-const (
-	queueSize = 5
-)
diff --git a/packages/autopeering/transport/errors.go b/packages/autopeering/transport/errors.go
deleted file mode 100644
index bb9ea0c1..00000000
--- a/packages/autopeering/transport/errors.go
+++ /dev/null
@@ -1,8 +0,0 @@
-package transport
-
-import "errors"
-
-var (
-	errClosed = errors.New("socket closed")
-	errPeer   = errors.New("could not determine peer")
-)
diff --git a/packages/autopeering/transport/p2p.go b/packages/autopeering/transport/p2p.go
deleted file mode 100644
index 1bb3bb6f..00000000
--- a/packages/autopeering/transport/p2p.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package transport
-
-import (
-	"io"
-	"net"
-	"sync"
-)
-
-// TransportP2P offers transfers between exactly two clients.
-type TransportP2P struct {
-	A, B Transport
-}
-
-// P2P creates a new in-memory two clients transport network.
-// All writes in one client will always be received by the other client, no
-// matter what address was specified.
-func P2P() *TransportP2P {
-	chanA := make(chan transfer, queueSize)
-	chanB := make(chan transfer, queueSize)
-
-	return &TransportP2P{
-		A: newChanTransport(chanA, chanB, "A"),
-		B: newChanTransport(chanB, chanA, "B"),
-	}
-}
-
-// Close closes each of the two client transport layers.
-func (t *TransportP2P) Close() {
-	t.A.Close()
-	t.B.Close()
-}
-
-// p2pAddr represents the address of an p2p end point.
-type p2pAddr struct {
-	address string
-}
-
-func (a p2pAddr) Network() string { return "p2p" }
-func (a p2pAddr) String() string  { return a.address }
-
-// chanTransport implements Transport by reading and writing to given channels.
-type chanTransport struct {
-	in   <-chan transfer
-	out  chan<- transfer
-	addr p2pAddr
-
-	closeOnce sync.Once
-	closing   chan struct{}
-}
-
-func newChanTransport(in <-chan transfer, out chan<- transfer, address string) *chanTransport {
-	return &chanTransport{
-		in:      in,
-		out:     out,
-		addr:    p2pAddr{address: address},
-		closing: make(chan struct{}),
-	}
-}
-
-// ReadFrom implements the Transport ReadFrom method.
-func (t *chanTransport) ReadFrom() ([]byte, string, error) {
-	select {
-	case res := <-t.in:
-		return res.pkt, res.addr, nil
-	case <-t.closing:
-		return nil, "", io.EOF
-	}
-}
-
-// WriteTo implements the Transport WriteTo method.
-func (t *chanTransport) WriteTo(pkt []byte, _ string) error {
-	// clone the packet before sending, just to make sure...
-	req := transfer{pkt: append([]byte{}, pkt...), addr: t.addr.address}
-
-	select {
-	case t.out <- req:
-		return nil
-	case <-t.closing:
-		return errClosed
-	}
-}
-
-// Close closes the transport layer.
-func (t *chanTransport) Close() {
-	t.closeOnce.Do(func() {
-		close(t.closing)
-	})
-}
-
-// LocalAddr returns the local network address.
-func (t *chanTransport) LocalAddr() net.Addr {
-	return t.addr
-}
diff --git a/packages/autopeering/transport/p2p_test.go b/packages/autopeering/transport/p2p_test.go
deleted file mode 100644
index 78a454cc..00000000
--- a/packages/autopeering/transport/p2p_test.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package transport
-
-import (
-	"io"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-var testPacket = []byte("TEST")
-
-func TestP2PReadClosed(t *testing.T) {
-	p2p := P2P()
-	defer p2p.Close()
-
-	p2p.A.Close()
-	_, _, err := p2p.A.ReadFrom()
-	assert.EqualError(t, err, io.EOF.Error())
-}
-
-func TestP2PPacket(t *testing.T) {
-	p2p := P2P()
-	defer p2p.Close()
-
-	err := p2p.A.WriteTo(testPacket, p2p.B.LocalAddr().String())
-	require.NoError(t, err)
-
-	pkt, addr, err := p2p.B.ReadFrom()
-	require.NoError(t, err)
-
-	assert.Equal(t, pkt, testPacket)
-	assert.Equal(t, addr, p2p.A.LocalAddr().String())
-}
diff --git a/packages/autopeering/transport/transport.go b/packages/autopeering/transport/transport.go
deleted file mode 100644
index 53a295e9..00000000
--- a/packages/autopeering/transport/transport.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// Package transport provides implementations for simple address-based packet
-// transfers.
-package transport
-
-import (
-	"net"
-)
-
-const (
-	// MaxPacketSize specifies the maximum allowed size of packets.
-	// Packets larger than this will be cut and thus treated as invalid.
-	MaxPacketSize = 1280
-)
-
-// Transport is generic network connection to transfer protobuf packages.
-// Multiple goroutines may invoke methods on a Conn simultaneously.
-type Transport interface {
-	// ReadFrom reads a packet from the connection. It returns the package and
-	// the return address for that package in string form.
-	ReadFrom() (pkt []byte, address string, err error)
-
-	// WriteTo writes a packet to the string encoded target address.
-	WriteTo(pkt []byte, address string) error
-
-	// Close closes the transport layer.
-	// Any blocked ReadFrom or WriteTo operations will return errors.
-	Close()
-
-	// LocalAddr returns the local network address.
-	LocalAddr() net.Addr
-}
-
-// transfer represents a send and contains the package and the return address.
-type transfer struct {
-	pkt  []byte
-	addr string
-}
diff --git a/packages/binary/identity/constants.go b/packages/binary/identity/constants.go
new file mode 100644
index 00000000..b8fb9850
--- /dev/null
+++ b/packages/binary/identity/constants.go
@@ -0,0 +1,7 @@
+package identity
+
+const (
+	PublicKeySize  = 32
+	PrivateKeySize = 64
+	SignatureSize  = 64
+)
diff --git a/packages/binary/identity/identity.go b/packages/binary/identity/identity.go
new file mode 100644
index 00000000..fd52c6f3
--- /dev/null
+++ b/packages/binary/identity/identity.go
@@ -0,0 +1,48 @@
+package identity
+
+import (
+	"crypto/rand"
+
+	"github.com/oasislabs/ed25519"
+)
+
+type Identity struct {
+	Type       Type
+	PublicKey  []byte
+	PrivateKey []byte
+}
+
+func New(publicKey []byte, optionalPrivateKey ...[]byte) *Identity {
+	this := &Identity{
+		PublicKey: make([]byte, len(publicKey)),
+	}
+
+	copy(this.PublicKey, publicKey)
+
+	if len(optionalPrivateKey) == 0 {
+		this.Type = Public
+	} else {
+		this.Type = Private
+		this.PrivateKey = optionalPrivateKey[0]
+	}
+
+	return this
+}
+
+func Generate() *Identity {
+	if public, private, err := ed25519.GenerateKey(rand.Reader); err != nil {
+		panic(err)
+	} else {
+		return New(public, private)
+	}
+}
+
+func (identity *Identity) Sign(data []byte) (sig []byte) {
+	sig = ed25519.Sign(identity.PrivateKey, data)
+
+	return
+}
+
+func (identity *Identity) VerifySignature(data []byte, signature []byte) bool {
+	return ed25519.Verify(identity.PublicKey, data, signature)
+}
diff --git a/packages/binary/identity/identity_test.go b/packages/binary/identity/identity_test.go
new file mode 100644
index 00000000..f5fc0d52
--- /dev/null
+++ b/packages/binary/identity/identity_test.go
@@ -0,0 +1,41 @@
+package identity
+
+import (
+	"sync"
+	"testing"
+
+	"github.com/panjf2000/ants/v2"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func BenchmarkIdentity_VerifySignature(b *testing.B) {
+	identity := Generate()
+	data := []byte("TESTDATA")
+	signature := identity.Sign(data)
+
+	var wg sync.WaitGroup
+
+	b.ResetTimer()
+
+	for i := 0; i < b.N; i++ {
+		wg.Add(1)
+
+		_ = ants.Submit(func() {
+			identity.VerifySignature(data, signature)
+
+			wg.Done()
+		})
+	}
+
+	wg.Wait()
+}
+
+func Test(t *testing.T) {
+	identity := Generate()
+
+	signature := identity.Sign([]byte("TESTDATA1"))
+
+	assert.Equal(t, true, identity.VerifySignature([]byte("TESTDATA1"), signature))
+	assert.Equal(t, false, identity.VerifySignature([]byte("TESTDATA2"), signature))
+}
diff --git a/packages/binary/identity/type.go b/packages/binary/identity/type.go
new file mode 100644
index 00000000..cc207b02
--- /dev/null
+++ b/packages/binary/identity/type.go
@@ -0,0 +1,8 @@
+package identity
+
+type Type int
+
+const (
+	Private = Type(0)
+	Public  = Type(1)
+)
diff --git a/packages/binary/signature/ed25119/ed25119.go b/packages/binary/signature/ed25119/ed25119.go
new file mode 100644
index 00000000..d4b65997
--- /dev/null
+++ b/packages/binary/signature/ed25119/ed25119.go
@@ -0,0 +1,18 @@
+package ed25119
+
+import (
+	"crypto/rand"
+
+	"github.com/oasislabs/ed25519"
+)
+
+func GenerateKeyPair() (keyPair KeyPair) {
+	if public, private, err := ed25519.GenerateKey(rand.Reader); err != nil {
+		panic(err)
+	} else {
+		copy(keyPair.PrivateKey[:], private)
+		copy(keyPair.PublicKey[:], public)
+
+		return
+	}
+}
diff --git a/packages/binary/signature/ed25119/key_pair.go b/packages/binary/signature/ed25119/key_pair.go
new file mode 100644
index 00000000..ad0c31bb
--- /dev/null
+++ b/packages/binary/signature/ed25119/key_pair.go
@@ -0,0 +1,6 @@
+package ed25119
+
+type KeyPair struct {
+	PrivateKey PrivateKey
+	PublicKey  PublicKey
+}
diff --git a/packages/binary/signature/ed25119/private_key.go b/packages/binary/signature/ed25119/private_key.go
new file mode 100644
index 00000000..89dc1a15
--- /dev/null
+++ b/packages/binary/signature/ed25119/private_key.go
@@ -0,0 +1,15 @@
+package ed25119
+
+import (
+	"github.com/oasislabs/ed25519"
+)
+
+type PrivateKey [PrivateKeySize]byte
+
+func (privateKey PrivateKey) Sign(data []byte) (result Signature) {
+	copy(result[:], ed25519.Sign(privateKey[:], data))
+
+	return
+}
+
+const PrivateKeySize = 64
diff --git a/packages/binary/signature/ed25119/public_key.go b/packages/binary/signature/ed25119/public_key.go
new file mode 100644
index 00000000..c9d58e25
--- /dev/null
+++ b/packages/binary/signature/ed25119/public_key.go
@@ -0,0 +1,25 @@
+package ed25119
+
+import (
+	"errors"
+
+	"github.com/oasislabs/ed25519"
+)
+
+type PublicKey [PublicKeySize]byte
+
+func (publicKey PublicKey) VerifySignature(data []byte, signature Signature) bool {
+	return ed25519.Verify(publicKey[:], data, signature[:])
+}
+
+func (publicKey *PublicKey) UnmarshalBinary(bytes []byte) (err error) {
+	if len(bytes) < PublicKeySize {
+		return errors.New("not enough bytes")
+	}
+
+	copy(publicKey[:], bytes[:])
+
+	return
+}
+
+const PublicKeySize = 32
diff --git a/packages/binary/signature/ed25119/signature.go b/packages/binary/signature/ed25119/signature.go
new file mode 100644
index 00000000..bd33e113
--- /dev/null
+++ b/packages/binary/signature/ed25119/signature.go
@@ -0,0 +1,19 @@
+package ed25119
+
+import (
+	"errors"
+)
+
+type Signature [SignatureSize]byte
+
+func (signature *Signature) UnmarshalBinary(bytes []byte) (err error) {
+	if len(bytes) < SignatureSize {
+		return errors.New("not enough bytes")
+	}
+
+	copy(signature[:], bytes[:])
+
+	return
+}
+
+const SignatureSize = 64
diff --git a/packages/binary/storageprefix/storageprefix.go b/packages/binary/storageprefix/storageprefix.go
new file mode 100644
index 00000000..1e55f2db
--- /dev/null
+++ b/packages/binary/storageprefix/storageprefix.go
@@ -0,0 +1,17 @@
+package storageprefix
+
+var (
+	TangleTransaction         = []byte{0}
+	TangleTransactionMetadata = []byte{1}
+	TangleApprovers           = []byte{2}
+	TangleMissingTransaction  = []byte{3}
+
+	ValueTangleTransferMetadata = []byte{4}
+	ValueTangleConsumers        = []byte{5}
+	ValueTangleMissingTransfers = []byte{6}
+
+	LedgerStateTransferOutput        = []byte{7}
+	LedgerStateTransferOutputBooking = []byte{8}
+	LedgerStateReality               = []byte{9}
+	LedgerStateConflictSet           = []byte{10}
+)
diff --git a/packages/binary/tangle/events.go b/packages/binary/tangle/events.go
new file mode 100644
index 00000000..d2bf3552
--- /dev/null
+++ b/packages/binary/tangle/events.go
@@ -0,0 +1,39 @@
+package tangle
+
+import (
+	"github.com/iotaledger/hive.go/events"
+
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction"
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transactionmetadata"
+)
+
+type Events struct {
+	TransactionAttached        *events.Event
+	TransactionSolid           *events.Event
+	MissingTransactionReceived *events.Event
+	TransactionMissing         *events.Event
+	TransactionUnsolidifiable  *events.Event
+	TransactionRemoved         *events.Event
+}
+
+func newEvents() *Events {
+	return &Events{
+		TransactionAttached:        events.NewEvent(cachedTransactionEvent),
+		TransactionSolid:           events.NewEvent(cachedTransactionEvent),
+		MissingTransactionReceived: events.NewEvent(cachedTransactionEvent),
+		TransactionMissing:         events.NewEvent(transactionIdEvent),
+		TransactionUnsolidifiable:  events.NewEvent(transactionIdEvent),
+		TransactionRemoved:         events.NewEvent(transactionIdEvent),
+	}
+}
+
+func transactionIdEvent(handler interface{}, params ...interface{}) {
+	handler.(func(transaction.Id))(params[0].(transaction.Id))
+}
+
+func cachedTransactionEvent(handler interface{}, params ...interface{}) {
+	handler.(func(*transaction.CachedTransaction, *transactionmetadata.CachedTransactionMetadata))(
+		params[0].(*transaction.CachedTransaction).Retain(),
+		params[1].(*transactionmetadata.CachedTransactionMetadata).Retain().(*transactionmetadata.CachedTransactionMetadata),
+	)
+}
diff --git a/packages/binary/tangle/model/approver/approver.go b/packages/binary/tangle/model/approver/approver.go
new file mode 100644
index 00000000..b08bf342
--- /dev/null
+++ b/packages/binary/tangle/model/approver/approver.go
@@ -0,0 +1,59 @@
+package approver
+
+import (
+	"github.com/iotaledger/hive.go/objectstorage"
+
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction"
+)
+
+type Approver struct {
+	objectstorage.StorableObjectFlags
+
+	storageKey            []byte
+	referencedTransaction transaction.Id
+	approvingTransaction  transaction.Id
+}
+
+func New(referencedTransaction transaction.Id, approvingTransaction transaction.Id) *Approver {
+	approver := &Approver{
+		storageKey:            make([]byte, transaction.IdLength+transaction.IdLength),
+		referencedTransaction: referencedTransaction,
+		approvingTransaction:  approvingTransaction,
+	}
+
+	copy(approver.storageKey[:transaction.IdLength], referencedTransaction[:])
+	copy(approver.storageKey[transaction.IdLength:], approvingTransaction[:])
+
+	return approver
+}
+
+func FromStorage(id []byte) (result objectstorage.StorableObject) {
+	approver := &Approver{
+		storageKey: make([]byte, transaction.IdLength+transaction.IdLength),
+	}
+	copy(approver.referencedTransaction[:], id[:transaction.IdLength])
+	copy(approver.approvingTransaction[:], id[transaction.IdLength:])
+	copy(approver.storageKey, id)
+
+	return approver
+}
+
+func (approver *Approver) GetStorageKey() []byte {
+	return approver.storageKey
+}
+
+func (approver *Approver) GetApprovingTransactionId() transaction.Id {
+	return approver.approvingTransaction
+}
+
+func (approver *Approver) Update(other objectstorage.StorableObject) {
+	panic("approvers should never be overwritten and only stored once to optimize IO")
+}
+
+func (approver *Approver) MarshalBinary() (result []byte, err error) {
+	return
+}
+
+func (approver *Approver) UnmarshalBinary(data []byte) (err error) {
+	return
+}
diff --git a/packages/binary/tangle/model/approver/cached_approver.go b/packages/binary/tangle/model/approver/cached_approver.go
new file mode 100644
index 00000000..c5284432
--- /dev/null
+++ b/packages/binary/tangle/model/approver/cached_approver.go
@@ -0,0 +1,33 @@
+package approver
+
+import (
+	"github.com/iotaledger/hive.go/objectstorage"
+)
+
+type CachedApprover struct {
+	objectstorage.CachedObject
+}
+
+func (cachedApprover *CachedApprover) Unwrap() *Approver {
+	if untypedObject := cachedApprover.Get(); untypedObject == nil {
+		return nil
+	} else {
+		if typedObject := untypedObject.(*Approver); typedObject == nil || typedObject.IsDeleted() {
+			return nil
+		} else {
+			return typedObject
+		}
+	}
+}
+
+type CachedApprovers []*CachedApprover
+
+func (cachedApprovers CachedApprovers) Consume(consumer func(approver *Approver)) (consumed bool) {
+	for _, cachedApprover := range cachedApprovers {
+		consumed = consumed || cachedApprover.Consume(func(object objectstorage.StorableObject) {
+			consumer(object.(*Approver))
+		})
+	}
+
+	return
+}
diff --git a/packages/binary/tangle/model/missingtransaction/cached_missingtransaction.go b/packages/binary/tangle/model/missingtransaction/cached_missingtransaction.go
new file mode 100644
index 00000000..f50f5321
--- /dev/null
+++ b/packages/binary/tangle/model/missingtransaction/cached_missingtransaction.go
@@ -0,0 +1,21 @@
+package missingtransaction
+
+import (
+	"github.com/iotaledger/hive.go/objectstorage"
+)
+
+type CachedMissingTransaction struct {
+	objectstorage.CachedObject
+}
+
+func (cachedObject *CachedMissingTransaction) Unwrap() *MissingTransaction {
+	if untypedObject := cachedObject.Get(); untypedObject == nil {
+		return nil
+	} else {
+		if typedObject := untypedObject.(*MissingTransaction); typedObject == nil || typedObject.IsDeleted() {
+			return nil
+		} else {
+			return typedObject
+		}
+	}
+}
diff --git a/packages/binary/tangle/model/missingtransaction/missingtransaction.go b/packages/binary/tangle/model/missingtransaction/missingtransaction.go
new file mode 100644
index 00000000..ea1715c8
--- /dev/null
+++ b/packages/binary/tangle/model/missingtransaction/missingtransaction.go
@@ -0,0 +1,53 @@
+package missingtransaction
+
+import (
+	"time"
+
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction"
+	"github.com/iotaledger/hive.go/objectstorage"
+)
+
+type MissingTransaction struct {
+	objectstorage.StorableObjectFlags
+
+	transactionId transaction.Id
+	missingSince  time.Time
+}
+
+func New(transactionId transaction.Id) *MissingTransaction {
+	return &MissingTransaction{
+		transactionId: transactionId,
+		missingSince:  time.Now(),
+	}
+}
+
+func FromStorage(key []byte) objectstorage.StorableObject {
+	result := &MissingTransaction{}
+	copy(result.transactionId[:], key)
+
+	return result
+}
+
+func (missingTransaction *MissingTransaction) GetTransactionId() transaction.Id {
+	return missingTransaction.transactionId
+}
+
+func (missingTransaction *MissingTransaction) GetMissingSince() time.Time {
+	return missingTransaction.missingSince
+}
+
+func (missingTransaction *MissingTransaction) GetStorageKey() []byte {
+	return missingTransaction.transactionId[:]
+}
+
+func (missingTransaction *MissingTransaction) Update(other objectstorage.StorableObject) {
+	panic("missing transactions should never be overwritten and only stored once to optimize IO")
+}
+
+func (missingTransaction *MissingTransaction) MarshalBinary() (result []byte, err error) {
+	return missingTransaction.missingSince.MarshalBinary()
+}
+
+func (missingTransaction *MissingTransaction) UnmarshalBinary(data []byte) (err error) {
+	return missingTransaction.missingSince.UnmarshalBinary(data)
+}
diff --git a/packages/binary/tangle/model/transaction/cached_transaction.go b/packages/binary/tangle/model/transaction/cached_transaction.go
new file mode 100644
index 00000000..5f177ea7
--- /dev/null
+++ b/packages/binary/tangle/model/transaction/cached_transaction.go
@@ -0,0 +1,31 @@
+package transaction
+
+import (
+	"github.com/iotaledger/hive.go/objectstorage"
+)
+
+type CachedTransaction struct {
+	objectstorage.CachedObject
+}
+
+func (cachedTransaction *CachedTransaction) Retain() *CachedTransaction {
+	return &CachedTransaction{cachedTransaction.CachedObject.Retain()}
+}
+
+func (cachedTransaction *CachedTransaction) Consume(consumer func(object *Transaction)) bool {
+	return cachedTransaction.CachedObject.Consume(func(object objectstorage.StorableObject) {
+		consumer(object.(*Transaction))
+	})
+}
+
+func (cachedTransaction *CachedTransaction) Unwrap() *Transaction {
+	if untypedTransaction := cachedTransaction.Get(); untypedTransaction == nil {
+		return nil
+	} else {
+		if typeCastedTransaction := untypedTransaction.(*Transaction); typeCastedTransaction == nil || typeCastedTransaction.IsDeleted() {
+			return nil
+		} else {
+			return typeCastedTransaction
+		}
+	}
+}
diff --git a/packages/binary/tangle/model/transaction/id.go b/packages/binary/tangle/model/transaction/id.go
new file mode 100644
index 00000000..dd5ca154
--- /dev/null
+++ b/packages/binary/tangle/model/transaction/id.go
@@ -0,0 +1,34 @@
+package transaction
+
+import (
+	"github.com/mr-tron/base58"
+)
+
+type Id [IdLength]byte
+
+func NewId(id []byte) (result Id) {
+	copy(result[:], id)
+
+	return
+}
+
+func (id *Id) MarshalBinary() (result []byte, err error) {
+	result = make([]byte, IdLength)
+	copy(result, id[:])
+
+	return
+}
+
+func (id *Id) UnmarshalBinary(data []byte) (err error) {
+	copy(id[:], data)
+
+	return
+}
+
+func (id Id) String() string {
+	return base58.Encode(id[:])
+}
+
+var EmptyId = Id{}
+
+const IdLength = 64
diff --git a/packages/binary/tangle/model/transaction/init.go b/packages/binary/tangle/model/transaction/init.go
new file mode 100644
index 00000000..5805588c
--- /dev/null
+++ b/packages/binary/tangle/model/transaction/init.go
@@ -0,0 +1,10 @@
+package transaction
+
+import (
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload"
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload/data"
+)
+
+func init() {
+	payload.SetGenericUnmarshalerFactory(data.GenericPayloadUnmarshalerFactory)
+}
diff --git a/packages/binary/tangle/model/transaction/payload/data/data.go b/packages/binary/tangle/model/transaction/payload/data/data.go
new file mode 100644
index 00000000..8b41b99c
--- /dev/null
+++ b/packages/binary/tangle/model/transaction/payload/data/data.go
@@ -0,0 +1,52 @@
+package data
+
+import (
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload"
+)
+
+type Data struct {
+	payloadType payload.Type
+	data        []byte
+}
+
+var Type = payload.Type(0)
+
+func New(data []byte) *Data {
+	return &Data{
+		payloadType: Type,
+		data:        data,
+	}
+}
+
+func (dataPayload *Data) GetType() payload.Type {
+	return dataPayload.payloadType
+}
+
+func (dataPayload *Data) GetData() []byte {
+	return dataPayload.data
+}
+
+func (dataPayload *Data) UnmarshalBinary(data []byte) error {
+	dataPayload.data = make([]byte, len(data))
+	copy(dataPayload.data, data)
+
+	return nil
+}
+
+func (dataPayload *Data) MarshalBinary() (data []byte, err error) {
+	data = make([]byte, len(dataPayload.data))
+	copy(data, dataPayload.data)
+
+	return
+}
+
+func GenericPayloadUnmarshalerFactory(payloadType payload.Type) payload.Unmarshaler {
+	return func(data []byte) (payload payload.Payload, err error) {
+		payload = &Data{
+			payloadType: payloadType,
+		}
+		err = payload.UnmarshalBinary(data)
+
+		return
+	}
+}
diff --git a/packages/binary/tangle/model/transaction/payload/data/init.go b/packages/binary/tangle/model/transaction/payload/data/init.go
new file mode 100644
index 00000000..547bca2c
--- /dev/null
+++ b/packages/binary/tangle/model/transaction/payload/data/init.go
@@ -0,0 +1,9 @@
+package data
+
+import (
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload"
+)
+
+func init() {
+	payload.RegisterType(Type, GenericPayloadUnmarshalerFactory(Type))
+}
diff --git a/packages/binary/tangle/model/transaction/payload/id.go b/packages/binary/tangle/model/transaction/payload/id.go
new file mode 100644
index 00000000..a20ce75f
--- /dev/null
+++ b/packages/binary/tangle/model/transaction/payload/id.go
@@ -0,0 +1,5 @@
+package payload
+
+type Id [IdLength]byte
+
+const IdLength = 64
diff --git a/packages/binary/tangle/model/transaction/payload/payload.go b/packages/binary/tangle/model/transaction/payload/payload.go
new file mode 100644
index 00000000..23ff09be
--- /dev/null
+++ b/packages/binary/tangle/model/transaction/payload/payload.go
@@ -0,0 +1,12 @@
+package payload
+
+import (
+	"encoding"
+)
+
+type Payload interface {
+	encoding.BinaryMarshaler
+	encoding.BinaryUnmarshaler
+
+	GetType() Type
+}
diff --git a/packages/binary/tangle/model/transaction/payload/type.go b/packages/binary/tangle/model/transaction/payload/type.go
new file mode 100644
index 00000000..a1594aa4
--- /dev/null
+++ b/packages/binary/tangle/model/transaction/payload/type.go
@@ -0,0 +1,3 @@
+package payload
+
+type Type = uint32
diff --git a/packages/binary/tangle/model/transaction/payload/type_register.go b/packages/binary/tangle/model/transaction/payload/type_register.go
new file mode 100644
index 00000000..aac9a919
--- /dev/null
+++ b/packages/binary/tangle/model/transaction/payload/type_register.go
@@ -0,0 +1,36 @@
+package payload
+
+import (
+	"sync"
+)
+
+type Unmarshaler func(data []byte) (Payload, error)
+
+var (
+	typeRegister              = make(map[Type]Unmarshaler)
+	typeRegisterMutex         sync.RWMutex
+	genericUnmarshalerFactory func(payloadType Type) Unmarshaler
+)
+
+func RegisterType(payloadType Type, unmarshaler Unmarshaler) {
+	typeRegisterMutex.Lock()
+	typeRegister[payloadType] = unmarshaler
+	typeRegisterMutex.Unlock()
+}
+
+func GetUnmarshaler(payloadType Type) Unmarshaler {
+	typeRegisterMutex.RLock()
+	if unmarshaler, exists := typeRegister[payloadType]; exists {
+		typeRegisterMutex.RUnlock()
+
+		return unmarshaler
+	} else {
+		typeRegisterMutex.RUnlock()
+
+		return genericUnmarshalerFactory(payloadType)
+	}
+}
+
+func SetGenericUnmarshalerFactory(unmarshalerFactory func(payloadType Type) Unmarshaler) {
+	genericUnmarshalerFactory = unmarshalerFactory
+}
diff --git a/packages/binary/tangle/model/transaction/test/transaction_test.go b/packages/binary/tangle/model/transaction/test/transaction_test.go
new file mode 100644
index 00000000..1ca51d61
--- /dev/null
+++ b/packages/binary/tangle/model/transaction/test/transaction_test.go
@@ -0,0 +1,77 @@
+package test
+
+import (
+	"runtime"
+	"sync"
+	"testing"
+
+	"github.com/iotaledger/hive.go/async"
+
+	"github.com/panjf2000/ants/v2"
+
+	"github.com/iotaledger/goshimmer/packages/binary/identity"
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction"
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload/data"
+)
+
+func BenchmarkVerifyDataTransactions(b *testing.B) {
+	var pool async.WorkerPool
+	pool.Tune(runtime.NumCPU() * 2)
+
+	transactions := make([][]byte, b.N)
+	for i := 0; i < b.N; i++ {
+		tx := transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("some data")))
+
+		if marshaledTransaction, err := tx.MarshalBinary(); err != nil {
+			b.Error(err)
+		} else {
+			transactions[i] = marshaledTransaction
+		}
+	}
+
+	b.ResetTimer()
+
+	for i := 0; i < b.N; i++ {
+		currentIndex := i
+		pool.Submit(func() {
+			if tx, err := transaction.FromBytes(transactions[currentIndex]); err != nil {
+				b.Error(err)
+			} else {
+				tx.VerifySignature()
+			}
+		})
+	}
+
+	pool.Shutdown()
+}
+
+func BenchmarkVerifySignature(b *testing.B) {
+	pool, _ := ants.NewPool(80, ants.WithNonblocking(false))
+
+	transactions := make([]*transaction.Transaction, b.N)
+	for i := 0; i < b.N; i++ {
+		transactions[i] = transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("test")))
+		transactions[i].GetBytes()
+	}
+
+	var wg sync.WaitGroup
+
+	b.ResetTimer()
+
+	for i := 0; i < b.N; i++ {
+		wg.Add(1)
+
+		currentIndex := i
+		if err := pool.Submit(func() {
+			transactions[currentIndex].VerifySignature()
+
+			wg.Done()
+		}); err != nil {
+			b.Error(err)
+
+			return
+		}
+	}
+
+	wg.Wait()
+}
diff --git a/packages/binary/tangle/model/transaction/transaction.go b/packages/binary/tangle/model/transaction/transaction.go
new file mode 100644
index 00000000..de18ffc4
--- /dev/null
+++ b/packages/binary/tangle/model/transaction/transaction.go
@@ -0,0 +1,277 @@
+package transaction
+
+import (
+	"encoding/binary"
+	"sync"
+
+	"github.com/iotaledger/hive.go/stringify"
+
+	"github.com/iotaledger/goshimmer/packages/binary/identity"
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload"
+
+	"github.com/iotaledger/hive.go/objectstorage"
+
+	"github.com/mr-tron/base58"
+
+	"golang.org/x/crypto/blake2b"
+)
+
+type Transaction struct {
+	// base functionality of StorableObject
+	objectstorage.StorableObjectFlags
+
+	// core properties (they are part of the transaction when being sent)
+	trunkTransactionId  Id
+	branchTransactionId Id
+	issuer              *identity.Identity
+	payload             payload.Payload
+	bytes               []byte
+	bytesMutex          sync.RWMutex
+	signature           [identity.SignatureSize]byte
+	signatureMutex      sync.RWMutex
+
+	// derived properties
+	id             *Id
+	idMutex        sync.RWMutex
+	payloadId      *payload.Id
+	payloadIdMutex sync.RWMutex
+}
+
+// Allows us to "issue" a transaction.
+func New(trunkTransactionId Id, branchTransactionId Id, issuer *identity.Identity, payload payload.Payload) (result *Transaction) {
+	return &Transaction{
+		trunkTransactionId:  trunkTransactionId,
+		branchTransactionId: branchTransactionId,
+		issuer:              issuer,
+		payload:             payload,
+	}
+}
+
+// Get's called when we restore a transaction from storage. The bytes and the content will be unmarshaled by an external
+// caller (the objectStorage factory).
+func FromStorage(id []byte) (result objectstorage.StorableObject) {
+	var transactionId Id
+	copy(transactionId[:], id)
+
+	result = &Transaction{
+		id: &transactionId,
+	}
+
+	return
+}
+
+func FromBytes(bytes []byte) (result *Transaction, err error) {
+	result = &Transaction{}
+	err = result.UnmarshalBinary(bytes)
+
+	return
+}
+
+func (transaction *Transaction) VerifySignature() (result bool) {
+	transactionBytes := transaction.GetBytes()
+
+	transaction.signatureMutex.RLock()
+	result = transaction.issuer.VerifySignature(transactionBytes[:len(transactionBytes)-identity.SignatureSize], transaction.signature[:])
+	transaction.signatureMutex.RUnlock()
+
+	return
+}
+
+func (transaction *Transaction) GetId() (result Id) {
+	transaction.idMutex.RLock()
+	if transaction.id == nil {
+		transaction.idMutex.RUnlock()
+
+		transaction.idMutex.Lock()
+		if transaction.id == nil {
+			result = transaction.calculateTransactionId()
+
+			transaction.id = &result
+		} else {
+			result = *transaction.id
+		}
+		transaction.idMutex.Unlock()
+	} else {
+		result = *transaction.id
+
+		transaction.idMutex.RUnlock()
+	}
+
+	return
+}
+
+func (transaction *Transaction) GetTrunkTransactionId() Id {
+	return transaction.trunkTransactionId
+}
+
+func (transaction *Transaction) GetBranchTransactionId() Id {
+	return transaction.branchTransactionId
+}
+
+func (transaction *Transaction) GetPayload() payload.Payload {
+	return transaction.payload
+}
+
+func (transaction *Transaction) GetPayloadId() (result payload.Id) {
+	transaction.payloadIdMutex.RLock()
+	if transaction.payloadId == nil {
+		transaction.payloadIdMutex.RUnlock()
+
+		transaction.payloadIdMutex.Lock()
+		if transaction.payloadId == nil {
+			result = transaction.calculatePayloadId()
+
+			transaction.payloadId = &result
+		} else {
+			result = *transaction.payloadId
+		}
+		transaction.payloadIdMutex.Unlock()
+	} else {
+		result = *transaction.payloadId
+
+		transaction.payloadIdMutex.RUnlock()
+	}
+
+	return
+}
+
+func (transaction *Transaction) GetBytes() []byte {
+	if result, err := transaction.MarshalBinary(); err != nil {
+		panic(err)
+	} else {
+		return result
+	}
+}
+
+func (transaction *Transaction) calculateTransactionId() Id {
+	payloadId := transaction.GetPayloadId()
+
+	hashBase := make([]byte, IdLength+IdLength+payload.IdLength)
+	offset := 0
+
+	copy(hashBase[offset:], transaction.trunkTransactionId[:])
+	offset += IdLength
+
+	copy(hashBase[offset:], transaction.branchTransactionId[:])
+	offset += IdLength
+
+	copy(hashBase[offset:], payloadId[:])
+	// offset += payloadIdLength
+
+	return blake2b.Sum512(hashBase)
+}
+
+func (transaction *Transaction) calculatePayloadId() payload.Id {
+	bytes := transaction.GetBytes()
+
+	return blake2b.Sum512(bytes[2*IdLength:])
+}
+
+// Since transactions are immutable and do not get changed after being created, we cache the result of the marshaling.
+func (transaction *Transaction) MarshalBinary() (result []byte, err error) {
+	transaction.bytesMutex.RLock()
+	if transaction.bytes == nil {
+		transaction.bytesMutex.RUnlock()
+
+		transaction.bytesMutex.Lock()
+		if transaction.bytes == nil {
+			var serializedPayload []byte
+			if transaction.payload != nil {
+				if serializedPayload, err = transaction.payload.MarshalBinary(); err != nil {
+					return
+				}
+			}
+			serializedPayloadLength := len(serializedPayload)
+
+			result = make([]byte, IdLength+IdLength+identity.PublicKeySize+4+serializedPayloadLength+identity.SignatureSize)
+			offset := 0
+
+			copy(result[offset:], transaction.trunkTransactionId[:])
+			offset += IdLength
+
+			copy(result[offset:], transaction.branchTransactionId[:])
+			offset += IdLength
+
+			if transaction.issuer != nil {
+				copy(result[offset:], transaction.issuer.PublicKey)
+			}
+			offset += identity.PublicKeySize
+
+			binary.LittleEndian.PutUint32(result[offset:], transaction.payload.GetType())
+			offset += 4
+
+			if serializedPayloadLength != 0 {
+				copy(result[offset:], serializedPayload)
+				offset += serializedPayloadLength
+			}
+
+			if transaction.issuer != nil {
+				transaction.signatureMutex.Lock()
+				copy(transaction.signature[:], transaction.issuer.Sign(result[:offset]))
+				transaction.signatureMutex.Unlock()
+				copy(result[offset:], transaction.signature[:])
+			}
+			// offset += identity.SignatureSize
+
+			transaction.bytes = result
+		} else {
+			result = transaction.bytes
+		}
+		transaction.bytesMutex.Unlock()
+	} else {
+		result = transaction.bytes
+
+		transaction.bytesMutex.RUnlock()
+	}
+
+	return
+}
+
+func (transaction *Transaction) UnmarshalBinary(data []byte) (err error) {
+	offset := 0
+
+	copy(transaction.trunkTransactionId[:], data[offset:])
+	offset += IdLength
+
+	copy(transaction.branchTransactionId[:], data[offset:])
+	offset += IdLength
+
+	transaction.issuer = identity.New(data[offset : offset+identity.PublicKeySize])
+	offset += identity.PublicKeySize
+
+	payloadType := binary.LittleEndian.Uint32(data[offset:])
+	offset += 4
+
+	if transaction.payload, err = payload.GetUnmarshaler(payloadType)(data[offset : len(data)-identity.SignatureSize]); err != nil {
+		return
+	}
+	offset += len(data) - identity.SignatureSize - offset
+
+	copy(transaction.signature[:], data[offset:])
+	// offset += identity.SignatureSize
+
+	transaction.bytes = make([]byte, len(data))
+	copy(transaction.bytes, data)
+
+	return
+}
+
+func (transaction *Transaction) GetStorageKey() []byte {
+	transactionId := transaction.GetId()
+
+	return transactionId[:]
+}
+
+func (transaction *Transaction) Update(other objectstorage.StorableObject) {
+	panic("transactions should never be overwritten and only stored once to optimize IO")
+}
+
+func (transaction *Transaction) String() string {
+	transactionId := transaction.GetId()
+
+	return stringify.Struct("Transaction",
+		stringify.StructField("id", base58.Encode(transactionId[:])),
+		stringify.StructField("trunkTransactionId", base58.Encode(transaction.trunkTransactionId[:])),
+		stringify.StructField("trunkTransactionId", base58.Encode(transaction.branchTransactionId[:])),
+	)
+}
diff --git a/packages/binary/tangle/model/transactionmetadata/cached_transactionmetadata.go b/packages/binary/tangle/model/transactionmetadata/cached_transactionmetadata.go
new file mode 100644
index 00000000..8b327806
--- /dev/null
+++ b/packages/binary/tangle/model/transactionmetadata/cached_transactionmetadata.go
@@ -0,0 +1,25 @@
+package transactionmetadata
+
+import (
+	"github.com/iotaledger/hive.go/objectstorage"
+)
+
+type CachedTransactionMetadata struct {
+	objectstorage.CachedObject
+}
+
+func (cachedObject *CachedTransactionMetadata) Retain() objectstorage.CachedObject {
+	return &CachedTransactionMetadata{cachedObject}
+}
+
+func (cachedObject *CachedTransactionMetadata) Unwrap() *TransactionMetadata {
+	if untypedObject := cachedObject.Get(); untypedObject == nil {
+		return nil
+	} else {
+		if typedObject := untypedObject.(*TransactionMetadata); typedObject == nil || typedObject.IsDeleted() {
+			return nil
+		} else {
+			return typedObject
+		}
+	}
+}
diff --git a/packages/binary/tangle/model/transactionmetadata/transactionmetadata.go b/packages/binary/tangle/model/transactionmetadata/transactionmetadata.go
new file mode 100644
index 00000000..f29a6e34
--- /dev/null
+++ b/packages/binary/tangle/model/transactionmetadata/transactionmetadata.go
@@ -0,0 +1,94 @@
+package transactionmetadata
+
+import (
+	"sync"
+	"time"
+
+	"github.com/iotaledger/hive.go/objectstorage"
+
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction"
+)
+
+type TransactionMetadata struct {
+	objectstorage.StorableObjectFlags
+
+	transactionId      transaction.Id
+	receivedTime       time.Time
+	solid              bool
+	solidificationTime time.Time
+
+	solidMutex              sync.RWMutex
+	solidificationTimeMutex sync.RWMutex
+}
+
+func New(transactionId transaction.Id) *TransactionMetadata {
+	return &TransactionMetadata{
+		transactionId: transactionId,
+		receivedTime:  time.Now(),
+	}
+}
+
+func FromStorage(id []byte) objectstorage.StorableObject {
+	result := &TransactionMetadata{}
+	copy(result.transactionId[:], id)
+
+	return result
+}
+
+func (transactionMetadata *TransactionMetadata) IsSolid() (result bool) {
+	transactionMetadata.solidMutex.RLock()
+	result = transactionMetadata.solid
+	transactionMetadata.solidMutex.RUnlock()
+
+	return
+}
+
+func (transactionMetadata *TransactionMetadata) SetSolid(solid bool) (modified bool) {
+	transactionMetadata.solidMutex.RLock()
+	if transactionMetadata.solid != solid {
+		transactionMetadata.solidMutex.RUnlock()
+
+		transactionMetadata.solidMutex.Lock()
+		if transactionMetadata.solid != solid {
+			transactionMetadata.solid = solid
+			if solid {
+				transactionMetadata.solidificationTimeMutex.Lock()
+				transactionMetadata.solidificationTime = time.Now()
+				transactionMetadata.solidificationTimeMutex.Unlock()
+			}
+
+			transactionMetadata.SetModified()
+
+			modified = true
+		}
+		transactionMetadata.solidMutex.Unlock()
+
+	} else {
+		transactionMetadata.solidMutex.RUnlock()
+	}
+
+	return
+}
+
+func (transactionMetadata *TransactionMetadata) GetSoldificationTime() time.Time {
+	transactionMetadata.solidificationTimeMutex.RLock()
+	defer transactionMetadata.solidificationTimeMutex.RUnlock()
+
+	return transactionMetadata.solidificationTime
+}
+
+func (transactionMetadata *TransactionMetadata) GetStorageKey() []byte {
+	return transactionMetadata.transactionId[:]
+}
+
+func (transactionMetadata *TransactionMetadata) Update(other objectstorage.StorableObject) {
+
+}
+
+func (transactionMetadata *TransactionMetadata) MarshalBinary() ([]byte, error) {
+	return nil, nil
+}
+
+func (transactionMetadata *TransactionMetadata) UnmarshalBinary([]byte) error {
+	return nil
+}
diff --git a/packages/binary/tangle/tangle.go b/packages/binary/tangle/tangle.go
new file mode 100644
index 00000000..18593704
--- /dev/null
+++ b/packages/binary/tangle/tangle.go
@@ -0,0 +1,323 @@
+package tangle
+
+import (
+	"container/list"
+	"time"
+
+	"github.com/dgraph-io/badger/v2"
+	"github.com/iotaledger/hive.go/types"
+
+	"github.com/iotaledger/goshimmer/packages/binary/storageprefix"
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/approver"
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/missingtransaction"
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction"
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transactionmetadata"
+
+	"github.com/iotaledger/hive.go/async"
+	"github.com/iotaledger/hive.go/objectstorage"
+)
+
+const (
+	MAX_MISSING_TIME_BEFORE_CLEANUP = 30 * time.Second
+	MISSING_CHECK_INTERVAL          = 5 * time.Second
+)
+
+type Tangle struct {
+	storageId []byte
+
+	transactionStorage         *objectstorage.ObjectStorage
+	transactionMetadataStorage *objectstorage.ObjectStorage
+	approverStorage            *objectstorage.ObjectStorage
+	missingTransactionsStorage *objectstorage.ObjectStorage
+
+	Events Events
+
+	storeTransactionsWorkerPool async.WorkerPool
+	solidifierWorkerPool        async.WorkerPool
+	cleanupWorkerPool           async.WorkerPool
+}
+
+// Constructor for the tangle.
+func New(badgerInstance *badger.DB, storageId []byte) (result *Tangle) {
+	result = &Tangle{
+		storageId:                  storageId,
+		transactionStorage:         objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleTransaction...), transaction.FromStorage, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
+		transactionMetadataStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleTransactionMetadata...), transactionmetadata.FromStorage, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
+		approverStorage:            objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleApprovers...), approver.FromStorage, objectstorage.CacheTime(10*time.Second), objectstorage.PartitionKey(transaction.IdLength, transaction.IdLength), objectstorage.LeakDetectionEnabled(false)),
+		missingTransactionsStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleMissingTransaction...), missingtransaction.FromStorage, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
+
+		Events: *newEvents(),
+	}
+
+	result.solidifierWorkerPool.Tune(1024)
+
+	return
+}
+
+// Returns the storage id of this tangle (can be used to create ontologies that follow the storage of the main tangle).
+func (tangle *Tangle) GetStorageId() []byte {
+	return tangle.storageId
+}
+
+// Attaches a new transaction to the tangle.
+func (tangle *Tangle) AttachTransaction(transaction *transaction.Transaction) {
+	tangle.storeTransactionsWorkerPool.Submit(func() { tangle.storeTransactionWorker(transaction) })
+}
+
+// Retrieves a transaction from the tangle.
+func (tangle *Tangle) GetTransaction(transactionId transaction.Id) *transaction.CachedTransaction {
+	return &transaction.CachedTransaction{CachedObject: tangle.transactionStorage.Load(transactionId[:])}
+}
+
+// Retrieves the metadata of a transaction from the tangle.
+func (tangle *Tangle) GetTransactionMetadata(transactionId transaction.Id) *transactionmetadata.CachedTransactionMetadata {
+	return &transactionmetadata.CachedTransactionMetadata{CachedObject: tangle.transactionMetadataStorage.Load(transactionId[:])}
+}
+
+// Retrieves the approvers of a transaction from the tangle.
+func (tangle *Tangle) GetApprovers(transactionId transaction.Id) approver.CachedApprovers {
+	approvers := make(approver.CachedApprovers, 0)
+	tangle.approverStorage.ForEach(func(key []byte, cachedObject objectstorage.CachedObject) bool {
+		approvers = append(approvers, &approver.CachedApprover{CachedObject: cachedObject})
+
+		return true
+	}, transactionId[:])
+
+	return approvers
+}
+
+// Deletes a transaction from the tangle (i.e. for local snapshots)
+func (tangle *Tangle) DeleteTransaction(transactionId transaction.Id) {
+	tangle.GetTransaction(transactionId).Consume(func(currentTransaction *transaction.Transaction) {
+		trunkTransactionId := currentTransaction.GetTrunkTransactionId()
+		tangle.deleteApprover(trunkTransactionId, transactionId)
+
+		branchTransactionId := currentTransaction.GetBranchTransactionId()
+		if branchTransactionId != trunkTransactionId {
+			tangle.deleteApprover(branchTransactionId, transactionId)
+		}
+
+		tangle.transactionMetadataStorage.Delete(transactionId[:])
+		tangle.transactionStorage.Delete(transactionId[:])
+
+		tangle.Events.TransactionRemoved.Trigger(transactionId)
+	})
+}
+
+// Marks the tangle as stopped, so it will not accept any new transactions (waits for all backgroundTasks to finish.
+func (tangle *Tangle) Shutdown() *Tangle {
+	tangle.storeTransactionsWorkerPool.ShutdownGracefully()
+	tangle.solidifierWorkerPool.ShutdownGracefully()
+	tangle.cleanupWorkerPool.ShutdownGracefully()
+
+	tangle.transactionStorage.Shutdown()
+	tangle.transactionMetadataStorage.Shutdown()
+	tangle.approverStorage.Shutdown()
+	tangle.missingTransactionsStorage.Shutdown()
+
+	return tangle
+}
+
+// Resets the database and deletes all objects (good for testing or "node resets").
+func (tangle *Tangle) Prune() error {
+	for _, storage := range []*objectstorage.ObjectStorage{
+		tangle.transactionStorage,
+		tangle.transactionMetadataStorage,
+		tangle.approverStorage,
+		tangle.missingTransactionsStorage,
+	} {
+		if err := storage.Prune(); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// Worker that stores the transactions and calls the corresponding "Storage events"
+func (tangle *Tangle) storeTransactionWorker(tx *transaction.Transaction) {
+	// store transaction
+	var cachedTransaction *transaction.CachedTransaction
+	if _tmp, transactionIsNew := tangle.transactionStorage.StoreIfAbsent(tx); !transactionIsNew {
+		return
+	} else {
+		cachedTransaction = &transaction.CachedTransaction{CachedObject: _tmp}
+	}
+
+	// store transaction metadata
+	transactionId := tx.GetId()
+	cachedTransactionMetadata := &transactionmetadata.CachedTransactionMetadata{CachedObject: tangle.transactionMetadataStorage.Store(transactionmetadata.New(transactionId))}
+
+	// store trunk approver
+	trunkTransactionID := tx.GetTrunkTransactionId()
+	tangle.approverStorage.Store(approver.New(trunkTransactionID, transactionId)).Release()
+
+	// store branch approver
+	if branchTransactionID := tx.GetBranchTransactionId(); branchTransactionID != trunkTransactionID {
+		tangle.approverStorage.Store(approver.New(branchTransactionID, transactionId)).Release()
+	}
+
+	// trigger events
+	if tangle.missingTransactionsStorage.DeleteIfPresent(transactionId[:]) {
+		tangle.Events.MissingTransactionReceived.Trigger(cachedTransaction, cachedTransactionMetadata)
+	}
+	tangle.Events.TransactionAttached.Trigger(cachedTransaction, cachedTransactionMetadata)
+
+	// check solidity
+	tangle.solidifierWorkerPool.Submit(func() {
+		tangle.solidifyTransactionWorker(cachedTransaction, cachedTransactionMetadata)
+	})
+}
+
+// Worker that solidifies the transactions (recursively from past to present).
+func (tangle *Tangle) solidifyTransactionWorker(cachedTransaction *transaction.CachedTransaction, cachedTransactionMetadata *transactionmetadata.CachedTransactionMetadata) {
+	isTransactionMarkedAsSolid := func(transactionId transaction.Id) bool {
+		if transactionId == transaction.EmptyId {
+			return true
+		}
+
+		transactionMetadataCached := tangle.GetTransactionMetadata(transactionId)
+		if transactionMetadata := transactionMetadataCached.Unwrap(); transactionMetadata == nil {
+			transactionMetadataCached.Release()
+
+			// if transaction is missing and was not reported as missing, yet
+			if cachedMissingTransaction, missingTransactionStored := tangle.missingTransactionsStorage.StoreIfAbsent(missingtransaction.New(transactionId)); missingTransactionStored {
+				cachedMissingTransaction.Consume(func(object objectstorage.StorableObject) {
+					tangle.monitorMissingTransactionWorker(object.(*missingtransaction.MissingTransaction).GetTransactionId())
+				})
+			}
+
+			return false
+		} else if !transactionMetadata.IsSolid() {
+			transactionMetadataCached.Release()
+
+			return false
+		}
+		transactionMetadataCached.Release()
+
+		return true
+	}
+
+	isTransactionSolid := func(transaction *transaction.Transaction, transactionMetadata *transactionmetadata.TransactionMetadata) bool {
+		if transaction == nil || transaction.IsDeleted() {
+			return false
+		}
+
+		if transactionMetadata == nil || transactionMetadata.IsDeleted() {
+			return false
+		}
+
+		if transactionMetadata.IsSolid() {
+			return true
+		}
+
+		return isTransactionMarkedAsSolid(transaction.GetTrunkTransactionId()) && isTransactionMarkedAsSolid(transaction.GetBranchTransactionId())
+	}
+
+	popElementsFromStack := func(stack *list.List) (*transaction.CachedTransaction, *transactionmetadata.CachedTransactionMetadata) {
+		currentSolidificationEntry := stack.Front()
+		currentCachedTransaction := currentSolidificationEntry.Value.([2]interface{})[0]
+		currentCachedTransactionMetadata := currentSolidificationEntry.Value.([2]interface{})[1]
+		stack.Remove(currentSolidificationEntry)
+
+		return currentCachedTransaction.(*transaction.CachedTransaction), currentCachedTransactionMetadata.(*transactionmetadata.CachedTransactionMetadata)
+	}
+
+	// initialize the stack
+	solidificationStack := list.New()
+	solidificationStack.PushBack([2]interface{}{cachedTransaction, cachedTransactionMetadata})
+
+	// process transactions that are supposed to be checked for solidity recursively
+	for solidificationStack.Len() > 0 {
+		currentCachedTransaction, currentCachedTransactionMetadata := popElementsFromStack(solidificationStack)
+
+		currentTransaction := currentCachedTransaction.Unwrap()
+		currentTransactionMetadata := currentCachedTransactionMetadata.Unwrap()
+		if currentTransaction == nil || currentTransactionMetadata == nil {
+			currentCachedTransaction.Release()
+			currentCachedTransactionMetadata.Release()
+
+			continue
+		}
+
+		// if current transaction is solid and was not marked as solid before: mark as solid and propagate
+		if isTransactionSolid(currentTransaction, currentTransactionMetadata) && currentTransactionMetadata.SetSolid(true) {
+			tangle.Events.TransactionSolid.Trigger(currentCachedTransaction, currentCachedTransactionMetadata)
+
+			tangle.GetApprovers(currentTransaction.GetId()).Consume(func(approver *approver.Approver) {
+				approverTransactionId := approver.GetApprovingTransactionId()
+
+				solidificationStack.PushBack([2]interface{}{
+					tangle.GetTransaction(approverTransactionId),
+					tangle.GetTransactionMetadata(approverTransactionId),
+				})
+			})
+		}
+
+		// release cached results
+		currentCachedTransaction.Release()
+		currentCachedTransactionMetadata.Release()
+	}
+}
+
+// Worker that Monitors the missing transactions (by scheduling regular checks).
+func (tangle *Tangle) monitorMissingTransactionWorker(transactionId transaction.Id) {
+	var scheduleNextMissingCheck func(transactionId transaction.Id)
+	scheduleNextMissingCheck = func(transactionId transaction.Id) {
+		time.AfterFunc(MISSING_CHECK_INTERVAL, func() {
+			tangle.missingTransactionsStorage.Load(transactionId[:]).Consume(func(object objectstorage.StorableObject) {
+				missingTransaction := object.(*missingtransaction.MissingTransaction)
+
+				if time.Since(missingTransaction.GetMissingSince()) >= MAX_MISSING_TIME_BEFORE_CLEANUP {
+					tangle.cleanupWorkerPool.Submit(func() {
+						tangle.Events.TransactionUnsolidifiable.Trigger(transactionId)
+
+						tangle.deleteSubtangle(missingTransaction.GetTransactionId())
+					})
+				} else {
+					// TRIGGER STILL MISSING EVENT?
+
+					scheduleNextMissingCheck(transactionId)
+				}
+			})
+		})
+	}
+
+	tangle.Events.TransactionMissing.Trigger(transactionId)
+
+	scheduleNextMissingCheck(transactionId)
+}
+
+func (tangle *Tangle) deleteApprover(approvedTransaction transaction.Id, approvingTransaction transaction.Id) {
+	idToDelete := make([]byte, transaction.IdLength+transaction.IdLength)
+	copy(idToDelete[:transaction.IdLength], approvedTransaction[:])
+	copy(idToDelete[transaction.IdLength:], approvingTransaction[:])
+	tangle.approverStorage.Delete(idToDelete)
+}
+
+// Deletes a transaction and all of its approvers (recursively).
+func (tangle *Tangle) deleteSubtangle(transactionId transaction.Id) {
+	cleanupStack := list.New()
+	cleanupStack.PushBack(transactionId)
+
+	processedTransactions := make(map[transaction.Id]types.Empty)
+	processedTransactions[transactionId] = types.Void
+
+	for cleanupStack.Len() >= 1 {
+		currentStackEntry := cleanupStack.Front()
+		currentTransactionId := currentStackEntry.Value.(transaction.Id)
+		cleanupStack.Remove(currentStackEntry)
+
+		tangle.DeleteTransaction(currentTransactionId)
+
+		tangle.GetApprovers(currentTransactionId).Consume(func(approver *approver.Approver) {
+			approverId := approver.GetApprovingTransactionId()
+
+			if _, transactionProcessed := processedTransactions[approverId]; !transactionProcessed {
+				cleanupStack.PushBack(approverId)
+
+				processedTransactions[approverId] = types.Void
+			}
+		})
+	}
+}
diff --git a/packages/binary/tangle/tangle_test.go b/packages/binary/tangle/tangle_test.go
new file mode 100644
index 00000000..c8ff887c
--- /dev/null
+++ b/packages/binary/tangle/tangle_test.go
@@ -0,0 +1,95 @@
+package tangle
+
+import (
+	"fmt"
+	"testing"
+	"time"
+
+	"github.com/dgraph-io/badger/v2"
+	"github.com/iotaledger/hive.go/events"
+
+	"github.com/iotaledger/hive.go/database"
+
+	"github.com/iotaledger/goshimmer/packages/binary/identity"
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction"
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload/data"
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transactionmetadata"
+	"github.com/iotaledger/goshimmer/plugins/config"
+)
+
+var testDatabase *badger.DB
+
+var _ = config.PLUGIN
+
+func init() {
+	testDatabase = database.GetBadgerInstance()
+}
+
+func BenchmarkTangle_AttachTransaction(b *testing.B) {
+	tangle := New(testDatabase, []byte("TEST_BINARY_TANGLE"))
+	if err := tangle.Prune(); err != nil {
+		b.Error(err)
+
+		return
+	}
+
+	testIdentity := identity.Generate()
+
+	transactionBytes := make([]*transaction.Transaction, b.N)
+	for i := 0; i < b.N; i++ {
+		transactionBytes[i] = transaction.New(transaction.EmptyId, transaction.EmptyId, testIdentity, data.New([]byte("some data")))
+		transactionBytes[i].GetBytes()
+	}
+
+	b.ResetTimer()
+
+	for i := 0; i < b.N; i++ {
+		tangle.AttachTransaction(transactionBytes[i])
+	}
+
+	tangle.Shutdown()
+}
+
+func TestTangle_AttachTransaction(t *testing.T) {
+	tangle := New(testDatabase, []byte("TEST_BINARY_TANGLE"))
+	if err := tangle.Prune(); err != nil {
+		t.Error(err)
+
+		return
+	}
+
+	tangle.Events.TransactionAttached.Attach(events.NewClosure(func(cachedTransaction *transaction.CachedTransaction, cachedTransactionMetadata *transactionmetadata.CachedTransactionMetadata) {
+		cachedTransaction.Consume(func(transaction *transaction.Transaction) {
+			fmt.Println("ATTACHED:", transaction.GetId())
+		})
+	}))
+
+	tangle.Events.TransactionSolid.Attach(events.NewClosure(func(cachedTransaction *transaction.CachedTransaction, cachedTransactionMetadata *transactionmetadata.CachedTransactionMetadata) {
+		cachedTransaction.Consume(func(transaction *transaction.Transaction) {
+			fmt.Println("SOLID:", transaction.GetId())
+		})
+	}))
+
+	tangle.Events.TransactionUnsolidifiable.Attach(events.NewClosure(func(transactionId transaction.Id) {
+		fmt.Println("UNSOLIDIFIABLE:", transactionId)
+	}))
+
+	tangle.Events.TransactionMissing.Attach(events.NewClosure(func(transactionId transaction.Id) {
+		fmt.Println("MISSING:", transactionId)
+	}))
+
+	tangle.Events.TransactionRemoved.Attach(events.NewClosure(func(transactionId transaction.Id) {
+		fmt.Println("REMOVED:", transactionId)
+	}))
+
+	newTransaction1 := transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("some data")))
+	newTransaction2 := transaction.New(newTransaction1.GetId(), newTransaction1.GetId(), identity.Generate(), data.New([]byte("some other data")))
+
+	tangle.AttachTransaction(newTransaction2)
+
+	time.Sleep(7 * time.Second)
+
+	tangle.AttachTransaction(newTransaction1)
+
+	tangle.Shutdown()
+}
diff --git a/packages/binary/tangle/transactionparser/builtinfilters/recently_seen_bytes_filter.go b/packages/binary/tangle/transactionparser/builtinfilters/recently_seen_bytes_filter.go
new file mode 100644
index 00000000..c0a6002f
--- /dev/null
+++ b/packages/binary/tangle/transactionparser/builtinfilters/recently_seen_bytes_filter.go
@@ -0,0 +1,68 @@
+package builtinfilters
+
+import (
+	"sync"
+
+	"github.com/iotaledger/hive.go/async"
+	"github.com/iotaledger/hive.go/bytesfilter"
+)
+
+type RecentlySeenBytesFilter struct {
+	bytesFilter      *bytesfilter.BytesFilter
+	onAcceptCallback func(bytes []byte)
+	onRejectCallback func(bytes []byte)
+	workerPool       async.WorkerPool
+
+	onAcceptCallbackMutex sync.RWMutex
+	onRejectCallbackMutex sync.RWMutex
+}
+
+func NewRecentlySeenBytesFilter() (result *RecentlySeenBytesFilter) {
+	result = &RecentlySeenBytesFilter{
+		bytesFilter: bytesfilter.New(100000),
+	}
+
+	return
+}
+
+func (filter *RecentlySeenBytesFilter) Filter(bytes []byte) {
+	filter.workerPool.Submit(func() {
+		if filter.bytesFilter.Add(bytes) {
+			filter.getAcceptCallback()(bytes)
+		} else {
+			filter.getRejectCallback()(bytes)
+		}
+	})
+}
+
+func (filter *RecentlySeenBytesFilter) OnAccept(callback func(bytes []byte)) {
+	filter.onAcceptCallbackMutex.Lock()
+	filter.onAcceptCallback = callback
+	filter.onAcceptCallbackMutex.Unlock()
+}
+
+func (filter *RecentlySeenBytesFilter) OnReject(callback func(bytes []byte)) {
+	filter.onRejectCallbackMutex.Lock()
+	filter.onRejectCallback = callback
+	filter.onRejectCallbackMutex.Unlock()
+}
+
+func (filter *RecentlySeenBytesFilter) getAcceptCallback() (result func(bytes []byte)) {
+	filter.onAcceptCallbackMutex.Lock()
+	result = filter.onAcceptCallback
+	filter.onAcceptCallbackMutex.Unlock()
+
+	return
+}
+
+func (filter *RecentlySeenBytesFilter) getRejectCallback() (result func(bytes []byte)) {
+	filter.onRejectCallbackMutex.Lock()
+	result = filter.onRejectCallback
+	filter.onRejectCallbackMutex.Unlock()
+
+	return
+}
+
+func (filter *RecentlySeenBytesFilter) Shutdown() {
+	filter.workerPool.ShutdownGracefully()
+}
diff --git a/packages/binary/tangle/transactionparser/builtinfilters/transaction_signature_filter.go b/packages/binary/tangle/transactionparser/builtinfilters/transaction_signature_filter.go
new file mode 100644
index 00000000..9160d821
--- /dev/null
+++ b/packages/binary/tangle/transactionparser/builtinfilters/transaction_signature_filter.go
@@ -0,0 +1,66 @@
+package builtinfilters
+
+import (
+	"sync"
+
+	"github.com/iotaledger/hive.go/async"
+
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction"
+)
+
+type TransactionSignatureFilter struct {
+	onAcceptCallback func(tx *transaction.Transaction)
+	onRejectCallback func(tx *transaction.Transaction)
+	workerPool       async.WorkerPool
+
+	onAcceptCallbackMutex sync.RWMutex
+	onRejectCallbackMutex sync.RWMutex
+}
+
+func NewTransactionSignatureFilter() (result *TransactionSignatureFilter) {
+	result = &TransactionSignatureFilter{}
+
+	return
+}
+
+func (filter *TransactionSignatureFilter) Filter(tx *transaction.Transaction) {
+	filter.workerPool.Submit(func() {
+		if tx.VerifySignature() {
+			filter.getAcceptCallback()(tx)
+		} else {
+			filter.getRejectCallback()(tx)
+		}
+	})
+}
+
+func (filter *TransactionSignatureFilter) OnAccept(callback func(tx *transaction.Transaction)) {
+	filter.onAcceptCallbackMutex.Lock()
+	filter.onAcceptCallback = callback
+	filter.onAcceptCallbackMutex.Unlock()
+}
+
+func (filter *TransactionSignatureFilter) OnReject(callback func(tx *transaction.Transaction)) {
+	filter.onRejectCallbackMutex.Lock()
+	filter.onRejectCallback = callback
+	filter.onRejectCallbackMutex.Unlock()
+}
+
+func (filter *TransactionSignatureFilter) Shutdown() {
+	filter.workerPool.ShutdownGracefully()
+}
+
+func (filter *TransactionSignatureFilter) getAcceptCallback() (result func(tx *transaction.Transaction)) {
+	filter.onAcceptCallbackMutex.RLock()
+	result = filter.onAcceptCallback
+	filter.onAcceptCallbackMutex.RUnlock()
+
+	return
+}
+
+func (filter *TransactionSignatureFilter) getRejectCallback() (result func(tx *transaction.Transaction)) {
+	filter.onRejectCallbackMutex.RLock()
+	result = filter.onRejectCallback
+	filter.onRejectCallbackMutex.RUnlock()
+
+	return
+}
diff --git a/packages/binary/tangle/transactionparser/bytes_filter.go b/packages/binary/tangle/transactionparser/bytes_filter.go
new file mode 100644
index 00000000..c8e2bab6
--- /dev/null
+++ b/packages/binary/tangle/transactionparser/bytes_filter.go
@@ -0,0 +1,8 @@
+package transactionparser
+
+type BytesFilter interface {
+	Filter(bytes []byte)
+	OnAccept(callback func(bytes []byte))
+	OnReject(callback func(bytes []byte))
+	Shutdown()
+}
diff --git a/packages/binary/tangle/transactionparser/events.go b/packages/binary/tangle/transactionparser/events.go
new file mode 100644
index 00000000..9bde1a04
--- /dev/null
+++ b/packages/binary/tangle/transactionparser/events.go
@@ -0,0 +1,9 @@
+package transactionparser
+
+import "github.com/iotaledger/hive.go/events"
+
+type transactionParserEvents struct {
+	BytesRejected       *events.Event
+	TransactionParsed   *events.Event
+	TransactionRejected *events.Event
+}
diff --git a/packages/binary/tangle/transactionparser/transaction_filter.go b/packages/binary/tangle/transactionparser/transaction_filter.go
new file mode 100644
index 00000000..39dfc277
--- /dev/null
+++ b/packages/binary/tangle/transactionparser/transaction_filter.go
@@ -0,0 +1,12 @@
+package transactionparser
+
+import (
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction"
+)
+
+type TransactionFilter interface {
+	Filter(tx *transaction.Transaction)
+	OnAccept(callback func(tx *transaction.Transaction))
+	OnReject(callback func(tx *transaction.Transaction))
+	Shutdown()
+}
diff --git a/packages/binary/tangle/transactionparser/transactionparser.go b/packages/binary/tangle/transactionparser/transactionparser.go
new file mode 100644
index 00000000..1d5f5366
--- /dev/null
+++ b/packages/binary/tangle/transactionparser/transactionparser.go
@@ -0,0 +1,137 @@
+package transactionparser
+
+import (
+	"sync"
+
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction"
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/transactionparser/builtinfilters"
+
+	"github.com/iotaledger/hive.go/events"
+	"github.com/iotaledger/hive.go/typeutils"
+)
+
+type TransactionParser struct {
+	bytesFilters       []BytesFilter
+	transactionFilters []TransactionFilter
+	Events             transactionParserEvents
+
+	byteFiltersModified        typeutils.AtomicBool
+	transactionFiltersModified typeutils.AtomicBool
+	bytesFiltersMutex          sync.Mutex
+	transactionFiltersMutex    sync.Mutex
+}
+
+func New() (result *TransactionParser) {
+	result = &TransactionParser{
+		bytesFilters:       make([]BytesFilter, 0),
+		transactionFilters: make([]TransactionFilter, 0),
+
+		Events: transactionParserEvents{
+			BytesRejected: events.NewEvent(func(handler interface{}, params ...interface{}) {
+				handler.(func([]byte))(params[0].([]byte))
+			}),
+			TransactionParsed: events.NewEvent(func(handler interface{}, params ...interface{}) {
+				handler.(func(*transaction.Transaction))(params[0].(*transaction.Transaction))
+			}),
+			TransactionRejected: events.NewEvent(func(handler interface{}, params ...interface{}) {
+				handler.(func(*transaction.Transaction))(params[0].(*transaction.Transaction))
+			}),
+		},
+	}
+
+	// add builtin filters
+	result.AddBytesFilter(builtinfilters.NewRecentlySeenBytesFilter())
+	result.AddTransactionsFilter(builtinfilters.NewTransactionSignatureFilter())
+
+	return
+}
+
+func (transactionParser *TransactionParser) Parse(transactionBytes []byte) {
+	transactionParser.setupBytesFilterDataFlow()
+	transactionParser.setupTransactionsFilterDataFlow()
+
+	transactionParser.bytesFilters[0].Filter(transactionBytes)
+}
+
+func (transactionParser *TransactionParser) AddBytesFilter(filter BytesFilter) {
+	transactionParser.bytesFiltersMutex.Lock()
+	transactionParser.bytesFilters = append(transactionParser.bytesFilters, filter)
+	transactionParser.bytesFiltersMutex.Unlock()
+
+	transactionParser.byteFiltersModified.Set()
+}
+
+func (transactionParser *TransactionParser) AddTransactionsFilter(filter TransactionFilter) {
+	transactionParser.transactionFiltersMutex.Lock()
+	transactionParser.transactionFilters = append(transactionParser.transactionFilters, filter)
+	transactionParser.transactionFiltersMutex.Unlock()
+
+	transactionParser.transactionFiltersModified.Set()
+}
+
+func (transactionParser *TransactionParser) Shutdown() {
+	transactionParser.bytesFiltersMutex.Lock()
+	for _, bytesFilter := range transactionParser.bytesFilters {
+		bytesFilter.Shutdown()
+	}
+	transactionParser.bytesFiltersMutex.Unlock()
+
+	transactionParser.transactionFiltersMutex.Lock()
+	for _, transactionFilter := range transactionParser.transactionFilters {
+		transactionFilter.Shutdown()
+	}
+	transactionParser.transactionFiltersMutex.Unlock()
+}
+
+func (transactionParser *TransactionParser) setupBytesFilterDataFlow() {
+	if !transactionParser.byteFiltersModified.IsSet() {
+		return
+	}
+
+	transactionParser.bytesFiltersMutex.Lock()
+	if transactionParser.byteFiltersModified.IsSet() {
+		transactionParser.byteFiltersModified.SetTo(false)
+
+		numberOfBytesFilters := len(transactionParser.bytesFilters)
+		for i := 0; i < numberOfBytesFilters; i++ {
+			if i == numberOfBytesFilters-1 {
+				transactionParser.bytesFilters[i].OnAccept(transactionParser.parseTransaction)
+			} else {
+				transactionParser.bytesFilters[i].OnAccept(transactionParser.bytesFilters[i+1].Filter)
+			}
+			transactionParser.bytesFilters[i].OnReject(func(bytes []byte) { transactionParser.Events.BytesRejected.Trigger(bytes) })
+		}
+	}
+	transactionParser.bytesFiltersMutex.Unlock()
+}
+
+func (transactionParser *TransactionParser) setupTransactionsFilterDataFlow() {
+	if !transactionParser.transactionFiltersModified.IsSet() {
+		return
+	}
+
+	transactionParser.transactionFiltersMutex.Lock()
+	if transactionParser.transactionFiltersModified.IsSet() {
+		transactionParser.transactionFiltersModified.SetTo(false)
+
+		numberOfTransactionFilters := len(transactionParser.transactionFilters)
+		for i := 0; i < numberOfTransactionFilters; i++ {
+			if i == numberOfTransactionFilters-1 {
+				transactionParser.transactionFilters[i].OnAccept(func(tx *transaction.Transaction) { transactionParser.Events.TransactionParsed.Trigger(tx) })
+			} else {
+				transactionParser.transactionFilters[i].OnAccept(transactionParser.transactionFilters[i+1].Filter)
+			}
+			transactionParser.transactionFilters[i].OnReject(func(tx *transaction.Transaction) { transactionParser.Events.TransactionRejected.Trigger(tx) })
+		}
+	}
+	transactionParser.transactionFiltersMutex.Unlock()
+}
+
+func (transactionParser *TransactionParser) parseTransaction(bytes []byte) {
+	if parsedTransaction, err := transaction.FromBytes(bytes); err != nil {
+		// trigger parsingError
+		panic(err)
+	} else {
+		transactionParser.transactionFilters[0].Filter(parsedTransaction)
+	}
+}
diff --git a/packages/binary/tangle/transactionparser/transactionparser_test.go b/packages/binary/tangle/transactionparser/transactionparser_test.go
new file mode 100644
index 00000000..c7dc3b18
--- /dev/null
+++ b/packages/binary/tangle/transactionparser/transactionparser_test.go
@@ -0,0 +1,56 @@
+package transactionparser
+
+import (
+	"fmt"
+	"strconv"
+	"testing"
+
+	"github.com/iotaledger/hive.go/events"
+
+	"github.com/iotaledger/goshimmer/packages/binary/identity"
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction"
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction/payload/data"
+)
+
+func BenchmarkTransactionParser_ParseBytesSame(b *testing.B) {
+	txBytes := transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("Test"))).GetBytes()
+	txParser := New()
+
+	b.ResetTimer()
+
+	for i := 0; i < b.N; i++ {
+		txParser.Parse(txBytes)
+	}
+
+	txParser.Shutdown()
+}
+
+func BenchmarkTransactionParser_ParseBytesDifferent(b *testing.B) {
+	transactionBytes := make([][]byte, b.N)
+	for i := 0; i < b.N; i++ {
+		transactionBytes[i] = transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("Test"+strconv.Itoa(i)))).GetBytes()
+	}
+
+	txParser := New()
+
+	b.ResetTimer()
+
+	for i := 0; i < b.N; i++ {
+		txParser.Parse(transactionBytes[i])
+	}
+
+	txParser.Shutdown()
+}
+
+func TestTransactionParser_ParseTransaction(t *testing.T) {
+	tx := transaction.New(transaction.EmptyId, transaction.EmptyId, identity.Generate(), data.New([]byte("Test")))
+
+	txParser := New()
+	txParser.Parse(tx.GetBytes())
+
+	txParser.Events.TransactionParsed.Attach(events.NewClosure(func(tx *transaction.Transaction) {
+		fmt.Println("PARSED!!!")
+	}))
+
+	txParser.Shutdown()
+}
diff --git a/packages/binary/tangle/transactionrequester/constants.go b/packages/binary/tangle/transactionrequester/constants.go
new file mode 100644
index 00000000..b9f59769
--- /dev/null
+++ b/packages/binary/tangle/transactionrequester/constants.go
@@ -0,0 +1,10 @@
+package transactionrequester
+
+import (
+	"time"
+)
+
+const (
+	DEFAULT_REQUEST_WORKER_COUNT = 1024
+	DEFAULT_RETRY_INTERVAL       = 10 * time.Second
+)
diff --git a/packages/binary/tangle/transactionrequester/events.go b/packages/binary/tangle/transactionrequester/events.go
new file mode 100644
index 00000000..e845d790
--- /dev/null
+++ b/packages/binary/tangle/transactionrequester/events.go
@@ -0,0 +1,9 @@
+package transactionrequester
+
+import (
+	"github.com/iotaledger/hive.go/events"
+)
+
+type Events struct {
+	SendRequest *events.Event
+}
diff --git a/packages/binary/tangle/transactionrequester/options.go b/packages/binary/tangle/transactionrequester/options.go
new file mode 100644
index 00000000..05db5db4
--- /dev/null
+++ b/packages/binary/tangle/transactionrequester/options.go
@@ -0,0 +1,37 @@
+package transactionrequester
+
+import (
+	"time"
+)
+
+type Options struct {
+	retryInterval time.Duration
+	workerCount   int
+}
+
+func newOptions(optionalOptions []Option) *Options {
+	result := &Options{
+		retryInterval: 10 * time.Second,
+		workerCount:   DEFAULT_REQUEST_WORKER_COUNT,
+	}
+
+	for _, optionalOption := range optionalOptions {
+		optionalOption(result)
+	}
+
+	return result
+}
+
+type Option func(*Options)
+
+func RetryInterval(interval time.Duration) Option {
+	return func(args *Options) {
+		args.retryInterval = interval
+	}
+}
+
+func WorkerCount(workerCount int) Option {
+	return func(args *Options) {
+		args.workerCount = workerCount
+	}
+}
diff --git a/packages/binary/tangle/transactionrequester/transactionrequester.go b/packages/binary/tangle/transactionrequester/transactionrequester.go
new file mode 100644
index 00000000..6f036e81
--- /dev/null
+++ b/packages/binary/tangle/transactionrequester/transactionrequester.go
@@ -0,0 +1,74 @@
+package transactionrequester
+
+import (
+	"sync"
+	"time"
+
+	"github.com/iotaledger/hive.go/async"
+	"github.com/iotaledger/hive.go/events"
+
+	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction"
+)
+
+type TransactionRequester struct {
+	scheduledRequests map[transaction.Id]*time.Timer
+	requestWorker     async.NonBlockingWorkerPool
+	options           *Options
+	Events            Events
+
+	scheduledRequestsMutex sync.RWMutex
+}
+
+func New(optionalOptions ...Option) *TransactionRequester {
+	requester := &TransactionRequester{
+		scheduledRequests: make(map[transaction.Id]*time.Timer),
+		options:           newOptions(optionalOptions),
+		Events: Events{
+			SendRequest: events.NewEvent(func(handler interface{}, params ...interface{}) {
+				handler.(func(transaction.Id))(params[0].(transaction.Id))
+			}),
+		},
+	}
+
+	requester.requestWorker.Tune(requester.options.workerCount)
+
+	return requester
+}
+
+func (requester *TransactionRequester) ScheduleRequest(transactionId transaction.Id) {
+	var retryRequest func(bool)
+	retryRequest = func(initialRequest bool) {
+		requester.requestWorker.Submit(func() {
+			requester.scheduledRequestsMutex.RLock()
+			if _, requestExists := requester.scheduledRequests[transactionId]; !initialRequest && !requestExists {
+				requester.scheduledRequestsMutex.RUnlock()
+
+				return
+			}
+			requester.scheduledRequestsMutex.RUnlock()
+
+			requester.Events.SendRequest.Trigger(transactionId)
+
+			requester.scheduledRequestsMutex.Lock()
+			requester.scheduledRequests[transactionId] = time.AfterFunc(requester.options.retryInterval, func() { retryRequest(false) })
+			requester.scheduledRequestsMutex.Unlock()
+		})
+	}
+
+	retryRequest(true)
+}
+
+func (requester *TransactionRequester) StopRequest(transactionId transaction.Id) {
+	requester.scheduledRequestsMutex.RLock()
+	if timer, timerExists := requester.scheduledRequests[transactionId]; timerExists {
+		requester.scheduledRequestsMutex.RUnlock()
+
+		timer.Stop()
+
+		requester.scheduledRequestsMutex.Lock()
+		delete(requester.scheduledRequests, transactionId)
+		requester.scheduledRequestsMutex.Unlock()
+	} else {
+		requester.scheduledRequestsMutex.RUnlock()
+	}
+}
diff --git a/packages/gossip/common.go b/packages/gossip/common.go
index 6f48f378..237e11ab 100644
--- a/packages/gossip/common.go
+++ b/packages/gossip/common.go
@@ -1,8 +1,8 @@
 package gossip
 
 import (
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
+	"github.com/iotaledger/hive.go/autopeering/peer"
+	"github.com/iotaledger/hive.go/autopeering/peer/service"
 )
 
 // IsSupported returns whether the peer supports the gossip service.
diff --git a/packages/gossip/events.go b/packages/gossip/events.go
index 5f96044a..96bec6af 100644
--- a/packages/gossip/events.go
+++ b/packages/gossip/events.go
@@ -1,7 +1,7 @@
 package gossip
 
 import (
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
+	"github.com/iotaledger/hive.go/autopeering/peer"
 	"github.com/iotaledger/hive.go/events"
 )
 
diff --git a/packages/gossip/manager.go b/packages/gossip/manager.go
index bc08ab56..49a9d0d9 100644
--- a/packages/gossip/manager.go
+++ b/packages/gossip/manager.go
@@ -7,9 +7,9 @@ import (
 	"sync"
 
 	"github.com/golang/protobuf/proto"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
 	pb "github.com/iotaledger/goshimmer/packages/gossip/proto"
 	"github.com/iotaledger/goshimmer/packages/gossip/server"
+	"github.com/iotaledger/hive.go/autopeering/peer"
 	"github.com/iotaledger/hive.go/events"
 	"go.uber.org/zap"
 )
diff --git a/packages/gossip/manager_test.go b/packages/gossip/manager_test.go
index 07dda401..83dba46e 100644
--- a/packages/gossip/manager_test.go
+++ b/packages/gossip/manager_test.go
@@ -7,11 +7,11 @@ import (
 	"time"
 
 	"github.com/golang/protobuf/proto"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
 	"github.com/iotaledger/goshimmer/packages/database/mapdb"
 	pb "github.com/iotaledger/goshimmer/packages/gossip/proto"
 	"github.com/iotaledger/goshimmer/packages/gossip/server"
+	"github.com/iotaledger/hive.go/autopeering/peer"
+	"github.com/iotaledger/hive.go/autopeering/peer/service"
 	"github.com/iotaledger/hive.go/events"
 	"github.com/iotaledger/hive.go/logger"
 	"github.com/stretchr/testify/assert"
diff --git a/packages/gossip/neighbor.go b/packages/gossip/neighbor.go
index 07509a52..a529aab2 100644
--- a/packages/gossip/neighbor.go
+++ b/packages/gossip/neighbor.go
@@ -7,10 +7,11 @@ import (
 	"strings"
 	"sync"
 
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
 	"github.com/iotaledger/goshimmer/packages/netutil"
 	"github.com/iotaledger/goshimmer/packages/netutil/buffconn"
+	"github.com/iotaledger/hive.go/autopeering/peer"
 	"github.com/iotaledger/hive.go/logger"
+	"go.uber.org/atomic"
 )
 
 var (
@@ -19,16 +20,18 @@ var (
 )
 
 const (
-	neighborQueueSize = 5000
-	maxNumReadErrors  = 10
+	neighborQueueSize        = 5000
+	maxNumReadErrors         = 10
+	droppedMessagesThreshold = 1000
 )
 
 type Neighbor struct {
 	*peer.Peer
 	*buffconn.BufferedConnection
 
-	log   *logger.Logger
-	queue chan []byte
+	log             *logger.Logger
+	queue           chan []byte
+	messagesDropped atomic.Int32
 
 	wg             sync.WaitGroup
 	closing        chan struct{}
@@ -150,6 +153,10 @@ func (n *Neighbor) Write(b []byte) (int, error) {
 	case <-n.closing:
 		return 0, nil
 	default:
-		return 0, ErrNeighborQueueFull
+		if n.messagesDropped.Inc() >= droppedMessagesThreshold {
+			n.messagesDropped.Store(0)
+			return 0, ErrNeighborQueueFull
+		}
+		return 0, nil
 	}
 }
diff --git a/packages/gossip/neighbor_test.go b/packages/gossip/neighbor_test.go
index fd1e0fc7..36c61534 100644
--- a/packages/gossip/neighbor_test.go
+++ b/packages/gossip/neighbor_test.go
@@ -7,8 +7,8 @@ import (
 	"testing"
 	"time"
 
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
+	"github.com/iotaledger/hive.go/autopeering/peer"
+	"github.com/iotaledger/hive.go/autopeering/peer/service"
 	"github.com/iotaledger/hive.go/events"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
@@ -87,8 +87,8 @@ func TestNeighborParallelWrite(t *testing.T) {
 	go func() {
 		defer wg.Done()
 		for i := 0; i < neighborQueueSize; i++ {
-			_, err := neighborA.Write(testData)
-			if err == ErrNeighborQueueFull {
+			l, err := neighborA.Write(testData)
+			if err == ErrNeighborQueueFull || l == 0 {
 				continue
 			}
 			assert.NoError(t, err)
@@ -99,8 +99,8 @@ func TestNeighborParallelWrite(t *testing.T) {
 	go func() {
 		defer wg.Done()
 		for i := 0; i < neighborQueueSize; i++ {
-			_, err := neighborA.Write(testData)
-			if err == ErrNeighborQueueFull {
+			l, err := neighborA.Write(testData)
+			if err == ErrNeighborQueueFull || l == 0 {
 				continue
 			}
 			assert.NoError(t, err)
diff --git a/packages/gossip/server/handshake.go b/packages/gossip/server/handshake.go
index fb291c8e..719ff0de 100644
--- a/packages/gossip/server/handshake.go
+++ b/packages/gossip/server/handshake.go
@@ -5,8 +5,8 @@ import (
 	"time"
 
 	"github.com/golang/protobuf/proto"
-	"github.com/iotaledger/goshimmer/packages/autopeering/server"
 	pb "github.com/iotaledger/goshimmer/packages/gossip/server/proto"
+	"github.com/iotaledger/hive.go/autopeering/server"
 )
 
 const (
diff --git a/packages/gossip/server/server.go b/packages/gossip/server/server.go
index c3853ac0..6185df51 100644
--- a/packages/gossip/server/server.go
+++ b/packages/gossip/server/server.go
@@ -12,10 +12,10 @@ import (
 	"time"
 
 	"github.com/golang/protobuf/proto"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
-	pb "github.com/iotaledger/goshimmer/packages/autopeering/server/proto"
 	"github.com/iotaledger/goshimmer/packages/netutil"
+	"github.com/iotaledger/hive.go/autopeering/peer"
+	"github.com/iotaledger/hive.go/autopeering/peer/service"
+	pb "github.com/iotaledger/hive.go/autopeering/server/proto"
 	"github.com/iotaledger/hive.go/backoff"
 	"go.uber.org/zap"
 )
diff --git a/packages/gossip/server/server_test.go b/packages/gossip/server/server_test.go
index 84155297..d3e95418 100644
--- a/packages/gossip/server/server_test.go
+++ b/packages/gossip/server/server_test.go
@@ -6,9 +6,9 @@ import (
 	"testing"
 	"time"
 
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
 	"github.com/iotaledger/goshimmer/packages/database/mapdb"
+	"github.com/iotaledger/hive.go/autopeering/peer"
+	"github.com/iotaledger/hive.go/autopeering/peer/service"
 	"github.com/iotaledger/hive.go/logger"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
diff --git a/packages/model/meta_transaction/meta_transaction.go b/packages/model/meta_transaction/meta_transaction.go
index 45550786..59c546ea 100644
--- a/packages/model/meta_transaction/meta_transaction.go
+++ b/packages/model/meta_transaction/meta_transaction.go
@@ -56,8 +56,11 @@ func FromTrits(trits trinary.Trits) *MetaTransaction {
 	}
 }
 
-func FromBytes(bytes []byte) (result *MetaTransaction) {
+func FromBytes(bytes []byte) (result *MetaTransaction, err error) {
 	trits := trinary.MustBytesToTrits(bytes)
+	if len(trits) < MARSHALED_TOTAL_SIZE {
+		return nil, fmt.Errorf("invalid size %v", len(trits))
+	}
 	result = FromTrits(trits[:MARSHALED_TOTAL_SIZE])
 	result.bytes = bytes
 
diff --git a/packages/model/meta_transaction/meta_transaction_test.go b/packages/model/meta_transaction/meta_transaction_test.go
index fa6ec565..7a349f2d 100644
--- a/packages/model/meta_transaction/meta_transaction_test.go
+++ b/packages/model/meta_transaction/meta_transaction_test.go
@@ -47,7 +47,9 @@ func TestMetaTransaction_SettersGetters(t *testing.T) {
 	assert.Equal(t, tx.IsHead(), head)
 	assert.Equal(t, tx.IsTail(), tail)
 	assert.Equal(t, tx.GetTransactionType(), transactionType)
-	assert.Equal(t, tx.GetHash(), FromBytes(tx.GetBytes()).GetHash())
+	metaTx, err := FromBytes(tx.GetBytes())
+	require.NoError(t, err)
+	assert.Equal(t, tx.GetHash(), metaTx.GetHash())
 
 	assert.EqualValues(t, "KKDVHBENVLQUNO9WOWWEJPBBHUSYRSRKIMZWCFCDB9RYZKYWLAYWRIBRQETBFKE9TIVWQPCKFWAMCLCAV", tx.GetHash())
 }
diff --git a/plugins/analysis/client/plugin.go b/plugins/analysis/client/plugin.go
index cbc41e18..fa962360 100644
--- a/plugins/analysis/client/plugin.go
+++ b/plugins/analysis/client/plugin.go
@@ -6,8 +6,6 @@ import (
 	"sync"
 	"time"
 
-	"github.com/iotaledger/goshimmer/packages/autopeering/discover"
-	"github.com/iotaledger/goshimmer/packages/autopeering/selection"
 	"github.com/iotaledger/goshimmer/packages/parameter"
 	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/goshimmer/plugins/analysis/types/addnode"
@@ -17,6 +15,8 @@ import (
 	"github.com/iotaledger/goshimmer/plugins/analysis/types/removenode"
 	"github.com/iotaledger/goshimmer/plugins/autopeering"
 	"github.com/iotaledger/goshimmer/plugins/autopeering/local"
+	"github.com/iotaledger/hive.go/autopeering/discover"
+	"github.com/iotaledger/hive.go/autopeering/selection"
 	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/events"
 	"github.com/iotaledger/hive.go/logger"
diff --git a/plugins/autopeering/autopeering.go b/plugins/autopeering/autopeering.go
index ca3b3de9..191d8471 100644
--- a/plugins/autopeering/autopeering.go
+++ b/plugins/autopeering/autopeering.go
@@ -7,17 +7,17 @@ import (
 	"net"
 	"strings"
 
-	"github.com/iotaledger/goshimmer/packages/autopeering/discover"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
-	"github.com/iotaledger/goshimmer/packages/autopeering/selection"
-	"github.com/iotaledger/goshimmer/packages/autopeering/server"
-	"github.com/iotaledger/goshimmer/packages/autopeering/transport"
 	"github.com/iotaledger/goshimmer/packages/netutil"
 	"github.com/iotaledger/goshimmer/packages/parameter"
 	"github.com/iotaledger/goshimmer/plugins/autopeering/local"
 	"github.com/iotaledger/goshimmer/plugins/cli"
 	"github.com/iotaledger/goshimmer/plugins/gossip"
+	"github.com/iotaledger/hive.go/autopeering/discover"
+	"github.com/iotaledger/hive.go/autopeering/peer"
+	"github.com/iotaledger/hive.go/autopeering/peer/service"
+	"github.com/iotaledger/hive.go/autopeering/selection"
+	"github.com/iotaledger/hive.go/autopeering/server"
+	"github.com/iotaledger/hive.go/autopeering/transport"
 	"github.com/iotaledger/hive.go/logger"
 	"github.com/iotaledger/hive.go/node"
 )
diff --git a/plugins/autopeering/local/local.go b/plugins/autopeering/local/local.go
index 65c71331..c9cb2efa 100644
--- a/plugins/autopeering/local/local.go
+++ b/plugins/autopeering/local/local.go
@@ -8,11 +8,11 @@ import (
 	"strings"
 	"sync"
 
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
 	"github.com/iotaledger/goshimmer/packages/database"
 	"github.com/iotaledger/goshimmer/packages/netutil"
 	"github.com/iotaledger/goshimmer/packages/parameter"
+	"github.com/iotaledger/hive.go/autopeering/peer"
+	"github.com/iotaledger/hive.go/autopeering/peer/service"
 	"github.com/iotaledger/hive.go/logger"
 )
 
@@ -40,7 +40,7 @@ func configureLocal() *peer.Local {
 		}
 	}
 	if !externalIP.IsGlobalUnicast() {
-		log.Fatalf("IP is not a global unicast address: %s", externalIP.String())
+		log.Warnf("IP is not a global unicast address: %s", externalIP.String())
 	}
 
 	peeringPort := strconv.Itoa(parameter.NodeConfig.GetInt(CFG_PORT))
diff --git a/plugins/autopeering/plugin.go b/plugins/autopeering/plugin.go
index cad1ba41..c8e5003a 100644
--- a/plugins/autopeering/plugin.go
+++ b/plugins/autopeering/plugin.go
@@ -3,11 +3,11 @@ package autopeering
 import (
 	"time"
 
-	"github.com/iotaledger/goshimmer/packages/autopeering/discover"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/selection"
 	"github.com/iotaledger/goshimmer/packages/gossip"
 	"github.com/iotaledger/goshimmer/packages/shutdown"
+	"github.com/iotaledger/hive.go/autopeering/discover"
+	"github.com/iotaledger/hive.go/autopeering/peer"
+	"github.com/iotaledger/hive.go/autopeering/selection"
 	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/events"
 	"github.com/iotaledger/hive.go/logger"
diff --git a/plugins/cli/plugin.go b/plugins/cli/plugin.go
index 8fbaeab0..13c03bc5 100644
--- a/plugins/cli/plugin.go
+++ b/plugins/cli/plugin.go
@@ -2,6 +2,7 @@ package cli
 
 import (
 	"fmt"
+	"os"
 
 	"github.com/iotaledger/goshimmer/packages/parameter"
 	"github.com/iotaledger/hive.go/events"
@@ -12,7 +13,7 @@ import (
 
 const (
 	// AppVersion version number
-	AppVersion = "v0.1.1"
+	AppVersion = "v0.1.2"
 	// AppName app code name
 	AppName = "GoShimmer"
 )
@@ -43,10 +44,20 @@ func parseParameters() {
 	}
 }
 
+func PrintVersion() {
+	version := flag.BoolP("version", "v", false, "Prints the GoShimmer version")
+	flag.Parse()
+	if *version {
+		fmt.Println(AppName + " " + AppVersion)
+		os.Exit(0)
+	}
+}
+
 func LoadConfig() {
 	if err := parameter.FetchConfig(false); err != nil {
 		panic(err)
 	}
+
 	parseParameters()
 
 	if err := logger.InitGlobalLogger(parameter.NodeConfig); err != nil {
diff --git a/plugins/config/config.go b/plugins/config/config.go
new file mode 100644
index 00000000..70513880
--- /dev/null
+++ b/plugins/config/config.go
@@ -0,0 +1,64 @@
+package config
+
+import (
+	"github.com/iotaledger/hive.go/logger"
+	"github.com/iotaledger/hive.go/node"
+	"github.com/iotaledger/hive.go/parameter"
+	flag "github.com/spf13/pflag"
+	"github.com/spf13/viper"
+)
+
+var (
+	// flags
+	configName    = flag.StringP("config", "c", "config", "Filename of the config file without the file extension")
+	configDirPath = flag.StringP("config-dir", "d", ".", "Path to the directory containing the config file")
+
+	// viper
+	NodeConfig *viper.Viper
+
+	// logger
+	defaultLoggerConfig = logger.Config{
+		Level:             "info",
+		DisableCaller:     false,
+		DisableStacktrace: false,
+		Encoding:          "console",
+		OutputPaths:       []string{"goshimmer.log"},
+		DisableEvents:     false,
+	}
+)
+
+func init() {
+	// set the default logger config
+	NodeConfig = viper.New()
+	NodeConfig.SetDefault(logger.ViperKey, defaultLoggerConfig)
+
+	if err := Fetch(false); err != nil {
+		panic(err)
+	}
+	parseParameters()
+}
+
+func parseParameters() {
+	for _, pluginName := range NodeConfig.GetStringSlice(node.CFG_DISABLE_PLUGINS) {
+		node.DisabledPlugins[node.GetPluginIdentifier(pluginName)] = true
+	}
+	for _, pluginName := range NodeConfig.GetStringSlice(node.CFG_ENABLE_PLUGINS) {
+		node.EnabledPlugins[node.GetPluginIdentifier(pluginName)] = true
+	}
+}
+
+// Fetch fetches config values from a dir defined via CLI flag --config-dir (or the current working dir if not set).
+//
+// It automatically reads in a single config file starting with "config" (can be changed via the --config CLI flag)
+// and ending with: .json, .toml, .yaml or .yml (in this sequence).
+func Fetch(printConfig bool, ignoreSettingsAtPrint ...[]string) error {
+	err := parameter.LoadConfigFile(NodeConfig, *configDirPath, *configName, true, true)
+	if err != nil {
+		return err
+	}
+
+	if printConfig {
+		parameter.PrintConfig(NodeConfig, ignoreSettingsAtPrint...)
+	}
+	return nil
+}
diff --git a/plugins/config/plugin.go b/plugins/config/plugin.go
new file mode 100644
index 00000000..0626fa17
--- /dev/null
+++ b/plugins/config/plugin.go
@@ -0,0 +1,12 @@
+package config
+
+import (
+	"github.com/iotaledger/hive.go/node"
+)
+
+// define the plugin as a placeholder, so the init methods get executed accordingly
+var PLUGIN = node.NewPlugin("Config", node.Enabled, run)
+
+func run(ctx *node.Plugin) {
+	// do nothing; everything is handled in the init method
+}
diff --git a/plugins/gossip/gossip.go b/plugins/gossip/gossip.go
index bdf1cca9..0293370e 100644
--- a/plugins/gossip/gossip.go
+++ b/plugins/gossip/gossip.go
@@ -6,14 +6,14 @@ import (
 	"strconv"
 	"sync"
 
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
 	gp "github.com/iotaledger/goshimmer/packages/gossip"
 	"github.com/iotaledger/goshimmer/packages/gossip/server"
 	"github.com/iotaledger/goshimmer/packages/parameter"
 	"github.com/iotaledger/goshimmer/plugins/autopeering/local"
 	"github.com/iotaledger/goshimmer/plugins/cli"
 	"github.com/iotaledger/goshimmer/plugins/tangle"
+	"github.com/iotaledger/hive.go/autopeering/peer"
+	"github.com/iotaledger/hive.go/autopeering/peer/service"
 	"github.com/iotaledger/hive.go/logger"
 	"github.com/iotaledger/hive.go/typeutils"
 	"github.com/iotaledger/iota.go/trinary"
diff --git a/plugins/gossip/plugin.go b/plugins/gossip/plugin.go
index 20e804a1..ff4b335f 100644
--- a/plugins/gossip/plugin.go
+++ b/plugins/gossip/plugin.go
@@ -1,12 +1,12 @@
 package gossip
 
 import (
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/selection"
 	"github.com/iotaledger/goshimmer/packages/gossip"
 	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
 	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/goshimmer/plugins/tangle"
+	"github.com/iotaledger/hive.go/autopeering/peer"
+	"github.com/iotaledger/hive.go/autopeering/selection"
 	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/events"
 	"github.com/iotaledger/hive.go/logger"
diff --git a/plugins/remotelog/plugin.go b/plugins/remotelog/plugin.go
index 0ca02c50..97f48981 100644
--- a/plugins/remotelog/plugin.go
+++ b/plugins/remotelog/plugin.go
@@ -9,20 +9,29 @@ import (
 	"encoding/json"
 	"fmt"
 	"net"
+	"os"
+	"path/filepath"
 	"runtime"
 	"time"
 
 	"github.com/iotaledger/goshimmer/packages/parameter"
 	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/goshimmer/plugins/autopeering/local"
+	"github.com/iotaledger/goshimmer/plugins/cli"
+
 	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/events"
 	"github.com/iotaledger/hive.go/logger"
 	"github.com/iotaledger/hive.go/node"
 	"github.com/iotaledger/hive.go/workerpool"
+
+	"gopkg.in/src-d/go-git.v4"
 )
 
 type logMessage struct {
+	Version   string    `json:"version"`
+	GitHead   string    `json:"gitHead,omitempty"`
+	GitBranch string    `json:"gitBranch,omitempty"`
 	NodeId    string    `json:"nodeId"`
 	Level     string    `json:"level"`
 	Name      string    `json:"name"`
@@ -37,11 +46,13 @@ const (
 )
 
 var (
-	PLUGIN     = node.NewPlugin(PLUGIN_NAME, node.Disabled, configure, run)
-	log        *logger.Logger
-	conn       net.Conn
-	myID       string
-	workerPool *workerpool.WorkerPool
+	PLUGIN      = node.NewPlugin(PLUGIN_NAME, node.Disabled, configure, run)
+	log         *logger.Logger
+	conn        net.Conn
+	myID        string
+	myGitHead   string
+	myGitBranch string
+	workerPool  *workerpool.WorkerPool
 )
 
 func configure(plugin *node.Plugin) {
@@ -63,6 +74,8 @@ func configure(plugin *node.Plugin) {
 		myID = hex.EncodeToString(local.GetInstance().ID().Bytes())
 	}
 
+	getGitInfo()
+
 	workerPool = workerpool.New(func(task workerpool.Task) {
 		sendLogMsg(task.Param(0).(logger.Level), task.Param(1).(string), task.Param(2).(string))
 
@@ -87,7 +100,54 @@ func run(plugin *node.Plugin) {
 }
 
 func sendLogMsg(level logger.Level, name string, msg string) {
-	m := logMessage{myID, level.CapitalString(), name, msg, time.Now()}
+	m := logMessage{
+		cli.AppVersion,
+		myGitHead,
+		myGitBranch,
+		myID,
+		level.CapitalString(),
+		name,
+		msg,
+		time.Now(),
+	}
 	b, _ := json.Marshal(m)
 	fmt.Fprint(conn, string(b))
 }
+
+func getGitInfo() {
+	r, err := git.PlainOpen(getGitDir())
+	if err != nil {
+		log.Debug("Could not open Git repo.")
+		return
+	}
+
+	// extract git branch and head
+	if h, err := r.Head(); err == nil {
+		myGitBranch = h.Name().String()
+		myGitHead = h.Hash().String()
+	}
+}
+
+func getGitDir() string {
+	var gitDir string
+
+	// this is valid when running an executable, when using "go run" this is a temp path
+	if ex, err := os.Executable(); err == nil {
+		temp := filepath.Join(filepath.Dir(ex), ".git")
+		if _, err := os.Stat(temp); err == nil {
+			gitDir = temp
+		}
+	}
+
+	// when running "go run" from the same directory
+	if gitDir == "" {
+		if wd, err := os.Getwd(); err == nil {
+			temp := filepath.Join(wd, ".git")
+			if _, err := os.Stat(temp); err == nil {
+				gitDir = temp
+			}
+		}
+	}
+
+	return gitDir
+}
diff --git a/plugins/remotelog/server/docker-compose.yml b/plugins/remotelog/server/docker-compose.yml
index f3c9db88..69ed87d8 100644
--- a/plugins/remotelog/server/docker-compose.yml
+++ b/plugins/remotelog/server/docker-compose.yml
@@ -13,7 +13,7 @@ services:
         source: elasticsearch
         target: /usr/share/elasticsearch/data
     environment:
-      ES_JAVA_OPTS: "-Xmx256m -Xms256m"
+      ES_JAVA_OPTS: "-Xmx2g -Xms2g"
       # Use single node discovery in order to disable production mode and avoid bootstrap checks
       # see https://www.elastic.co/guide/en/elasticsearch/reference/current/bootstrap-checks.html
       discovery.type: single-node
@@ -35,7 +35,7 @@ services:
     ports:
       - "5213:5213/udp"
     environment:
-      LS_JAVA_OPTS: "-Xmx256m -Xms256m"
+      LS_JAVA_OPTS: "-Xmx1g -Xms1g"
     networks:
       - elk
     depends_on:
diff --git a/plugins/spa/plugin.go b/plugins/spa/plugin.go
index 829d3609..7141a88f 100644
--- a/plugins/spa/plugin.go
+++ b/plugins/spa/plugin.go
@@ -7,7 +7,6 @@ import (
 	"time"
 
 	"github.com/gorilla/websocket"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
 	"github.com/iotaledger/goshimmer/packages/parameter"
 	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/goshimmer/plugins/autopeering"
@@ -15,6 +14,7 @@ import (
 	"github.com/iotaledger/goshimmer/plugins/cli"
 	"github.com/iotaledger/goshimmer/plugins/gossip"
 	"github.com/iotaledger/goshimmer/plugins/metrics"
+	"github.com/iotaledger/hive.go/autopeering/peer/service"
 	"github.com/labstack/echo"
 	"github.com/labstack/echo/middleware"
 
diff --git a/plugins/tangle/solidifier.go b/plugins/tangle/solidifier.go
index 02d84440..0c274c49 100644
--- a/plugins/tangle/solidifier.go
+++ b/plugins/tangle/solidifier.go
@@ -42,8 +42,12 @@ func configureSolidifier() {
 	requestedTxs = NewUnsolidTxs()
 
 	gossip.Events.TransactionReceived.Attach(events.NewClosure(func(ev *gossip.TransactionReceivedEvent) {
-		metaTx := meta_transaction.FromBytes(ev.Data)
-		if err := metaTx.Validate(); err != nil {
+		metaTx, err := meta_transaction.FromBytes(ev.Data)
+		if err != nil {
+			log.Warnf("invalid transaction: %s", err)
+			return
+		}
+		if err = metaTx.Validate(); err != nil {
 			log.Warnf("invalid transaction: %s", err)
 			return
 		}
diff --git a/plugins/tangle/solidifier_test.go b/plugins/tangle/solidifier_test.go
index 28a63bc2..9cd09962 100644
--- a/plugins/tangle/solidifier_test.go
+++ b/plugins/tangle/solidifier_test.go
@@ -131,7 +131,11 @@ func TestTangle(t *testing.T) {
 
 // transactionReceived mocks the TransactionReceived event by allowing lower mwm
 func transactionReceived(ev *gossip.TransactionReceivedEvent) {
-	metaTx := meta_transaction.FromBytes(ev.Data)
+	metaTx, err := meta_transaction.FromBytes(ev.Data)
+	if err != nil {
+		log.Warnf("invalid transaction: %s", err)
+		return
+	}
 	if metaTx.GetWeightMagnitude() < testMWM {
 		log.Warnf("invalid weight magnitude: %d / %d", metaTx.GetWeightMagnitude(), testMWM)
 		return
diff --git a/plugins/webapi/getNeighbors/plugin.go b/plugins/webapi/getNeighbors/plugin.go
index 1ac033ce..fe9c3971 100644
--- a/plugins/webapi/getNeighbors/plugin.go
+++ b/plugins/webapi/getNeighbors/plugin.go
@@ -4,10 +4,10 @@ import (
 	"encoding/base64"
 	"net/http"
 
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
-	"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
 	"github.com/iotaledger/goshimmer/plugins/autopeering"
 	"github.com/iotaledger/goshimmer/plugins/webapi"
+	"github.com/iotaledger/hive.go/autopeering/peer"
+	"github.com/iotaledger/hive.go/autopeering/peer/service"
 	"github.com/iotaledger/hive.go/node"
 	"github.com/labstack/echo"
 )
-- 
GitLab