From e4f4c6ffb15be692f65ce08d943a7f6b33463e79 Mon Sep 17 00:00:00 2001
From: Hans Moog <hm@mkjc.net>
Date: Wed, 18 Dec 2019 19:10:39 +0100
Subject: [PATCH] Feat: added approvers model for the tangle

---
 packages/binary/approvers/approvers.go    | 111 ++++++++++++++++++++++
 packages/binary/approvers/types.go        |   5 +
 packages/binary/identity/identity.go      |   4 +-
 packages/binary/identity/identity_test.go |   3 -
 packages/binary/identity/type.go          |   4 +-
 packages/binary/tangle/tangle.go          |   9 ++
 6 files changed, 129 insertions(+), 7 deletions(-)
 create mode 100644 packages/binary/approvers/approvers.go
 create mode 100644 packages/binary/approvers/types.go

diff --git a/packages/binary/approvers/approvers.go b/packages/binary/approvers/approvers.go
new file mode 100644
index 00000000..f9ba5afe
--- /dev/null
+++ b/packages/binary/approvers/approvers.go
@@ -0,0 +1,111 @@
+package approvers
+
+import (
+	"sync"
+
+	"github.com/iotaledger/goshimmer/packages/binary/transaction"
+	"github.com/iotaledger/hive.go/objectstorage"
+)
+
+type Approvers struct {
+	objectstorage.StorableObjectFlags
+
+	transactionId  transaction.Id
+	approvers      map[transaction.Id]empty
+	approversMutex sync.RWMutex
+}
+
+func New(transactionId transaction.Id) *Approvers {
+	return &Approvers{
+		transactionId: transactionId,
+		approvers:     make(map[transaction.Id]empty),
+	}
+}
+
+// Get's called when we restore the approvers from storage. The bytes and the content will be unmarshaled by an external
+// caller (the objectStorage factory).
+func FromStorage(id []byte) (result *Approvers) {
+	var transactionId transaction.Id
+	copy(transactionId[:], id)
+
+	result = &Approvers{
+		transactionId: transactionId,
+	}
+
+	return
+}
+
+func (approvers *Approvers) GetTransactionId() transaction.Id {
+	return approvers.transactionId
+}
+
+func (approvers *Approvers) Get() (result map[transaction.Id]empty) {
+	approvers.approversMutex.RLock()
+	result = make(map[transaction.Id]empty, len(approvers.approvers))
+	for approverId := range approvers.approvers {
+		result[approverId] = void
+	}
+	approvers.approversMutex.RUnlock()
+
+	return
+}
+
+func (approvers *Approvers) Add(transactionId transaction.Id) (modified bool) {
+	approvers.approversMutex.RLock()
+	if _, exists := approvers.approvers[transactionId]; !exists {
+		approvers.approversMutex.RUnlock()
+
+		approvers.approversMutex.Lock()
+		if _, exists := approvers.approvers[transactionId]; !exists {
+			approvers.approvers[transactionId] = void
+
+			modified = true
+
+			approvers.SetModified()
+		}
+		approvers.approversMutex.Unlock()
+	} else {
+		approvers.approversMutex.RUnlock()
+	}
+
+	return
+}
+
+func (approvers *Approvers) Remove(transactionId transaction.Id) (modified bool) {
+	approvers.approversMutex.RLock()
+	if _, exists := approvers.approvers[transactionId]; exists {
+		approvers.approversMutex.RUnlock()
+
+		approvers.approversMutex.Lock()
+		if _, exists := approvers.approvers[transactionId]; exists {
+			delete(approvers.approvers, transactionId)
+
+			modified = true
+
+			approvers.SetModified()
+		}
+		approvers.approversMutex.Unlock()
+	} else {
+		approvers.approversMutex.RUnlock()
+	}
+
+	return
+}
+
+func (approvers *Approvers) GetStorageKey() []byte {
+	transactionId := approvers.GetTransactionId()
+
+	return transactionId[:]
+}
+
+func (approvers *Approvers) Update(other objectstorage.StorableObject) {
+	panic("approvers should never be overwritten and only stored once to optimize IO")
+}
+
+func (approvers *Approvers) MarshalBinary() (result []byte, err error) {
+	return
+}
+
+func (approvers *Approvers) UnmarshalBinary(data []byte) (err error) {
+	return
+}
diff --git a/packages/binary/approvers/types.go b/packages/binary/approvers/types.go
new file mode 100644
index 00000000..99c78a42
--- /dev/null
+++ b/packages/binary/approvers/types.go
@@ -0,0 +1,5 @@
+package approvers
+
+type empty struct{}
+
+var void empty
diff --git a/packages/binary/identity/identity.go b/packages/binary/identity/identity.go
index 8cf7ce3a..fd52c6f3 100644
--- a/packages/binary/identity/identity.go
+++ b/packages/binary/identity/identity.go
@@ -20,9 +20,9 @@ func New(publicKey []byte, optionalPrivateKey ...[]byte) *Identity {
 	copy(this.PublicKey, publicKey)
 
 	if len(optionalPrivateKey) == 0 {
-		this.Type = PUBLIC_TYPE
+		this.Type = Public
 	} else {
-		this.Type = PRIVATE_TYPE
+		this.Type = Private
 		this.PrivateKey = optionalPrivateKey[0]
 	}
 
diff --git a/packages/binary/identity/identity_test.go b/packages/binary/identity/identity_test.go
index f53ed760..f5fc0d52 100644
--- a/packages/binary/identity/identity_test.go
+++ b/packages/binary/identity/identity_test.go
@@ -1,7 +1,6 @@
 package identity
 
 import (
-	"fmt"
 	"sync"
 	"testing"
 
@@ -37,8 +36,6 @@ func Test(t *testing.T) {
 
 	signature := identity.Sign([]byte("TESTDATA1"))
 
-	fmt.Println(len(signature))
-
 	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
index f89c4769..cc207b02 100644
--- a/packages/binary/identity/type.go
+++ b/packages/binary/identity/type.go
@@ -3,6 +3,6 @@ package identity
 type Type int
 
 const (
-	PRIVATE_TYPE = Type(0)
-	PUBLIC_TYPE  = Type(1)
+	Private = Type(0)
+	Public  = Type(1)
 )
diff --git a/packages/binary/tangle/tangle.go b/packages/binary/tangle/tangle.go
index 2d6210fc..1b4bbd41 100644
--- a/packages/binary/tangle/tangle.go
+++ b/packages/binary/tangle/tangle.go
@@ -1,17 +1,20 @@
 package tangle
 
 import (
+	"github.com/iotaledger/goshimmer/packages/binary/approvers"
 	"github.com/iotaledger/goshimmer/packages/binary/transaction"
 	"github.com/iotaledger/hive.go/objectstorage"
 )
 
 type Tangle struct {
 	transactionStorage *objectstorage.ObjectStorage
+	approversStorage   *objectstorage.ObjectStorage
 }
 
 func New(storageId string) *Tangle {
 	return &Tangle{
 		transactionStorage: objectstorage.New(storageId+"TANGLE_TRANSACTION_STORAGE", transactionFactory),
+		approversStorage:   objectstorage.New(storageId+"TANGLE_APPROVERS_STORAGE", approversFactory),
 	}
 }
 
@@ -20,3 +23,9 @@ func transactionFactory(key []byte) objectstorage.StorableObject {
 
 	return result
 }
+
+func approversFactory(key []byte) objectstorage.StorableObject {
+	result := approvers.FromStorage(key)
+
+	return result
+}
-- 
GitLab