Skip to content
Snippets Groups Projects
Commit 2c6c6d45 authored by Hans Moog's avatar Hans Moog
Browse files

Fix: fixed memory leak

parent 584569ef
Branches
Tags
No related merge requests found
Showing
with 614 additions and 101 deletions
...@@ -7,8 +7,12 @@ import ( ...@@ -7,8 +7,12 @@ import (
"github.com/iotaledger/goshimmer/plugins/cli" "github.com/iotaledger/goshimmer/plugins/cli"
"github.com/iotaledger/goshimmer/plugins/gossip" "github.com/iotaledger/goshimmer/plugins/gossip"
"github.com/iotaledger/goshimmer/plugins/gracefulshutdown" "github.com/iotaledger/goshimmer/plugins/gracefulshutdown"
"github.com/iotaledger/goshimmer/plugins/spammer"
"github.com/iotaledger/goshimmer/plugins/statusscreen" "github.com/iotaledger/goshimmer/plugins/statusscreen"
"github.com/iotaledger/goshimmer/plugins/tangle" "github.com/iotaledger/goshimmer/plugins/tangle"
"github.com/iotaledger/goshimmer/plugins/tipselection"
"github.com/iotaledger/goshimmer/plugins/webapi"
webapi_gtta "github.com/iotaledger/goshimmer/plugins/webapi-gtta"
) )
func main() { func main() {
...@@ -20,5 +24,10 @@ func main() { ...@@ -20,5 +24,10 @@ func main() {
analysis.PLUGIN, analysis.PLUGIN,
statusscreen.PLUGIN, statusscreen.PLUGIN,
gracefulshutdown.PLUGIN, gracefulshutdown.PLUGIN,
tipselection.PLUGIN,
spammer.PLUGIN,
webapi.PLUGIN,
webapi_gtta.PLUGIN,
) )
} }
...@@ -15,6 +15,7 @@ type HashRequest struct { ...@@ -15,6 +15,7 @@ type HashRequest struct {
type BatchHasher struct { type BatchHasher struct {
hashRequests chan HashRequest hashRequests chan HashRequest
tasks chan []HashRequest
hashLength int hashLength int
rounds int rounds int
} }
...@@ -24,13 +25,25 @@ func NewBatchHasher(hashLength int, rounds int) *BatchHasher { ...@@ -24,13 +25,25 @@ func NewBatchHasher(hashLength int, rounds int) *BatchHasher {
hashLength: hashLength, hashLength: hashLength,
rounds: rounds, rounds: rounds,
hashRequests: make(chan HashRequest), hashRequests: make(chan HashRequest),
tasks: make(chan []HashRequest, NUMBER_OF_WORKERS),
} }
go this.startDispatcher() go this.startDispatcher()
this.startWorkers()
return this return this
} }
func (this *BatchHasher) startWorkers() {
for i := 0; i < NUMBER_OF_WORKERS; i++ {
go func() {
for {
this.processHashes(<-this.tasks)
}
}()
}
}
func (this *BatchHasher) startDispatcher() { func (this *BatchHasher) startDispatcher() {
for { for {
collectedHashRequests := make([]HashRequest, 0) collectedHashRequests := make([]HashRequest, 0)
...@@ -53,7 +66,7 @@ func (this *BatchHasher) startDispatcher() { ...@@ -53,7 +66,7 @@ func (this *BatchHasher) startDispatcher() {
} }
} }
go this.processHashes(collectedHashRequests) this.tasks <- collectedHashRequests
} }
} }
...@@ -102,3 +115,7 @@ func (this *BatchHasher) Hash(trinary ternary.Trits) chan ternary.Trits { ...@@ -102,3 +115,7 @@ func (this *BatchHasher) Hash(trinary ternary.Trits) chan ternary.Trits {
return hashRequest.output return hashRequest.output
} }
const (
NUMBER_OF_WORKERS = 100
)
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
"sync" "sync"
"github.com/dgraph-io/badger" "github.com/dgraph-io/badger"
"github.com/dgraph-io/badger/options"
) )
var databasesByName = make(map[string]*databaseImpl) var databasesByName = make(map[string]*databaseImpl)
...@@ -58,6 +59,7 @@ func (this *databaseImpl) Open() error { ...@@ -58,6 +59,7 @@ func (this *databaseImpl) Open() error {
opts.ValueDir = opts.Dir opts.ValueDir = opts.Dir
opts.Logger = &logger{} opts.Logger = &logger{}
opts.Truncate = true opts.Truncate = true
opts.TableLoadingMode = options.MemoryMap
db, err := badger.Open(opts) db, err := badger.Open(opts)
if err != nil { if err != nil {
......
...@@ -238,22 +238,26 @@ func (list *DoublyLinkedList) removeEntry(entry *DoublyLinkedListEntry) errors.I ...@@ -238,22 +238,26 @@ func (list *DoublyLinkedList) removeEntry(entry *DoublyLinkedListEntry) errors.I
return ErrNoSuchElement.Derive("the entry is not part of the list") return ErrNoSuchElement.Derive("the entry is not part of the list")
} }
prevEntry := entry.GetPrev()
nextEntry := entry.GetNext() nextEntry := entry.GetNext()
if nextEntry != nil { if nextEntry != nil {
nextEntry.SetPrev(entry.GetPrev()) nextEntry.SetPrev(prevEntry)
} }
if list.head == entry { if list.head == entry {
list.head = nextEntry list.head = nextEntry
} }
prevEntry := entry.GetPrev()
if prevEntry != nil { if prevEntry != nil {
prevEntry.SetNext(entry.GetNext()) prevEntry.SetNext(nextEntry)
} }
if list.tail == entry { if list.tail == entry {
list.tail = prevEntry list.tail = prevEntry
} }
entry.SetNext(nil)
entry.SetPrev(nil)
list.count-- list.count--
return nil return nil
......
...@@ -14,14 +14,23 @@ type LRUCache struct { ...@@ -14,14 +14,23 @@ type LRUCache struct {
doublyLinkedList *DoublyLinkedList doublyLinkedList *DoublyLinkedList
capacity int capacity int
size int size int
options *LRUCacheOptions
mutex sync.RWMutex mutex sync.RWMutex
} }
func NewLRUCache(capacity int) *LRUCache { func NewLRUCache(capacity int, options ...*LRUCacheOptions) *LRUCache {
var currentOptions *LRUCacheOptions
if len(options) < 1 || options[0] == nil {
currentOptions = DEFAULT_OPTIONS
} else {
currentOptions = options[0]
}
return &LRUCache{ return &LRUCache{
directory: make(map[interface{}]*DoublyLinkedListEntry, capacity), directory: make(map[interface{}]*DoublyLinkedListEntry, capacity),
doublyLinkedList: &DoublyLinkedList{}, doublyLinkedList: &DoublyLinkedList{},
capacity: capacity, capacity: capacity,
options: currentOptions,
} }
} }
...@@ -49,7 +58,14 @@ func (cache *LRUCache) set(key interface{}, value interface{}) { ...@@ -49,7 +58,14 @@ func (cache *LRUCache) set(key interface{}, value interface{}) {
if element, err := cache.doublyLinkedList.removeLastEntry(); err != nil { if element, err := cache.doublyLinkedList.removeLastEntry(); err != nil {
panic(err) panic(err)
} else { } else {
delete(directory, element.value.(*lruCacheElement).key) lruCacheElement := element.value.(*lruCacheElement)
removedElementKey := lruCacheElement.key
delete(directory, removedElementKey)
if cache.options.EvictionCallback != nil {
cache.options.EvictionCallback(removedElementKey, lruCacheElement.value)
}
} }
} else { } else {
cache.size++ cache.size++
...@@ -85,8 +101,10 @@ func (cache *LRUCache) ComputeIfPresent(key interface{}, callback func(value int ...@@ -85,8 +101,10 @@ func (cache *LRUCache) ComputeIfPresent(key interface{}, callback func(value int
if entry, exists := cache.directory[key]; exists { if entry, exists := cache.directory[key]; exists {
result = entry.GetValue().(*lruCacheElement).value result = entry.GetValue().(*lruCacheElement).value
if result = callback(result); result != nil { if callbackResult := callback(result); result != nil {
cache.set(key, result) result = callbackResult
cache.set(key, callbackResult)
} else { } else {
if err := cache.doublyLinkedList.removeEntry(entry); err != nil { if err := cache.doublyLinkedList.removeEntry(entry); err != nil {
panic(err) panic(err)
...@@ -94,6 +112,10 @@ func (cache *LRUCache) ComputeIfPresent(key interface{}, callback func(value int ...@@ -94,6 +112,10 @@ func (cache *LRUCache) ComputeIfPresent(key interface{}, callback func(value int
delete(cache.directory, key) delete(cache.directory, key)
cache.size-- cache.size--
if cache.options.EvictionCallback != nil {
cache.options.EvictionCallback(key, result)
}
} }
} else { } else {
result = nil result = nil
...@@ -166,6 +188,10 @@ func (cache *LRUCache) Delete(key interface{}) bool { ...@@ -166,6 +188,10 @@ func (cache *LRUCache) Delete(key interface{}) bool {
cache.size-- cache.size--
if cache.options.EvictionCallback != nil {
cache.options.EvictionCallback(key, entry.GetValue().(*lruCacheElement).key)
}
return true return true
} }
......
package datastructure
import (
"time"
)
type LRUCacheOptions struct {
EvictionCallback func(key interface{}, value interface{})
IdleTimeout time.Duration
}
var DEFAULT_OPTIONS = &LRUCacheOptions{
EvictionCallback: nil,
IdleTimeout: 30 * time.Second,
}
package datastructure
import (
"math/rand"
"sync"
"time"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
type randomMapEntry struct {
key interface{}
value interface{}
keyIndex int
}
type RandomMap struct {
rawMap map[interface{}]*randomMapEntry
keys []interface{}
size int
mutex sync.RWMutex
}
func NewRandomMap() *RandomMap {
return &RandomMap{
rawMap: make(map[interface{}]*randomMapEntry),
keys: make([]interface{}, 0),
}
}
func (rmap *RandomMap) Set(key interface{}, value interface{}) {
rmap.mutex.Lock()
if entry, exists := rmap.rawMap[key]; exists {
entry.value = value
} else {
rmap.rawMap[key] = &randomMapEntry{
key: key,
value: value,
keyIndex: rmap.size,
}
rmap.keys = append(rmap.keys, key)
rmap.size++
}
rmap.mutex.Unlock()
}
func (rmap *RandomMap) Get(key interface{}) (result interface{}, exists bool) {
rmap.mutex.RLock()
if entry, entryExists := rmap.rawMap[key]; entryExists {
result = entry.value
exists = entryExists
}
rmap.mutex.RUnlock()
return
}
func (rmap *RandomMap) Delete(key interface{}) (result interface{}, exists bool) {
rmap.mutex.RLock()
if _, entryExists := rmap.rawMap[key]; entryExists {
rmap.mutex.RUnlock()
rmap.mutex.Lock()
if entry, entryExists := rmap.rawMap[key]; entryExists {
delete(rmap.rawMap, key)
rmap.size--
if entry.keyIndex != rmap.size {
oldKey := entry.keyIndex
movedKey := rmap.keys[rmap.size]
rmap.rawMap[movedKey].keyIndex = oldKey
rmap.keys[oldKey] = movedKey
}
rmap.keys = rmap.keys[:rmap.size]
result = entry.value
exists = true
}
rmap.mutex.Unlock()
} else {
rmap.mutex.RUnlock()
}
return
}
func (rmap *RandomMap) Size() (result int) {
rmap.mutex.RLock()
result = rmap.size
rmap.mutex.RUnlock()
return
}
func (rmap *RandomMap) RandomEntry() (result interface{}) {
rmap.mutex.RLock()
if rmap.size >= 1 {
result = rmap.rawMap[rmap.keys[rand.Intn(rmap.size)]].value
}
rmap.mutex.RUnlock()
return
}
...@@ -3,8 +3,23 @@ package events ...@@ -3,8 +3,23 @@ package events
import ( import (
"fmt" "fmt"
"strconv" "strconv"
"testing"
) )
func BenchmarkEvent_Trigger(b *testing.B) {
event := NewEvent(intStringCaller)
event.Attach(NewClosure(func(param1 int, param2 string) {
// do nothing just get called
}))
b.ResetTimer()
for i := 0; i < b.N; i++ {
event.Trigger(4, "test")
}
}
// define how the event converts the generic parameters to the typed params - ugly but go has no generics :( // define how the event converts the generic parameters to the typed params - ugly but go has no generics :(
func intStringCaller(handler interface{}, params ...interface{}) { func intStringCaller(handler interface{}, params ...interface{}) {
handler.(func(int, string))(params[0].(int), params[1].(string)) handler.(func(int, string))(params[0].(int), params[1].(string))
......
package meta_transaction package meta_transaction
import (
"github.com/iotaledger/goshimmer/packages/ternary"
)
const ( const (
SHARD_MARKER_OFFSET = 0 SHARD_MARKER_OFFSET = 0
TRUNK_TRANSACTION_HASH_OFFSET = SHARD_MARKER_END TRUNK_TRANSACTION_HASH_OFFSET = SHARD_MARKER_END
...@@ -9,13 +13,13 @@ const ( ...@@ -9,13 +13,13 @@ const (
TRANSACTION_TYPE_OFFSET = TAIL_END TRANSACTION_TYPE_OFFSET = TAIL_END
DATA_OFFSET = TRANSACTION_TYPE_END DATA_OFFSET = TRANSACTION_TYPE_END
SHARD_MARKER_SIZE = 12 SHARD_MARKER_SIZE = 11
TRUNK_TRANSACTION_HASH_SIZE = 243 TRUNK_TRANSACTION_HASH_SIZE = 243
BRANCH_TRANSACTION_HASH_SIZE = 243 BRANCH_TRANSACTION_HASH_SIZE = 243
HEAD_SIZE = 1 HEAD_SIZE = 1
TAIL_SIZE = 1 TAIL_SIZE = 1
TRANSACTION_TYPE_SIZE = 22 TRANSACTION_TYPE_SIZE = 8
DATA_SIZE = 5000 DATA_SIZE = 6993
SHARD_MARKER_END = SHARD_MARKER_OFFSET + SHARD_MARKER_SIZE SHARD_MARKER_END = SHARD_MARKER_OFFSET + SHARD_MARKER_SIZE
TRUNK_TRANSACTION_HASH_END = TRUNK_TRANSACTION_HASH_OFFSET + TRUNK_TRANSACTION_HASH_SIZE TRUNK_TRANSACTION_HASH_END = TRUNK_TRANSACTION_HASH_OFFSET + TRUNK_TRANSACTION_HASH_SIZE
...@@ -26,4 +30,6 @@ const ( ...@@ -26,4 +30,6 @@ const (
DATA_END = DATA_OFFSET + DATA_SIZE DATA_END = DATA_OFFSET + DATA_SIZE
MARSHALLED_TOTAL_SIZE = DATA_END MARSHALLED_TOTAL_SIZE = DATA_END
BRANCH_NULL_HASH = ternary.Trinary("999999999999999999999999999999999999999999999999999999999999999999999999999999999")
) )
...@@ -53,11 +53,11 @@ func FromBytes(bytes []byte) (result *MetaTransaction) { ...@@ -53,11 +53,11 @@ func FromBytes(bytes []byte) (result *MetaTransaction) {
return return
} }
func (this *MetaTransaction) LockHasher() { func (this *MetaTransaction) BlockHasher() {
this.hasherMutex.RLock() this.hasherMutex.RLock()
} }
func (this *MetaTransaction) UnlockHasher() { func (this *MetaTransaction) UnblockHasher() {
this.hasherMutex.RUnlock() this.hasherMutex.RUnlock()
} }
...@@ -120,8 +120,6 @@ func (this *MetaTransaction) parseHashRelatedDetails() { ...@@ -120,8 +120,6 @@ func (this *MetaTransaction) parseHashRelatedDetails() {
this.hash = &hashTrinary this.hash = &hashTrinary
this.weightMagnitude = hashTrits.TrailingZeroes() this.weightMagnitude = hashTrits.TrailingZeroes()
return
} }
// getter for the shard marker (supports concurrency) // getter for the shard marker (supports concurrency)
...@@ -454,7 +452,7 @@ func (this *MetaTransaction) GetBytes() (result []byte) { ...@@ -454,7 +452,7 @@ func (this *MetaTransaction) GetBytes() (result []byte) {
this.bytes = this.trits.ToBytes() this.bytes = this.trits.ToBytes()
this.hasherMutex.Unlock() this.hasherMutex.Unlock()
} else { } else {
this.hasherMutex.RUnlock() this.bytesMutex.RUnlock()
} }
result = make([]byte, len(this.bytes)) result = make([]byte, len(this.bytes))
......
...@@ -41,9 +41,9 @@ func BenchmarkMetaTransaction_GetHash(b *testing.B) { ...@@ -41,9 +41,9 @@ func BenchmarkMetaTransaction_GetHash(b *testing.B) {
var waitGroup sync.WaitGroup var waitGroup sync.WaitGroup
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
go func() { waitGroup.Add(1)
waitGroup.Add(1)
go func() {
New().GetHash() New().GetHash()
waitGroup.Done() waitGroup.Done()
......
package transaction package value_transaction
const ( const (
// sizes of the transaction fields ADDRESS_OFFSET = 0
SIGNATURE_MESSAGE_FRAGMENT_SIZE = 6561 VALUE_OFFSET = ADDRESS_END
TIMESTAMP_OFFSET = VALUE_END
NONCE_OFFSET = TIMESTAMP_END
SIGNATURE_MESSAGE_FRAGMENT_OFFSET = NONCE_END
ADDRESS_SIZE = 243 ADDRESS_SIZE = 243
VALUE_SIZE = 81 VALUE_SIZE = 81
TIMESTAMP_SIZE = 27 TIMESTAMP_SIZE = 27
CURRENT_INDEX_SIZE = 27
LATEST_INDEX_SIZE = 27
BUNDLE_HASH_SIZE = 243
TRUNK_TRANSACTION_HASH_SIZE = 243
BRANCH_TRANSACTION_HASH_SIZE = 243
TAG_SIZE = 81
NONCE_SIZE = 81 NONCE_SIZE = 81
SIGNATURE_MESSAGE_FRAGMENT_SIZE = 6561
// offsets of the transaction fields
SIGNATURE_MESSAGE_FRAGMENT_OFFSET = 0
ADDRESS_OFFSET = SIGNATURE_MESSAGE_FRAGMENT_END
VALUE_OFFSET = ADDRESS_END
TIMESTAMP_OFFSET = VALUE_END
CURRENT_INDEX_OFFSET = TIMESTAMP_END
LATEST_INDEX_OFFSET = CURRENT_INDEX_END
BUNDLE_HASH_OFFSET = LATEST_INDEX_END
TRUNK_TRANSACTION_HASH_OFFSET = BUNDLE_HASH_END
BRANCH_TRANSACTION_HASH_OFFSET = TRUNK_TRANSACTION_HASH_END
TAG_OFFSET = BRANCH_TRANSACTION_HASH_END
NONCE_OFFSET = TAG_END
// ends of the transaction fields
SIGNATURE_MESSAGE_FRAGMENT_END = SIGNATURE_MESSAGE_FRAGMENT_OFFSET + SIGNATURE_MESSAGE_FRAGMENT_SIZE
ADDRESS_END = ADDRESS_OFFSET + ADDRESS_SIZE ADDRESS_END = ADDRESS_OFFSET + ADDRESS_SIZE
VALUE_END = VALUE_OFFSET + VALUE_SIZE VALUE_END = VALUE_OFFSET + VALUE_SIZE
TIMESTAMP_END = TIMESTAMP_OFFSET + TIMESTAMP_SIZE TIMESTAMP_END = TIMESTAMP_OFFSET + TIMESTAMP_SIZE
CURRENT_INDEX_END = CURRENT_INDEX_OFFSET + CURRENT_INDEX_SIZE
LATEST_INDEX_END = LATEST_INDEX_OFFSET + LATEST_INDEX_SIZE
BUNDLE_HASH_END = BUNDLE_HASH_OFFSET + BUNDLE_HASH_SIZE
TRUNK_TRANSACTION_HASH_END = TRUNK_TRANSACTION_HASH_OFFSET + TRUNK_TRANSACTION_HASH_SIZE
BRANCH_TRANSACTION_HASH_END = BRANCH_TRANSACTION_HASH_OFFSET + BRANCH_TRANSACTION_HASH_SIZE
TAG_END = TAG_OFFSET + TAG_SIZE
NONCE_END = NONCE_OFFSET + NONCE_SIZE NONCE_END = NONCE_OFFSET + NONCE_SIZE
SIGNATURE_MESSAGE_FRAGMENT_END = SIGNATURE_MESSAGE_FRAGMENT_OFFSET + SIGNATURE_MESSAGE_FRAGMENT_SIZE
// the full size of a transaction TOTAL_SIZE = SIGNATURE_MESSAGE_FRAGMENT_END
MARSHALLED_TOTAL_SIZE = NONCE_END
) )
package value_transaction package value_transaction
import ( import (
"sync"
"github.com/iotaledger/goshimmer/packages/model/meta_transaction" "github.com/iotaledger/goshimmer/packages/model/meta_transaction"
"github.com/iotaledger/goshimmer/packages/ternary" "github.com/iotaledger/goshimmer/packages/ternary"
) )
...@@ -8,7 +10,18 @@ import ( ...@@ -8,7 +10,18 @@ import (
type ValueTransaction struct { type ValueTransaction struct {
*meta_transaction.MetaTransaction *meta_transaction.MetaTransaction
data ternary.Trits address *ternary.Trinary
addressMutex sync.RWMutex
value *int64
valueMutex sync.RWMutex
timestamp *uint
timestampMutex sync.RWMutex
nonce *ternary.Trinary
nonceMutex sync.RWMutex
signatureMessageFragment *ternary.Trinary
signatureMessageFragmentMutex sync.RWMutex
trits ternary.Trits
} }
func New() (result *ValueTransaction) { func New() (result *ValueTransaction) {
...@@ -16,7 +29,256 @@ func New() (result *ValueTransaction) { ...@@ -16,7 +29,256 @@ func New() (result *ValueTransaction) {
MetaTransaction: meta_transaction.New(), MetaTransaction: meta_transaction.New(),
} }
result.data = result.MetaTransaction.GetData() result.trits = result.MetaTransaction.GetData()
return
}
func FromMetaTransaction(metaTransaction *meta_transaction.MetaTransaction) *ValueTransaction {
return &ValueTransaction{
MetaTransaction: metaTransaction,
}
}
func FromBytes(bytes []byte) (result *ValueTransaction) {
result = &ValueTransaction{
MetaTransaction: meta_transaction.FromTrits(ternary.BytesToTrits(bytes)[:meta_transaction.MARSHALLED_TOTAL_SIZE]),
}
return return
} }
// getter for the address (supports concurrency)
func (this *ValueTransaction) GetAddress() (result ternary.Trinary) {
this.addressMutex.RLock()
if this.address == nil {
this.addressMutex.RUnlock()
this.addressMutex.Lock()
defer this.addressMutex.Unlock()
if this.address == nil {
address := this.trits[ADDRESS_OFFSET:ADDRESS_END].ToTrinary()
this.address = &address
}
} else {
defer this.addressMutex.RUnlock()
}
result = *this.address
return
}
// setter for the address (supports concurrency)
func (this *ValueTransaction) SetAddress(address ternary.Trinary) bool {
this.addressMutex.RLock()
if this.address == nil || *this.address != address {
this.addressMutex.RUnlock()
this.addressMutex.Lock()
defer this.addressMutex.Unlock()
if this.address == nil || *this.address != address {
this.address = &address
this.BlockHasher()
copy(this.trits[ADDRESS_OFFSET:ADDRESS_END], address.ToTrits()[:ADDRESS_SIZE])
this.UnblockHasher()
this.SetModified(true)
this.ReHash()
return true
}
} else {
this.addressMutex.RUnlock()
}
return false
}
// getter for the value (supports concurrency)
func (this *ValueTransaction) GetValue() (result int64) {
this.valueMutex.RLock()
if this.value == nil {
this.valueMutex.RUnlock()
this.valueMutex.Lock()
defer this.valueMutex.Unlock()
if this.value == nil {
value := this.trits[VALUE_OFFSET:VALUE_END].ToInt64()
this.value = &value
}
} else {
defer this.valueMutex.RUnlock()
}
result = *this.value
return
}
// setter for the value (supports concurrency)
func (this *ValueTransaction) SetValue(value int64) bool {
this.valueMutex.RLock()
if this.value == nil || *this.value != value {
this.valueMutex.RUnlock()
this.valueMutex.Lock()
defer this.valueMutex.Unlock()
if this.value == nil || *this.value != value {
this.value = &value
this.BlockHasher()
copy(this.trits[VALUE_OFFSET:VALUE_END], ternary.Int64ToTrits(value)[:VALUE_SIZE])
this.UnblockHasher()
this.SetModified(true)
this.ReHash()
return true
}
} else {
this.valueMutex.RUnlock()
}
return false
}
// getter for the timestamp (supports concurrency)
func (this *ValueTransaction) GetTimestamp() (result uint) {
this.timestampMutex.RLock()
if this.timestamp == nil {
this.timestampMutex.RUnlock()
this.timestampMutex.Lock()
defer this.timestampMutex.Unlock()
if this.timestamp == nil {
timestamp := this.trits[TIMESTAMP_OFFSET:TIMESTAMP_END].ToUint()
this.timestamp = &timestamp
}
} else {
defer this.timestampMutex.RUnlock()
}
result = *this.timestamp
return
}
// setter for the timestamp (supports concurrency)
func (this *ValueTransaction) SetTimestamp(timestamp uint) bool {
this.timestampMutex.RLock()
if this.timestamp == nil || *this.timestamp != timestamp {
this.timestampMutex.RUnlock()
this.timestampMutex.Lock()
defer this.timestampMutex.Unlock()
if this.timestamp == nil || *this.timestamp != timestamp {
this.timestamp = &timestamp
this.BlockHasher()
copy(this.trits[TIMESTAMP_OFFSET:TIMESTAMP_END], ternary.UintToTrits(timestamp)[:TIMESTAMP_SIZE])
this.UnblockHasher()
this.SetModified(true)
this.ReHash()
return true
}
} else {
this.timestampMutex.RUnlock()
}
return false
}
// getter for the nonce (supports concurrency)
func (this *ValueTransaction) GetNonce() (result ternary.Trinary) {
this.nonceMutex.RLock()
if this.nonce == nil {
this.nonceMutex.RUnlock()
this.nonceMutex.Lock()
defer this.nonceMutex.Unlock()
if this.nonce == nil {
nonce := this.trits[NONCE_OFFSET:NONCE_END].ToTrinary()
this.nonce = &nonce
}
} else {
defer this.nonceMutex.RUnlock()
}
result = *this.nonce
return
}
// setter for the nonce (supports concurrency)
func (this *ValueTransaction) SetNonce(nonce ternary.Trinary) bool {
this.nonceMutex.RLock()
if this.nonce == nil || *this.nonce != nonce {
this.nonceMutex.RUnlock()
this.nonceMutex.Lock()
defer this.nonceMutex.Unlock()
if this.nonce == nil || *this.nonce != nonce {
this.nonce = &nonce
this.BlockHasher()
copy(this.trits[NONCE_OFFSET:NONCE_END], nonce.ToTrits()[:NONCE_SIZE])
this.UnblockHasher()
this.SetModified(true)
this.ReHash()
return true
}
} else {
this.nonceMutex.RUnlock()
}
return false
}
// getter for the signatureMessageFragmetn (supports concurrency)
func (this *ValueTransaction) GetSignatureMessageFragment() (result ternary.Trinary) {
this.signatureMessageFragmentMutex.RLock()
if this.signatureMessageFragment == nil {
this.signatureMessageFragmentMutex.RUnlock()
this.signatureMessageFragmentMutex.Lock()
defer this.signatureMessageFragmentMutex.Unlock()
if this.signatureMessageFragment == nil {
signatureMessageFragment := this.trits[SIGNATURE_MESSAGE_FRAGMENT_OFFSET:SIGNATURE_MESSAGE_FRAGMENT_END].ToTrinary()
this.signatureMessageFragment = &signatureMessageFragment
}
} else {
defer this.signatureMessageFragmentMutex.RUnlock()
}
result = *this.signatureMessageFragment
return
}
// setter for the nonce (supports concurrency)
func (this *ValueTransaction) SetSignatureMessageFragment(signatureMessageFragment ternary.Trinary) bool {
this.signatureMessageFragmentMutex.RLock()
if this.signatureMessageFragment == nil || *this.signatureMessageFragment != signatureMessageFragment {
this.signatureMessageFragmentMutex.RUnlock()
this.signatureMessageFragmentMutex.Lock()
defer this.signatureMessageFragmentMutex.Unlock()
if this.signatureMessageFragment == nil || *this.signatureMessageFragment != signatureMessageFragment {
this.signatureMessageFragment = &signatureMessageFragment
this.BlockHasher()
copy(this.trits[SIGNATURE_MESSAGE_FRAGMENT_OFFSET:SIGNATURE_MESSAGE_FRAGMENT_END], signatureMessageFragment.ToTrits()[:SIGNATURE_MESSAGE_FRAGMENT_SIZE])
this.UnblockHasher()
this.SetModified(true)
this.ReHash()
return true
}
} else {
this.signatureMessageFragmentMutex.RUnlock()
}
return false
}
...@@ -8,27 +8,15 @@ import ( ...@@ -8,27 +8,15 @@ import (
"github.com/magiconair/properties/assert" "github.com/magiconair/properties/assert"
) )
func TestMetaTransaction_SettersGetters(t *testing.T) { func TestValueTransaction_SettersGetters(t *testing.T) {
shardMarker := ternary.Trinary("NPHTQORL9XKA") address := ternary.Trinary("A9999999999999999999999999999999999999999999999999999999999999999999999999999999F")
trunkTransactionHash := ternary.Trinary("99999999999999999999999999999999999999999999999999999999999999999999999999999999A")
branchTransactionHash := ternary.Trinary("99999999999999999999999999999999999999999999999999999999999999999999999999999999B")
head := true
tail := true
transaction := New() transaction := New()
transaction.SetShardMarker(shardMarker) transaction.SetAddress(address)
transaction.SetTrunkTransactionHash(trunkTransactionHash)
transaction.SetBranchTransactionHash(branchTransactionHash)
transaction.SetHead(head)
transaction.SetTail(tail)
assert.Equal(t, transaction.GetWeightMagnitude(), 0) assert.Equal(t, transaction.GetAddress(), address)
assert.Equal(t, transaction.GetShardMarker(), shardMarker)
assert.Equal(t, transaction.GetTrunkTransactionHash(), trunkTransactionHash)
assert.Equal(t, transaction.GetBranchTransactionHash(), branchTransactionHash)
assert.Equal(t, transaction.GetHead(), head)
assert.Equal(t, transaction.GetTail(), tail)
//assert.Equal(t, transaction.GetHash(), FromBytes(transaction.GetBytes()).GetHash()) //assert.Equal(t, transaction.GetHash(), FromBytes(transaction.GetBytes()).GetHash())
fmt.Println(transaction.GetHash()) fmt.Println(transaction.GetHash())
fmt.Println(transaction.GetAddress())
} }
package ternary package ternary
import "bytes" import (
"bytes"
)
const ( const (
NUMBER_OF_TRITS_IN_A_BYTE = 5 NUMBER_OF_TRITS_IN_A_BYTE = 5
...@@ -111,6 +113,58 @@ func BytesToTrits(bytes []byte) Trits { ...@@ -111,6 +113,58 @@ func BytesToTrits(bytes []byte) Trits {
return trits return trits
} }
func Int64ToTrits(value int64) (result Trits) {
negative := value < 0
shiftedValue := value >> 63
valueAbs := (value ^ shiftedValue) - shiftedValue
for valueAbs != 0 {
trit := Trit((valueAbs+1)%3 - 1)
if negative {
trit = -trit
}
result = append(result, trit)
valueAbs++
valueAbs /= 3
}
for i := len(result); i < 81; i++ {
result = append(result, 0)
}
return
}
func UintToTrits(value uint) (result Trits) {
for value != 0 {
trit := Trit((value+1)%3 - 1)
result = append(result, trit)
value++
value /= 3
}
for i := len(result); i < 27; i++ {
result = append(result, 0)
}
return
}
func Uint64ToTrits(value uint64) (result Trits) {
for value != 0 {
trit := Trit((value+1)%3 - 1)
result = append(result, trit)
value++
value /= 3
}
for i := len(result); i < 81; i++ {
result = append(result, 0)
}
return
}
func TritsToString(trits Trits, offset int, size int) string { func TritsToString(trits Trits, offset int, size int) string {
var buffer bytes.Buffer var buffer bytes.Buffer
for i := 0; i < (size+NUMBER_OF_TRITS_IN_A_TRYTE-1)/NUMBER_OF_TRITS_IN_A_TRYTE; i++ { for i := 0; i < (size+NUMBER_OF_TRITS_IN_A_TRYTE-1)/NUMBER_OF_TRITS_IN_A_TRYTE; i++ {
......
package ternary
import (
"testing"
"github.com/magiconair/properties/assert"
)
func TestInt64Conversion(t *testing.T) {
assert.Equal(t, Int64ToTrits(9223372036854775807).ToInt64(), int64(9223372036854775807))
assert.Equal(t, Int64ToTrits(1337).ToInt64(), int64(1337))
assert.Equal(t, Int64ToTrits(0).ToInt64(), int64(0))
assert.Equal(t, Int64ToTrits(-1337).ToInt64(), int64(-1337))
assert.Equal(t, Int64ToTrits(-9223372036854775808).ToInt64(), int64(-9223372036854775808))
}
func TestUInt64Conversion(t *testing.T) {
assert.Equal(t, Uint64ToTrits(18446744073709551615).ToUint64(), uint64(18446744073709551615))
assert.Equal(t, Uint64ToTrits(1337).ToUint64(), uint64(1337))
assert.Equal(t, Uint64ToTrits(0).ToUint64(), uint64(0))
}
...@@ -66,6 +66,14 @@ func (this Trits) TrailingZeroes() int { ...@@ -66,6 +66,14 @@ func (this Trits) TrailingZeroes() int {
return zeros return zeros
} }
func (this Trits) ToUint() (result uint) {
for i := len(this) - 1; i >= 0; i-- {
result = result*3 + uint(this[i])
}
return
}
func (this Trits) ToInt64() int64 { func (this Trits) ToInt64() int64 {
var val int64 var val int64
for i := len(this) - 1; i >= 0; i-- { for i := len(this) - 1; i >= 0; i-- {
......
package transaction
import (
"github.com/iotaledger/goshimmer/packages/curl"
"github.com/iotaledger/goshimmer/packages/ternary"
)
type Transaction struct {
SignatureMessageFragment ternary.Trits
Address ternary.Trits
Value ternary.Trits
Timestamp ternary.Trits
CurrentIndex ternary.Trits
LatestIndex ternary.Trits
BundleHash ternary.Trits
TrunkTransactionHash ternary.Trits
BranchTransactionHash ternary.Trits
Tag ternary.Trits
Nonce ternary.Trits
Hash ternary.Trits
WeightMagnitude int
Bytes []byte
Trits ternary.Trits
}
func FromTrits(trits ternary.Trits, optionalHash ...ternary.Trits) *Transaction {
hash := <-curl.CURLP81.Hash(trits)
transaction := &Transaction{
SignatureMessageFragment: trits[SIGNATURE_MESSAGE_FRAGMENT_OFFSET:SIGNATURE_MESSAGE_FRAGMENT_END],
Address: trits[ADDRESS_OFFSET:ADDRESS_END],
Value: trits[VALUE_OFFSET:VALUE_END],
Timestamp: trits[TIMESTAMP_OFFSET:TIMESTAMP_END],
CurrentIndex: trits[CURRENT_INDEX_OFFSET:CURRENT_INDEX_END],
LatestIndex: trits[LATEST_INDEX_OFFSET:LATEST_INDEX_END],
BundleHash: trits[BUNDLE_HASH_OFFSET:BUNDLE_HASH_END],
TrunkTransactionHash: trits[TRUNK_TRANSACTION_HASH_OFFSET:TRUNK_TRANSACTION_HASH_END],
BranchTransactionHash: trits[BRANCH_TRANSACTION_HASH_OFFSET:BRANCH_TRANSACTION_HASH_END],
Tag: trits[TAG_OFFSET:TAG_END],
Nonce: trits[NONCE_OFFSET:NONCE_END],
Hash: hash,
WeightMagnitude: hash.TrailingZeroes(),
Trits: trits,
}
return transaction
}
func FromBytes(bytes []byte) *Transaction {
transaction := FromTrits(ternary.BytesToTrits(bytes)[:MARSHALLED_TOTAL_SIZE])
transaction.Bytes = bytes
return transaction
}
...@@ -4,8 +4,8 @@ import ( ...@@ -4,8 +4,8 @@ import (
"github.com/iotaledger/goshimmer/packages/errors" "github.com/iotaledger/goshimmer/packages/errors"
"github.com/iotaledger/goshimmer/packages/events" "github.com/iotaledger/goshimmer/packages/events"
"github.com/iotaledger/goshimmer/packages/identity" "github.com/iotaledger/goshimmer/packages/identity"
"github.com/iotaledger/goshimmer/packages/model/meta_transaction"
"github.com/iotaledger/goshimmer/packages/network" "github.com/iotaledger/goshimmer/packages/network"
"github.com/iotaledger/goshimmer/packages/transaction"
) )
var Events = pluginEvents{ var Events = pluginEvents{
...@@ -93,5 +93,5 @@ func dataCaller(handler interface{}, params ...interface{}) { ...@@ -93,5 +93,5 @@ func dataCaller(handler interface{}, params ...interface{}) {
} }
func transactionCaller(handler interface{}, params ...interface{}) { func transactionCaller(handler interface{}, params ...interface{}) {
handler.(func(*transaction.Transaction))(params[0].(*transaction.Transaction)) handler.(func(*meta_transaction.MetaTransaction))(params[0].(*meta_transaction.MetaTransaction))
} }
...@@ -181,7 +181,7 @@ func (neighbor *Neighbor) Marshal() []byte { ...@@ -181,7 +181,7 @@ func (neighbor *Neighbor) Marshal() []byte {
} }
func (neighbor *Neighbor) Equals(other *Neighbor) bool { func (neighbor *Neighbor) Equals(other *Neighbor) bool {
return neighbor.Identity.StringIdentifier == neighbor.Identity.StringIdentifier && return neighbor.Identity.StringIdentifier == other.Identity.StringIdentifier &&
neighbor.Port == other.Port && neighbor.Address.String() == other.Address.String() neighbor.Port == other.Port && neighbor.Address.String() == other.Address.String()
} }
...@@ -195,11 +195,11 @@ func AddNeighbor(newNeighbor *Neighbor) { ...@@ -195,11 +195,11 @@ func AddNeighbor(newNeighbor *Neighbor) {
Events.AddNeighbor.Trigger(newNeighbor) Events.AddNeighbor.Trigger(newNeighbor)
} else { } else {
if !newNeighbor.Equals(neighbor) { if !newNeighbor.Equals(neighbor) {
neighbor.Identity = neighbor.Identity neighbor.Identity = newNeighbor.Identity
neighbor.Port = neighbor.Port neighbor.Port = newNeighbor.Port
neighbor.Address = neighbor.Address neighbor.Address = newNeighbor.Address
Events.UpdateNeighbor.Trigger(newNeighbor) Events.UpdateNeighbor.Trigger(neighbor)
} }
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment