Select Git revision
approvers.go
approvers.go 4.27 KiB
package approvers
import (
"encoding/binary"
"strconv"
"sync"
"github.com/iotaledger/goshimmer/packages/errors"
"github.com/iotaledger/goshimmer/packages/ternary"
"github.com/iotaledger/goshimmer/packages/typeutils"
)
type Approvers struct {
hash ternary.Trytes
hashes map[ternary.Trytes]bool
hashesMutex sync.RWMutex
modified bool
}
func New(hash ternary.Trytes) *Approvers {
return &Approvers{
hash: hash,
hashes: make(map[ternary.Trytes]bool),
modified: false,
}
}
// region public methods with locking //////////////////////////////////////////////////////////////////////////////////
func (approvers *Approvers) Add(transactionHash ternary.Trytes) {
approvers.hashesMutex.Lock()
approvers.add(transactionHash)
approvers.hashesMutex.Unlock()
}
func (approvers *Approvers) Remove(approverHash ternary.Trytes) {
approvers.hashesMutex.Lock()
approvers.remove(approverHash)
approvers.hashesMutex.Unlock()
}
func (approvers *Approvers) GetHashes() (result []ternary.Trytes) {
approvers.hashesMutex.RLock()
result = approvers.getHashes()
approvers.hashesMutex.RUnlock()
return
}
func (approvers *Approvers) GetHash() (result ternary.Trytes) {
approvers.hashesMutex.RLock()
result = approvers.hash
approvers.hashesMutex.RUnlock()
return
}
func (approvers *Approvers) GetModified() bool {
return true
}
func (approvers *Approvers) SetModified(modified bool) {
}
func (approvers *Approvers) Marshal() (result []byte) {
approvers.hashesMutex.RLock()
result = make([]byte, MARSHALED_APPROVERS_MIN_SIZE+len(approvers.hashes)*MARSHALED_APPROVERS_HASH_SIZE)
binary.BigEndian.PutUint64(result[MARSHALED_APPROVERS_HASHES_COUNT_START:MARSHALED_APPROVERS_HASHES_COUNT_END], uint64(len(approvers.hashes)))
copy(result[MARSHALED_APPROVERS_HASH_START:MARSHALED_APPROVERS_HASH_END], approvers.hash.CastToBytes())
i := 0
for hash := range approvers.hashes {
var HASH_START = MARSHALED_APPROVERS_HASHES_START + i*(MARSHALED_APPROVERS_HASH_SIZE)
var HASH_END = HASH_START + MARSHALED_APPROVERS_HASH_SIZE
copy(result[HASH_START:HASH_END], hash.CastToBytes())
i++
}
approvers.hashesMutex.RUnlock()
return
}
func (approvers *Approvers) Unmarshal(data []byte) (err errors.IdentifiableError) {
dataLen := len(data)
if dataLen < MARSHALED_APPROVERS_MIN_SIZE {
return ErrMarshallFailed.Derive(errors.New("unmarshall failed"), "marshaled approvers are too short")
}
hashesCount := binary.BigEndian.Uint64(data[MARSHALED_APPROVERS_HASHES_COUNT_START:MARSHALED_APPROVERS_HASHES_COUNT_END])
if dataLen < MARSHALED_APPROVERS_MIN_SIZE+int(hashesCount)*MARSHALED_APPROVERS_HASH_SIZE {
return ErrMarshallFailed.Derive(errors.New("unmarshall failed"), "marshaled approvers are too short for "+strconv.FormatUint(hashesCount, 10)+" approvers")
}
approvers.hashesMutex.Lock()
approvers.hash = ternary.Trytes(typeutils.BytesToString(data[MARSHALED_APPROVERS_HASH_START:MARSHALED_APPROVERS_HASH_END]))
approvers.hashes = make(map[ternary.Trytes]bool, hashesCount)
for i := uint64(0); i < hashesCount; i++ {
var HASH_START = MARSHALED_APPROVERS_HASHES_START + i*(MARSHALED_APPROVERS_HASH_SIZE)
var HASH_END = HASH_START + MARSHALED_APPROVERS_HASH_SIZE
approvers.hashes[ternary.Trytes(typeutils.BytesToString(data[HASH_START:HASH_END]))] = true
}
approvers.hashesMutex.Unlock()
return
}
// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
// region private methods without locking //////////////////////////////////////////////////////////////////////////////
func (approvers *Approvers) add(transactionHash ternary.Trytes) {
if _, exists := approvers.hashes[transactionHash]; !exists {
approvers.hashes[transactionHash] = true
approvers.modified = true
}
}
func (approvers *Approvers) remove(approverHash ternary.Trytes) {
if _, exists := approvers.hashes[approverHash]; exists {
delete(approvers.hashes, approverHash)
approvers.modified = true
}
}
func (approvers *Approvers) getHashes() (result []ternary.Trytes) {
result = make([]ternary.Trytes, len(approvers.hashes))
counter := 0
for hash := range approvers.hashes {
result[counter] = hash
counter++
}
return
}
// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////