diff --git a/main.go b/main.go
index 7ab4b3abc41f3f141454f7493c241cce9e1e6d75..9bf4f875e21537d586f1fe931a957d7cd3ae3ee3 100644
--- a/main.go
+++ b/main.go
@@ -9,6 +9,7 @@ import (
 	"github.com/iotaledger/goshimmer/plugins/gossip"
 	gossip_on_solidification "github.com/iotaledger/goshimmer/plugins/gossip-on-solidification"
 	"github.com/iotaledger/goshimmer/plugins/gracefulshutdown"
+	"github.com/iotaledger/goshimmer/plugins/metrics"
 	"github.com/iotaledger/goshimmer/plugins/statusscreen"
 	statusscreen_tps "github.com/iotaledger/goshimmer/plugins/statusscreen-tps"
 	"github.com/iotaledger/goshimmer/plugins/tangle"
@@ -31,6 +32,7 @@ func main() {
 		gracefulshutdown.PLUGIN,
 		tipselection.PLUGIN,
 		zeromq.PLUGIN,
+		metrics.PLUGIN,
 
 		statusscreen.PLUGIN,
 		statusscreen_tps.PLUGIN,
diff --git a/packages/curl/batch_hasher_test.go b/packages/curl/batch_hasher_test.go
index 9c9c3eec8f53c77e940f6121dee18291d1eddbef..009cc6bf9bf26c3b27f696e140a4d97a55fbee1d 100644
--- a/packages/curl/batch_hasher_test.go
+++ b/packages/curl/batch_hasher_test.go
@@ -4,12 +4,12 @@ import (
 	"sync"
 	"testing"
 
-	"github.com/iotaledger/goshimmer/packages/ternary"
+	"github.com/iotaledger/iota.go/trinary"
 )
 
 func BenchmarkBatchHasher_Hash(b *testing.B) {
 	batchHasher := NewBatchHasher(243, 81)
-	tritsToHash := ternary.Trytes("A999999FF").ToTrits()
+	tritsToHash := trinary.MustTrytesToTrits(trinary.Trytes("A999999FF"))
 
 	b.ResetTimer()
 
diff --git a/plugins/bundleprocessor/bundleprocessor_test.go b/plugins/bundleprocessor/bundleprocessor_test.go
index f2132dc94a610ccb2fd013f0b993e6d5b1bbc05f..5da9cc4db4ee3140fa9e38a08129e1a20fafbf42 100644
--- a/plugins/bundleprocessor/bundleprocessor_test.go
+++ b/plugins/bundleprocessor/bundleprocessor_test.go
@@ -7,8 +7,8 @@ import (
 	"github.com/iotaledger/goshimmer/packages/events"
 	"github.com/iotaledger/goshimmer/packages/model/bundle"
 	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
-	"github.com/iotaledger/goshimmer/packages/ternary"
 	"github.com/iotaledger/goshimmer/plugins/tangle"
+	"github.com/iotaledger/iota.go/trinary"
 	"github.com/magiconair/properties/assert"
 )
 
@@ -35,7 +35,7 @@ func TestProcessSolidBundleHead(t *testing.T) {
 	if err != nil {
 		t.Error(err)
 	} else {
-		assert.Equal(t, result.GetHash(), ternary.Trytes("UFWJYEWKMEQDNSQUCUWBGOFRHVBGHVVYEZCLCGRDTRQSMAFALTIPMJEEYFDPMQCNJWLXUWFMBZGHQRO99"), "invalid bundle hash")
+		assert.Equal(t, result.GetHash(), trinary.Trytes("UFWJYEWKMEQDNSQUCUWBGOFRHVBGHVVYEZCLCGRDTRQSMAFALTIPMJEEYFDPMQCNJWLXUWFMBZGHQRO99"), "invalid bundle hash")
 		assert.Equal(t, result.IsValueBundle(), true, "invalid value bundle status")
 	}
 }
diff --git a/plugins/metrics/events.go b/plugins/metrics/events.go
new file mode 100644
index 0000000000000000000000000000000000000000..1bcab96ef91ae91543d49f842e0d4d2ea3101576
--- /dev/null
+++ b/plugins/metrics/events.go
@@ -0,0 +1,20 @@
+package metrics
+
+import (
+	"github.com/iotaledger/goshimmer/packages/events"
+)
+
+// define a struct with the available events
+type pluginEvents struct {
+	ReceivedTPSUpdated *events.Event
+}
+
+// define a function that maps our event parameters to the correct type: uint64 (GO has no generics)
+func uint64EventCaller(handler interface{}, params ...interface{}) {
+	handler.(func(uint64))(params[0].(uint64))
+}
+
+// expose our event API
+var Events = pluginEvents{
+	ReceivedTPSUpdated: events.NewEvent(uint64EventCaller),
+}
diff --git a/plugins/metrics/plugin.go b/plugins/metrics/plugin.go
new file mode 100644
index 0000000000000000000000000000000000000000..837a7bfe8ca3514c2481f936b963ede50aa966bf
--- /dev/null
+++ b/plugins/metrics/plugin.go
@@ -0,0 +1,27 @@
+package metrics
+
+import (
+	"time"
+
+	"github.com/iotaledger/goshimmer/packages/daemon"
+	"github.com/iotaledger/goshimmer/packages/events"
+	"github.com/iotaledger/goshimmer/packages/model/meta_transaction"
+	"github.com/iotaledger/goshimmer/packages/node"
+	"github.com/iotaledger/goshimmer/packages/timeutil"
+	"github.com/iotaledger/goshimmer/plugins/gossip"
+)
+
+// create configure handler (get's called when the PLUGIN is "loaded" by the node)
+func configure(plugin *node.Plugin) {
+	// increase received TPS counter whenever we receive a new transaction
+	gossip.Events.ReceiveTransaction.Attach(events.NewClosure(func(_ *meta_transaction.MetaTransaction) { increaseReceivedTPSCounter() }))
+}
+
+// create run handler (get's called when the PLUGIN is "executed" by the node)
+func run(plugin *node.Plugin) {
+	// create a background worker that "measures" the TPS value every second
+	daemon.BackgroundWorker("Metrics TPS Updater", func() { timeutil.Ticker(measureReceivedTPS, 1*time.Second) })
+}
+
+// export plugin
+var PLUGIN = node.NewPlugin("Metrics", configure, run)
diff --git a/plugins/metrics/tps.go b/plugins/metrics/tps.go
new file mode 100644
index 0000000000000000000000000000000000000000..4acdd176af5eda06513af810031af0124193350a
--- /dev/null
+++ b/plugins/metrics/tps.go
@@ -0,0 +1,36 @@
+package metrics
+
+import (
+	"sync/atomic"
+)
+
+// public api method to proactively retrieve the received TPS value
+func GetReceivedTPS() uint64 {
+	return atomic.LoadUint64(&measuredReceivedTPS)
+}
+
+// counter for the received TPS
+var tpsReceivedSinceLastMeasurement uint64
+
+// measured value of the received TPS
+var measuredReceivedTPS uint64
+
+// increases the received TPS counter
+func increaseReceivedTPSCounter() {
+	atomic.AddUint64(&tpsReceivedSinceLastMeasurement, 1)
+}
+
+// measures the received TPS value
+func measureReceivedTPS() {
+	// sample the current counter value into a measured TPS value
+	sampledTPS := atomic.LoadUint64(&tpsReceivedSinceLastMeasurement)
+
+	// store the measured value
+	atomic.StoreUint64(&measuredReceivedTPS, sampledTPS)
+
+	// reset the counter
+	atomic.StoreUint64(&tpsReceivedSinceLastMeasurement, 0)
+
+	// trigger events for outside listeners
+	Events.ReceivedTPSUpdated.Trigger(sampledTPS)
+}
diff --git a/plugins/validator/plugin.go b/plugins/validator/plugin.go
index 9b898d799c734236ab247367456b129db2a11127..dce2129b6d57b502f65a8f1621149ce8fa7e7119 100644
--- a/plugins/validator/plugin.go
+++ b/plugins/validator/plugin.go
@@ -8,6 +8,7 @@ import (
 	"github.com/iotaledger/goshimmer/plugins/bundleprocessor"
 	"github.com/iotaledger/iota.go/address"
 	. "github.com/iotaledger/iota.go/consts"
+	"github.com/iotaledger/iota.go/kerl"
 	"github.com/iotaledger/iota.go/signing"
 	. "github.com/iotaledger/iota.go/trinary"
 )
@@ -17,7 +18,6 @@ var PLUGIN = node.NewPlugin("Validator", configure, run)
 // Creates bundle signature fragments and the corresponding address to validate against.
 // Each signature fragment after the first must go into its own meta transaction with value = 0.
 func demoSign(seed Trytes, index uint64, sec SecurityLevel, bundleHash Hash) (Hash, []Trytes) {
-
 	addr, _ := address.GenerateAddress(seed, index, sec)
 
 	// compute seed based on address index
@@ -63,7 +63,7 @@ func validateSignatures(bundleHash Hash, txs []*value_transaction.ValueTransacti
 		}
 
 		// validate all the fragments against the address using Kerl
-		valid, err := signing.ValidateSignatures(address, fragments, bundleHash, signing.NewKerl)
+		valid, err := signing.ValidateSignatures(address, fragments, bundleHash, kerl.NewKerl())
 		if err != nil {
 			return false, err
 		}
@@ -77,7 +77,7 @@ func validateSignatures(bundleHash Hash, txs []*value_transaction.ValueTransacti
 
 func configure(plugin *node.Plugin) {
 
-	bundleprocessor.Events.ValueBundleReceived.Attach(events.NewClosure(func(b *bundle.Bundle, txs []*value_transaction.ValueTransaction) {
+	bundleprocessor.Events.BundleSolid.Attach(events.NewClosure(func(b *bundle.Bundle, txs []*value_transaction.ValueTransaction) {
 		// signature are verified against the bundle hash
 		valid, _ := validateSignatures(b.GetBundleEssenceHash(), txs)
 		if !valid {