def test_whenNodeRestarts_andNodeHasLessThanTwoOutgoingConnections_andElevenSecondsElapsed_receivesIPsFromSeeder(self): # patch MAX_OUTGOING instances in network.py so our node doesnt make any connections self.nodePeer.learnIP(self.nodePeer2.ipV4Addr, self.sourceIP) self.nodePeer.addToTried(self.nodePeer2.ipV4Addr, 0) restartEvent = event(srcNode=self.nodePeer, destNode=None, eventType=RESTART, info=None) self.network.eventQueue.put((0, restartEvent)) # process RESTART event self.network.processNextEvent() # get time of REJOIN, place back in eventQueue rejoinTime, rejoinEvent = self.network.eventQueue.get() self.assertEqual(rejoinEvent.eventType, REJOIN) self.network.eventQueue.put((rejoinTime, rejoinEvent)) # process REJOIN, AFTER_REJOIN_MAYBE_REQUEST_SEEDER events self.network.processNextEvent() self.network.processNextEvent() nextTime, nextEvent = self.network.eventQueue.get() # assert seeder request more than 11 seconds from rejoin event self.assertTrue(rejoinTime + 11 <= nextTime) # assert correct nodes involved in REQUEST_CONNECTION_INFO event self.assertEqual(nextEvent.srcNode, self.nodePeer) self.assertTrue(nextEvent.destNode in self.network.seederNodes) self.assertEqual(nextEvent.eventType, REQUEST_CONNECTION_INFO)
def test_whenConnectSuccessToPeer_peerAddressInsertedIntoTried(self): # generate node with space for at least 1 new connection self.sourceIP = self.network.assignIP() for ip in [ self.network.assignIP() for i in range(MAX_OUTGOING - random.randint(1, MAX_OUTGOING)) ]: self.nodePeer.outgoingCnxs.append(ip) self.nodePeer.learnIP(ip, self.sourceIP) # communicating nodes have heard of each other before self.nodePeer.learnIP(self.nodePeer2.ipV4Addr, self.sourceIP) self.nodePeer2.learnIP(self.nodePeer.ipV4Addr, self.sourceIP) # add CONNECT event to network.eventQueue as only existing event connectEvent = event(srcNode=self.nodePeer, destNode=self.nodePeer2, eventType=CONNECT, info=None) self.network.eventQueue.put((self.network.globalTime, connectEvent)) # collect data, process event, collect data peerIP = self.nodePeer2.ipV4Addr bucket = self.nodePeer.mapToTriedBucket(peerIP) isPeerInTriedTableBefore = (peerIP in self.nodePeer.triedTable[bucket]) self.network.processNextEvent() isPeerInTriedTableAfter = (peerIP in self.nodePeer.triedTable[bucket]) # assert data correct self.assertFalse(isPeerInTriedTableBefore) self.assertTrue(isPeerInTriedTableAfter)
def test_whenConnectSuccessToPeer_peerAddressInsertedIntoTried(self): # generate node with space for at least 1 new connection self.sourceIP = self.network.assignIP() for ip in [self.network.assignIP() for i in range(MAX_OUTGOING - random.randint(1, MAX_OUTGOING))]: self.nodePeer.outgoingCnxs.append(ip) self.nodePeer.learnIP(ip, self.sourceIP) # communicating nodes have heard of each other before self.nodePeer.learnIP(self.nodePeer2.ipV4Addr, self.sourceIP) self.nodePeer2.learnIP(self.nodePeer.ipV4Addr, self.sourceIP) # add CONNECT event to network.eventQueue as only existing event connectEvent = event(srcNode=self.nodePeer, destNode=self.nodePeer2, eventType=CONNECT, info=None) self.network.eventQueue.put((self.network.globalTime, connectEvent)) # collect data, process event, collect data peerIP = self.nodePeer2.ipV4Addr bucket = self.nodePeer.mapToTriedBucket(peerIP) isPeerInTriedTableBefore = (peerIP in self.nodePeer.triedTable[bucket]) self.network.processNextEvent() isPeerInTriedTableAfter = (peerIP in self.nodePeer.triedTable[bucket]) # assert data correct self.assertFalse(isPeerInTriedTableBefore) self.assertTrue(isPeerInTriedTableAfter)
def test_whenAddressFromDnsSeeder_onlyAddedToNewTable(self): ip = self.network.assignIP() self.nodePeer2.ipV4Addr = ip self.network.ipToNodes[ip] = self.nodePeer2 self.nodePeer.nonce = 'some nonce' # fill nodePeer's outgoing connection to force ip into new table for i in range(MAX_OUTGOING): outIp = self.network.assignIP() self.nodePeer.outgoingCnxs.append(outIp) connectionInfoEvent = event(srcNode=self.seederNode, destNode=self.nodePeer, eventType=CONNECTION_INFO, info=(DNS_MSG, [ip])) self.network.eventQueue.put((self.network.globalTime, connectionInfoEvent)) self.nodePeer.learnIP(ip, self.seederNode.ipV4Addr) # run code (CONNECTION_INFO, and CONNECT) self.network.processNextEvent() # verify ip appears in new table and not tried table foundInNew = False for bucketNum, addressDictionary in enumerate(self.nodePeer.newTable): if ip in addressDictionary.keys(): foundInNew = True foundInTried = False for bucketNum, addressDictionary in enumerate(self.nodePeer.triedTable): if ip in addressDictionary.keys(): foundInTried = True self.assertTrue(foundInNew) self.assertFalse(foundInTried)
def test_whenNodeRestarts_andNodeHasLessThanTwoOutgoingConnections_andElevenSecondsElapsed_receivesIPsFromSeeder( self): # patch MAX_OUTGOING instances in network.py so our node doesnt make any connections self.nodePeer.learnIP(self.nodePeer2.ipV4Addr, self.sourceIP) self.nodePeer.addToTried(self.nodePeer2.ipV4Addr, 0) restartEvent = event(srcNode=self.nodePeer, destNode=None, eventType=RESTART, info=None) self.network.eventQueue.put((0, restartEvent)) # process RESTART event self.network.processNextEvent() # get time of REJOIN, place back in eventQueue rejoinTime, rejoinEvent = self.network.eventQueue.get() self.assertEqual(rejoinEvent.eventType, REJOIN) self.network.eventQueue.put((rejoinTime, rejoinEvent)) # process REJOIN, AFTER_REJOIN_MAYBE_REQUEST_SEEDER events self.network.processNextEvent() self.network.processNextEvent() nextTime, nextEvent = self.network.eventQueue.get() # assert seeder request more than 11 seconds from rejoin event self.assertTrue(rejoinTime + 11 <= nextTime) # assert correct nodes involved in REQUEST_CONNECTION_INFO event self.assertEqual(nextEvent.srcNode, self.nodePeer) self.assertTrue(nextEvent.destNode in self.network.seederNodes) self.assertEqual(nextEvent.eventType, REQUEST_CONNECTION_INFO)
def test_whenOutgoingConnectionEstablishedWithPeer_receiveAddrMsgFromPeer(self): # prepare nodes for CONNECT self.nodePeer.learnIP(self.nodePeer2.ipV4Addr, self.sourceIP) self.nodePeer2.learnIP(self.nodePeer.ipV4Addr, self.sourceIP) # populate nodePeer2's tables with some IPs (that will be sent in ADDR) someIPs = [self.network.assignIP() for _ in range(100)] for ip in someIPs[:50]: self.nodePeer2.learnIP(ip, self.sourceIP) self.nodePeer2.addToTried(ip, 0) for ip in someIPs[50:]: self.nodePeer2.learnIP(ip, self.sourceIP) self.nodePeer2.addToNew(ip, 0) # prepare eventQueue connectEvent = event(srcNode=self.nodePeer, destNode=self.nodePeer2, eventType=CONNECT, info=None) self.network.eventQueue.put((self.network.globalTime, connectEvent)) # process CONNECT event self.network.processNextEvent() # assert generated event is ADDR between correct nodes nextTime, nextEvent = self.network.eventQueue.get() self.assertEqual(nextEvent.eventType, CONNECTION_INFO) self.assertEqual(nextEvent.srcNode, self.nodePeer2) self.assertEqual(nextEvent.destNode, self.nodePeer) self.assertEqual(nextEvent.info[0], ADDR_MSG) # assert sent IPs come from nodePeer2's tables flattenedIPs = [] for bucket in self.nodePeer2.triedTable: flattenedIPs.extend(bucket.keys()) for bucket in self.nodePeer2.newTable: flattenedIPs.extend(bucket.keys()) [self.assertTrue(ip in flattenedIPs) for ip in nextEvent.info[1]]
def test_whenNodeMakesOutgoingConnectionRequest_doesNotExceedMaxOutgoingConnections(self): # generate node with max outgoing connections for ip in [self.network.assignIP() for i in range(MAX_OUTGOING)]: self.nodePeer.outgoingCnxs.append(ip) self.nodePeer.learnIP(ip, self.sourceIP) # communicating nodes have heard of each other before self.nodePeer.learnIP(self.nodePeer2.ipV4Addr, self.sourceIP) self.nodePeer2.learnIP(self.nodePeer.ipV4Addr, self.sourceIP) # add CONNECT event to network.eventQueue as only existing event connectEvent = event(srcNode=self.nodePeer, destNode=self.nodePeer2, eventType=CONNECT, info=None) self.network.eventQueue.put((self.network.globalTime, connectEvent)) # mock eventQueue.put from here forward so we can monitor when it is called self.network.eventQueue.put = mock.Mock() # mock randomness out latency = 0.1 self.network.generateLatency = mock.Mock(return_value=latency) # collect data, process event, collect data numConnectionsBefore = len(self.nodePeer.outgoingCnxs) self.network.processNextEvent() numConnectionsAfter = len(self.nodePeer.outgoingCnxs) # assert data correct and monitored method called as expected self.assertEqual(numConnectionsBefore, numConnectionsAfter) self.network.eventQueue.put.assert_called_once_with((self.network.globalTime+latency, event(srcNode=self.nodePeer2, destNode=self.nodePeer, eventType=CONNECTION_FAILURE, info=None)))
def test_whenBlacklistedNodeAttemptsToConnect_ignoreIt( self, mock_node_selectAddrs): # patch node.selectAddrs() to return too many addresses such that another node will blacklist it tooManyIPs = [[ self.network.assignIP() for _ in range(MAX_ADDRS_PER_MSG + 1) ]] mock_node_selectAddrs.return_value = tooManyIPs # take measurements before totalConnectionsBefore1 = sum(self.nodePeer.incomingCnxs) + sum( self.nodePeer.outgoingCnxs) totalConnectionsBefore2 = sum(self.nodePeer2.incomingCnxs) + sum( self.nodePeer2.outgoingCnxs) newTableSizeBefore = sum([len(b) for b in self.nodePeer.newTable]) triedTableSizeBefore = sum([len(b) for b in self.nodePeer.triedTable]) # prepare nodes for CONNECT self.nodePeer.learnIP(self.nodePeer2.ipV4Addr, self.sourceIP) self.nodePeer2.learnIP(self.nodePeer.ipV4Addr, self.sourceIP) # prepare eventQueue connectEvent = event(srcNode=self.nodePeer, destNode=self.nodePeer2, eventType=CONNECT, info=None) self.network.eventQueue.put((self.network.globalTime, connectEvent)) # process CONNECT, CONNECTION_INFO events self.network.processNextEvent() self.network.processNextEvent() # assert ip is blacklisted self.assertTrue( self.nodePeer2.ipV4Addr in self.nodePeer.blacklistedIPs) # assert no connections kept totalConnectionsAfter1 = sum(self.nodePeer.incomingCnxs) + sum( self.nodePeer.outgoingCnxs) totalConnectionsAfter2 = sum(self.nodePeer2.incomingCnxs) + sum( self.nodePeer2.outgoingCnxs) self.assertEqual(totalConnectionsBefore1, totalConnectionsAfter1) self.assertEqual(totalConnectionsBefore2, totalConnectionsAfter2) # assert nothing was added to new table newTableSizeAfter = sum([len(b) for b in self.nodePeer.newTable]) triedTableSizeAfter = sum([len(b) for b in self.nodePeer.triedTable]) self.assertEqual(newTableSizeBefore, newTableSizeAfter) self.assertEqual(triedTableSizeBefore + 1, triedTableSizeAfter) # assert nodePeer's tried table only contains blacklisted ip flattenedIPs = [] for bucket in self.nodePeer.triedTable: flattenedIPs.extend(bucket.keys()) self.assertEqual(len(flattenedIPs), 1) self.assertTrue(self.nodePeer2.ipV4Addr in flattenedIPs)
def test_whenNodeJoinsNetwork_andSeederFailsToReply_usesHardcodedIPs(self): # patch constant SEEDER_REPLY_FAIL_RATE so we automatically decide seeder will timeout joinEvent = event(srcNode=self.nodePeer, destNode=None, eventType=JOIN, info=None) self.network.eventQueue.put((0, joinEvent)) newTableSizeBefore = sum([len(b) for b in self.nodePeer.newTable]) triedTableSizeBefore = sum([len(b) for b in self.nodePeer.triedTable]) # process JOIN self.network.processNextEvent() # remove RESTART event time1, event1 = self.network.eventQueue.get() time2, event2 = self.network.eventQueue.get() if event1.eventType == REQUEST_CONNECTION_INFO: self.network.eventQueue.put((time1, event1)) else: self.network.eventQueue.put((time2, event2)) # process REQUEST_CONNECTION_INFO and USE_HARDCODED_IPS events self.network.processNextEvent() self.network.processNextEvent() newTableSizeAfter = sum([len(b) for b in self.nodePeer.newTable]) triedTableSizeAfter = sum([len(b) for b in self.nodePeer.triedTable]) # assert all IPs in new table from HARDCODED_IP_SOURCE and network's hardcoded ip list for ip in self.nodePeer.ipToAddr.keys(): sourceIP = self.nodePeer.ipToAddr[ip].sourceIP self.assertEqual(sourceIP, HARDCODED_IP_SOURCE) self.assertTrue(ip in self.network.hardcodedIPs) self.assertEqual(newTableSizeBefore + len(self.network.hardcodedIPs), newTableSizeAfter) # assert tried table remains empty self.assertEqual(triedTableSizeBefore, 0) self.assertEqual(triedTableSizeAfter, 0) # assert MAX_OUTGOING connect events in eventQueue, all with source nodePeer, dest ip in hardcoded_list self.assertEqual(self.network.eventQueue.qsize(), MAX_OUTGOING) for i in range(MAX_OUTGOING): timestamp, thisEvent = self.network.eventQueue.get() self.assertEqual(thisEvent.eventType, CONNECT) self.assertEqual(thisEvent.srcNode, self.nodePeer) self.assertTrue( thisEvent.destNode.ipV4Addr in self.network.hardcodedIPs)
def test_whenNodeReceivesIncomingConnectionRequest_doesNotExceedMaxIncomingConnections_andGeneratesConnectionFailureEvent( self): # generate node with max incoming connections for ip in [self.network.assignIP() for i in range(MAX_INCOMING)]: self.nodePeer.incomingCnxs.append(ip) self.nodePeer.learnIP(ip, self.sourceIP) # communicating nodes have heard of each other before self.nodePeer.learnIP(self.nodePeer2.ipV4Addr, self.sourceIP) self.nodePeer2.learnIP(self.nodePeer.ipV4Addr, self.sourceIP) # add CONNECT event to network.eventQueue as only existing event connectEvent = event(srcNode=self.nodePeer2, destNode=self.nodePeer, eventType=CONNECT, info=None) self.network.eventQueue.put((self.network.globalTime, connectEvent)) # mock eventQueue.put from here forward so we can monitor when it is called self.network.eventQueue.put = mock.Mock() # mock randomness out latency = 0.1 self.network.generateLatency = mock.Mock(return_value=latency) # collect data, process event, collect data numConnectionsBefore = len(self.nodePeer.incomingCnxs) self.network.processNextEvent() numConnectionsAfter = len(self.nodePeer.incomingCnxs) # assert data correct and monitored method called as expected self.assertEqual(numConnectionsBefore, numConnectionsAfter) self.network.eventQueue.put.assert_called_once_with( (self.network.globalTime + latency, event(srcNode=self.nodePeer, destNode=self.nodePeer2, eventType=CONNECTION_FAILURE, info=None)))
def test_whenNodeJoinsNetwork_andSeederFailsToReply_usesHardcodedIPs(self): # patch constant SEEDER_REPLY_FAIL_RATE so we automatically decide seeder will timeout joinEvent = event(srcNode=self.nodePeer, destNode=None, eventType=JOIN, info=None) self.network.eventQueue.put((0, joinEvent)) newTableSizeBefore = sum([len(b) for b in self.nodePeer.newTable]) triedTableSizeBefore = sum([len(b) for b in self.nodePeer.triedTable]) # process JOIN self.network.processNextEvent() # remove RESTART event time1, event1 = self.network.eventQueue.get() time2, event2 = self.network.eventQueue.get() if event1.eventType == REQUEST_CONNECTION_INFO: self.network.eventQueue.put((time1, event1)) else: self.network.eventQueue.put((time2, event2)) # process REQUEST_CONNECTION_INFO and USE_HARDCODED_IPS events self.network.processNextEvent() self.network.processNextEvent() newTableSizeAfter = sum([len(b) for b in self.nodePeer.newTable]) triedTableSizeAfter = sum([len(b) for b in self.nodePeer.triedTable]) # assert all IPs in new table from HARDCODED_IP_SOURCE and network's hardcoded ip list for ip in self.nodePeer.ipToAddr.keys(): sourceIP = self.nodePeer.ipToAddr[ip].sourceIP self.assertEqual(sourceIP, HARDCODED_IP_SOURCE) self.assertTrue(ip in self.network.hardcodedIPs) self.assertEqual(newTableSizeBefore + len(self.network.hardcodedIPs), newTableSizeAfter) # assert tried table remains empty self.assertEqual(triedTableSizeBefore, 0) self.assertEqual(triedTableSizeAfter, 0) # assert MAX_OUTGOING connect events in eventQueue, all with source nodePeer, dest ip in hardcoded_list self.assertEqual(self.network.eventQueue.qsize(), MAX_OUTGOING) for i in range(MAX_OUTGOING): timestamp, thisEvent = self.network.eventQueue.get() self.assertEqual(thisEvent.eventType, CONNECT) self.assertEqual(thisEvent.srcNode, self.nodePeer) self.assertTrue(thisEvent.destNode.ipV4Addr in self.network.hardcodedIPs)
def test_whenBlacklistedNodeAttemptsToConnect_ignoreIt(self, mock_node_selectAddrs): # patch node.selectAddrs() to return too many addresses such that another node will blacklist it tooManyIPs = [[self.network.assignIP() for _ in range(MAX_ADDRS_PER_MSG+1)]] mock_node_selectAddrs.return_value = tooManyIPs # take measurements before totalConnectionsBefore1 = sum(self.nodePeer.incomingCnxs) + sum(self.nodePeer.outgoingCnxs) totalConnectionsBefore2 = sum(self.nodePeer2.incomingCnxs) + sum(self.nodePeer2.outgoingCnxs) newTableSizeBefore = sum([len(b) for b in self.nodePeer.newTable]) triedTableSizeBefore = sum([len(b) for b in self.nodePeer.triedTable]) # prepare nodes for CONNECT self.nodePeer.learnIP(self.nodePeer2.ipV4Addr, self.sourceIP) self.nodePeer2.learnIP(self.nodePeer.ipV4Addr, self.sourceIP) # prepare eventQueue connectEvent = event(srcNode=self.nodePeer, destNode=self.nodePeer2, eventType=CONNECT, info=None) self.network.eventQueue.put((self.network.globalTime, connectEvent)) # process CONNECT, CONNECTION_INFO events self.network.processNextEvent() self.network.processNextEvent() # assert ip is blacklisted self.assertTrue(self.nodePeer2.ipV4Addr in self.nodePeer.blacklistedIPs) # assert no connections kept totalConnectionsAfter1 = sum(self.nodePeer.incomingCnxs) + sum(self.nodePeer.outgoingCnxs) totalConnectionsAfter2 = sum(self.nodePeer2.incomingCnxs) + sum(self.nodePeer2.outgoingCnxs) self.assertEqual(totalConnectionsBefore1, totalConnectionsAfter1) self.assertEqual(totalConnectionsBefore2, totalConnectionsAfter2) # assert nothing was added to new table newTableSizeAfter = sum([len(b) for b in self.nodePeer.newTable]) triedTableSizeAfter = sum([len(b) for b in self.nodePeer.triedTable]) self.assertEqual(newTableSizeBefore, newTableSizeAfter) self.assertEqual(triedTableSizeBefore + 1, triedTableSizeAfter) # assert nodePeer's tried table only contains blacklisted ip flattenedIPs = [] for bucket in self.nodePeer.triedTable: flattenedIPs.extend(bucket.keys()) self.assertEqual(len(flattenedIPs), 1) self.assertTrue(self.nodePeer2.ipV4Addr in flattenedIPs)
def test_whenSelectingBucket_useSchemeFromPaper(self): ip = self.network.assignIP() self.nodePeer2.ipV4Addr = ip self.network.ipToNodes[ip] = self.nodePeer2 self.nodePeer.nonce = 'some nonce' # fill nodePeer's outgoing connection to force ip into new table for i in range(MAX_OUTGOING): outIp = self.network.assignIP() self.nodePeer.outgoingCnxs.append(outIp) connectionInfoEvent = event(srcNode=self.seederNode, destNode=self.nodePeer, eventType=CONNECTION_INFO, info=(DNS_MSG, [ip])) self.network.eventQueue.put( (self.network.globalTime, connectionInfoEvent)) self.nodePeer.learnIP(ip, self.seederNode.ipV4Addr) sourceIp = self.nodePeer.ipToAddr[ip].sourceIP # compute bucket manually ipTemp = ip.split('.') ipGroup = ipTemp[0] + '.' + ipTemp[1] sourceTemp = sourceIp.split('.') srcIPGroup = sourceTemp[0] + '.' + sourceTemp[1] nonce = str(self.nodePeer.nonce) i = hash(nonce + ipGroup + srcIPGroup) % 32 expectedBucket = hash(nonce + srcIPGroup + str(i)) % 256 # run code self.network.processNextEvent() # verify bucket actualBucket = [] for bucketNum, addressDictionary in enumerate(self.nodePeer.newTable): if ip in addressDictionary.keys(): actualBucket.append(bucketNum) self.assertEqual(len(actualBucket), 1) self.assertEqual(actualBucket[0], expectedBucket)
def test_whenNodeJoinsNetwork_receivesIPsFromSeeder(self): # patch constant SEEDER_REPLY_FAIL_RATE so we automatically decide seeder does not timeout joinEvent = event(srcNode=self.nodePeer, destNode=None, eventType=JOIN, info=None) self.network.eventQueue.put((0, joinEvent)) newTableSizeBefore = sum([len(b) for b in self.nodePeer.newTable]) triedTableSizeBefore = sum([len(b) for b in self.nodePeer.triedTable]) # process JOIN self.network.processNextEvent() # get a hold of seeder node, place event back in eventQueue eventTime, reqConInfoEvent = self.network.eventQueue.get() self.assertEquals(reqConInfoEvent.eventType, REQUEST_CONNECTION_INFO) self.seederNode = reqConInfoEvent.destNode self.network.eventQueue.put((eventTime, reqConInfoEvent)) # process REQUEST_CONNECTION_INFO and CONNECTION_INFO self.network.processNextEvent() self.network.processNextEvent() newTableSizeAfter = sum([len(b) for b in self.nodePeer.newTable]) triedTableSizeAfter = sum([len(b) for b in self.nodePeer.triedTable]) # assert all new table entries from seeder for ip in self.nodePeer.ipToAddr.keys(): sourceIP = self.nodePeer.ipToAddr[ip].sourceIP self.assertEqual(sourceIP, self.seederNode.ipV4Addr) self.assertTrue(ip in self.seederNode.knownIPs) self.assertEqual(newTableSizeBefore + DNS_QUERY_SIZE, newTableSizeAfter) # assert tried table remains empty self.assertEqual(triedTableSizeBefore, 0) self.assertEqual(triedTableSizeAfter, 0)
def test_whenSelectingBucket_useSchemeFromPaper(self): ip = self.network.assignIP() self.nodePeer2.ipV4Addr = ip self.network.ipToNodes[ip] = self.nodePeer2 self.nodePeer.nonce = 'some nonce' # fill nodePeer's outgoing connection to force ip into new table for i in range(MAX_OUTGOING): outIp = self.network.assignIP() self.nodePeer.outgoingCnxs.append(outIp) connectionInfoEvent = event(srcNode=self.seederNode, destNode=self.nodePeer, eventType=CONNECTION_INFO, info=(DNS_MSG, [ip])) self.network.eventQueue.put((self.network.globalTime, connectionInfoEvent)) self.nodePeer.learnIP(ip, self.seederNode.ipV4Addr) sourceIp = self.nodePeer.ipToAddr[ip].sourceIP # compute bucket manually ipTemp = ip.split('.') ipGroup = ipTemp[0] + '.' + ipTemp[1] sourceTemp = sourceIp.split('.') srcIPGroup = sourceTemp[0] + '.' + sourceTemp[1] nonce = str(self.nodePeer.nonce) i = hash(nonce + ipGroup + srcIPGroup) % 32 expectedBucket = hash(nonce + srcIPGroup + str(i)) % 256 # run code self.network.processNextEvent() # verify bucket actualBucket = [] for bucketNum, addressDictionary in enumerate(self.nodePeer.newTable): if ip in addressDictionary.keys(): actualBucket.append(bucketNum) self.assertEqual(len(actualBucket), 1) self.assertEqual(actualBucket[0], expectedBucket)
def test_whenOutgoingConnectionEstablishedWithPeer_receiveAddrMsgFromPeer( self): # prepare nodes for CONNECT self.nodePeer.learnIP(self.nodePeer2.ipV4Addr, self.sourceIP) self.nodePeer2.learnIP(self.nodePeer.ipV4Addr, self.sourceIP) # populate nodePeer2's tables with some IPs (that will be sent in ADDR) someIPs = [self.network.assignIP() for _ in range(100)] for ip in someIPs[:50]: self.nodePeer2.learnIP(ip, self.sourceIP) self.nodePeer2.addToTried(ip, 0) for ip in someIPs[50:]: self.nodePeer2.learnIP(ip, self.sourceIP) self.nodePeer2.addToNew(ip, 0) # prepare eventQueue connectEvent = event(srcNode=self.nodePeer, destNode=self.nodePeer2, eventType=CONNECT, info=None) self.network.eventQueue.put((self.network.globalTime, connectEvent)) # process CONNECT event self.network.processNextEvent() # assert generated event is ADDR between correct nodes nextTime, nextEvent = self.network.eventQueue.get() self.assertEqual(nextEvent.eventType, CONNECTION_INFO) self.assertEqual(nextEvent.srcNode, self.nodePeer2) self.assertEqual(nextEvent.destNode, self.nodePeer) self.assertEqual(nextEvent.info[0], ADDR_MSG) # assert sent IPs come from nodePeer2's tables flattenedIPs = [] for bucket in self.nodePeer2.triedTable: flattenedIPs.extend(bucket.keys()) for bucket in self.nodePeer2.newTable: flattenedIPs.extend(bucket.keys()) [self.assertTrue(ip in flattenedIPs) for ip in nextEvent.info[1]]
def test_whenAddressFromDnsSeeder_onlyAddedToNewTable(self): ip = self.network.assignIP() self.nodePeer2.ipV4Addr = ip self.network.ipToNodes[ip] = self.nodePeer2 self.nodePeer.nonce = 'some nonce' # fill nodePeer's outgoing connection to force ip into new table for i in range(MAX_OUTGOING): outIp = self.network.assignIP() self.nodePeer.outgoingCnxs.append(outIp) connectionInfoEvent = event(srcNode=self.seederNode, destNode=self.nodePeer, eventType=CONNECTION_INFO, info=(DNS_MSG, [ip])) self.network.eventQueue.put( (self.network.globalTime, connectionInfoEvent)) self.nodePeer.learnIP(ip, self.seederNode.ipV4Addr) # run code (CONNECTION_INFO, and CONNECT) self.network.processNextEvent() # verify ip appears in new table and not tried table foundInNew = False for bucketNum, addressDictionary in enumerate(self.nodePeer.newTable): if ip in addressDictionary.keys(): foundInNew = True foundInTried = False for bucketNum, addressDictionary in enumerate( self.nodePeer.triedTable): if ip in addressDictionary.keys(): foundInTried = True self.assertTrue(foundInNew) self.assertFalse(foundInTried)
def test_whenNodeJoinsNetwork_receivesIPsFromSeeder(self): # patch constant SEEDER_REPLY_FAIL_RATE so we automatically decide seeder does not timeout joinEvent = event(srcNode = self.nodePeer, destNode = None, eventType = JOIN, info = None) self.network.eventQueue.put((0, joinEvent)) newTableSizeBefore = sum([len(b) for b in self.nodePeer.newTable]) triedTableSizeBefore = sum([len(b) for b in self.nodePeer.triedTable]) # process JOIN self.network.processNextEvent() # get a hold of seeder node, place event back in eventQueue eventTime, reqConInfoEvent = self.network.eventQueue.get() self.assertEquals(reqConInfoEvent.eventType, REQUEST_CONNECTION_INFO) self.seederNode = reqConInfoEvent.destNode self.network.eventQueue.put((eventTime, reqConInfoEvent)) # process REQUEST_CONNECTION_INFO and CONNECTION_INFO self.network.processNextEvent() self.network.processNextEvent() newTableSizeAfter = sum([len(b) for b in self.nodePeer.newTable]) triedTableSizeAfter = sum([len(b) for b in self.nodePeer.triedTable]) # assert all new table entries from seeder for ip in self.nodePeer.ipToAddr.keys(): sourceIP = self.nodePeer.ipToAddr[ip].sourceIP self.assertEqual(sourceIP, self.seederNode.ipV4Addr) self.assertTrue(ip in self.seederNode.knownIPs) self.assertEqual(newTableSizeBefore + DNS_QUERY_SIZE, newTableSizeAfter) # assert tried table remains empty self.assertEqual(triedTableSizeBefore, 0) self.assertEqual(triedTableSizeAfter, 0)