Skip to content
Snippets Groups Projects
approvers.go 3.86 KiB
package approvers_old

import (
	"encoding/binary"
	"sync"

	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/transaction"
	"github.com/iotaledger/goshimmer/packages/binary/types"

	"github.com/iotaledger/hive.go/objectstorage"
)

type Approvers struct {
	objectstorage.StorableObjectFlags

	transactionId  transaction.Id
	approvers      map[transaction.Id]types.Empty
	approversMutex sync.RWMutex
}

func New(transactionId transaction.Id) *Approvers {
	return &Approvers{
		transactionId: transactionId,
		approvers:     make(map[transaction.Id]types.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 objectstorage.StorableObject) {
	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]types.Empty) {
	approvers.approversMutex.RLock()
	result = make(map[transaction.Id]types.Empty, len(approvers.approvers))
	for approverId := range approvers.approvers {
		result[approverId] = types.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] = types.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) Size() (result int) {
	approvers.approversMutex.RLock()
	result = len(approvers.approvers)
	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) {
	approvers.approversMutex.RLock()

	approversCount := len(approvers.approvers)
	result = make([]byte, 4+approversCount*transaction.IdLength)
	offset := 0

	binary.LittleEndian.PutUint32(result[offset:], uint32(approversCount))
	offset += 4

	for approverId := range approvers.approvers {
		marshaledBytes, marshalErr := approverId.MarshalBinary()
		if marshalErr != nil {
			err = marshalErr

			approvers.approversMutex.RUnlock()

			return
		}

		copy(result[offset:], marshaledBytes)
		offset += len(marshaledBytes)
	}

	approvers.approversMutex.RUnlock()

	return
}

func (approvers *Approvers) UnmarshalBinary(data []byte) (err error) {
	approvers.approvers = make(map[transaction.Id]types.Empty)
	offset := 0

	approversCount := int(binary.LittleEndian.Uint32(data[offset:]))
	offset += 4

	for i := 0; i < approversCount; i++ {
		var approverId transaction.Id
		if err = approverId.UnmarshalBinary(data[offset:]); err != nil {
			return
		}
		offset += transaction.IdLength

		approvers.approvers[approverId] = types.Void
	}

	return
}