123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- from dht_common import compute_document_ID, MAX_ID
- from base_node import Base_Node
- import math
- class DHT_Simulator(object):
- def __init__(self, nodeType, numGroups, documentSize, numNodes):
- if nodeType == Base_Node:
- self.nodes = [nodeType(self.index_to_owner_node(i, numGroups), documentSize) for i in range(numGroups)]
- else:
- self.nodes = [nodeType(self.index_to_owner_node(i, numGroups), documentSize, numNodes) for i in range(numGroups)]
- self.__init_finger_tables()
- # Nobody else needs to call this, but when we put together all the nodes they need their finger table values updated
- def __init_finger_tables(self):
- numNodes = len(self.nodes)
- numEntries = math.ceil(math.log(numNodes, 2))
- [[self.nodes[i].insert_relation(self.index_to_owner_node(x), x) for x in [(2**j + i) % numNodes for j in range(numEntries)]] for i in range(numNodes)]
- # convert an index (of its internal data structure; consider this analogous to routing information)
- # to which node it should belong to (note that IDs are SHA3 outputs)
- def index_to_owner_node(self, which, numNodes=None):
- if not numNodes:
- numNodes = len(self.nodes)
- fullID = math.floor(which * MAX_ID / numNodes)
- return (fullID).to_bytes(32, byteorder="big")
- # convert a node ID (SHA3 output) to which index in the internal data structure it should be
- def owner_node_to_index(self, nodeID):
- numNodes = len(self.nodes)
- v = int.from_bytes(nodeID, byteorder='big')
- return math.floor(v * numNodes / MAX_ID)
- # let a client "route" to the node in question (accepts indices, which are analogous to routing information)
- def access_node(self, nodeID):
- if nodeID >= 0 and nodeID < len(self.nodes):
- return self.nodes[nodeID]
- else:
- return None
- def get_num_rounds_base(self, nodeID):
- if nodeID >= 0 and nodeID < len(self.nodes):
- return self.nodes[nodeID].get_num_rounds()
- else:
- return None
- def get_recent_num_rounds_base(self, nodeID):
- if nodeID >= 0 and nodeID < len(self.nodes):
- return self.nodes[nodeID].get_recent_num_rounds()
- else:
- return None
- def get_num_rounds(self, quorumID, nodeID):
- if quorumID >= 0 and quorumID < len(self.nodes):
- return self.nodes[quorumID].get_num_rounds(nodeID)
- else:
- return None
- def get_recent_num_rounds(self, quorumID, nodeID):
- if quorumID >= 0 and quorumID < len(self.nodes):
- return self.nodes[quorumID].get_recent_num_rounds(nodeID)
- else:
- return None
- def get_num_messages_sent_base(self, nodeID):
- if nodeID >= 0 and nodeID < len(self.nodes):
- return self.nodes[nodeID].get_num_messages_sent()
- else:
- return None
- def get_recent_num_messages_sent_base(self, nodeID):
- if nodeID >= 0 and nodeID < len(self.nodes):
- return self.nodes[nodeID].get_recent_num_messages_sent()
- else:
- return None
- def get_num_messages_sent(self, quorumID, nodeID):
- if quorumID >= 0 and quorumID < len(self.nodes):
- return self.nodes[quorumID].get_num_messages_sent(nodeID)
- else:
- return None
- def get_recent_num_messages_sent(self, quorumID, nodeID):
- if quorumID >= 0 and quorumID < len(self.nodes):
- return self.nodes[quorumID].get_recent_num_messages_sent(nodeID)
- else:
- return None
- def get_num_messages_recv_base(self, nodeID):
- if nodeID >= 0 and nodeID < len(self.nodes):
- return self.nodes[nodeID].get_num_messages_recv()
- else:
- return None
- def get_recent_num_messages_recv_base(self, nodeID):
- if nodeID >= 0 and nodeID < len(self.nodes):
- return self.nodes[nodeID].get_recent_num_messages_recv()
- else:
- return None
- def get_num_messages_recv(self, quorumID, nodeID):
- if quorumID >= 0 and quorumID < len(self.nodes):
- return self.nodes[quorumID].get_num_messages_recv(nodeID)
- else:
- return None
- def get_recent_num_messages_recv(self, quorumID, nodeID):
- if quorumID >= 0 and quorumID < len(self.nodes):
- return self.nodes[quorumID].get_recent_num_messages_recv(nodeID)
- else:
- return None
- def get_num_bytes_sent_base(self, nodeID):
- if nodeID >= 0 and nodeID < len(self.nodes):
- return self.nodes[nodeID].get_num_bytes_sent()
- else:
- return None
- def get_recent_num_bytes_sent_base(self, nodeID):
- if nodeID >= 0 and nodeID < len(self.nodes):
- return self.nodes[nodeID].get_recent_num_bytes_sent()
- else:
- return None
- def get_num_bytes_sent(self, quorumID, nodeID):
- if quorumID >= 0 and quorumID < len(self.nodes):
- return self.nodes[quorumID].get_num_bytes_sent(nodeID)
- else:
- return None
- def get_recent_num_bytes_sent(self, quorumID, nodeID):
- if quorumID >= 0 and quorumID < len(self.nodes):
- return self.nodes[quorumID].get_recent_num_bytes_sent(nodeID)
- else:
- return None
- def get_num_bytes_recv_base(self, nodeID):
- if nodeID >= 0 and nodeID < len(self.nodes):
- return self.nodes[nodeID].get_num_bytes_recv()
- else:
- return None
- def get_recent_num_bytes_recv_base(self, nodeID):
- if nodeID >= 0 and nodeID < len(self.nodes):
- return self.nodes[nodeID].get_recent_num_bytes_recv()
- else:
- return None
- def get_num_bytes_recv(self, quorumID, nodeID):
- if quorumID >= 0 and quorumID < len(self.nodes):
- return self.nodes[quorumID].get_num_bytes_recv(nodeID)
- else:
- return None
- def get_recent_num_bytes_recv(self, quorumID, nodeID):
- if quorumID >= 0 and quorumID < len(self.nodes):
- return self.nodes[quorumID].get_recent_num_bytes_recv(nodeID)
- else:
- return None
- # ONLY QP Nodes and higher will have these
- def get_finger_table_range_accesses(self, quorumID, nodeID):
- if quorumID >= 0 and quorumID < len(self.nodes):
- return self.nodes[quorumID].get_finger_table_range_accesses(nodeID)
- else:
- return None
- def get_finger_table_accesses(self, quorumID, nodeID):
- if quorumID >= 0 and quorumID < len(self.nodes):
- return self.nodes[quorumID].get_finger_table_accesses(nodeID)
- else:
- return None
- # ONLY QPLastHop Nodes will have these
- def get_database_accesses(self, quorumID, nodeID):
- if quorumID >= 0 and quorumID < len(self.nodes):
- return self.nodes[quorumID].get_database_accesses(nodeID)
- else:
- return None
- # ONLY DHTPIR Nodes will have these
- def get_PHF_generations(self, quorumID, nodeID):
- if quorumID >= 0 and quorumID < len(self.nodes):
- return self.nodes[quorumID].get_PHF_generations(nodeID)
- else:
- return None
- def get_PIR_retrievals(self, quorumID, nodeID):
- if quorumID >= 0 and quorumID < len(self.nodes):
- return self.nodes[quorumID].get_PIR_retrievals(nodeID)
- else:
- return None
- # End insert for calcuations
- def __access_node_tables(self, nodeID):
- if nodeID >= 0 and nodeID < len(self.nodes):
- return self.nodes[nodeID].table
- else:
- return None
- def get_num_nodes(self):
- return len(self.nodes)
- def test_tables(self):
- if self.get_num_nodes() == 10:
- retval = True
- table = self.__access_node_tables(5)
- retval = retval and table[b'\x99\x99\x99\x99\x99\x99\x98\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'] == 6
- retval = retval and table[b'\xb3333330\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'] == 7
- retval = retval and table[b'\xe6fffffh\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'] == 9
- retval = retval and table[b'L\xcc\xcc\xcc\xcc\xcc\xcc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'] == 3
- table = self.__access_node_tables(9)
- retval = retval and table[b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'] == 0
- retval = retval and table[b'\xb3333330\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'] == 7
- retval = retval and table[b'\x19\x99\x99\x99\x99\x99\x9a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'] == 1
- retval = retval and table[b'L\xcc\xcc\xcc\xcc\xcc\xcc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'] == 3
- return retval
- else:
- print("Assumed testing conditions not met; no tests run.")
- return False
- # Normally this file is a class to be used elsewhere,
- # but if you run it directly it performs some rudimentary unit tests
- if __name__ == "__main__":
- from base_node import Base_Node
- SIZE_OF_DOCUMENTS_IN_TEST = 1024
- NUM_NODES_IN_TEST = 10
-
- # The 1 here isn't used at all within the simulator,
- # but it is customary to invoke DHT_Simulator with that value there for Base_Node
- test = DHT_Simulator(Base_Node, NUM_NODES_IN_TEST, SIZE_OF_DOCUMENTS_IN_TEST, 1)
- assert test.index_to_owner_node(8) == b'\xcc\xcc\xcc\xcc\xcc\xcc\xd0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
- assert test.index_to_owner_node(4) == b'ffffffh\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
- assert test.owner_node_to_index(b'3333334\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') == 2
- assert test.owner_node_to_index(b'\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') == 5
- print("Index to nodeID conversion functioning correctly.")
- assert test.test_tables()
- print("Finger tables correctly generated.")
|