from dht_common import compute_document_ID, SIZE_OF_HASH, SIZE_OF_IP_ADDRESS, SIZE_OF_KEY, SIZE_OF_SIGNATURE, SIZE_OF_TIMESTAMP from base_client import Base_Client from random import Random class RCP_Client(Base_Client): def __init__(self, DHT, knownQuorum, documentSize, numNodes): Base_Client.__init__(self, DHT, knownQuorum, documentSize) self.numNodes = numNodes self.cryptogen = Random(self.DHT.access_node(knownQuorum).nodeID) # Needs to be here to use new iterative search def test_iterative_search(self): if self.DHT.get_num_nodes() == 10: return self.__iterative_search__(b'\xb5\xe0\xf4\xd8\xe9\x1e\xf6i\xc4=^\xc2Y\xac\xdc\x88p\x8a+\x10t\x90\xa5\xc9\x1f\x98\xc61\xda\x7fH\x92') == 7 else: print("Assumed testing conditions not met; no tests run.") return False def __iterative_search_prelude__(self, documentID): whichQuorum = self.knownNode [self.DHT.access_node(whichQuorum).get_first_auth(whichNode) for whichNode in range(self.numNodes)] # Asker's ID sizeOfRequest = SIZE_OF_HASH # timestamp sizeOfRequest += SIZE_OF_TIMESTAMP # response is just the whole thing signed sizeOfResponse = sizeOfRequest + SIZE_OF_SIGNATURE self.numRounds += 1 self.numMessagesSent += self.numNodes - 1 self.numMessagesRecv += self.numNodes - 1 self.numBytesSent += (self.numNodes - 1) * sizeOfRequest self.numBytesRecv += (self.numNodes - 1) * sizeOfResponse options = [x for (x,y) in self.actualNodeEntry.table.items() if x <= documentID] closest = max(options) if len(options) > 0 else max([x for (x,y) in self.actualNodeEntry.table.items()]) whichQuorum = self.actualNodeEntry.table[closest] # This group's key is the only one to start, numKeys = 1 # and the group signature from the first authorization is there numSignatures = 1 return whichQuorum, numKeys, numSignatures # implements a simulation of iteratively searching the DHT (captured as the dht_simulator, or here "DHT") # main change from base_client is the inclusion of keys and signatures def __iterative_search__(self, documentID): whichQuorum, numKeys, numSignatures = self.__iterative_search_prelude__(documentID) flagFound = False while not flagFound: randomNode = self.cryptogen.randrange(self.numNodes) recv = self.DHT.access_node(whichQuorum).get_finger_table_val(randomNode, documentID, numKeys, numSignatures) # key of previous group sizeOfResponse = SIZE_OF_KEY # next groups ID/routing information sizeOfResponse += SIZE_OF_IP_ADDRESS * self.numNodes + SIZE_OF_HASH # key of next group sizeOfResponse += SIZE_OF_KEY # sign the whole thing sizeOfResponse += SIZE_OF_SIGNATURE # Asker's ID sizeOfRequest = SIZE_OF_HASH # timestamp sizeOfRequest += SIZE_OF_TIMESTAMP # Keys in request sizeOfRequest += SIZE_OF_KEY * numKeys # signatures in request sizeOfRequest += SIZE_OF_SIGNATURE * numSignatures # ID being searched for sizeOfRequest += SIZE_OF_HASH self.numRounds += 1 self.numMessagesSent += 1 self.numMessagesRecv += 1 self.numBytesSent += sizeOfRequest self.numBytesRecv += sizeOfResponse _, nextFind = recv if nextFind == -1: flagFound = True else: whichQuorum = nextFind numKeys += 1 numSignatures += 1 return whichQuorum, numKeys, numSignatures # Needs to be here to use new iterative search def insert_file(self, document): documentID = compute_document_ID(document) whichQuorum, numKeys, numSignatures = self.__iterative_search__(documentID) self.DHT.access_node(whichQuorum).insert(numKeys, numSignatures) # Asker's ID sizeOfRequest = SIZE_OF_HASH # timestamp sizeOfRequest += SIZE_OF_TIMESTAMP # keys in request sizeOfRequest += SIZE_OF_KEY * numKeys # signatures in request sizeOfRequest += SIZE_OF_SIGNATURE * numSignatures # actual document sent sizeOfRequest += self.documentSize # signature over whole thing sizeOfRequest += SIZE_OF_SIGNATURE sizeOfResponse = SIZE_OF_HASH + SIZE_OF_SIGNATURE self.numRounds += 1 self.numMessagesSent += 1 self.numMessagesRecv += 1 self.numBytesSent += sizeOfRequest self.numBytesRecv += sizeOfResponse return documentID # Minor change from base_client; retrieving from a quorum, you should specify which specific node to retrieve from def retrieve_file(self, documentID): whichQuorum, numKeys, numSignatures = self.__iterative_search__(documentID) randomNode = self.cryptogen.randrange(self.numNodes) self.DHT.access_node(whichQuorum).retrieve(randomNode, numKeys, numSignatures) # Asker's ID sizeOfRequest = SIZE_OF_HASH # timestamp sizeOfRequest += SIZE_OF_TIMESTAMP # keys in request sizeOfRequest += SIZE_OF_KEY * numKeys # signatures in request sizeOfRequest += SIZE_OF_SIGNATURE * numSignatures # actual hash requested sizeOfRequest += SIZE_OF_HASH # signature over whole thing sizeOfRequest += SIZE_OF_SIGNATURE sizeOfResponse = self.documentSize + SIZE_OF_SIGNATURE self.numRounds += 1 self.numMessagesSent += 1 self.numMessagesRecv += 1 self.numBytesSent += sizeOfRequest self.numBytesRecv += sizeOfResponse # TODO: Add unit tests for size calculations if __name__ == "__main__": from dht_simulator import DHT_Simulator from rcp_node import RCP_Quorum NUM_QUORUMS_IN_TEST = 10 SIZE_OF_DOCUMENTS_IN_TEST = 1024 NUM_NODES_PER_QUORUM_IN_TEST = 10 testbed = DHT_Simulator(RCP_Quorum, NUM_QUORUMS_IN_TEST, SIZE_OF_DOCUMENTS_IN_TEST, NUM_NODES_PER_QUORUM_IN_TEST) client = RCP_Client(testbed, 0, SIZE_OF_DOCUMENTS_IN_TEST, NUM_NODES_PER_QUORUM_IN_TEST) assert client.test_iterative_search() print("Iterative search functioning correctly.") file = b'\xc3\xa7\x0c\xc3\x97!\xc3\xb2offy\x13\xc2\x81~\xc2\x9f\xc3\xb5\xc3\xa1\xc3\xb9C\xc2\x92f\xc2\x968\x01\xc2\x9183D\xc3\x84\xc3\xa9\xc3\x8e\t\x0f\xc2\xa1<\xc2\xad%G\xc3\x9dq\xc2\xb7\x1b\x7f\xc2\x82\xc3\x84\xc3\xb4\xc3\x81\x1c\xc3\x8dqgH(H\\C&\x14\xc2\x98\xc3\x93`\xc3\xbe\xc3\x95\xc3\xad\xc3\x8d\xc3\xb5\xc2\x8d.\xc2\x94D\x13IK\xc3\x9a\xc2\x8dS\xc3\x8b\xc2\xa7\xc2\xb6\xc2\x9d\x1fY\xc3\xbe\xc3\x85[\r\xc2\x85\x0e#\xc2\xb85B4\x15\xc3\xaf\xc2\x81_g\xc3\xb3;!|\xc3\xbc\xc3\xaa;\xc3\xbd(m\xc2\xbd\xc3\x96b\xc2\x88\xc3\x9d\xc2\x87N\xc3\xb9\xc3\xb5\xc3\xa54\xc2\xb6(\xc2\xa7\xc3\x950\xc3\x82\x1c\xc3\x95\xc2\x85\xc2\x983\xc3\xbfy\xc2\x89lQ\xc2\x8aN\xc2\xb0\x05\xc2\x9f\xc2\xac\xc2\xa3T+z.D1\xc2\xae\xc2\xae+\xc3\x86\xc2\xb3\xc2\xb0\xc3\x8d,\x04\xc2\x96\xc2\xa7\xc3\xba\xc2\xb4A\xc2\x95P"*\x1d\x0b\xc3\xbd!e\xc2\xaa\xc2\xa4UL\xc3\x84j\xc2\xb9>h\x01\x08\xc3\xb1\xc2\x85\xc3\x81\xc2\xb0b\xc2\x9b\x0fY\xc3\xb7V ^\xc3\xb0Z~r%\xc2\x9c\xc2\x91Q\x03+9(\x14\xc2\xa1`\x17\xc3\x8c\x18+\xc3\xb4\xc2\xb4Z&l9L\xc2\x94\xc2\xae\xc2\x83\x7fJt\xc2\xbbt\xc2\x89\n\xc2\xab\xc2\x94\xc2\x90I3\xc3\xa8\xc2\xbb\x14\xc3\x9ekM\x170}r\xc2\x9c>\xc3\xa2!\xc2\x8d\xc2\x91f\xc3\xb2\xc3\xaeh\xc3\x82\xc2\x94\x11*\xc2\x97D`\xc3\xba\xc3\xa0\x17\xc3\xab!An\x7f\xc2\x89Rrh\xc3\x80\xc2\xaf\x1f*}j\xc2\xaf\xc2\x84\xc2\xa4\xc2\x92\xc2\x97\xc2\x83\xc2\x8cf\xc3\xb6\x1f\xc3\xadfb\xc2\xb1\xc2\xa3\xc3\x8f7\xc3\x82 \xc3\xbb\xc2\x84\xc3\xb0sh\xc2\x9d|\x7f\xc3\xbda\xc3\x84\xc2\x80\x08\xc3\x88\xc2\xa8mBi\xc2\xae)\x02}K\xc3\x9f\xc2\xa7\xc3\x95\xc3\x94[[D\n\xc2\x98AQH\xc2\xb9\xc2\xb3\xc3\xb3"\x08\xc2\x9f\xc3\x98\xc3\x91B[\xc2\x8b\xc2\x86xhMK\xc3\xbb\xc2\x83`\xc2\xa7\x02\xc3\x8a\xc3\x89\xc3\x8f\xc3\xb0\xc2\xa9\xc3\x99\xc3\x9b\xc2\xb2\xc3\x9a\xc3\xaa5\xc2\xb7T\xc2\x81\x0f\xc3\x90\x0c\xc3\xb3\x05\xc3\x8d\xc3\x85S\xc2\xbb\x17\xc3\x86\xc3\xb2\xc3\xa3\xc3\xb0V\x07\x0e\xc2\xb0y\xc2\x8e\xc2\xb1\xc3\x8f;\xc2\xb9Tc\xc3\xadM\xc2\xad\xc2\x98#\xc2\xb0\x01`\x1c\xc2\x84d' fileID = b'\xb5\xe0\xf4\xd8\xe9\x1e\xf6i\xc4=^\xc2Y\xac\xdc\x88p\x8a+\x10t\x90\xa5\xc9\x1f\x98\xc61\xda\x7fH\x92' client.insert_file(file) client.retrieve_file(fileID) print("Basic insertion/retrieval fires correctly.")