github.com/klaytn/klaytn@v1.12.1/networks/p2p/discover/discover_storage_simple_test.go (about)

     1  // Copyright 2019 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The klaytn library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package discover
    18  
    19  import (
    20  	"crypto/rand"
    21  	rand2 "math/rand"
    22  	"net"
    23  	"testing"
    24  
    25  	"github.com/klaytn/klaytn/common"
    26  	"github.com/klaytn/klaytn/crypto"
    27  	"github.com/pkg/errors"
    28  )
    29  
    30  var (
    31  	testData = [5][]*Node{
    32  		NodeTypeUnknown: {
    33  			MustParseNode("kni://2d2d43be39c40e1b104952cc351127fb3783b66ca065ba4b8c46f6e73e603e511203e399154c5b96c8ca13f8dd9086f6d29c74867a3b7ea6bd4f0205b25522b6@0.0.0.1:32323?discport=32323"),
    34  			MustParseNode("kni://e2fc0988b6286fd15a9c208bdf283fb456575357911d618e2f47326ce534db1f94c3a1edc6cb7a399797b35ad7dd82a2647ba9ec43b33948302cefb9edd2c9b2@0.0.0.2:32323?discport=32323"),
    35  			MustParseNode("kni://e898d53588ed46888ace5a6a61c2ca71034ae23aa004b8525a5045a5a51d43dd72b9ca49b346ed0155cc6e2cd143486109a6fe21845a59778012994ea7d9e128@0.0.0.3:32323?discport=32323"),
    36  			MustParseNode("kni://79ce147a6e955cbf43004e19480c4d8139eeb71ec99ee872499e4cb05e37ec711049781702200f958698246475e7bcf898acad261d1950c280abf5090ea00ac0@0.0.0.4:32323?discport=32323"),
    37  			MustParseNode("kni://693d678f8497a0a6019acdcc6388c489a0078387bb0dafa27e36b856765b20abe6a7c6e69b6bb4c0028babf490f7aea5481c2c39f69153c4f670af720ec59f67@0.0.0.5:32323?discport=32323"),
    38  			MustParseNode("kni://850555871dd0eeea187d7ad0f219b4def2a377cee8a6b40dff985b907687c4a36afa337a8499aff157ef41dadba8dcfb202786bb86d0a13371c8a517db3bfade@0.0.0.6:32323?discport=32323"),
    39  			MustParseNode("kni://dda3ce1adf19a1d88fba5fe91d856aa8c5a9fb71892b4cf75ffc19f28a6a38cc8eb3d4cdd83c2013ba8e8112fe44a43de0198e639171c4d5887452f0f7b21712@0.0.0.7:32323?discport=32323"),
    40  			MustParseNode("kni://473e2e359e2de9922eff61269a719004768c96733da823aaabbe6c926540f40156107b7fac931703d9f01a9cfc33652889c98fb62dbffe6a04a9ce2c93bc7512@0.0.0.8:32323?discport=32323"),
    41  			MustParseNode("kni://26a8bd88faadfe401787e99ca7909793cbe388562a0e43286488c2306770a73173ed0a50c5c894ae9e390da21c9091f4edf924d3e4299b303434628198b8a38a@0.0.0.9:32323?discport=32323"),
    42  			MustParseNode("kni://dbc67e54732ca531c8c3b2175858d712d1a1cac4a59ad6b639c6fe72bc261916c2236a38227502975f10e5353e4554dc50daaede6f8c9203beb36438af356d99@0.0.0.10:32323?discport=32323"),
    43  		},
    44  		NodeTypeCN: {
    45  			MustParseNode("kni://385730c3ca13a8a469fe8530216a3f17f1befe2f4a32394b58a63744f24170a135e1b9d22f34dcc6f52c98aa4248f8978a6ae9e22dc4a5869f8bf3e4154902fd@0.0.0.20:32323?discport=32323&ntype=cn"),
    46  			MustParseNode("kni://9114a018b91ed64c5e8b3e41494079d447bef4de19b3b41d36e46241cd06a69799a2fc6ed38a38f444ba508724efdea10ea4f3d95d331bb797c8601d0074fe5b@0.0.0.21:32323?discport=32323&ntype=cn"),
    47  			MustParseNode("kni://d3bc248af75576d88a8f8077e124f2d6d3980a40e0eeba093a06ba43ccd32b79ad8abb69ac38d349d3b52565033ebe917104b6a37108ce9c0fbdfcb52ad3c2b8@0.0.0.22:32323?discport=32323&ntype=cn"),
    48  			MustParseNode("kni://1914b4f6ee1eb996ee56551d0a95496ef617afeedc264f02db7abb97bee731f21e8fcd2354362a7ca3e043ace4541a54714e0287430228a802b4882154b941ba@0.0.0.23:32323?discport=32323&ntype=cn"),
    49  			MustParseNode("kni://6648a7c1c479c31e7c3410464f624f1a28819c9eb008930bf80a5614e0cf67d1a656024efca51971ac7f6a202355957e0574e6f02383bfeab444327291b335af@0.0.0.24:32323?discport=32323&ntype=cn"),
    50  			MustParseNode("kni://860a1057975bfd40bde03bdb376b33f290af988f378e6a6a2c78d7fd931ba84a16c9f4af193f77d7b642e5faa7f9333b2e980960b10f04cd915ce47837bb109f@0.0.0.25:32323?discport=32323&ntype=cn"),
    51  			MustParseNode("kni://dee90a411b0746300614041dde915979ff3763e7191414b4ee03ab5ab75ceabfd575cb85b1a033731535beb4a06b67c129df6e7ee7558c8775c8f1cf6fd6c289@0.0.0.26:32323?discport=32323&ntype=cn"),
    52  			MustParseNode("kni://7cf836b7f3518e632b939197fb1836547aa6d751ad48b31b5afb06a85404cd6731d2fcb3b123715c9efef996468fe3d3201b86a1a05d0f767c69ac6495d8b49b@0.0.0.27:32323?discport=32323&ntype=cn"),
    53  			MustParseNode("kni://2416d306b78af7de6f1ffec1e047adced5355d00d027442a247c48c34f5aa1693521dc8fe3b08bc50c7ccfecfc42350e67ccf48e834fda8f8ca42fb0125a2d08@0.0.0.28:32323?discport=32323&ntype=cn"),
    54  			MustParseNode("kni://da4bcb9afda40ef3b23c548387c464d656843640d0be14fd64c487e42c009922dcd3a1a2d7b76e86b8266666c826e9b5f462cddd89eab202336aec7762988cf7@0.0.0.29:32323?discport=32323&ntype=cn"),
    55  		},
    56  		NodeTypePN: {
    57  			MustParseNode("kni://1240e51c2afb39b00983a8b2ccefb6dbc69106573172495fb939c093e1dbf8f2465e0fc6e8d92f4a4392dd3e790b4fefe99644e21593bcc71f1ded132e701cf1@0.0.0.30:32323?discport=32323&ntype=pn"),
    58  			MustParseNode("kni://df9adb43f4f4c9d3ec8916658165af95ab152615917ebdd683fcc9e72bf91b43562ff0292eeb06a5beef643106605b99fda64583ad9367129b18ffd1b2150745@0.0.0.31:32323?discport=32323&ntype=pn"),
    59  			MustParseNode("kni://913e6c1fc9b07e9491449e004533f981930897270aeb662a3699d97fe597744c098741f7507339cdd3a664bdbc2030e0518166634350d662f2193701bf66789d@0.0.0.32:32323?discport=32323&ntype=pn"),
    60  			MustParseNode("kni://9ca4fc863979534d25ea380f090d14b9b06834d8b9dd0a99b5b6bd96490cffbab643a11a57d468969a9aca1e7f5b4e18a021ea96480c2f1c609be932af10f9ca@0.0.0.33:32323?discport=32323&ntype=pn"),
    61  			MustParseNode("kni://4075e26855d5f36c2bc1f8c925015b541a95a8119786058a931a1faa9a29288c82d8eec4a93637ce93245926832054d1f18237a6f12d6964566b1a8b9229955a@0.0.0.34:32323?discport=32323&ntype=pn"),
    62  			MustParseNode("kni://9b919bb71ba339d7085bb2a134c4848822ed3d30874cbf39e990bb6c99dd40e2b476370e81fe477a92d609be5e6e085592fbaa5b171b7b43b41b26478ec87071@0.0.0.35:32323?discport=32323&ntype=pn"),
    63  			MustParseNode("kni://652061a27cfb14000cf3d7cf3e9a1eff345ecfc6926159aa4c113cfac351825f85173747fae780579365cb7ec27563583048be0aa47e0e86bdca22c7bf8e961c@0.0.0.36:32323?discport=32323&ntype=pn"),
    64  			MustParseNode("kni://dd3928a718ead22ba43586fcb552b796534aec09d066a3a966bf1f3baf6cfb02fff9490795388a7c59db796507b3267aa8dbd74ecc42266b0a668b67c0058a66@0.0.0.37:32323?discport=32323&ntype=pn"),
    65  			MustParseNode("kni://3cd62e0d8ab04c1af5bfa843bbb06ef45b88e86373b1851f8876cffdd30442f1d245789416d284b55a97ec8000b420e98ac305bb2f89d99be3822257e23f83e4@0.0.0.38:32323?discport=32323&ntype=pn"),
    66  			MustParseNode("kni://1ae4d5bd01661dc3e12831b5224f5938b71d2e62b00da4f6f2923d273dbcd47512df1861941a394af21827e69f9712820e8fd281ef3f8e8db23af94865f9378e@0.0.0.39:32323?discport=32323&ntype=pn"),
    67  		},
    68  		NodeTypeEN: {
    69  			MustParseNode("kni://7dc47bde51af36d33655e6ddc5e447921fa89a573451ea2f5b19a95de863ea6bf8d9ecb70f58a83b181d8e2a4d2e6552e5cd93b9bb5d6afd89b343c8a1f5e9cb@0.0.0.40:32323?discport=32323&ntype=en"),
    70  			MustParseNode("kni://a9eac3b14f6331a2f37146f32d8f408b9bf55137268c4b5b01bbcd7778d435e0c3b54422cb0b34d09c505bbf4e45b231c59c40a0fe61d1a0b42ecbc4f7e029cc@0.0.0.41:32323?discport=32323&ntype=en"),
    71  			MustParseNode("kni://9bc13d089dd9875c1f3bd5875beed7ba347c2e94c30a3ad2a3dfba5924041d8146d28af61e5f715223eade8852c34959e95d525b6293f8bb4a485d226c3bc8c3@0.0.0.42:32323?discport=32323&ntype=en"),
    72  			MustParseNode("kni://3ab832146617d1c65b0ea9b6c84741899a592a3cc4c9cb932088db35ae22484f32f283c70552d1978e49e3ad2d26c7676e88d8c65bdea1e54e85bdd6cdd8c576@0.0.0.43:32323?discport=32323&ntype=en"),
    73  			MustParseNode("kni://3619dd865d84d0d56f4e2ada241002338216eba72ddc1f5e2fa4fe814afd2823e3470b5818980cfc2af223be63f4087a37bbaa1e7b20ca9b52306da6170fe185@0.0.0.44:32323?discport=32323&ntype=en"),
    74  			MustParseNode("kni://63001c32619da5364b46e7cdb18cac53b90e9b9348674d581a71376c1b09eda637564e3c491c116c8a99c6d4e56c6ee8b45c4e87ed430467a79202cf2de4e9ef@0.0.0.45:32323?discport=32323&ntype=en"),
    75  			MustParseNode("kni://4c3bf139758bea0392f243cb09273894446a7966ddddc434be9d093ba1365535f19251e2f10e3c452b782bb23e7f68e340bbf0109eba9d9ebd4dbefb7288771a@0.0.0.46:32323?discport=32323&ntype=en"),
    76  			MustParseNode("kni://3034d5f70c79bb0bd7b6b7dedf39b2d60f3c75ac5ece83dd23d293cd7d5c68f84c56fa4cbde7eeafb4389d4c9c553e8c0eec14ac6c6ffa9a76ff6225e88406cd@0.0.0.47:32323?discport=32323&ntype=en"),
    77  			MustParseNode("kni://3ba9d852e21065f03d56b0fefc7e91d192d8bd8e4cc154733a6a273771b2074cec7fa612a77f454c8a43709e82e7e359bde86388f133b4eaf197370f839ce160@0.0.0.48:32323?discport=32323&ntype=en"),
    78  			MustParseNode("kni://3837b626353aa94a787bf4b12e6da93aaf6763fc2e825c5a43c5d59255b48a8bb73ed27a35b76171c979b947c167ddaa22eec398ea5a38b58c8027be1b792aca@0.0.0.49:32323?discport=32323&ntype=en"),
    79  		},
    80  		NodeTypeBN: {
    81  			MustParseNode("kni://cea98c8c8bfb04113d217b018f341b49c348a2332eb4a8838e1d3cd1042b78dfc7155b538e9d24ac06f4b43b768f1cd2e7fe02f4e4f90da288c43af691c3b76f@0.0.0.10:32323?discport=32323&ntype=bn"),
    82  			MustParseNode("kni://e95e84d61398a4fc36b901004a7afb223b2761aa3aefaf875c9d119d308ab37a2c21632db51a0109e9d4bd368591ba9a9d814ec0c8ff39e8b5c6f42b74b6c731@0.0.0.11:32323?discport=32323&ntype=bn"),
    83  			MustParseNode("kni://8ec3c47e34a0e6c14ff7a82a16da98c155a57c197c4baefa2b3cebce260b6eb26b60f17d775474f859585ade32ede2c3dc6b916a7266ae10aa09f967546fa708@0.0.0.12:32323?discport=32323&ntype=bn"),
    84  		},
    85  	}
    86  	testStorages = [6]*simpleStorage{
    87  		NodeTypeUnknown: {targetType: NodeTypeUnknown, noDiscover: true, max: 100, nodes: testData[NodeTypeUnknown]},
    88  		NodeTypeCN:      {targetType: NodeTypeCN, noDiscover: true, max: 100, nodes: testData[NodeTypeCN]},
    89  		NodeTypePN:      {targetType: NodeTypePN, noDiscover: true, max: 100, nodes: testData[NodeTypePN]},
    90  		NodeTypeEN:      {targetType: NodeTypeEN, noDiscover: true, max: 100, nodes: testData[NodeTypeEN]},
    91  		NodeTypeBN:      {targetType: NodeTypeBN, noDiscover: true, max: 100, nodes: testData[NodeTypeBN]},
    92  	}
    93  	testNet = &simpleTestnet{
    94  		network: testData,
    95  	}
    96  )
    97  
    98  type simpleTestnet struct {
    99  	network [5][]*Node
   100  }
   101  
   102  func (tn *simpleTestnet) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID, nType NodeType, max int) ([]*Node, error) {
   103  	switch nType {
   104  	case NodeTypeUnknown:
   105  		return testData[NodeTypeUnknown], nil
   106  	case NodeTypeCN:
   107  		return testData[NodeTypeCN], nil
   108  	case NodeTypePN:
   109  		return testData[NodeTypePN], nil
   110  	case NodeTypeEN:
   111  		return testData[NodeTypeEN], nil
   112  	case NodeTypeBN:
   113  		return testData[NodeTypeBN], nil
   114  	default:
   115  		return nil, errors.New("No node type exist")
   116  	}
   117  }
   118  
   119  func (*simpleTestnet) close()                                      {}
   120  func (*simpleTestnet) waitping(from NodeID) error                  { return nil }
   121  func (*simpleTestnet) ping(toid NodeID, toaddr *net.UDPAddr) error { return nil }
   122  
   123  func isIn(candidate *Node, list []*Node) bool {
   124  	for _, node := range list {
   125  		if candidate.CompareNode(node) {
   126  			return true
   127  		}
   128  	}
   129  	return false
   130  }
   131  
   132  func TestShuffle(t *testing.T) {
   133  	testStorages[NodeTypeUnknown].init()
   134  	// shuffle empty list
   135  	empty := testStorages[NodeTypeUnknown].shuffle([]*Node{})
   136  	if len(empty) != 0 {
   137  		t.Errorf("the length of the shuffled empty list. expected: %v, actual: %v\n", 0, len(empty))
   138  	}
   139  
   140  	// shuffle an element list
   141  	oneElement := testStorages[NodeTypeUnknown].shuffle([]*Node{testData[NodeTypeUnknown][0]})
   142  	if len(oneElement) != 1 {
   143  		t.Errorf("the length of shuffled an element list. expected: %v, actual: %v\n", 1, len(oneElement))
   144  	}
   145  	if !oneElement[0].CompareNode(testData[NodeTypeUnknown][0]) {
   146  		t.Errorf("the shuffled result is wrong. expected: %v, acutal: %v\n", testData[NodeTypeUnknown][0].String(), oneElement[0].String())
   147  	}
   148  
   149  	// shuffle the predefined list
   150  	list := testStorages[NodeTypeUnknown].shuffle(testData[NodeTypeUnknown])
   151  	if len(list) != len(testData[NodeTypeUnknown]) {
   152  		t.Errorf("the length of shuffled list is wrong. expected: %v, actual: %v\n", len(testData[NodeTypeUnknown]), len(list))
   153  	}
   154  	isOrderChanged := false
   155  	for idx, shuffled := range list {
   156  		if !testData[NodeTypeUnknown][idx].CompareNode(shuffled) {
   157  			isOrderChanged = true
   158  		}
   159  	}
   160  	if !isOrderChanged {
   161  		t.Error("the order of the list is not changed.")
   162  	}
   163  	for _, shuffled := range list {
   164  		if !isIn(shuffled, testData[NodeTypeUnknown]) {
   165  			t.Errorf("one of the elements does not exist after shuffling. missing: %v\n", shuffled.String())
   166  		}
   167  	}
   168  }
   169  
   170  func TestSimple_lookup(t *testing.T) {
   171  	self := nodeAtDistance(common.Hash{}, 0, NodeTypeUnknown)
   172  	conf := Config{
   173  		udp:        testNet,
   174  		Id:         self.ID,
   175  		Addr:       &net.UDPAddr{},
   176  		Bootnodes:  testData[NodeTypeBN],
   177  		NodeDBPath: "",
   178  		NodeType:   NodeTypeUnknown,
   179  	}
   180  	discv, _ := newTable(&conf)
   181  	tab := discv.(*Table)
   182  
   183  	// lookup on empty table returns no nodes
   184  	typeList := []NodeType{NodeTypeUnknown, NodeTypeCN, NodeTypePN, NodeTypeEN, NodeTypeBN}
   185  	for _, ntype := range typeList {
   186  		storage := &simpleStorage{targetType: ntype, noDiscover: true, max: 100, nodes: testData[ntype]}
   187  		tab.addStorage(ntype, storage)
   188  	}
   189  
   190  	for _, nType := range typeList {
   191  		storage := tab.storages[nType]
   192  		results := storage.lookup(NodeID{}, true, nType) // second parameter is not used
   193  		if len(results) != len(testData[nType]) {
   194  			t.Errorf("the size of lookup result is wrong. expected: %v, actual: %v\n", len(testData[nType]), len(results))
   195  		}
   196  		for _, actual := range results {
   197  			if !isIn(actual, testData[nType]) {
   198  				t.Errorf("the node does not exist in the lookup result. expected: %v", actual)
   199  			}
   200  		}
   201  	}
   202  }
   203  
   204  func TestSimple_doRevalidate(t *testing.T) {
   205  	self := nodeAtDistance(common.Hash{}, 0, NodeTypeUnknown)
   206  	conf := Config{
   207  		udp:        testNet,
   208  		Id:         self.ID,
   209  		Addr:       &net.UDPAddr{},
   210  		Bootnodes:  testData[NodeTypeBN],
   211  		NodeDBPath: "",
   212  		NodeType:   NodeTypeUnknown,
   213  	}
   214  	discv, _ := newTable(&conf)
   215  	tab := discv.(*Table)
   216  	size := len(testData[NodeTypeUnknown])
   217  	candidate := make([]*Node, size)
   218  	copy(candidate, testData[NodeTypeUnknown])
   219  	testStorages[NodeTypeUnknown].nodes = candidate
   220  	tab.addStorage(NodeTypeUnknown, testStorages[NodeTypeUnknown])
   221  
   222  	for idx, node := range testData[NodeTypeUnknown] {
   223  		if !node.CompareNode(candidate[idx]) {
   224  			t.Errorf("copy nodelist is wrong. expected: %v, actual: %v", node, candidate[idx])
   225  		}
   226  	}
   227  
   228  	for i := 1; i < size; i++ {
   229  		testStorages[NodeTypeUnknown].doRevalidate()
   230  		for idx, node := range testData[NodeTypeUnknown] {
   231  			if !node.CompareNode(candidate[(idx+i)%size]) {
   232  				t.Fatalf("the result of doRevalidate is wrong. expected: %v, actual: %v", node, candidate[(idx+1)%size])
   233  			}
   234  		}
   235  	}
   236  }
   237  
   238  func TestSimple_getNodes(t *testing.T) {
   239  	self := nodeAtDistance(common.Hash{}, 0, NodeTypeUnknown)
   240  	conf := Config{
   241  		udp:        testNet,
   242  		Id:         self.ID,
   243  		Addr:       &net.UDPAddr{},
   244  		Bootnodes:  testData[NodeTypeBN],
   245  		NodeDBPath: "",
   246  		NodeType:   NodeTypeUnknown,
   247  	}
   248  	discv, _ := newTable(&conf)
   249  	tab := discv.(*Table)
   250  	nodeTypes := []NodeType{NodeTypeUnknown, NodeTypeCN, NodeTypePN, NodeTypeEN}
   251  	for _, nodeType := range nodeTypes {
   252  		results := tab.GetNodes(nodeType, 1)
   253  		if len(results) != 0 {
   254  			t.Errorf("Returns something although there is nothing. expected: 0, actual: %v", len(results))
   255  		}
   256  	}
   257  	for _, ntype := range nodeTypes {
   258  		storage := &simpleStorage{targetType: ntype, noDiscover: true, max: 100, nodes: testData[ntype]}
   259  		tab.addStorage(ntype, storage)
   260  	}
   261  
   262  	for _, nodeType := range nodeTypes {
   263  		size := len(testData[nodeType])
   264  		for i := 0; i <= 2*size; i++ {
   265  			results := tab.GetNodes(nodeType, i)
   266  			if i <= size {
   267  				if len(results) != i {
   268  					t.Errorf("the length of getNodes is wrong. expected: %v, acutal: %v", i, len(results))
   269  				}
   270  				for _, node := range results {
   271  					if !isIn(node, testData[nodeType]) {
   272  						t.Errorf("the result does not exist in the test data. wrong output: %v", node)
   273  					}
   274  				}
   275  			} else {
   276  				if len(results) != size {
   277  					t.Errorf("the length of getNodes is wrong. expected: %v, acutal: %v", i, len(results))
   278  				}
   279  				for _, node := range results {
   280  					if !isIn(node, testData[nodeType]) {
   281  						t.Errorf("the result does not exist in the test data. wrong output: %v", node)
   282  					}
   283  				}
   284  			}
   285  			// Post processing in order to bond each node again
   286  			for _, node := range results {
   287  				tab.db.deleteNode(node.ID)
   288  			}
   289  		}
   290  	}
   291  }
   292  
   293  func TestSimple_closest(t *testing.T) {
   294  	typeList := []NodeType{NodeTypeUnknown, NodeTypeCN, NodeTypePN, NodeTypeEN}
   295  	for _, ntype := range typeList {
   296  		var target NodeID
   297  		rand.Read(target[:])
   298  		hash := crypto.Keccak256Hash(target[:]) // randome target hash
   299  		storage := testStorages[ntype]
   300  		storage.init()
   301  		storage.max = 5
   302  		results := storage.closest(hash, rand2.Int()) // second parameter is not used
   303  		if len(results.entries) != 5 {
   304  			t.Errorf("the length of the results.entries is wrong. expected: %v, actual: %v", 5, len(results.entries))
   305  		}
   306  		for _, node := range results.entries {
   307  			if !isIn(node, storage.nodes) {
   308  				t.Errorf("node does not exist in the storage. unknown node: %v", node)
   309  			}
   310  		}
   311  		storage.max = 50
   312  		results = storage.closest(hash, rand2.Int())
   313  		if len(results.entries) != 10 {
   314  			t.Errorf("the length of the results.entries is wrong. expected: %v, actual: %v", 10, len(results.entries))
   315  		}
   316  		for _, node := range results.entries {
   317  			if !isIn(node, storage.nodes) {
   318  				t.Errorf("node does not exist in the storage. unknown node: %v", node)
   319  			}
   320  		}
   321  	}
   322  }