diff --git a/go.mod b/go.mod index 879290b9064cf1156475acb01ea751623e0fc1f4..31b7140aa08af74b45636d7d44a92b84c0e27e42 100644 --- a/go.mod +++ b/go.mod @@ -14,10 +14,10 @@ require ( github.com/kr/pretty v0.1.0 // indirect github.com/labstack/echo v3.3.10+incompatible github.com/labstack/gommon v0.2.9 // indirect - github.com/magiconair/properties v1.8.1 github.com/pkg/errors v0.8.1 github.com/rivo/tview v0.0.0-20190721135419-23dc8a0944e4 github.com/rivo/uniseg v0.1.0 // indirect + github.com/stretchr/testify v1.3.0 golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e // indirect diff --git a/go.sum b/go.sum index 331a8ca2b0606ab27d583513ff5d7204af6baa29..3190f6cf086e2f9237295e991a2a9f0de4aa3630 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,6 @@ github.com/labstack/gommon v0.2.9/go.mod h1:E8ZTmW9vw5az5/ZyHWCp0Lw4OH2ecsaBP1C/ github.com/lucasb-eyer/go-colorful v1.0.2 h1:mCMFu6PgSozg9tDNMMK3g18oJBX7oYGrC09mS6CXfO4= github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= diff --git a/packages/ca/heartbeat/serialization_test.go b/packages/ca/heartbeat/serialization_test.go index 39226bc5bf1980905ba8348fc428bc049030b272..c98c532bbbffc27525eb8fc9d5825a420c4cd6d1 100644 --- a/packages/ca/heartbeat/serialization_test.go +++ b/packages/ca/heartbeat/serialization_test.go @@ -15,11 +15,11 @@ import ( func TestMarshal(t *testing.T) { ownNodeId := identity.GenerateRandomIdentity().Identifier - toggledTransactions := make([]*heartbeatproto.ToggledTransaction, 1000) + toggledTransactions := make([]*heartbeatproto.ToggledTransaction, 10000) for i := 0; i < len(toggledTransactions); i++ { toggledTransactions[i] = &heartbeatproto.ToggledTransaction{ - TransactionId: make([]byte, 32), + TransactionId: make([]byte, 3), ToggleReason: 0, } } diff --git a/packages/datastructure/prefix_trie.go b/packages/datastructure/prefix_trie.go new file mode 100644 index 0000000000000000000000000000000000000000..a7e712a685ee52dbb9cfc323917e9d986e66553a --- /dev/null +++ b/packages/datastructure/prefix_trie.go @@ -0,0 +1,188 @@ +package datastructure + +import ( + "bytes" + "fmt" + "sync" +) + +type PrefixTrie struct { + value []byte + children map[byte]*PrefixTrie + size int + mutex sync.RWMutex +} + +func NewPrefixTree() *PrefixTrie { + return &PrefixTrie{ + value: nil, + children: make(map[byte]*PrefixTrie), + } +} + +func (prefixTrie *PrefixTrie) Get(byteSequenceOrPrefix []byte) (result [][]byte) { + prefixTrie.mutex.RLock() + defer prefixTrie.mutex.RUnlock() + + result = make([][]byte, 0) + + currentNode := prefixTrie + + for currentLevel := 0; currentLevel < len(byteSequenceOrPrefix); currentLevel++ { + if currentNode.value != nil && bytes.HasPrefix(currentNode.value, byteSequenceOrPrefix) { + result = append(result, currentNode.value) + + return + } + + if existingNode, exists := currentNode.children[byteSequenceOrPrefix[currentLevel]]; exists { + currentNode = existingNode + } else { + // error tried to inflate non-existing entry + return + } + } + + if currentNode.value != nil { + result = append(result, currentNode.value) + } else { + // traverse child elements + if false { + fmt.Println("WAS") + } + } + + return +} + +func (prefixTrie *PrefixTrie) GetPrefix(insertedBytes []byte) []byte { + prefixTrie.mutex.RLock() + defer prefixTrie.mutex.RUnlock() + + currentNode := prefixTrie + currentLevel := 0 + + for { + // if we have reached our target + if bytes.Equal(currentNode.value, insertedBytes) { + return insertedBytes[:currentLevel] + } + + // if we have arrived at the wrong node: return nil + if currentNode.value != nil { + return nil + } + + if childNode, exists := currentNode.children[insertedBytes[currentLevel]]; !exists { + return nil + } else { + currentNode = childNode + } + + // increase level counter + currentLevel++ + } +} + +func (prefixTrie *PrefixTrie) Insert(byteSequence []byte) bool { + prefixTrie.mutex.Lock() + defer prefixTrie.mutex.Unlock() + + currentNode := prefixTrie + currentLevel := 0 + + for { + // if we have reached our target node: insert value + if currentNode.value == nil && len(currentNode.children) == 0 { + currentNode.value = byteSequence + + prefixTrie.size++ + + return true + } + + // if we have reached a previous leaf + if currentNode.value != nil { + // return if same element + if bytes.Equal(currentNode.value, byteSequence) { + return false + } + + // move current value to correct sub element + currentNode.children[currentNode.value[currentLevel]] = &PrefixTrie{ + value: currentNode.value, + children: make(map[byte]*PrefixTrie), + } + + // set the value to nil + currentNode.value = nil + } + + // traverse or create correct child element + if existingChildNode, exists := currentNode.children[byteSequence[currentLevel]]; exists { + currentNode = existingChildNode + } else { + newNode := &PrefixTrie{ + children: make(map[byte]*PrefixTrie), + } + + currentNode.children[byteSequence[currentLevel]] = newNode + + currentNode = newNode + } + + // increase level counter + currentLevel++ + } +} + +func (prefixTrie *PrefixTrie) Delete(byteSequence []byte) bool { + prefixTrie.mutex.Lock() + defer prefixTrie.mutex.Unlock() + + currentNode := prefixTrie + + // trivial case: delete from root + if bytes.Equal(currentNode.value, byteSequence) { + currentNode.value = nil + + prefixTrie.size-- + + return true + } + + // non-trivial case: delete leaf + for currentLevel := 0; currentLevel < len(byteSequence); currentLevel++ { + if existingNode, exists := currentNode.children[byteSequence[currentLevel]]; exists { + if bytes.Equal(existingNode.value, byteSequence) { + delete(currentNode.children, byteSequence[currentLevel]) + + if len(currentNode.children) == 1 { + for index, currentChild := range currentNode.children { + if currentChild.value != nil { + currentNode.value = currentChild.value + delete(currentNode.children, index) + } + } + } + + prefixTrie.size-- + + return true + } + + currentNode = existingNode + } else { + return false + } + } + + return false +} + +func (prefixTrie *PrefixTrie) GetSize() int { + prefixTrie.mutex.RLock() + defer prefixTrie.mutex.RUnlock() + + return prefixTrie.size +} diff --git a/packages/datastructure/prefix_trie_test.go b/packages/datastructure/prefix_trie_test.go new file mode 100644 index 0000000000000000000000000000000000000000..34eb6e4fa8b6d6d24fe8b083f45f9ea36ab1a22c --- /dev/null +++ b/packages/datastructure/prefix_trie_test.go @@ -0,0 +1,142 @@ +package datastructure + +import ( + "bytes" + "math/rand" + "testing" + + "github.com/iotaledger/iota.go/trinary" + "github.com/stretchr/testify/assert" +) + +func BenchmarkByteTrie_Insert(b *testing.B) { + trie := &PrefixTrie{ + value: nil, + children: make(map[byte]*PrefixTrie), + } + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + token := make([]byte, 50) + rand.Read(token) + + trie.Insert(token) + } +} + +func TestPrefixTrie_GetPrefix(t *testing.T) { + trie := &PrefixTrie{ + value: nil, + children: make(map[byte]*PrefixTrie), + } + + var token []byte + for i := 0; i < 64000; i++ { + token = make([]byte, 50) + rand.Read(token) + + trie.Insert(token) + } + + assert.True(t, len(trie.GetPrefix(token)) <= 3) +} + +func TestPrefixTrie_Insert(t *testing.T) { + trie := NewPrefixTree() + + tx1Hash := trinary.MustTrytesToBytes("NDMXEXQFVRJKHVRGYURKMRMUUYUNPCREQHEZKNSEHK9SWSIQDU9IF9IHXTOIVVHWXGLJHHUR9NIGMAUQC") + tx2Hash := trinary.MustTrytesToBytes("HWTXYVLGPKUUFXGBBGKLMRCI9VOW9MEJRCJPRMUGCKHOVCCMFSZNAFEWOOVYUEHGYDWPWBEKWJPAZ9999") + tx3Hash := trinary.MustTrytesToBytes("IPVMHNESBZUKAIYFJCYEVXDBICITTLDUQIOVZODAISWCNEMBLWHVBDTEHNWRENIDEGVVODLXHTXGA9999") + + assert.Equal(t, 0, trie.GetSize()) + + assert.Equal(t, true, trie.Insert(tx1Hash)) + assert.Equal(t, true, trie.Insert(tx2Hash)) + assert.Equal(t, true, trie.Insert(tx3Hash)) + assert.Equal(t, false, trie.Insert(tx1Hash)) + + assert.Equal(t, 3, trie.GetSize()) + + txFound := false + for _, hash := range trie.Get(trie.GetPrefix(tx1Hash)) { + if bytes.Equal(hash, tx1Hash) { + txFound = true + } + } + assert.True(t, txFound) + + assert.Equal(t, true, trie.Delete(tx1Hash)) + assert.Equal(t, false, trie.Delete(tx1Hash)) + assert.Equal(t, true, trie.Delete(tx2Hash)) + + assert.Equal(t, 1, trie.GetSize()) +} + +func TestPrefixTrie_Get(t *testing.T) { + trie := NewPrefixTree() + + tx1Hash := trinary.MustTrytesToBytes("NDMXEXQFVRJKHVRGYURKMRMUUYUNPCREQHEZKNSEHK9SWSIQDU9IF9IHXTOIVVHWXGLJHHUR9NIGMAUQC") + tx2Hash := trinary.MustTrytesToBytes("HWTXYVLGPKUUFXGBBGKLMRCI9VOW9MEJRCJPRMUGCKHOVCCMFSZNAFEWOOVYUEHGYDWPWBEKWJPAZ9999") + + trie.Insert(tx1Hash) + trie.Insert(tx2Hash) + + prefix := trie.GetPrefix(tx1Hash) + + resultsByPrefix := trie.Get(prefix) + resultsByFullHash := trie.Get(tx1Hash) + + assert.Equal(t, len(resultsByPrefix), len(resultsByFullHash)) + for i, foundHashCandidate := range resultsByPrefix { + assert.True(t, bytes.Equal(foundHashCandidate, resultsByFullHash[i])) + } +} + +func TestPrefixTrie_GetSize(t *testing.T) { + trie := NewPrefixTree() + + assert.Equal(t, 0, trie.GetSize()) + + tx1Hash := trinary.MustTrytesToBytes("NDMXEXQFVRJKHVRGYURKMRMUUYUNPCREQHEZKNSEHK9SWSIQDU9IF9IHXTOIVVHWXGLJHHUR9NIGMAUQC") + tx2Hash := trinary.MustTrytesToBytes("HWTXYVLGPKUUFXGBBGKLMRCI9VOW9MEJRCJPRMUGCKHOVCCMFSZNAFEWOOVYUEHGYDWPWBEKWJPAZ9999") + tx3Hash := trinary.MustTrytesToBytes("IPVMHNESBZUKAIYFJCYEVXDBICITTLDUQIOVZODAISWCNEMBLWHVBDTEHNWRENIDEGVVODLXHTXGA9999") + + trie.Insert(tx1Hash) + trie.Insert(tx2Hash) + assert.Equal(t, 2, trie.GetSize()) + + trie.Insert(tx3Hash) + assert.Equal(t, 3, trie.GetSize()) + + trie.Delete(tx1Hash) + assert.Equal(t, 2, trie.GetSize()) + + trie.Delete(tx2Hash) + assert.Equal(t, 1, trie.GetSize()) + + trie.Delete(tx3Hash) + assert.Equal(t, 0, trie.GetSize()) + + trie.Delete(tx3Hash) + assert.Equal(t, 0, trie.GetSize()) +} + +func TestPrefixTrie_Delete(t *testing.T) { + trie := NewPrefixTree() + + tx1Hash := trinary.MustTrytesToBytes("NDMXEXQFVRJKHVRGYURKMRMUUYUNPCREQHEZKNSEHK9SWSIQDU9IF9IHXTOIVVHWXGLJHHUR9NIGMAUQC") + tx2Hash := trinary.MustTrytesToBytes("HWTXYVLGPKUUFXGBBGKLMRCI9VOW9MEJRCJPRMUGCKHOVCCMFSZNAFEWOOVYUEHGYDWPWBEKWJPAZ9999") + tx3Hash := trinary.MustTrytesToBytes("IPVMHNESBZUKAIYFJCYEVXDBICITTLDUQIOVZODAISWCNEMBLWHVBDTEHNWRENIDEGVVODLXHTXGA9999") + + trie.Insert(tx1Hash) + trie.Insert(tx2Hash) + + assert.Equal(t, true, trie.Delete(tx1Hash)) + assert.Equal(t, false, trie.Delete(tx1Hash)) + + assert.Equal(t, true, trie.Delete(tx2Hash)) + assert.Equal(t, false, trie.Delete(tx3Hash)) + + assert.Equal(t, 0, trie.GetSize()) +} diff --git a/packages/model/approvers/approvers_test.go b/packages/model/approvers/approvers_test.go index 926c5c070c83b7360447c022f5bac89e2ee5a1ee..71ec80421f49ce52c81eeef992c9c69742a1a9f2 100644 --- a/packages/model/approvers/approvers_test.go +++ b/packages/model/approvers/approvers_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/iotaledger/iota.go/trinary" - "github.com/magiconair/properties/assert" + "github.com/stretchr/testify/assert" ) func TestApprovers_SettersGetters(t *testing.T) { diff --git a/packages/model/bundle/bundle_test.go b/packages/model/bundle/bundle_test.go index d00bb6ec462fe91ce7c4a4d78bd6d8e1f9654a09..46a171ac0d81f7b9db1216711d98cc8847a74ffd 100644 --- a/packages/model/bundle/bundle_test.go +++ b/packages/model/bundle/bundle_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/iotaledger/iota.go/trinary" - "github.com/magiconair/properties/assert" + "github.com/stretchr/testify/assert" ) func TestBundle_SettersGetters(t *testing.T) { diff --git a/packages/model/meta_transaction/meta_transaction_test.go b/packages/model/meta_transaction/meta_transaction_test.go index 2ba055b76a74928485bfd0b11a9d959d68bd47ac..2cd47e58c2a18ba47ddc281ff44b37fc264d812b 100644 --- a/packages/model/meta_transaction/meta_transaction_test.go +++ b/packages/model/meta_transaction/meta_transaction_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/iotaledger/iota.go/trinary" - "github.com/magiconair/properties/assert" + "github.com/stretchr/testify/assert" ) func TestMetaTransaction_SettersGetters(t *testing.T) { diff --git a/packages/model/value_transaction/value_transaction_test.go b/packages/model/value_transaction/value_transaction_test.go index c1f732d69dee0eca2717b88e362a4859b89e564b..71fa3bd55a5b75d9288a2c4aea6d90f5c28bfead 100644 --- a/packages/model/value_transaction/value_transaction_test.go +++ b/packages/model/value_transaction/value_transaction_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/iotaledger/iota.go/trinary" - "github.com/magiconair/properties/assert" + "github.com/stretchr/testify/assert" ) func TestValueTransaction_SettersGetters(t *testing.T) { diff --git a/plugins/autopeering/types/peer/peer_test.go b/plugins/autopeering/types/peer/peer_test.go index 8d73ab17ceb794e32ec6361e088c1bc35a4e5252..c540650108e27339d4cc92d2d34cac199ea4b85c 100644 --- a/plugins/autopeering/types/peer/peer_test.go +++ b/plugins/autopeering/types/peer/peer_test.go @@ -8,7 +8,7 @@ import ( "github.com/iotaledger/goshimmer/plugins/autopeering/types/salt" "github.com/iotaledger/goshimmer/packages/identity" - "github.com/magiconair/properties/assert" + "github.com/stretchr/testify/assert" ) func TestPeer_MarshalUnmarshal(t *testing.T) { diff --git a/plugins/bundleprocessor/bundleprocessor_test.go b/plugins/bundleprocessor/bundleprocessor_test.go index 14834c67c2b0ed49ef7b418cee8309c5f7e21afd..f3aef46ec403a9154d2eac778341aef554c03f1d 100644 --- a/plugins/bundleprocessor/bundleprocessor_test.go +++ b/plugins/bundleprocessor/bundleprocessor_test.go @@ -16,7 +16,7 @@ import ( "github.com/iotaledger/goshimmer/plugins/tangle" "github.com/iotaledger/iota.go/consts" - "github.com/magiconair/properties/assert" + "github.com/stretchr/testify/assert" ) var seed = client.NewSeed("YFHQWAUPCXC9S9DSHP9NDF9RLNPMZVCMSJKUKQP9SWUSUCPRQXCMDVDVZ9SHHESHIQNCXWBJF9UJSWE9Z", consts.SecurityLevelMedium)