diff --git a/dapps/faucet/packages/faucet.go b/dapps/faucet/packages/faucet.go index b8f40d4f7af64a6f1797fe5e279714640499bbd4..2e4d57e448dd16f27abe05606f4a16b8a2f595ab 100644 --- a/dapps/faucet/packages/faucet.go +++ b/dapps/faucet/packages/faucet.go @@ -14,9 +14,9 @@ import ( "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/balance" "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/tangle" "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction" - "github.com/iotaledger/goshimmer/packages/binary/datastructure/orderedmap" "github.com/iotaledger/goshimmer/packages/binary/messagelayer/message" "github.com/iotaledger/goshimmer/plugins/issuer" + "github.com/iotaledger/hive.go/datastructure/orderedmap" ) var ( diff --git a/dapps/valuetransfers/packages/tipmanager/tipmanager.go b/dapps/valuetransfers/packages/tipmanager/tipmanager.go index 41d9cda9f6e7ea0504c18b2fda9b25196bb06853..805cde39f5a568a30b38be43b2f62bca1577ad89 100644 --- a/dapps/valuetransfers/packages/tipmanager/tipmanager.go +++ b/dapps/valuetransfers/packages/tipmanager/tipmanager.go @@ -2,21 +2,21 @@ package tipmanager import ( "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/payload" - "github.com/iotaledger/goshimmer/packages/binary/datastructure" + "github.com/iotaledger/hive.go/datastructure/randommap" "github.com/iotaledger/hive.go/events" ) // TipManager manages liked tips and emits events for their removal and addition. type TipManager struct { // tips are all currently liked tips. - tips *datastructure.RandomMap + tips *randommap.RandomMap Events Events } // New creates a new TipManager. func New() *TipManager { return &TipManager{ - tips: datastructure.NewRandomMap(), + tips: randommap.New(), Events: Events{ TipAdded: events.NewEvent(payloadIDEvent), TipRemoved: events.NewEvent(payloadIDEvent), diff --git a/dapps/valuetransfers/packages/transaction/inputs.go b/dapps/valuetransfers/packages/transaction/inputs.go index f5071c62cebbed30e2410292a82166732d098a73..eee31984fe3d42820182ac41263ecf60c164abfb 100644 --- a/dapps/valuetransfers/packages/transaction/inputs.go +++ b/dapps/valuetransfers/packages/transaction/inputs.go @@ -2,7 +2,7 @@ package transaction import ( "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/address" - "github.com/iotaledger/goshimmer/packages/binary/datastructure/orderedmap" + "github.com/iotaledger/hive.go/datastructure/orderedmap" "github.com/iotaledger/hive.go/marshalutil" ) diff --git a/dapps/valuetransfers/packages/transaction/outputs.go b/dapps/valuetransfers/packages/transaction/outputs.go index f287b1839b305c7f6057e5a29b7c050c60ed1381..9c3b9d95c2878f311cc55e0509e7dd30dbf34673 100644 --- a/dapps/valuetransfers/packages/transaction/outputs.go +++ b/dapps/valuetransfers/packages/transaction/outputs.go @@ -6,7 +6,7 @@ import ( "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/address" "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/balance" - "github.com/iotaledger/goshimmer/packages/binary/datastructure/orderedmap" + "github.com/iotaledger/hive.go/datastructure/orderedmap" "github.com/iotaledger/hive.go/marshalutil" ) diff --git a/dapps/valuetransfers/packages/transaction/signatures.go b/dapps/valuetransfers/packages/transaction/signatures.go index 2a5879c03e454d7b577025c8beae6b09ee1be959..eddfddd926d28d1cc0a6587bcf7fdc64e361d662 100644 --- a/dapps/valuetransfers/packages/transaction/signatures.go +++ b/dapps/valuetransfers/packages/transaction/signatures.go @@ -1,11 +1,11 @@ package transaction import ( + "github.com/iotaledger/hive.go/datastructure/orderedmap" "github.com/iotaledger/hive.go/marshalutil" "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/address" "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/address/signaturescheme" - "github.com/iotaledger/goshimmer/packages/binary/datastructure/orderedmap" ) // Signatures represents a container for the address signatures of a value transfer. diff --git a/packages/binary/datastructure/orderedmap/element.go b/packages/binary/datastructure/orderedmap/element.go deleted file mode 100644 index d8c4c03143999b3f752171cbeccd9322d19800fb..0000000000000000000000000000000000000000 --- a/packages/binary/datastructure/orderedmap/element.go +++ /dev/null @@ -1,9 +0,0 @@ -package orderedmap - -// Element defines the model of each element of the orderedMap. -type Element struct { - key interface{} - value interface{} - prev *Element - next *Element -} diff --git a/packages/binary/datastructure/orderedmap/orderedmap.go b/packages/binary/datastructure/orderedmap/orderedmap.go deleted file mode 100644 index dc6f19be417e3818dc745614b7ba2e6131cf117f..0000000000000000000000000000000000000000 --- a/packages/binary/datastructure/orderedmap/orderedmap.go +++ /dev/null @@ -1,133 +0,0 @@ -package orderedmap - -import ( - "sync" -) - -// OrderedMap provides a concurrent-safe ordered map. -type OrderedMap struct { - head *Element - tail *Element - dictionary map[interface{}]*Element - size int - mutex sync.RWMutex -} - -// New returns a new *OrderedMap. -func New() *OrderedMap { - return &OrderedMap{ - dictionary: make(map[interface{}]*Element), - } -} - -// Get returns the value mapped to the given key if exists. -func (orderedMap *OrderedMap) Get(key interface{}) (interface{}, bool) { - orderedMap.mutex.RLock() - defer orderedMap.mutex.RUnlock() - - orderedMapElement, orderedMapElementExists := orderedMap.dictionary[key] - if !orderedMapElementExists { - return nil, false - } - return orderedMapElement.value, true - -} - -// Set adds a key-value pair to the orderedMap. It returns false if the same pair already exists. -func (orderedMap *OrderedMap) Set(key interface{}, newValue interface{}) bool { - if oldValue, oldValueExists := orderedMap.Get(key); oldValueExists && oldValue == newValue { - return false - } - - orderedMap.mutex.Lock() - defer orderedMap.mutex.Unlock() - - if oldValue, oldValueExists := orderedMap.dictionary[key]; oldValueExists { - if oldValue.value == newValue { - return false - } - - oldValue.value = newValue - - return true - } - - newElement := &Element{ - key: key, - value: newValue, - } - - if orderedMap.head == nil { - orderedMap.head = newElement - } else { - orderedMap.tail.next = newElement - newElement.prev = orderedMap.tail - } - orderedMap.tail = newElement - orderedMap.size++ - - orderedMap.dictionary[key] = newElement - - return true -} - -// ForEach iterates through the orderedMap and calls the consumer function for every element. -// The iteration can be aborted by returning false in the consumer. -func (orderedMap *OrderedMap) ForEach(consumer func(key, value interface{}) bool) bool { - orderedMap.mutex.RLock() - currentEntry := orderedMap.head - orderedMap.mutex.RUnlock() - - for currentEntry != nil { - if !consumer(currentEntry.key, currentEntry.value) { - return false - } - - orderedMap.mutex.RLock() - currentEntry = currentEntry.next - orderedMap.mutex.RUnlock() - } - - return true -} - -// Delete deletes the given key (and related value) from the orderedMap. -// It returns false if the key is not found. -func (orderedMap *OrderedMap) Delete(key interface{}) bool { - if _, valueExists := orderedMap.Get(key); !valueExists { - return false - } - - orderedMap.mutex.Lock() - defer orderedMap.mutex.Unlock() - - value, valueExists := orderedMap.dictionary[key] - if !valueExists { - return false - } - - delete(orderedMap.dictionary, key) - orderedMap.size-- - - if value.prev != nil { - value.prev.next = value.next - } else { - orderedMap.head = value.next - } - - if value.next != nil { - value.next.prev = value.prev - } else { - orderedMap.tail = value.prev - } - - return true -} - -// Size returns the size of the orderedMap. -func (orderedMap *OrderedMap) Size() int { - orderedMap.mutex.RLock() - defer orderedMap.mutex.RUnlock() - - return orderedMap.size -} diff --git a/packages/binary/datastructure/orderedmap/orderedmap_test.go b/packages/binary/datastructure/orderedmap/orderedmap_test.go deleted file mode 100644 index 0b202a0878ec52a82dba784cb149d992c1fce03d..0000000000000000000000000000000000000000 --- a/packages/binary/datastructure/orderedmap/orderedmap_test.go +++ /dev/null @@ -1,169 +0,0 @@ -package orderedmap - -import ( - "fmt" - "sync" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestOrderedMap_Size(t *testing.T) { - orderedMap := New() - - assert.Equal(t, 0, orderedMap.Size()) - - orderedMap.Set(1, 1) - - assert.Equal(t, 1, orderedMap.Size()) - - orderedMap.Set(3, 1) - orderedMap.Set(2, 1) - - assert.Equal(t, 3, orderedMap.Size()) - - orderedMap.Set(2, 2) - - assert.Equal(t, 3, orderedMap.Size()) - - orderedMap.Delete(2) - - assert.Equal(t, 2, orderedMap.Size()) -} - -func TestNew(t *testing.T) { - orderedMap := New() - require.NotNil(t, orderedMap) - - assert.Equal(t, 0, orderedMap.Size()) - - assert.Nil(t, orderedMap.head) - assert.Nil(t, orderedMap.tail) -} - -func TestSetGetDelete(t *testing.T) { - orderedMap := New() - require.NotNil(t, orderedMap) - - // when adding the first new key,value pair, we must return true - keyValueAdded := orderedMap.Set("key", "value") - assert.True(t, keyValueAdded) - - // we should be able to retrieve the just added element - value, ok := orderedMap.Get("key") - assert.Equal(t, "value", value) - assert.True(t, ok) - - // head and tail should NOT be nil and match and size should be 1 - assert.NotNil(t, orderedMap.head) - assert.Same(t, orderedMap.head, orderedMap.tail) - assert.Equal(t, 1, orderedMap.Size()) - - // when adding the same key,value pair must return false - // and size should not change; - keyValueAdded = orderedMap.Set("key", "value") - assert.False(t, keyValueAdded) - assert.Equal(t, 1, orderedMap.Size()) - - // when retrieving something that does not exist we - // should get nil, false - value, ok = orderedMap.Get("keyNotStored") - assert.Nil(t, value) - assert.False(t, ok) - - // when deleting an existing element, we must get true, - // the element must be removed, and size decremented. - deleted := orderedMap.Delete("key") - assert.True(t, deleted) - value, ok = orderedMap.Get("key") - assert.Nil(t, value) - assert.False(t, ok) - assert.Equal(t, 0, orderedMap.Size()) - - // if we delete the only element, head and tail should be both nil - assert.Nil(t, orderedMap.head) - assert.Same(t, orderedMap.head, orderedMap.tail) - - // when deleting a NON existing element, we must get false - deleted = orderedMap.Delete("key") - assert.False(t, deleted) -} - -func TestForEach(t *testing.T) { - orderedMap := New() - require.NotNil(t, orderedMap) - - testElements := []Element{ - {key: "one", value: 1}, - {key: "two", value: 2}, - {key: "three", value: 3}, - } - - for _, element := range testElements { - keyValueAdded := orderedMap.Set(element.key, element.value) - assert.True(t, keyValueAdded) - } - - // test that all elements are positive via ForEach - testPositive := orderedMap.ForEach(func(key, value interface{}) bool { - return value.(int) > 0 - }) - assert.True(t, testPositive) - - testNegative := orderedMap.ForEach(func(key, value interface{}) bool { - return value.(int) < 0 - }) - assert.False(t, testNegative) -} - -func TestConcurrencySafe(t *testing.T) { - orderedMap := New() - require.NotNil(t, orderedMap) - - // initialize a slice of 100 elements - set := make([]Element, 100) - for i := 0; i < 100; i++ { - element := Element{key: fmt.Sprintf("%d", i), value: i} - set[i] = element - } - - // let 10 workers fill the orderedMap - workers := 10 - var wg sync.WaitGroup - wg.Add(workers) - for i := 0; i < workers; i++ { - go func() { - defer wg.Done() - for i := 0; i < 100; i++ { - ele := set[i] - orderedMap.Set(ele.key, ele.value) - } - }() - } - wg.Wait() - - // check that all the elements consumed from the set - // have been stored in the orderedMap and its size matches - for i := 0; i < 100; i++ { - value, ok := orderedMap.Get(set[i].key) - assert.Equal(t, set[i].value, value) - assert.True(t, ok) - } - assert.Equal(t, 100, orderedMap.Size()) - - // let 10 workers delete elements from the orderedMAp - wg.Add(workers) - for i := 0; i < workers; i++ { - go func() { - defer wg.Done() - for i := 0; i < 100; i++ { - ele := set[i] - orderedMap.Delete(ele.key) - } - }() - } - wg.Wait() - - assert.Equal(t, 0, orderedMap.Size()) -} diff --git a/packages/binary/datastructure/queue/queue.go b/packages/binary/datastructure/queue/queue.go deleted file mode 100644 index 042e405c44e92fbf84476216c7f0f7c0026ffbf0..0000000000000000000000000000000000000000 --- a/packages/binary/datastructure/queue/queue.go +++ /dev/null @@ -1,74 +0,0 @@ -package queue - -import ( - "sync" -) - -// Queue represents a ring buffer. -type Queue struct { - ringBuffer []interface{} - read int - write int - capacity int - size int - mutex sync.Mutex -} - -// New creates a new queue with the specified capacity. -func New(capacity int) *Queue { - return &Queue{ - ringBuffer: make([]interface{}, capacity), - capacity: capacity, - } -} - -// Size returns the size of the queue. -func (queue *Queue) Size() int { - queue.mutex.Lock() - defer queue.mutex.Unlock() - - return queue.size -} - -// Capacity returns the capacity of the queue. -func (queue *Queue) Capacity() int { - queue.mutex.Lock() - defer queue.mutex.Unlock() - - return queue.capacity -} - -// Offer adds an element to the queue and returns true. -// If the queue is full, it drops it and returns false. -func (queue *Queue) Offer(element interface{}) bool { - queue.mutex.Lock() - defer queue.mutex.Unlock() - - if queue.size == queue.capacity { - return false - } - - queue.ringBuffer[queue.write] = element - queue.write = (queue.write + 1) % queue.capacity - queue.size++ - - return true -} - -// Poll returns and removes the oldest element in the queue and true if successful. -// If returns false if the queue is empty. -func (queue *Queue) Poll() (element interface{}, success bool) { - queue.mutex.Lock() - defer queue.mutex.Unlock() - - if success = queue.size != 0; !success { - return - } - - element = queue.ringBuffer[queue.read] - queue.ringBuffer[queue.read] = nil - queue.read = (queue.read + 1) % queue.capacity - queue.size-- - - return -} diff --git a/packages/binary/datastructure/queue/queue_test.go b/packages/binary/datastructure/queue/queue_test.go deleted file mode 100644 index 5a39242be2dafd56203d5b82e2cad48ac7f26cd5..0000000000000000000000000000000000000000 --- a/packages/binary/datastructure/queue/queue_test.go +++ /dev/null @@ -1,112 +0,0 @@ -package queue - -import ( - "sync" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestNewQueue(t *testing.T) { - queue := New(2) - require.NotNil(t, queue) - assert.Equal(t, 0, queue.Size()) - assert.Equal(t, 2, queue.Capacity()) -} - -func TestQueueOfferPoll(t *testing.T) { - queue := New(2) - require.NotNil(t, queue) - - // offer element to queue - assert.True(t, queue.Offer(1)) - assert.Equal(t, 1, queue.Size()) - - assert.True(t, queue.Offer(2)) - assert.Equal(t, 2, queue.Size()) - - assert.False(t, queue.Offer(3)) - - // Poll element from queue - polledValue, ok := queue.Poll() - assert.True(t, ok) - assert.Equal(t, 1, polledValue) - assert.Equal(t, 1, queue.Size()) - - polledValue, ok = queue.Poll() - assert.True(t, ok) - assert.Equal(t, 2, polledValue) - assert.Equal(t, 0, queue.Size()) - - polledValue, ok = queue.Poll() - assert.False(t, ok) - assert.Nil(t, polledValue) - assert.Equal(t, 0, queue.Size()) - - // Offer the empty queue again - assert.True(t, queue.Offer(3)) - assert.Equal(t, 1, queue.Size()) -} - -func TestQueueOfferConcurrencySafe(t *testing.T) { - queue := New(100) - require.NotNil(t, queue) - - // let 10 workers fill the queue - workers := 10 - var wg sync.WaitGroup - wg.Add(workers) - for i := 0; i < workers; i++ { - go func() { - defer wg.Done() - for j := 0; j < 10; j++ { - queue.Offer(j) - } - }() - } - wg.Wait() - - // check that all the elements are offered - assert.Equal(t, 100, queue.Size()) - - counter := make([]int, 10) - for i := 0; i < 100; i++ { - value, ok := queue.Poll() - assert.True(t, ok) - counter[value.(int)]++ - } - assert.Equal(t, 0, queue.Size()) - - // check that the insert numbers are correct - for i := 0; i < 10; i++ { - assert.Equal(t, 10, counter[i]) - } -} - -func TestQueuePollConcurrencySafe(t *testing.T) { - queue := New(100) - require.NotNil(t, queue) - - for j := 0; j < 100; j++ { - queue.Offer(j) - } - - // let 10 workers poll the queue - workers := 10 - var wg sync.WaitGroup - wg.Add(workers) - for i := 0; i < workers; i++ { - go func() { - defer wg.Done() - for j := 0; j < 10; j++ { - _, ok := queue.Poll() - assert.True(t, ok) - } - }() - } - wg.Wait() - - // check that all the elements are polled - assert.Equal(t, 0, queue.Size()) -} diff --git a/packages/binary/datastructure/random_map.go b/packages/binary/datastructure/random_map.go deleted file mode 100644 index 290a74733aeca477f9e4b312341ee7983c86bab9..0000000000000000000000000000000000000000 --- a/packages/binary/datastructure/random_map.go +++ /dev/null @@ -1,170 +0,0 @@ -package datastructure - -import ( - "math/rand" - "sync" - "time" -) - -func init() { - rand.Seed(time.Now().UnixNano()) -} - -type randomMapEntry struct { - key interface{} - value interface{} - keyIndex int -} - -// RandomMap defines a map with extended ability to return a random entry. -type RandomMap struct { - rawMap map[interface{}]*randomMapEntry - keys []interface{} - size int - mutex sync.RWMutex -} - -// NewRandomMap creates a new random map -func NewRandomMap() *RandomMap { - return &RandomMap{ - rawMap: make(map[interface{}]*randomMapEntry), - keys: make([]interface{}, 0), - } -} - -// Set associates the specified value with the specified key. -// If the association already exists, it updates the value. -func (rmap *RandomMap) Set(key interface{}, value interface{}) (updated bool) { - rmap.mutex.Lock() - - if entry, exists := rmap.rawMap[key]; exists { - if entry.value != value { - entry.value = value - - updated = true - } - } else { - rmap.rawMap[key] = &randomMapEntry{ - key: key, - value: value, - keyIndex: rmap.size, - } - - updated = true - - rmap.keys = append(rmap.keys, key) - - rmap.size++ - } - - rmap.mutex.Unlock() - - return -} - -// Get returns the value to which the specified key is mapped. -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 -} - -// Delete removes the mapping for the specified key in the map. -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 -} - -// Size returns the number of key-value mappings in the map. -func (rmap *RandomMap) Size() (result int) { - rmap.mutex.RLock() - - result = rmap.size - - rmap.mutex.RUnlock() - - return -} - -// ForEach iterates through the elements in the map and calls the consumer function for each element. -func (rmap *RandomMap) ForEach(consumer func(key interface{}, value interface{})) { - rmap.mutex.RLock() - defer rmap.mutex.RUnlock() - - for _, key := range rmap.keys { - consumer(key, rmap.rawMap[key].value) - } -} - -// RandomKey returns a random key from the map. -func (rmap *RandomMap) RandomKey() (result interface{}) { - rmap.mutex.RLock() - defer rmap.mutex.RUnlock() - - return rmap.randomKey() -} - -// RandomEntry returns a random value from the map. -func (rmap *RandomMap) RandomEntry() (result interface{}) { - rmap.mutex.RLock() - - if rmap.size >= 1 { - result = rmap.rawMap[rmap.randomKey()].value - } - - rmap.mutex.RUnlock() - - return -} - -// Keys returns the list of keys stored in the RandomMap. -func (rmap *RandomMap) Keys() (result []interface{}) { - rmap.mutex.RLock() - defer rmap.mutex.RUnlock() - - result = make([]interface{}, rmap.size) - copy(result, rmap.keys) - - return -} - -func (rmap *RandomMap) randomKey() (result interface{}) { - return rmap.keys[rand.Intn(rmap.size)] -} diff --git a/packages/binary/messagelayer/tangle/tangle_test.go b/packages/binary/messagelayer/tangle/tangle_test.go index 1d1ad4caa5d5298ab43dc970df4c67e9deca1dec..ce3b1fddfc613322d70a227816b65790463ce64d 100644 --- a/packages/binary/messagelayer/tangle/tangle_test.go +++ b/packages/binary/messagelayer/tangle/tangle_test.go @@ -8,11 +8,11 @@ import ( "testing" "time" - "github.com/iotaledger/goshimmer/packages/binary/datastructure" "github.com/iotaledger/goshimmer/packages/binary/messagelayer/message" "github.com/iotaledger/goshimmer/packages/binary/messagelayer/messagefactory" "github.com/iotaledger/goshimmer/packages/binary/messagelayer/payload" "github.com/iotaledger/hive.go/crypto/ed25519" + "github.com/iotaledger/hive.go/datastructure/randommap" "github.com/iotaledger/hive.go/events" "github.com/iotaledger/hive.go/identity" "github.com/iotaledger/hive.go/kvstore/mapdb" @@ -107,7 +107,7 @@ func TestTangle_MissingMessages(t *testing.T) { require.NoError(t, err) // map to keep track of the tips - tips := datastructure.NewRandomMap() + tips := randommap.New() tips.Set(message.EmptyID, message.EmptyID) // setup the message factory diff --git a/packages/binary/messagelayer/tipselector/tipselector.go b/packages/binary/messagelayer/tipselector/tipselector.go index 3bd9bda0879ac2c1aa3d3a035779bb15ab03bd4f..04d11300049abfed885bf8c3f5c40bef71a98906 100644 --- a/packages/binary/messagelayer/tipselector/tipselector.go +++ b/packages/binary/messagelayer/tipselector/tipselector.go @@ -1,20 +1,20 @@ package tipselector import ( - "github.com/iotaledger/goshimmer/packages/binary/datastructure" "github.com/iotaledger/goshimmer/packages/binary/messagelayer/message" + "github.com/iotaledger/hive.go/datastructure/randommap" ) // TipSelector manages a map of tips and emits events for their removal and addition. type TipSelector struct { - tips *datastructure.RandomMap + tips *randommap.RandomMap Events *Events } // New creates a new tip-selector. func New(tips ...message.ID) *TipSelector { tipSelector := &TipSelector{ - tips: datastructure.NewRandomMap(), + tips: randommap.New(), Events: newEvents(), }