diff --git a/go.mod b/go.mod
index 4526aae3d5501de31344e16c149200b281287a1c..879290b9064cf1156475acb01ea751623e0fc1f4 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ require (
 	github.com/ethereum/go-ethereum v1.9.1
 	github.com/gdamore/tcell v1.2.0
 	github.com/go-zeromq/zmq4 v0.5.0
-	github.com/golang/protobuf v1.3.2 // indirect
+	github.com/golang/protobuf v1.3.2
 	github.com/google/open-location-code/go v0.0.0-20190723034300-2c7115db77a3
 	github.com/gorilla/websocket v1.4.0
 	github.com/iotaledger/iota.go v1.0.0-beta.7
diff --git a/packages/ca/heartbeat/proto/heartbeat.pb.go b/packages/ca/heartbeat/proto/heartbeat.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..c18bcd3efed1de5edfddbe1af3a0fdee83f45e33
--- /dev/null
+++ b/packages/ca/heartbeat/proto/heartbeat.pb.go
@@ -0,0 +1,105 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: heartbeat.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 HeartBeat struct {
+	NodeId               []byte              `protobuf:"bytes,1,opt,name=nodeId,proto3" json:"nodeId,omitempty"`
+	OwnStatement         *OpinionStatement   `protobuf:"bytes,2,opt,name=ownStatement,proto3" json:"ownStatement,omitempty"`
+	NeighborStatements   []*OpinionStatement `protobuf:"bytes,3,rep,name=neighborStatements,proto3" json:"neighborStatements,omitempty"`
+	Signature            []byte              `protobuf:"bytes,4,opt,name=signature,proto3" json:"signature,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}            `json:"-"`
+	XXX_unrecognized     []byte              `json:"-"`
+	XXX_sizecache        int32               `json:"-"`
+}
+
+func (m *HeartBeat) Reset()         { *m = HeartBeat{} }
+func (m *HeartBeat) String() string { return proto.CompactTextString(m) }
+func (*HeartBeat) ProtoMessage()    {}
+func (*HeartBeat) Descriptor() ([]byte, []int) {
+	return fileDescriptor_3c667767fb9826a9, []int{0}
+}
+
+func (m *HeartBeat) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_HeartBeat.Unmarshal(m, b)
+}
+func (m *HeartBeat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_HeartBeat.Marshal(b, m, deterministic)
+}
+func (m *HeartBeat) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_HeartBeat.Merge(m, src)
+}
+func (m *HeartBeat) XXX_Size() int {
+	return xxx_messageInfo_HeartBeat.Size(m)
+}
+func (m *HeartBeat) XXX_DiscardUnknown() {
+	xxx_messageInfo_HeartBeat.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_HeartBeat proto.InternalMessageInfo
+
+func (m *HeartBeat) GetNodeId() []byte {
+	if m != nil {
+		return m.NodeId
+	}
+	return nil
+}
+
+func (m *HeartBeat) GetOwnStatement() *OpinionStatement {
+	if m != nil {
+		return m.OwnStatement
+	}
+	return nil
+}
+
+func (m *HeartBeat) GetNeighborStatements() []*OpinionStatement {
+	if m != nil {
+		return m.NeighborStatements
+	}
+	return nil
+}
+
+func (m *HeartBeat) GetSignature() []byte {
+	if m != nil {
+		return m.Signature
+	}
+	return nil
+}
+
+func init() {
+	proto.RegisterType((*HeartBeat)(nil), "proto.HeartBeat")
+}
+
+func init() { proto.RegisterFile("heartbeat.proto", fileDescriptor_3c667767fb9826a9) }
+
+var fileDescriptor_3c667767fb9826a9 = []byte{
+	// 172 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xcf, 0x48, 0x4d, 0x2c,
+	0x2a, 0x49, 0x4a, 0x4d, 0x2c, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x53, 0x52,
+	0xe2, 0xf9, 0x05, 0x99, 0x79, 0x99, 0xf9, 0x79, 0xf1, 0xc5, 0x25, 0x89, 0x25, 0xa9, 0xb9, 0xa9,
+	0x79, 0x50, 0x79, 0xa5, 0xe3, 0x8c, 0x5c, 0x9c, 0x1e, 0x20, 0x3d, 0x4e, 0xa9, 0x89, 0x25, 0x42,
+	0x62, 0x5c, 0x6c, 0x79, 0xf9, 0x29, 0xa9, 0x9e, 0x29, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x3c, 0x41,
+	0x50, 0x9e, 0x90, 0x35, 0x17, 0x4f, 0x7e, 0x79, 0x5e, 0x30, 0x4c, 0xaf, 0x04, 0x93, 0x02, 0xa3,
+	0x06, 0xb7, 0x91, 0x38, 0xc4, 0x0c, 0x3d, 0x7f, 0x88, 0xd9, 0x70, 0xe9, 0x20, 0x14, 0xc5, 0x42,
+	0xee, 0x5c, 0x42, 0x79, 0xa9, 0x99, 0xe9, 0x19, 0x49, 0xf9, 0x45, 0x70, 0xc1, 0x62, 0x09, 0x66,
+	0x05, 0x66, 0x7c, 0x46, 0x60, 0xd1, 0x22, 0x24, 0xc3, 0xc5, 0x59, 0x9c, 0x99, 0x9e, 0x97, 0x58,
+	0x52, 0x5a, 0x94, 0x2a, 0xc1, 0x02, 0x76, 0x20, 0x42, 0x20, 0x89, 0x0d, 0x6c, 0x92, 0x31, 0x20,
+	0x00, 0x00, 0xff, 0xff, 0x53, 0x6b, 0x3e, 0x03, 0x03, 0x01, 0x00, 0x00,
+}
diff --git a/packages/ca/heartbeat/proto/heartbeat.proto b/packages/ca/heartbeat/proto/heartbeat.proto
new file mode 100644
index 0000000000000000000000000000000000000000..74c49f3362c4521ab3cc00d7ece9977dfb7ae136
--- /dev/null
+++ b/packages/ca/heartbeat/proto/heartbeat.proto
@@ -0,0 +1,13 @@
+syntax = "proto3";
+
+import "opinion_statement.proto";
+
+package proto;
+
+message HeartBeat {
+    bytes nodeId = 1;
+    OpinionStatement ownStatement = 2;
+    repeated OpinionStatement neighborStatements = 3;
+    bytes signature = 4;
+}
+
diff --git a/packages/ca/heartbeat/proto/opinion_statement.pb.go b/packages/ca/heartbeat/proto/opinion_statement.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..1b71fec0ab3cbf2ef1304504599995fa4ec91076
--- /dev/null
+++ b/packages/ca/heartbeat/proto/opinion_statement.pb.go
@@ -0,0 +1,105 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: opinion_statement.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 OpinionStatement struct {
+	NodeId               []byte                `protobuf:"bytes,1,opt,name=nodeId,proto3" json:"nodeId,omitempty"`
+	Time                 uint64                `protobuf:"varint,2,opt,name=time,proto3" json:"time,omitempty"`
+	ToggledTransactions  []*ToggledTransaction `protobuf:"bytes,3,rep,name=toggledTransactions,proto3" json:"toggledTransactions,omitempty"`
+	Signature            []byte                `protobuf:"bytes,4,opt,name=signature,proto3" json:"signature,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}              `json:"-"`
+	XXX_unrecognized     []byte                `json:"-"`
+	XXX_sizecache        int32                 `json:"-"`
+}
+
+func (m *OpinionStatement) Reset()         { *m = OpinionStatement{} }
+func (m *OpinionStatement) String() string { return proto.CompactTextString(m) }
+func (*OpinionStatement) ProtoMessage()    {}
+func (*OpinionStatement) Descriptor() ([]byte, []int) {
+	return fileDescriptor_a5a0e519e658baf5, []int{0}
+}
+
+func (m *OpinionStatement) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_OpinionStatement.Unmarshal(m, b)
+}
+func (m *OpinionStatement) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_OpinionStatement.Marshal(b, m, deterministic)
+}
+func (m *OpinionStatement) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_OpinionStatement.Merge(m, src)
+}
+func (m *OpinionStatement) XXX_Size() int {
+	return xxx_messageInfo_OpinionStatement.Size(m)
+}
+func (m *OpinionStatement) XXX_DiscardUnknown() {
+	xxx_messageInfo_OpinionStatement.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_OpinionStatement proto.InternalMessageInfo
+
+func (m *OpinionStatement) GetNodeId() []byte {
+	if m != nil {
+		return m.NodeId
+	}
+	return nil
+}
+
+func (m *OpinionStatement) GetTime() uint64 {
+	if m != nil {
+		return m.Time
+	}
+	return 0
+}
+
+func (m *OpinionStatement) GetToggledTransactions() []*ToggledTransaction {
+	if m != nil {
+		return m.ToggledTransactions
+	}
+	return nil
+}
+
+func (m *OpinionStatement) GetSignature() []byte {
+	if m != nil {
+		return m.Signature
+	}
+	return nil
+}
+
+func init() {
+	proto.RegisterType((*OpinionStatement)(nil), "proto.OpinionStatement")
+}
+
+func init() { proto.RegisterFile("opinion_statement.proto", fileDescriptor_a5a0e519e658baf5) }
+
+var fileDescriptor_a5a0e519e658baf5 = []byte{
+	// 174 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xcf, 0x2f, 0xc8, 0xcc,
+	0xcb, 0xcc, 0xcf, 0x8b, 0x2f, 0x2e, 0x49, 0x2c, 0x49, 0xcd, 0x4d, 0xcd, 0x2b, 0xd1, 0x2b, 0x28,
+	0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x53, 0x52, 0x92, 0x25, 0xf9, 0xe9, 0xe9, 0x39, 0xa9, 0x29,
+	0xf1, 0x25, 0x45, 0x89, 0x79, 0xc5, 0x89, 0xc9, 0x25, 0x99, 0xf9, 0x79, 0x10, 0x15, 0x4a, 0x2b,
+	0x19, 0xb9, 0x04, 0xfc, 0x21, 0xba, 0x83, 0x61, 0x9a, 0x85, 0xc4, 0xb8, 0xd8, 0xf2, 0xf2, 0x53,
+	0x52, 0x3d, 0x53, 0x24, 0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0xa0, 0x3c, 0x21, 0x21, 0x2e, 0x96,
+	0x92, 0xcc, 0xdc, 0x54, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x96, 0x20, 0x30, 0x5b, 0xc8, 0x9b, 0x4b,
+	0x18, 0x6a, 0x7a, 0x08, 0xc2, 0xf0, 0x62, 0x09, 0x66, 0x05, 0x66, 0x0d, 0x6e, 0x23, 0x49, 0x88,
+	0x2d, 0x7a, 0x21, 0x18, 0x2a, 0x82, 0xb0, 0xe9, 0x12, 0x92, 0xe1, 0xe2, 0x2c, 0xce, 0x4c, 0xcf,
+	0x4b, 0x2c, 0x29, 0x2d, 0x4a, 0x95, 0x60, 0x01, 0xdb, 0x8d, 0x10, 0x48, 0x62, 0x03, 0x1b, 0x66,
+	0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x22, 0xe9, 0x1c, 0x03, 0xef, 0x00, 0x00, 0x00,
+}
diff --git a/packages/ca/heartbeat/proto/opinion_statement.proto b/packages/ca/heartbeat/proto/opinion_statement.proto
new file mode 100644
index 0000000000000000000000000000000000000000..c3d24b70ba6c0047064f549b22e3c46d3f23211a
--- /dev/null
+++ b/packages/ca/heartbeat/proto/opinion_statement.proto
@@ -0,0 +1,12 @@
+syntax = "proto3";
+
+import "toggled_transaction.proto";
+
+package proto;
+
+message OpinionStatement {
+    bytes nodeId = 1;
+    uint64 time = 2;
+    repeated ToggledTransaction toggledTransactions = 3;
+    bytes signature = 4;
+};
\ No newline at end of file
diff --git a/packages/ca/heartbeat/proto/toggle_type.pb.go b/packages/ca/heartbeat/proto/toggle_type.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..bb9e8534b0705caeebc1d5514b2e71d1605ba1c0
--- /dev/null
+++ b/packages/ca/heartbeat/proto/toggle_type.pb.go
@@ -0,0 +1,62 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: toggle_type.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 ToggleType int32
+
+const (
+	ToggleType_Like    ToggleType = 0
+	ToggleType_Dislike ToggleType = 1
+)
+
+var ToggleType_name = map[int32]string{
+	0: "Like",
+	1: "Dislike",
+}
+
+var ToggleType_value = map[string]int32{
+	"Like":    0,
+	"Dislike": 1,
+}
+
+func (x ToggleType) String() string {
+	return proto.EnumName(ToggleType_name, int32(x))
+}
+
+func (ToggleType) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor_f8d4c81885a98bf0, []int{0}
+}
+
+func init() {
+	proto.RegisterEnum("proto.ToggleType", ToggleType_name, ToggleType_value)
+}
+
+func init() { proto.RegisterFile("toggle_type.proto", fileDescriptor_f8d4c81885a98bf0) }
+
+var fileDescriptor_f8d4c81885a98bf0 = []byte{
+	// 83 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2c, 0xc9, 0x4f, 0x4f,
+	0xcf, 0x49, 0x8d, 0x2f, 0xa9, 0x2c, 0x48, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05,
+	0x53, 0x5a, 0xca, 0x5c, 0x5c, 0x21, 0x60, 0xb9, 0x90, 0xca, 0x82, 0x54, 0x21, 0x0e, 0x2e, 0x16,
+	0x9f, 0xcc, 0xec, 0x54, 0x01, 0x06, 0x21, 0x6e, 0x2e, 0x76, 0x97, 0xcc, 0xe2, 0x1c, 0x10, 0x87,
+	0x31, 0x89, 0x0d, 0xac, 0xd6, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0xad, 0x5e, 0x8a, 0xc7, 0x47,
+	0x00, 0x00, 0x00,
+}
diff --git a/packages/ca/heartbeat/proto/toggle_type.proto b/packages/ca/heartbeat/proto/toggle_type.proto
new file mode 100644
index 0000000000000000000000000000000000000000..51435c992de7a03703ea9354f78ae006e76017ba
--- /dev/null
+++ b/packages/ca/heartbeat/proto/toggle_type.proto
@@ -0,0 +1,8 @@
+syntax = "proto3";
+
+package proto;
+
+enum ToggleType {
+    Like = 0;
+    Dislike = 1;
+}
\ No newline at end of file
diff --git a/packages/ca/heartbeat/proto/toggled_transaction.pb.go b/packages/ca/heartbeat/proto/toggled_transaction.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..593cbeaed69ca5c6e61c24fdb3034d517990b611
--- /dev/null
+++ b/packages/ca/heartbeat/proto/toggled_transaction.pb.go
@@ -0,0 +1,87 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: toggled_transaction.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 ToggledTransaction struct {
+	TransactionId        []byte     `protobuf:"bytes,1,opt,name=transactionId,proto3" json:"transactionId,omitempty"`
+	ToggleReason         ToggleType `protobuf:"varint,2,opt,name=toggleReason,proto3,enum=proto.ToggleType" json:"toggleReason,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}   `json:"-"`
+	XXX_unrecognized     []byte     `json:"-"`
+	XXX_sizecache        int32      `json:"-"`
+}
+
+func (m *ToggledTransaction) Reset()         { *m = ToggledTransaction{} }
+func (m *ToggledTransaction) String() string { return proto.CompactTextString(m) }
+func (*ToggledTransaction) ProtoMessage()    {}
+func (*ToggledTransaction) Descriptor() ([]byte, []int) {
+	return fileDescriptor_ddb0b50608ac9f9d, []int{0}
+}
+
+func (m *ToggledTransaction) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_ToggledTransaction.Unmarshal(m, b)
+}
+func (m *ToggledTransaction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_ToggledTransaction.Marshal(b, m, deterministic)
+}
+func (m *ToggledTransaction) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ToggledTransaction.Merge(m, src)
+}
+func (m *ToggledTransaction) XXX_Size() int {
+	return xxx_messageInfo_ToggledTransaction.Size(m)
+}
+func (m *ToggledTransaction) XXX_DiscardUnknown() {
+	xxx_messageInfo_ToggledTransaction.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_ToggledTransaction proto.InternalMessageInfo
+
+func (m *ToggledTransaction) GetTransactionId() []byte {
+	if m != nil {
+		return m.TransactionId
+	}
+	return nil
+}
+
+func (m *ToggledTransaction) GetToggleReason() ToggleType {
+	if m != nil {
+		return m.ToggleReason
+	}
+	return ToggleType_Like
+}
+
+func init() {
+	proto.RegisterType((*ToggledTransaction)(nil), "proto.ToggledTransaction")
+}
+
+func init() { proto.RegisterFile("toggled_transaction.proto", fileDescriptor_ddb0b50608ac9f9d) }
+
+var fileDescriptor_ddb0b50608ac9f9d = []byte{
+	// 130 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2c, 0xc9, 0x4f, 0x4f,
+	0xcf, 0x49, 0x4d, 0x89, 0x2f, 0x29, 0x4a, 0xcc, 0x2b, 0x4e, 0x4c, 0x2e, 0xc9, 0xcc, 0xcf, 0xd3,
+	0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x53, 0x52, 0x82, 0x10, 0x15, 0xf1, 0x25, 0x95,
+	0x05, 0xa9, 0x10, 0x19, 0xa5, 0x42, 0x2e, 0xa1, 0x10, 0x88, 0xb6, 0x10, 0x84, 0x2e, 0x21, 0x15,
+	0x2e, 0x5e, 0x24, 0x43, 0x3c, 0x53, 0x24, 0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0x50, 0x05, 0x85,
+	0x4c, 0xb9, 0x78, 0x20, 0x06, 0x06, 0xa5, 0x26, 0x16, 0xe7, 0xe7, 0x49, 0x30, 0x29, 0x30, 0x6a,
+	0xf0, 0x19, 0x09, 0x42, 0x4c, 0xd6, 0x83, 0x18, 0x1b, 0x52, 0x59, 0x90, 0x1a, 0x84, 0xa2, 0x2c,
+	0x89, 0x0d, 0x2c, 0x6f, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0xed, 0xb6, 0x2b, 0x6a, 0xb0, 0x00,
+	0x00, 0x00,
+}
diff --git a/packages/ca/heartbeat/proto/toggled_transaction.proto b/packages/ca/heartbeat/proto/toggled_transaction.proto
new file mode 100644
index 0000000000000000000000000000000000000000..99558098336b91ad50660874fc97f41e1a1e832f
--- /dev/null
+++ b/packages/ca/heartbeat/proto/toggled_transaction.proto
@@ -0,0 +1,10 @@
+syntax = "proto3";
+
+import "toggle_type.proto";
+
+package proto;
+
+message ToggledTransaction {
+    bytes transactionId = 1;
+    ToggleType toggleReason = 2;
+};
\ No newline at end of file
diff --git a/packages/ca/heartbeat/serialization_test.go b/packages/ca/heartbeat/serialization_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..39226bc5bf1980905ba8348fc428bc049030b272
--- /dev/null
+++ b/packages/ca/heartbeat/serialization_test.go
@@ -0,0 +1,59 @@
+package heartbeat
+
+import (
+	"fmt"
+	"testing"
+	"time"
+
+	"github.com/iotaledger/goshimmer/packages/identity"
+
+	"github.com/golang/protobuf/proto"
+
+	heartbeatproto "github.com/iotaledger/goshimmer/packages/ca/heartbeat/proto"
+)
+
+func TestMarshal(t *testing.T) {
+	ownNodeId := identity.GenerateRandomIdentity().Identifier
+
+	toggledTransactions := make([]*heartbeatproto.ToggledTransaction, 1000)
+
+	for i := 0; i < len(toggledTransactions); i++ {
+		toggledTransactions[i] = &heartbeatproto.ToggledTransaction{
+			TransactionId: make([]byte, 32),
+			ToggleReason:  0,
+		}
+	}
+
+	ownStatement := &heartbeatproto.OpinionStatement{
+		NodeId:              ownNodeId,
+		Time:                uint64(time.Now().Unix()),
+		ToggledTransactions: toggledTransactions,
+		Signature:           make([]byte, 32),
+	}
+
+	neighborStatements := make([]*heartbeatproto.OpinionStatement, 8)
+	for i := 0; i < len(neighborStatements); i++ {
+		neighborStatements[i] = &heartbeatproto.OpinionStatement{
+			NodeId:              ownNodeId,
+			Time:                uint64(time.Now().Unix()),
+			ToggledTransactions: toggledTransactions,
+			Signature:           make([]byte, 32),
+		}
+	}
+
+	heartbeat := &heartbeatproto.HeartBeat{
+		NodeId:             ownNodeId,
+		OwnStatement:       ownStatement,
+		NeighborStatements: neighborStatements,
+		Signature:          make([]byte, 32),
+	}
+
+	serializedHeartbeat, err := proto.Marshal(heartbeat)
+	if err != nil {
+		t.Error(err)
+
+		return
+	}
+
+	fmt.Println(len(serializedHeartbeat))
+}