def setup(self):
        print("TestUM:setup() before each test method")
        self.crypto = ECCrypto()
        self.my_key1 = self.crypto.generate_key(u"medium")
        self.my_key2 = self.crypto.generate_key(u"medium")
        self.my_key3 = self.crypto.generate_key(u"medium")
        self.my_key4 = self.crypto.generate_key(u"medium")
        self.my_key5 = self.crypto.generate_key(u"medium")
        self.my_key6 = self.crypto.generate_key(u"medium")

        self.my_identity1 = self.crypto.key_to_hash(self.my_key1.pub())
        self.my_identity2 = self.crypto.key_to_hash(self.my_key2.pub())
        self.my_identity3 = self.crypto.key_to_hash(self.my_key3.pub())
        self.my_identity4 = self.crypto.key_to_hash(self.my_key4.pub())
        self.my_identity5 = self.crypto.key_to_hash(self.my_key5.pub())
        self.my_identity6 = self.crypto.key_to_hash(self.my_key6.pub())

        self.my_public_key1 = self.crypto.key_to_bin(self.my_key1.pub())
        self.my_public_key2 = self.crypto.key_to_bin(self.my_key2.pub())
        self.my_public_key3 = self.crypto.key_to_bin(self.my_key3.pub())
        self.my_public_key4 = self.crypto.key_to_bin(self.my_key4.pub())
        self.my_public_key5 = self.crypto.key_to_bin(self.my_key5.pub())
        self.my_public_key6 = self.crypto.key_to_bin(self.my_key6.pub())

        if os.path.isfile('BlockDataBase.db'):
            os.remove('BlockDataBase.db')
        self.database = HalfBlockDatabase(
            os.path.join(BASE, 'BlockDataBase.db'))
 def sign(self, key):
     """
     Signs this block with the given key
     :param key: the key to sign this block with
     """
     crypto = ECCrypto()
     self.signature = crypto.create_signature(key,
                                              self.pack(signature=False))
Ejemplo n.º 3
0
    def __init__(self,
                 port=25000,
                 is_tracker=False,
                 step_limit=None,
                 is_listening=True,
                 message_sender=None,
                 neighbor_group=NeighborGroup()):
        self.is_tracker = is_tracker
        #get the network interface which connected to public Internet, (8.8.8.8,8) is the root DNS server
        #so that the network interface connected to it is guranteed to be connected to public Internet
        #private_ip means LAN ip, public_ip means WAN ip
        #limited the amount of steps
        self.message_sender = message_sender
        self.step_count = 0
        self.step_limit = step_limit
        self.private_ip = util.get_private_IP(("8.8.8.8", 8))
        self.private_port = port
        self.private_address = (self.private_ip, self.private_port)
        #we have no knowledge for our wan IP for now.
        self.public_ip = "0.0.0.0"
        self.public_port = 0
        self.public_address = ("0.0.0.0", 0)
        self.PUBLIC_ADDRESS_VOTE = dict()
        #NeighborGroup is the module to store, manage, clean the neighbor we discovered
        self.neighbor_group = neighbor_group
        self.global_time = 1
        self.is_listening = is_listening
        self.block_received = 0
        #hard coded master_key for multichain community
        """
        self.master_key = "3081a7301006072a8648ce3d020106052b81040027038192000407afa96c83660dccfbf02a45b68f4bc" + \
                     "4957539860a3fe1ad4a18ccbfc2a60af1174e1f5395a7917285d09ab67c3d80c56caf5396fc5b231d84ceac23627" + \
                     "930b4c35cbfce63a49805030dabbe9b5302a966b80eefd7003a0567c65ccec5ecde46520cfe1875b1187d469823d" + \
                     "221417684093f63c33a8ff656331898e4bc853bcfaac49bc0b2a99028195b7c7dca0aea65"
        """
        self.master_key = "3081a7301006072a8648ce3d020106052b8104002703819200040503dac58c19267f12cb0cf667e480816cd2574acae" \
                     "5293b59d7c3da32e02b4747f7e2e9e9c880d2e5e2ba8b7fcc9892cb39b797ef98483ffd58739ed20990f8e3df7d1ec5" \
                     "a7ad2c0338dc206c4383a943e3e2c682ac4b585880929a947ffd50057b575fc30ec88eada3ce6484e5e4d6fdf41984c" \
                     "d1e51aaacc5f9a51bcc8393aea1f786fc47cbf994cb1339f706df4a"
        self.master_key_hex = self.master_key.decode("HEX")
        self.crypto = ECCrypto()

        self.ec = self.crypto.generate_key(u"medium")
        self.key = self.crypto.key_from_public_bin(self.master_key_hex)
        self.master_identity = self.crypto.key_to_hash(self.key.pub())
        self.dispersy_version = "\x00"
        self.community_version = "\x01"
        #abandom name "prefix", use "header" to replace
        self.start_header = self.dispersy_version + self.community_version + self.master_identity

        if os.path.isfile(os.path.join(BASE, 'ec_multichain.pem')):
            print("key already exists, loading")
            with open(os.path.join(BASE, 'ec_multichain.pem'),
                      'rb') as keyfile:
                binarykey = keyfile.read()
                self.my_key = LibNaCLSK(binarykey=binarykey)
        else:
            self.my_key = self.crypto.generate_key(u"medium")
        self.my_identity = self.crypto.key_to_hash(self.my_key.pub())
        self.my_public_key = self.crypto.key_to_bin(self.my_key.pub())
        self.reactor = reactor
        self.listening_port = self.reactor.listenUDP(self.private_port, self)
        #self.database = Trusted_Walker_Database()
        self.database = HalfBlockDatabase(my_public_key=self.my_public_key)
Ejemplo n.º 4
0
class NeighborDiscover(DatagramProtocol):

    #when run() is called, the startProtocol() will be called, which register the looping call of visit_a_neighbor()
    #visit_a_neighbor() will send a introduction request to a random neighbor
    #when an UDP packet received, the datagramReceived() will be called, which will call a message handling function according to message_type_id

    def __init__(self,
                 port=25000,
                 is_tracker=False,
                 step_limit=None,
                 is_listening=True,
                 message_sender=None,
                 neighbor_group=NeighborGroup()):
        self.is_tracker = is_tracker
        #get the network interface which connected to public Internet, (8.8.8.8,8) is the root DNS server
        #so that the network interface connected to it is guranteed to be connected to public Internet
        #private_ip means LAN ip, public_ip means WAN ip
        #limited the amount of steps
        self.message_sender = message_sender
        self.step_count = 0
        self.step_limit = step_limit
        self.private_ip = util.get_private_IP(("8.8.8.8", 8))
        self.private_port = port
        self.private_address = (self.private_ip, self.private_port)
        #we have no knowledge for our wan IP for now.
        self.public_ip = "0.0.0.0"
        self.public_port = 0
        self.public_address = ("0.0.0.0", 0)
        self.PUBLIC_ADDRESS_VOTE = dict()
        #NeighborGroup is the module to store, manage, clean the neighbor we discovered
        self.neighbor_group = neighbor_group
        self.global_time = 1
        self.is_listening = is_listening
        self.block_received = 0
        #hard coded master_key for multichain community
        """
        self.master_key = "3081a7301006072a8648ce3d020106052b81040027038192000407afa96c83660dccfbf02a45b68f4bc" + \
                     "4957539860a3fe1ad4a18ccbfc2a60af1174e1f5395a7917285d09ab67c3d80c56caf5396fc5b231d84ceac23627" + \
                     "930b4c35cbfce63a49805030dabbe9b5302a966b80eefd7003a0567c65ccec5ecde46520cfe1875b1187d469823d" + \
                     "221417684093f63c33a8ff656331898e4bc853bcfaac49bc0b2a99028195b7c7dca0aea65"
        """
        self.master_key = "3081a7301006072a8648ce3d020106052b8104002703819200040503dac58c19267f12cb0cf667e480816cd2574acae" \
                     "5293b59d7c3da32e02b4747f7e2e9e9c880d2e5e2ba8b7fcc9892cb39b797ef98483ffd58739ed20990f8e3df7d1ec5" \
                     "a7ad2c0338dc206c4383a943e3e2c682ac4b585880929a947ffd50057b575fc30ec88eada3ce6484e5e4d6fdf41984c" \
                     "d1e51aaacc5f9a51bcc8393aea1f786fc47cbf994cb1339f706df4a"
        self.master_key_hex = self.master_key.decode("HEX")
        self.crypto = ECCrypto()

        self.ec = self.crypto.generate_key(u"medium")
        self.key = self.crypto.key_from_public_bin(self.master_key_hex)
        self.master_identity = self.crypto.key_to_hash(self.key.pub())
        self.dispersy_version = "\x00"
        self.community_version = "\x01"
        #abandom name "prefix", use "header" to replace
        self.start_header = self.dispersy_version + self.community_version + self.master_identity

        if os.path.isfile(os.path.join(BASE, 'ec_multichain.pem')):
            print("key already exists, loading")
            with open(os.path.join(BASE, 'ec_multichain.pem'),
                      'rb') as keyfile:
                binarykey = keyfile.read()
                self.my_key = LibNaCLSK(binarykey=binarykey)
        else:
            self.my_key = self.crypto.generate_key(u"medium")
        self.my_identity = self.crypto.key_to_hash(self.my_key.pub())
        self.my_public_key = self.crypto.key_to_bin(self.my_key.pub())
        self.reactor = reactor
        self.listening_port = self.reactor.listenUDP(self.private_port, self)
        #self.database = Trusted_Walker_Database()
        self.database = HalfBlockDatabase(my_public_key=self.my_public_key)

    def startProtocol(self):
        #print("neighbor discovery module started")
        #every 5 seconds, we take a step (visit a known neighbor)
        if (self.is_tracker == False):
            loop = task.LoopingCall(self.visit_a_neighbor)
            loop.start(0.1)

    def stopProtocol(self):
        #time.sleep(5)
        self.database.close()
        self.database.trust_graph.draw_graph()
        print("the trusted list is now:")
        #for neighbor in self.neighbor_group.trusted_neighbors:
        #print (neighbor.get_private_address())

    #take one step,visit a known neighbor (candidate)
    def visit_a_neighbor(self):
        #NeighborGroup return a neighbor to walk
        #self.neighbor_group.insert_trusted_neighbor(my_public_key=my_public_key,Graph=self.database.TrustGraph)
        neighbor_to_walk = self.neighbor_group.get_neighbor_to_walk()
        neighbor_to_walk_ADDR = neighbor_to_walk.get_public_address()
        #create new Message and specify its  parameter, make it a Introduction Request
        message_introduction_request = Message(
            neighbor_discovery=self,
            destination_address=neighbor_to_walk_ADDR,
            source_private_address=self.private_address,
            source_public_address=self.public_address)
        #encode the message to a introduction request, the binary string will be stored at attribute packet
        message_introduction_request.encode_introduction_request()
        #send the introduction request
        #self.transport.write(message_introduction_request.packet,neighbor_to_walk_ADDR)
        self.send_message(message_introduction_request.packet,
                          neighbor_to_walk_ADDR)
        logger.info("take step to: " + str(neighbor_to_walk_ADDR))

        if self.step_limit:
            self.step_count = self.step_count + 1
            if self.step_count > self.step_limit:
                print("already reach step_limit, stopping")
                self.listening_port.stopListening()
                time.sleep(10)
                self.reactor.stop()

    def send_message(self, packet, addr):
        if self.message_sender == None:
            self.transport.write(packet, addr)
        else:
            self.message_sender(packet, addr)

    def datagramReceived(self, data, addr):
        """
        built-in function of twisted.internet.protocol.DatagramProtocol.
        will be call whenever a UDP packet comes in
        """
        print("received data from" + str(addr))
        #now we receive a UDP datagram, call decode_message to decode it
        if self.is_listening:
            self.handle_message(data, addr)

    def handle_message(self, packet, addr):
        #call different message handler according to its message_type
        #TODO:we should ask for public key of other members here
        message_type = ord(packet[22])
        #logger.info("message id is:"+str(message_type))
        #print("message id is:"+str(message_type))
        if message_type == 247:
            print("here is a missing-identity message")
            self.on_missing_identity(packet, addr)
        if message_type == 245:
            print("here is a introduction-response")
            self.on_introduction_response(packet, addr)
        if message_type == 246:
            print("here is a introduction-request")
            self.on_introduction_request(packet, addr)
        if message_type == 250:
            print("here is a puncture request")
            self.on_puncture_request(packet, addr)
        if message_type == 249:
            print("here is a puncture")
        if message_type == 248:
            print("here is an dispersy-identity")
            self.on_identity(packet, addr)
        if message_type == 1:
            #print ("here is a halfblock message")
            self.on_halfblock(packet, addr)
        #if message_type == 2:
        #print("here is a crawl_request")
        #self.on_crawl_request(packet,addr)
        #if message_type == 3:
        #print("here is a crawl_response")
        #self.on_crawl_response(packet,addr)
        #if message_type == 4:
        #print("here is a crawl_resume.............................................................:D")
        #self.on_crawl_resume(packet,addr)

    def on_introduction_request(self, packet, addr):
        """
        1.decode a introduction request
        2.introduce a neighbor we known to the requester
        3.send a puncture request to the neighbor we introduce in step 2
        """
        message_request = Message(packet=packet)
        message_request.decode_introduction_request()
        self.global_time = message_request.global_time
        requester_neighbor = Neighbor(message_request.source_private_address,
                                      addr,
                                      identity=message_request.sender_identity)
        self.neighbor_group.add_neighbor_to_incoming_list(requester_neighbor)
        #do public_address_vote
        self.public_address_vote(message_request.destination_address, addr)
        #we don't have codes to determine whether the candidate is within our lan, so we use wan address.
        #candidate_request = Wcandidate(message_request.source_lan_address,message_request.source_wan_address)
        neighbor_to_introduce = self.neighbor_group.get_neighbor_to_introduce(
            requester_neighbor)
        if neighbor_to_introduce != None:
            introduced_private_address = neighbor_to_introduce.get_private_address(
            )
            introduced_public_address = neighbor_to_introduce.get_public_address(
            )
            print("private address is:" + introduced_private_address[0])
            print("private address is:" + introduced_public_address[0])
        else:
            introduced_private_address = ("0.0.0.0", 0)
            introduced_public_address = ("0.0.0.0", 0)
        message_response = Message(
            neighbor_discovery=self,
            identifier=message_request.identifier,
            destination_address=addr,
            source_private_address=self.private_address,
            source_public_address=self.public_address,
            private_introduction_address=introduced_private_address,
            public_introduction_address=introduced_public_address)
        message_response.encode_introduction_response()
        #now it is time to create puncture request
        if neighbor_to_introduce != None:
            message_puncture_request = Message(
                neighbor_discovery=self,
                source_private_address=message_request.source_private_address,
                source_public_address=message_request.source_public_address,
                private_address_to_puncture=message_request.
                source_private_address,
                public_address_to_puncture=addr)
            message_puncture_request.encode_puncture_request()
            #send one puncture request to private ip and one puncture request to public ip
            #self.transport.write(message_puncture_request.packet,neighbor_to_introduce.get_public_address())
            self.send_message(message_puncture_request.packet,
                              neighbor_to_introduce.get_public_address())

            #self.transport.write(message_puncture_request.packet,neighbor_to_introduce.get_public_address())
            #self.send_message.write(message_puncture_request.packet,neighbor_to_introduce.get_public_address())

        #self.transport.write(message_response.packet,addr)
        self.send_message(message_response.packet, addr)

    def on_introduction_response(self, packet, addr):
        """
        1.decode a introduction response
        2.do public address vote to determine our public address
        3.add the introduced neighbor to neighbor_group
        """
        self.database.add_visit_count_record(ip=addr[0],
                                             port=addr[1],
                                             public_key="000")
        message = Message(packet=packet)
        message.decode_introduction_response()
        self.global_time = message.global_time
        self.public_address_vote(message.destination_address, addr)
        message_sender = Neighbor(message.source_private_address,
                                  addr,
                                  identity=message.sender_identity)
        self.neighbor_group.add_neighbor_to_outgoing_list(message_sender)
        print("the introduced candidate is: " +
              str(message.public_introduction_address))
        if message.private_introduction_address != (
                "0.0.0.0",
                0) and message.public_introduction_address != ("0.0.0.0", 0):
            introduced_neighbor = Neighbor(
                message.private_introduction_address,
                message.public_introduction_address)
            self.neighbor_group.add_neighbor_to_intro_list(introduced_neighbor)
            self.neighbor_group.update_current_neighbor(
                responder=message_sender,
                introduced_neighbor=introduced_neighbor)
            print("new candidate has been added to intro list")
        #send a missing identity by the way
        identity = message.sender_identity
        responder_member = self.database.get_member(identity=identity)
        if responder_member is None:
            message_missing_identity = Message(
                neighbor_discovery=self,
                the_missing_identity=message.sender_identity)
            message_missing_identity.encode_missing_identity()
            #self.transport.write(message_missing_identity.packet,addr)
            self.send_message(message_missing_identity.packet, addr)
            print(
                "receive introduction response, send missing identity message")

        member = self.database.get_member(identity=identity)
        if member is not None:
            print("the member of the introduction response is: " +
                  str(member[0]))
            public_key = member[1]
            requested_sequence_number = self.database.get_latest_sequence_number(
                public_key=public_key) + 1
            #message_crawl_request = Message(neighbor_discovery=self,requested_sequence_number = requested_sequence_number)
            #message_crawl_request.encode_crawl_request()
            message_crawl = Message(
                neighbor_discovery=self,
                requested_sequence_number=requested_sequence_number)
            message_crawl.encode_crawl()
            #self.transport.write(message_crawl.packet,addr)
            self.send_message(message_crawl.packet, addr)
            print("crawl sent")

    def on_puncture_request(self, packet, addr):
        """
        1.decode a puncture request and knows which neighbor we should send the puncture to
        2.send a puncture to both private and public address of that neighbor
        """
        message_puncture_request = Message(packet=packet)
        message_puncture_request.decode_puncture_request()
        self.global_time = message_puncture_request.global_time
        private_address_to_puncture = message_puncture_request.private_address_to_puncture
        public_address_to_puncture = message_puncture_request.public_address_to_puncture
        self.public_address = self.get_majority_vote()
        print("the public addr from majority vote is:")
        print(self.public_address)
        message_puncture = Message(neighbor_discovery=self,
                                   source_private_address=self.private_address,
                                   source_public_address=self.public_address)
        message_puncture.encode_puncture()
        #self.transport.write(message_puncture.packet,private_address_to_puncture)
        self.send_message(message_puncture.packet, private_address_to_puncture)
        #self.transport.write(message_puncture.packet,public_address_to_puncture)
        self.send_message(message_puncture.packet, public_address_to_puncture)

    def on_missing_identity(self, packet, addr):
        """
        1.decode a missing identity
        2.send a dispersy-identity message with our public key
        """
        message_missing_identity = Message(packet=packet)
        message_missing_identity.decode_missing_identity()
        self.global_time = message_missing_identity.global_time
        message_identity = Message(neighbor_discovery=self)
        message_identity.encode_identity()
        #self.transport.write(message_identity.packet,addr)
        self.send_message(message_identity.packet, addr)

    def on_identity(self, packet, addr):
        """
        1.decode a dispersy-identity message
        2.store the public key in the message to our database
        3.associate this key with the candidate
        4.move this candidate to trusted neigbhors list
        """
        message_identity = Message(packet=packet)
        message_identity.decode_identity()
        sender_identity = sha1(message_identity.key_received).digest()
        if (self.database.get_member(
                public_key=message_identity.key_received) == None):
            self.database.add_member(identity=sender_identity,
                                     public_key=message_identity.key_received)
            self.database.add_visit_record(
                ip=addr[0],
                port=addr[1],
                public_key=message_identity.key_received)
            #then send a crawl request
            requested_sequence_number = self.database.get_latest_sequence_number(
                public_key=message_identity.key_received) + 1
            message_crawl = Message(
                neighbor_discovery=self,
                requested_sequence_number=requested_sequence_number)
            message_crawl.encode_crawl()
            self.send_message(message_crawl.packet, addr)
            print("receive identity, send crawl request")
        self.neighbor_group.associate_neigbhor_with_public_key(
            public_ip=addr,
            identity=sender_identity,
            public_key=message_identity.key_received)
        self.neighbor_group.insert_trusted_neighbor(
            Graph=self.database.trust_graph, my_public_key=self.my_public_key)

    def on_crawl_request(self, packet, addr):
        pass

    def on_crawl_response(self, packet, addr):
        """
        it is a message in old protocol, should we still support old protocol?
        """
        message_crawl_response = Message(packet=packet)
        message_crawl_response.decode_crawl_response()
        block = message_crawl_response.block
        block.show()
        #it is possible that some guys send us a send block twice due to network latency
        #but we add a block to the database without checking whether it is already in the database
        #it is time consuming to check it using SELECT ... WHERE has_requester =?
        #if a block is already in database, the database will returns a PRIMARY KEY constraint error. It does no harm to us
        self.database.add_block(block)

    def on_halfblock(self, packet, addr):
        """
        decode a halfblock message, store the block inside to our database
        """
        message_crawl_response = Message(packet=packet)
        message_crawl_response.decode_halfblock()
        block = message_crawl_response.block
        #block.show()
        #it is possible that some guys send us a send block twice due to network latency
        #but we add a block to the database without checking whether it is already in the database
        #it is time consuming to check it using SELECT ... WHERE has_requester =?
        #if a block is already in database, the database will returns a PRIMARY KEY constraint error. It does no harm to us
        #self.block_received = self.block_received +1
        #if self.block_received%30000==0:
        #self.database.add_block(block)
        #else:
        #self.database.add_block(block,commit=False)
        self.database.add_block(block)

    """
    def on_crawl_resume(self,packet,addr):
        message_resume = Message(packet=packet)
        message_resume.decode_crawl_resume()
        identity = message_resume.sender_identity
        #now we already have the identity (20bytes hash of public key)
        #we can use it to retrieve public key in the database
        #and get the latest sequence number of this public key
        member = self.database.get_member(identity=identity)
        public_key = str(member[1])
        latest_sequence_number = self.database.get_latest_sequence_number(public_key=public_key)
        message_crawl_request = Message(neighbor_discovery=self,requested_sequence_number=latest_sequence_number+1)
        message_crawl_request.encode_crawl_request()
        self.transport.write(message_crawl_request.packet,addr)
    """

    def public_address_vote(self, address, neighbor_addr):
        """
        1.if the address (which is our public address in the view of another neighbor) of a message isn't in the PUBLIC_ADDRESS_VOTE,
        add the address to it.
        2. if the address is already in PUBLIC_ADDRESS_VOTE, check whether neighbor_addr is in voter list, if not  add it to the list
        """
        assert isinstance(address, tuple), type(address)
        assert isinstance(neighbor_addr, tuple), type(neighbor_addr)
        #@param:addr my address which is perceived by the voter
        #@param:candidate_addr the candidate's (voter) addr
        change_flag = 0
        ip = address[0]
        port = address[1]
        addr = ip + ":" + str(port)
        if addr in self.PUBLIC_ADDRESS_VOTE:
            neighbor_vote_list = self.PUBLIC_ADDRESS_VOTE[addr]
            if neighbor_addr not in neighbor_vote_list:
                self.PUBLIC_ADDRESS_VOTE[addr].append(neighbor_addr)
                change_flag = 1
        else:
            self.PUBLIC_ADDRESS_VOTE[addr] = [neighbor_addr]
            change_flag = 1
        #if there is any update in PUBLIC_ADDRESS_VOTE
        if (change_flag == 1):
            new_public_addr = self.get_majority_vote()
            self.public_ip = new_public_addr[0]
            self.public_port = new_public_addr[1]
            self.public_addr = new_public_addr

        #get the majority votes
    def get_majority_vote(self):
        """
        determine our public address by using majority rule on self.PUBLIC_ADDRESS_VOTE
        """
        max_vote = 0
        majority = self.public_ip + ":" + str(self.public_port)
        for key in self.PUBLIC_ADDRESS_VOTE:
            num_vote = len(self.PUBLIC_ADDRESS_VOTE[key])
            if num_vote > max_vote:
                majority = key
        majority_list = majority.split(":")
        majority_ip = majority_list[0]
        majority_port = int(majority_list[1])
        return (majority_ip, majority_port)

    #start the neighbor_discovery module(walker)
    def run(self):
        self.reactor.run()
    def setup(self):
        print("TestUM:setup() before each test method")
        self.crypto = ECCrypto()
        self.my_key1 = self.crypto.generate_key(u"medium")
        self.my_key2 = self.crypto.generate_key(u"medium")
        self.my_key3 = self.crypto.generate_key(u"medium")
        self.my_key4 = self.crypto.generate_key(u"medium")
        self.my_key5 = self.crypto.generate_key(u"medium")

        self.my_identity1 = self.crypto.key_to_hash(self.my_key1.pub())
        self.my_identity2 = self.crypto.key_to_hash(self.my_key2.pub())
        self.my_identity3 = self.crypto.key_to_hash(self.my_key3.pub())
        self.my_identity3 = self.crypto.key_to_hash(self.my_key4.pub())
        self.my_identity3 = self.crypto.key_to_hash(self.my_key5.pub())

        self.my_public_key1 = self.crypto.key_to_bin(self.my_key1.pub())
        self.my_public_key2 = self.crypto.key_to_bin(self.my_key2.pub())
        self.my_public_key3 = self.crypto.key_to_bin(self.my_key3.pub())
        self.my_public_key4 = self.crypto.key_to_bin(self.my_key4.pub())
        self.my_public_key5 = self.crypto.key_to_bin(self.my_key5.pub())
        """
        if os.path.isfile('BlockDataBase.db'):
            os.remove('BlockDataBase.db')
        self.database = Trusted_Walker_Database()
        """

        self.block1 = Block()
        self.block1.init(public_key_requester=self.my_public_key1,
                         public_key_responder=self.my_public_key2,
                         up=200,
                         down=300,
                         total_up_requester=3,
                         total_down_requester=4,
                         sequence_number_requester=5,
                         previous_hash_requester="h1",
                         signature_requester="s1",
                         total_up_responder=8,
                         total_down_responder=9,
                         sequence_number_responder=10,
                         previous_hash_responder="h2",
                         signature_responder="s2")

        self.block2 = Block()
        self.block2.init(public_key_requester=self.my_public_key2,
                         public_key_responder=self.my_public_key3,
                         up=500,
                         down=0,
                         total_up_requester=3,
                         total_down_requester=4,
                         sequence_number_requester=5,
                         previous_hash_requester="h1",
                         signature_requester="s1",
                         total_up_responder=8,
                         total_down_responder=9,
                         sequence_number_responder=10,
                         previous_hash_responder="h2",
                         signature_responder="s2")

        self.block3 = Block()
        self.block3.init(public_key_requester=self.my_public_key4,
                         public_key_responder=self.my_public_key2,
                         up=600,
                         down=0,
                         total_up_requester=3,
                         total_down_requester=4,
                         sequence_number_requester=5,
                         previous_hash_requester="h1",
                         signature_requester="s1",
                         total_up_responder=8,
                         total_down_responder=9,
                         sequence_number_responder=10,
                         previous_hash_responder="h2",
                         signature_responder="s2")
class Test_Message:
    def setup(self):
        print("TestUM:setup() before each test method")
        self.crypto = ECCrypto()
        self.my_key1 = self.crypto.generate_key(u"medium")
        self.my_key2 = self.crypto.generate_key(u"medium")
        self.my_key3 = self.crypto.generate_key(u"medium")
        self.my_key4 = self.crypto.generate_key(u"medium")
        self.my_key5 = self.crypto.generate_key(u"medium")

        self.my_identity1 = self.crypto.key_to_hash(self.my_key1.pub())
        self.my_identity2 = self.crypto.key_to_hash(self.my_key2.pub())
        self.my_identity3 = self.crypto.key_to_hash(self.my_key3.pub())
        self.my_identity3 = self.crypto.key_to_hash(self.my_key4.pub())
        self.my_identity3 = self.crypto.key_to_hash(self.my_key5.pub())

        self.my_public_key1 = self.crypto.key_to_bin(self.my_key1.pub())
        self.my_public_key2 = self.crypto.key_to_bin(self.my_key2.pub())
        self.my_public_key3 = self.crypto.key_to_bin(self.my_key3.pub())
        self.my_public_key4 = self.crypto.key_to_bin(self.my_key4.pub())
        self.my_public_key5 = self.crypto.key_to_bin(self.my_key5.pub())
        """
        if os.path.isfile('BlockDataBase.db'):
            os.remove('BlockDataBase.db')
        self.database = Trusted_Walker_Database()
        """

        self.block1 = Block()
        self.block1.init(public_key_requester=self.my_public_key1,
                         public_key_responder=self.my_public_key2,
                         up=200,
                         down=300,
                         total_up_requester=3,
                         total_down_requester=4,
                         sequence_number_requester=5,
                         previous_hash_requester="h1",
                         signature_requester="s1",
                         total_up_responder=8,
                         total_down_responder=9,
                         sequence_number_responder=10,
                         previous_hash_responder="h2",
                         signature_responder="s2")

        self.block2 = Block()
        self.block2.init(public_key_requester=self.my_public_key2,
                         public_key_responder=self.my_public_key3,
                         up=500,
                         down=0,
                         total_up_requester=3,
                         total_down_requester=4,
                         sequence_number_requester=5,
                         previous_hash_requester="h1",
                         signature_requester="s1",
                         total_up_responder=8,
                         total_down_responder=9,
                         sequence_number_responder=10,
                         previous_hash_responder="h2",
                         signature_responder="s2")

        self.block3 = Block()
        self.block3.init(public_key_requester=self.my_public_key4,
                         public_key_responder=self.my_public_key2,
                         up=600,
                         down=0,
                         total_up_requester=3,
                         total_down_requester=4,
                         sequence_number_requester=5,
                         previous_hash_requester="h1",
                         signature_requester="s1",
                         total_up_responder=8,
                         total_down_responder=9,
                         sequence_number_responder=10,
                         previous_hash_responder="h2",
                         signature_responder="s2")

        #self.TG = TrustGraph()

    def teardown(self):
        print("TestUM:teardown() after each test method")

    @classmethod
    def setup_class(cls):
        print("setup_class() before any methods in this class")
        #cls.walker = Walker(port=23334)

    @classmethod
    def teardown_class(cls):
        print("teardown_class() after any methods in this class")

    def test_add_edge(self):
        TG = TrustGraph()
        TG.add_block(self.block1)
        assert TG.Graph[self.my_public_key1][
            self.my_public_key2]["weight"] == self.block1.up
        assert TG.Graph[self.my_public_key2][
            self.my_public_key1]["weight"] == self.block1.down

    def test_has_trust_path(self):
        TG = TrustGraph()
        TG.add_block(self.block1)
        TG.add_block(self.block2)
        TG.add_block(self.block3)
        #TG.draw_graph()
        assert TG.has_trust_path(
            your_node=self.my_public_key4,
            node_to_be_trusted=self.my_public_key1) == False
        assert TG.has_trust_path(
            your_node=self.my_public_key1,
            node_to_be_trusted=self.my_public_key4) == True
        assert TG.has_trust_path(
            your_node=self.my_public_key3,
            node_to_be_trusted=self.my_public_key4) == True

    def test_error(self):
        assert 1 > 2
    def __init__(self, port=25000, is_tracker=False):
        #super(Walker, self).__init__():
        #tracker_ADDR is reserved for convenience of testing
        #self.tracker_ADDR = [
        #(u"127.0.0.1"     ,1235),
        #(u"130.161.119.206"      , 6421),
        #(u"130.161.119.206"      , 6422),
        #(u"131.180.27.155"       , 6423),
        #(u"83.149.70.6"          , 6424),
        #(u"95.211.155.142"       , 6427),
        #(u"95.211.155.131"       , 6428),
        #]
        #how many times other candidates walk to you, only for load balancing experiment use
        self.visited_count = 0
        self.loop_count = 0
        self.is_tracker = is_tracker
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        #get the network interface which connected to public Internet (8.8.8.8,8) is the root DNS server
        #so that the network interface connected to it is guranteed to be connected to public Internet
        self.lan_ip = self.get_lan_IP(("8.8.8.8", 8))
        self.lan_port = port
        self.lan_netmask = self.get_netmask(self.lan_ip)
        self.lan_addr = (self.lan_ip, self.lan_port)
        #we have no knowledge for our wan IP for now.
        self.wan_ip = "0.0.0.0"
        self.wan_port = 0
        self.wan_addr = ("0.0.0.0", 0)
        #self.sock.bind(self.lan_addr)

        #indicates the current wan IP vote contains only 0.0.0.0 and the voter is nothing (empty list)
        #self.WAN_VOTE = {"0.0.0.0:0":[]}
        self.WAN_VOTE = dict()
        self.candidate_group = WcandidateGroup()
        self._global_time = 1

        self._struct_B = Struct(">B")
        self._struct_BBH = Struct(">BBH")
        self._struct_BH = Struct(">BH")
        self._struct_H = Struct(">H")
        self._struct_HH = Struct(">HH")
        self._struct_LL = Struct(">LL")
        self._struct_Q = Struct(">Q")
        self._struct_QH = Struct(">QH")
        self._struct_QL = Struct(">QL")
        self._struct_QQHHBH = Struct(">QQHHBH")
        self._struct_ccB = Struct(">ccB")
        self._struct_4SH = Struct(">4sH")
        #(u"dispersy4.st.tudelft.nl", 6424),
        self._encode_message_map = dict()  # message.name : EncodeFunctions
        self._decode_message_map = dict()  # byte : DecodeFunctions

        # the dispersy-introduction-request and dispersy-introduction-response have several bitfield
        # flags that must be set correctly
        # reserve 1st bit for enable/disable advice
        self._encode_advice_map = {True: int("1", 2), False: int("0", 2)}
        self._decode_advice_map = dict(
            (value, key) for key, value in self._encode_advice_map.iteritems())
        # reserve 2nd bit for enable/disable sync
        self._encode_sync_map = {True: int("10", 2), False: int("00", 2)}
        self._decode_sync_map = dict(
            (value, key) for key, value in self._encode_sync_map.iteritems())
        # reserve 3rd bit for enable/disable tunnel (02/05/12)
        self._encode_tunnel_map = {True: int("100", 2), False: int("000", 2)}
        self._decode_tunnel_map = dict(
            (value, key) for key, value in self._encode_tunnel_map.iteritems())
        # 4th, 5th and 6th bits are currently unused
        # reserve 7th and 8th bits for connection type
        self._encode_connection_type_map = {
            u"unknown": int("00000000", 2),
            u"public": int("10000000", 2),
            u"symmetric-NAT": int("11000000", 2)
        }
        self._decode_connection_type_map = dict(
            (value, key)
            for key, value in self._encode_connection_type_map.iteritems())
        #this is the master-key for multichain community
        self.master_key = "3081a7301006072a8648ce3d020106052b81040027038192000407afa96c83660dccfbf02a45b68f4bc" + \
                     "4957539860a3fe1ad4a18ccbfc2a60af1174e1f5395a7917285d09ab67c3d80c56caf5396fc5b231d84ceac23627" + \
                     "930b4c35cbfce63a49805030dabbe9b5302a966b80eefd7003a0567c65ccec5ecde46520cfe1875b1187d469823d" + \
                     "221417684093f63c33a8ff656331898e4bc853bcfaac49bc0b2a99028195b7c7dca0aea65"
        self.master_key_hex = self.master_key.decode("HEX")

        self.crypto = ECCrypto()
        self.ec = self.crypto.generate_key(u"medium")
        self.key = self.crypto.key_from_public_bin(self.master_key_hex)
        self.mid = self.crypto.key_to_hash(self.key.pub())
        #the dispersy vesion and community version of multichain community version of multichain community in the tracker
        self.dispersy_version = "\x00"
        self.community_version = "\x01"
        #print ord(self.community_version)
        #create my key in multichain community, and convert it to mid for signiture use
        self.prefix = self.dispersy_version + self.community_version + self.mid
        self.my_key = self.crypto.generate_key(u"medium")
        self.my_mid = self.crypto.key_to_hash(self.my_key.pub())
        self.my_public_key = self.crypto.key_to_bin(self.my_key.pub())
        #print len(self.my_mid)
        #get my lan_IP
        #self.lan_ip = self.get_lan_IP()
        #self.lan_port = 32000
        #self.lan_addr = (self.lan_ip,self.lan_port)
        #print self.lan_addr
        #this is similar to the container in conversion.encode_message()
        self.container = [self.prefix, chr(246)]
        self.reactor = reactor
        self.listening_port = self.reactor.listenUDP(self.lan_port, self)
class Walker(DatagramProtocol):
    def __init__(self, port=25000, is_tracker=False):
        #super(Walker, self).__init__():
        #tracker_ADDR is reserved for convenience of testing
        #self.tracker_ADDR = [
        #(u"127.0.0.1"     ,1235),
        #(u"130.161.119.206"      , 6421),
        #(u"130.161.119.206"      , 6422),
        #(u"131.180.27.155"       , 6423),
        #(u"83.149.70.6"          , 6424),
        #(u"95.211.155.142"       , 6427),
        #(u"95.211.155.131"       , 6428),
        #]
        #how many times other candidates walk to you, only for load balancing experiment use
        self.visited_count = 0
        self.loop_count = 0
        self.is_tracker = is_tracker
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        #get the network interface which connected to public Internet (8.8.8.8,8) is the root DNS server
        #so that the network interface connected to it is guranteed to be connected to public Internet
        self.lan_ip = self.get_lan_IP(("8.8.8.8", 8))
        self.lan_port = port
        self.lan_netmask = self.get_netmask(self.lan_ip)
        self.lan_addr = (self.lan_ip, self.lan_port)
        #we have no knowledge for our wan IP for now.
        self.wan_ip = "0.0.0.0"
        self.wan_port = 0
        self.wan_addr = ("0.0.0.0", 0)
        #self.sock.bind(self.lan_addr)

        #indicates the current wan IP vote contains only 0.0.0.0 and the voter is nothing (empty list)
        #self.WAN_VOTE = {"0.0.0.0:0":[]}
        self.WAN_VOTE = dict()
        self.candidate_group = WcandidateGroup()
        self._global_time = 1

        self._struct_B = Struct(">B")
        self._struct_BBH = Struct(">BBH")
        self._struct_BH = Struct(">BH")
        self._struct_H = Struct(">H")
        self._struct_HH = Struct(">HH")
        self._struct_LL = Struct(">LL")
        self._struct_Q = Struct(">Q")
        self._struct_QH = Struct(">QH")
        self._struct_QL = Struct(">QL")
        self._struct_QQHHBH = Struct(">QQHHBH")
        self._struct_ccB = Struct(">ccB")
        self._struct_4SH = Struct(">4sH")
        #(u"dispersy4.st.tudelft.nl", 6424),
        self._encode_message_map = dict()  # message.name : EncodeFunctions
        self._decode_message_map = dict()  # byte : DecodeFunctions

        # the dispersy-introduction-request and dispersy-introduction-response have several bitfield
        # flags that must be set correctly
        # reserve 1st bit for enable/disable advice
        self._encode_advice_map = {True: int("1", 2), False: int("0", 2)}
        self._decode_advice_map = dict(
            (value, key) for key, value in self._encode_advice_map.iteritems())
        # reserve 2nd bit for enable/disable sync
        self._encode_sync_map = {True: int("10", 2), False: int("00", 2)}
        self._decode_sync_map = dict(
            (value, key) for key, value in self._encode_sync_map.iteritems())
        # reserve 3rd bit for enable/disable tunnel (02/05/12)
        self._encode_tunnel_map = {True: int("100", 2), False: int("000", 2)}
        self._decode_tunnel_map = dict(
            (value, key) for key, value in self._encode_tunnel_map.iteritems())
        # 4th, 5th and 6th bits are currently unused
        # reserve 7th and 8th bits for connection type
        self._encode_connection_type_map = {
            u"unknown": int("00000000", 2),
            u"public": int("10000000", 2),
            u"symmetric-NAT": int("11000000", 2)
        }
        self._decode_connection_type_map = dict(
            (value, key)
            for key, value in self._encode_connection_type_map.iteritems())
        #this is the master-key for multichain community
        self.master_key = "3081a7301006072a8648ce3d020106052b81040027038192000407afa96c83660dccfbf02a45b68f4bc" + \
                     "4957539860a3fe1ad4a18ccbfc2a60af1174e1f5395a7917285d09ab67c3d80c56caf5396fc5b231d84ceac23627" + \
                     "930b4c35cbfce63a49805030dabbe9b5302a966b80eefd7003a0567c65ccec5ecde46520cfe1875b1187d469823d" + \
                     "221417684093f63c33a8ff656331898e4bc853bcfaac49bc0b2a99028195b7c7dca0aea65"
        self.master_key_hex = self.master_key.decode("HEX")

        self.crypto = ECCrypto()
        self.ec = self.crypto.generate_key(u"medium")
        self.key = self.crypto.key_from_public_bin(self.master_key_hex)
        self.mid = self.crypto.key_to_hash(self.key.pub())
        #the dispersy vesion and community version of multichain community version of multichain community in the tracker
        self.dispersy_version = "\x00"
        self.community_version = "\x01"
        #print ord(self.community_version)
        #create my key in multichain community, and convert it to mid for signiture use
        self.prefix = self.dispersy_version + self.community_version + self.mid
        self.my_key = self.crypto.generate_key(u"medium")
        self.my_mid = self.crypto.key_to_hash(self.my_key.pub())
        self.my_public_key = self.crypto.key_to_bin(self.my_key.pub())
        #print len(self.my_mid)
        #get my lan_IP
        #self.lan_ip = self.get_lan_IP()
        #self.lan_port = 32000
        #self.lan_addr = (self.lan_ip,self.lan_port)
        #print self.lan_addr
        #this is similar to the container in conversion.encode_message()
        self.container = [self.prefix, chr(246)]
        self.reactor = reactor
        self.listening_port = self.reactor.listenUDP(self.lan_port, self)

    def startProtocol(self):
        print("protocol started")
        if (self.is_tracker == False):
            loop = task.LoopingCall(self.take_step)
            loop.start(5.0)
            #loop_c = task.LoopingCall(self.loop_counting)
            #loop_c.start(10)

    def stopProtocol(self):
        conn = sqlite3.connect('load_balancing.db')
        cur = conn.cursor()
        sql = ''' UPDATE visit
                  SET min1 = ? ,
                  min2 = ? ,
                  min3 = ? ,
                  min4 = ? ,
                  min5 = ? 
                  WHERE walker = ?'''
        data = (self.visited_count, self.visited_count, self.visited_count,
                self.visited_count, self.visited_count, self.lan_port)
        cur.execute(sql, data)
        conn.commit()
        conn.close()

    def loop_counting(self):
        self.loop_count = self.loop_count + 1
        if (self.loop_count > 5):
            #self.transport.loseConnection()
            reactor.stop()

    #take one step
    def take_step(self):
        print("walker " + str(self.lan_port) + " take step#################")
        candidate_to_walk = self.get_candidate_to_walk()
        #print candidate_to_walk
        candidate_to_walk_ADDR = candidate_to_walk.get_WAN_ADDR()
        #message_puncture_request = self.create_puncture_request(("8.8.8.8",8),("8.8.8.8",8))
        message_introduction_request = self.create_introduction_request(
            candidate_to_walk_ADDR, self.lan_addr, self.lan_addr)
        #message_puncture_request = self.create_puncture_request(("8.8.8.8",8),("8.8.8.8",8))

        #self.sock.sendto(message_introduction_request.packet,candidate_to_walk_ADDR)
        self.transport.write(message_introduction_request.packet,
                             candidate_to_walk_ADDR)
        #self.transport.write(message_puncture_request.packet,candidate_to_walk_ADDR)
        logger.info("take step to: " + str(candidate_to_walk_ADDR))

    #a bunch of message creator
    def create_introduction_request(self, destination_address,
                                    source_lan_address, source_wan_address):
        identifier = int(random() * 2**16)
        data = [
            inet_aton(destination_address[0]),
            self._struct_H.pack(destination_address[1]),
            inet_aton(source_lan_address[0]),
            self._struct_H.pack(source_lan_address[1]),
            inet_aton(source_wan_address[0]),
            self._struct_H.pack(source_wan_address[1]),
            self._struct_B.pack(self._encode_advice_map[True]
                                | self._encode_connection_type_map[u"unknown"]
                                | self._encode_sync_map[False]),
            self._struct_H.pack(identifier)
        ]
        container = [self.prefix, chr(246)]
        #container.append(self.my_mid)
        my_public_key = self.my_public_key
        #container.extend((self._struct_H.pack(len(my_public_key)), my_public_key))
        container.append(self.my_mid)
        #now = int(time())
        now = self._struct_Q.pack(self._global_time)
        container.append(now)
        container.extend(data)
        #print container
        packet = "".join(container)
        #print ("the packet length is: "+str(len(packet)))
        signiture = self.crypto.create_signature(self.my_key, packet)
        #print ("the signiture length is: "+str(len(signiture)))
        packet = packet + signiture
        #print repr(signiture)
        #message = Message.introduction_request()
        #message.destination_addr = destination_address
        #message.sender_lan_addr = source_lan_address
        #message.sender_wan_addr = source_wan_address
        #message.identifier = identifier
        #message.mid = self.my_mid
        #message.global_time = now
        #message.signiture = signiture
        #message.message_type = 246
        #message.prefix = self.prefix
        #message.packet = packet
        self.visited_count = self.visited_count + 1

        message = Message.message(destination_address=destination_address,
                                  source_lan_address=source_lan_address,
                                  source_wan_address=source_wan_address,
                                  identifier=identifier,
                                  mid=self.mid,
                                  global_time=now,
                                  signiture=signiture,
                                  message_type=246,
                                  prefix=self.prefix,
                                  packet=packet)
        return message

    def create_introduction_response(self, identifier, destination_address,
                                     source_lan_address, source_wan_address,
                                     lan_introduction_address,
                                     wan_introduction_address):
        data = (
            inet_aton(destination_address[0]),
            self._struct_H.pack(destination_address[1]),
            inet_aton(source_lan_address[0]),
            self._struct_H.pack(source_lan_address[1]),
            inet_aton(source_wan_address[0]),
            self._struct_H.pack(source_wan_address[1]),
            inet_aton(lan_introduction_address[0]),
            self._struct_H.pack(lan_introduction_address[1]),
            inet_aton(wan_introduction_address[0]),
            self._struct_H.pack(wan_introduction_address[1]),
            self._struct_B.pack(self._encode_connection_type_map[u"unknown"]
                                | self._encode_tunnel_map[False]),
            self._struct_H.pack(identifier))
        container = [self.prefix, chr(245)]
        container.append(self.my_mid)
        now = self._struct_Q.pack(self._global_time)
        container.append(now)
        container.extend(data)
        packet = "".join(container)
        signiture = self.crypto.create_signature(self.my_key, packet)
        packet = packet + signiture

        #message = Message.introduction_response()
        #message.destination_addr = destination_address
        #message.sender_lan_addr = source_lan_address
        #message.sender_wan_addr = source_wan_address
        #message.lan_introducted_addr = lan_introduction_address
        #message.wan_introducted_addr = wan_introduction_address
        #message.identifier = identifier
        #message.mid = self.my_mid
        #message.global_time = now
        #message.signiture = signiture
        #message.message_type = 246
        #message.prefix = self.prefix
        #message.packet = packet

        message = Message.message(
            destination_address=destination_address,
            source_lan_address=source_lan_address,
            source_wan_address=source_wan_address,
            lan_introduction_address=lan_introduction_address,
            wan_introduction_address=wan_introduction_address,
            identifier=identifier,
            mid=self.mid,
            global_time=now,
            signiture=signiture,
            message_type=245,
            prefix=self.prefix,
            packet=packet)
        return message

    def create_puncture_request(self, lan_walker_address, wan_walker_address):
        identifier = int(random() * 2**16)
        data = (inet_aton(lan_walker_address[0]),
                self._struct_H.pack(lan_walker_address[1]),
                inet_aton(wan_walker_address[0]),
                self._struct_H.pack(wan_walker_address[1]),
                self._struct_H.pack(identifier))
        container = [self.prefix, chr(250)]
        #my_public_key = self.my_public_key
        now = self._struct_Q.pack(self._global_time)
        container.append(now)
        container.extend(data)
        #print container
        packet = "".join(container)
        #since it uses NoAuthentication, the signiture is ""
        signiture = ""
        packet = packet + signiture

        #message = Message.puncture_request()
        #message.lan_walker_addr = lan_walker_addr
        #message.wan_walker_addr = wan_walker_addr
        #message.identifier = identifier
        #message.mid = self.my_mid
        #message.global_time = now
        #message.signiture = signiture
        #message.message_type = 250
        #message.prefix = self.prefix
        #message.packet = packet

        message = Message.message(lan_walker_address=lan_walker_address,
                                  wan_walker_address=wan_walker_address,
                                  identifier=identifier,
                                  mid=self.mid,
                                  global_time=now,
                                  signiture=signiture,
                                  message_type=250,
                                  prefix=self.prefix,
                                  packet=packet)
        return message

    def create_puncture(self, identifier, source_lan_address,
                        source_wan_address):
        #the identifier of dispersy-puncture should be same to corresponding puncture-request
        #but since this is only an experiment, so be it...
        assert isinstance(source_lan_address, tuple), source_lan_address
        assert isinstance(source_wan_address, tuple), source_wan_address
        data = (inet_aton(source_lan_address[0]),
                self._struct_H.pack(source_lan_address[1]),
                inet_aton(source_wan_address[0]),
                self._struct_H.pack(source_wan_address[1]),
                self._struct_H.pack(identifier))
        container = [self.prefix, chr(249)]
        container.append(self.my_mid)
        now = self._struct_Q.pack(self._global_time)
        container.append(now)
        container.extend(data)
        packet = "".join(container)
        signiture = self.crypto.create_signature(self.my_key, packet)
        packet = packet + signiture

        #message = Message.puncture()
        #message.sender_lan_addr = source_lan_address
        #message.sender_wan_addr = source_wan_address
        #message.identifier = identifier
        #message.mid = self.my_mid
        #message.global_time = now
        #message.signiture = signiture
        #message.message_type = 250
        #message.prefix = self.prefix
        #message.packet = packet

        message = Message.message(source_lan_address=source_lan_address,
                                  source_wan_address=source_wan_address,
                                  identifier=identifier,
                                  mid=self.mid,
                                  global_time=now,
                                  signiture=signiture,
                                  message_type=249,
                                  prefix=self.prefix,
                                  packet=packet)
        return message

    def create_identity(self):
        identifier = int(random() * 2**16)
        container = [self.prefix, chr(248)]
        #container.append(self.my_mid)
        #for dispersy-identity, it always uses "bin" as encoding
        #regardless of community-version
        my_public_key = self.my_public_key
        container.extend(
            (self._struct_H.pack(len(my_public_key)), my_public_key))
        #now = int(time())
        #global_time = (self._global_time,0)
        #print "global time tuple is: "+str(global_time)
        #print type(global_time)
        now = self._struct_Q.pack(self._global_time)
        container.append(now)
        data = ()
        container.extend(data)
        #print container
        packet = "".join(container)
        signiture = self.crypto.create_signature(self.my_key, packet)
        packet = packet + signiture

        #message = Message.identity()
        #message.identifier = identifier
        #message.mid = self.my_mid
        #message.global_time = now
        #message.signiture = signiture
        #message.message_type = 248
        #message.prefix = self.prefix
        #message.packet = packet

        message = Message.message(identifier=identifier,
                                  mid=self.mid,
                                  global_time=now,
                                  signiture=signiture,
                                  message_type=248,
                                  prefix=self.prefix,
                                  packet=packet)
        return message

    def datagramReceived(self, data, addr):
        #print("received %r from %s" % (data, addr))
        print("received data from" + str(addr))
        #now we receive a UDP datagram, call decode_message to decode it
        self.decode_message(data, addr)
        #self.transport.write(data, addr)

    def decode_message(self, packet, addr):
        message_id = ord(packet[22])
        logger.info("message id is:" + str(message_id))
        print("message id is:" + str(message_id))
        if message_id == 247:
            print("here is a missing-identity message")
            #placeholder = PlaceHolder(23)
            self.on_missing_identity(packet, addr)
        if message_id == 245:
            print("here is a introduction-response")
            #placeholder = PlaceHolder(23)
            self.on_introduction_response(packet, addr)
        if message_id == 246:
            print("here is a introduction-request")
            #placeholder = PlaceHolder(23)
            self.on_introduction_request(packet, addr)
        if message_id == 250:
            print("here is a puncture request")
            #placeholder = PlaceHolder(23)
            self.on_puncture_request(packet, addr)
        if message_id == 249:
            print("here is a puncture")

    # a bunch of message handler
    def on_introduction_request(self, packet, addr):
        #placeholder = PlaceHolder(23)
        message_request = self.decode_introduction_request(packet)
        stumble_candidate = Wcandidate(message_request.source_lan_address,
                                       addr)
        self.candidate_group.add_candidate_to_stumble_list(stumble_candidate)
        #do wan_vote
        self.wan_address_vote(message_request.destination_address, addr)
        #we don't have codes to determine whether the candidate is within our lan, so we use wan address.
        candidate_request = Wcandidate(message_request.source_lan_address,
                                       message_request.source_wan_address)
        candidate_to_introduce = self.candidate_group.get_candidate_to_introduce(
            candidate_request)
        if candidate_to_introduce != None:
            introduced_lan_addr = candidate_to_introduce.get_LAN_ADDR()
            introduced_wan_addr = candidate_to_introduce.get_WAN_ADDR()
        else:
            introduced_lan_addr = ("0.0.0.0", 0)
            introduced_wan_addr = ("0.0.0.0", 0)
        message_response = self.create_introduction_response(
            message_request.identifier, addr, self.lan_addr, self.lan_addr,
            introduced_lan_addr, introduced_wan_addr)
        #now it is time to create puncture request
        if candidate_to_introduce != None:
            message_puncture_request = self.create_puncture_request(
                message_request.source_lan_address,
                message_request.source_lan_address)
            self.transport.write(message_puncture_request.packet,
                                 candidate_to_introduce.get_WAN_ADDR())
            self.transport.write(message_puncture_request.packet,
                                 candidate_to_introduce.get_LAN_ADDR())
        self.transport.write(message_response.packet, addr)

    def on_introduction_response(self, packet, addr):
        #placeholder = PlaceHolder(23)
        message = self.decode_introduction_response(packet)
        self.wan_address_vote(message.destination_address, addr)
        walk_candidate = Wcandidate(message.source_lan_address, addr)
        self.candidate_group.add_candidate_to_walk_list(walk_candidate)
        print("the introduced candidate is: " +
              str(message.wan_introduction_address))
        if message.lan_introduction_address != (
                "0.0.0.0",
                0) and message.wan_introduction_address != ("0.0.0.0", 0):
            introduced_candidate = Wcandidate(message.lan_introduction_address,
                                              message.wan_introduction_address)
            self.candidate_group.add_candidate_to_intro_list(
                introduced_candidate)
            print("new candidate has been added to intro list")

    def on_puncture_request(self, packet, addr):
        #placeholder = PlaceHolder(23)
        message_puncture_request = self.decode_puncture_request(packet)
        lan_walker_address = message_puncture_request.lan_walker_address
        wan_walker_address = message_puncture_request.wan_walker_address
        self.wan_addr = self.get_majority_vote()
        print("the wan addr from majority vote is:")
        print(self.wan_addr)
        message_puncture = self.create_puncture(
            message_puncture_request.identifier, self.lan_addr, self.wan_addr)
        self.transport.write(message_puncture.packet, lan_walker_address)
        self.transport.write(message_puncture.packet, wan_walker_address)

    def on_puncture(self, packet):
        pass

    def on_missing_identity(self, packet, addr):
        message = self.create_identity()
        self.transport.write(message.packet, addr)

    def on_identity(self, packet):
        pass

    #a bunch of message decoder below:
    def decode_introduction_request(self, packet):
        offset = 23
        #offset = placeholder.offset
        if len(packet) < offset + 21:
            print("insufficient packet length")
        #MemberAuthentication uses sha1
        member_id = packet[offset:offset + 20]
        offset = offset + 20
        #uses directDistribution
        global_time, = self._struct_Q.unpack_from(packet, offset)
        print("global time is:" + str(global_time))
        offset = offset + 8
        self._global_time = global_time

        destination_ip, destination_port = self._struct_4SH.unpack_from(
            packet, offset)
        destination_address = (inet_ntoa(destination_ip), destination_port)
        print("destination address is:" + str(destination_address))
        offset += 6

        source_lan_ip, source_lan_port = self._struct_4SH.unpack_from(
            packet, offset)
        source_lan_address = (inet_ntoa(source_lan_ip), source_lan_port)
        print("source_lan_address is: " + str(source_lan_address))
        offset += 6

        source_wan_ip, source_wan_port = self._struct_4SH.unpack_from(
            packet, offset)
        source_wan_address = (inet_ntoa(source_wan_ip), source_wan_port)
        print("source_wan_address is: " + str(source_wan_address))
        offset += 6

        flags, identifier = self._struct_BH.unpack_from(packet, offset)
        offset += 3

        advice = self._decode_advice_map.get(flags & int("1", 2))
        print("advice is: " + str(advice))

        signiture = packet[offset:]
        prefix = packet[0:offset]

        #message = Message.introduction_request()
        #message.destination_addr = destination_address
        #message.sender_lan_addr = source_lan_address
        #message.sender_wan_addr = source_wan_address
        #message.identifier = identifier
        #message.mid = member_id
        #message.global_time = global_time
        #message.signiture = signiture
        #message.prefix = self.prefix
        #message.packet = packet

        message = Message.message(message_type=246,
                                  destination_address=destination_address,
                                  source_lan_address=source_lan_address,
                                  source_wan_address=source_wan_address,
                                  identifier=identifier,
                                  mid=self.mid,
                                  global_time=global_time,
                                  signiture=signiture,
                                  prefix=prefix,
                                  packet=packet)
        return message

    def decode_introduction_response(self, packet):
        #offset = placeholder.offset
        offset = 23
        #introduction request use MemberAuthentication
        member_id = packet[offset:offset + 20]
        offset = offset + 20
        global_time, = self._struct_Q.unpack_from(packet, offset)
        self._global_time = global_time
        print("global time is:" + str(global_time))
        offset = offset + 8
        #it is time to decode the payload
        destination_ip, destination_port = self._struct_4SH.unpack_from(
            packet, offset)
        destination_address = (inet_ntoa(destination_ip), destination_port)
        print("destination address is:" + str(destination_address))
        offset += 6

        source_lan_ip, source_lan_port = self._struct_4SH.unpack_from(
            packet, offset)
        source_lan_address = (inet_ntoa(source_lan_ip), source_lan_port)
        print("source_lan_address is: " + str(source_lan_address))
        offset += 6

        source_wan_ip, source_wan_port = self._struct_4SH.unpack_from(
            packet, offset)
        source_wan_address = (inet_ntoa(source_wan_ip), source_wan_port)
        print("source_wan_address is: " + str(source_wan_address))
        offset += 6

        introduce_lan_ip, introduce_lan_port = self._struct_4SH.unpack_from(
            packet, offset)
        lan_introduction_address = (inet_ntoa(introduce_lan_ip),
                                    introduce_lan_port)
        print("lan_introduction_address is: " + str(lan_introduction_address))
        offset += 6

        introduce_wan_ip, introduce_wan_port = self._struct_4SH.unpack_from(
            packet, offset)
        wan_introduction_address = (inet_ntoa(introduce_wan_ip),
                                    introduce_wan_port)
        print("wan_introduction_address is:" + str(wan_introduction_address))
        offset += 6

        flags, identifier, = self._struct_BH.unpack_from(packet, offset)
        offset += 3

        connection_type = self._decode_connection_type_map.get(
            flags & int("11000000", 2))
        print("connection type is: " + str(connection_type))
        if connection_type is None:
            raise DropPacket("Invalid connection type flag")

        tunnel = self._decode_tunnel_map.get(flags & int("100", 2))
        print("tunnel is:" + str(tunnel))
        if lan_introduction_address == (
                "0.0.0.0", 0) and wan_introduction_address == ("0.0.0.0", 0):
            print("it is an empty introduction response")

        signiture = packet[offset:]
        prefix = packet[0:offset]

        #message = Message.introduction_response()
        #message.destination_addr = destination_address
        #message.sender_lan_addr = source_lan_address
        #message.sender_wan_addr = source_wan_address
        #message.lan_introducted_addr=lan_introduction_address
        #message.wan_introducted_addr = wan_introduction_address
        #message.lan_introduction_address = lan_introduction_address
        #message.wan_introduction_address = wan_introduction_address
        #message.identifier = identifier
        #message.mid = member_id
        #message.global_time = global_time
        #message.signiture = signiture
        #message.prefix = self.prefix
        #message.packet = packet

        message = Message.message(
            message_type=245,
            destination_address=destination_address,
            source_lan_address=source_lan_address,
            source_wan_address=source_wan_address,
            lan_introduction_address=lan_introduction_address,
            wan_introduction_address=wan_introduction_address,
            identifier=identifier,
            mid=member_id,
            global_time=global_time,
            signiture=signiture,
            prefix=self.prefix,
            packet=packet)
        return message

    #this function is never called for now, but we may need it later for statistical information
    def decode_missing_identity(self, packet):
        offset = 23
        #offset = placeholder.offset
        #missing-identity message us NoAuthentication
        key_length = 0
        #it use PublicResoulution, so we need to do nothing
        #it use directDitribution, we need to take out the global time
        global_time = self._struct_Q.unpack_from(packet, offset)
        print("the global time is: " + str(global_time[0]))
        self._global_time = global_time[0]

        #message = Message.missing_identity()
        #message.packet = packet
        message = Message.message(message_type=247, packet=packet)

    def decode_puncture_request(self, packet):
        #offset = placeholder.offset
        offset = 23
        #puncture-request uses NoAuthentication
        #puncture-request uses DirectDistribution
        global_time, = self._struct_Q.unpack_from(packet, offset)
        print("global time is:" + str(global_time))
        offset = offset + 8

        if len(packet) < offset + 14:
            print("the length is insufficient")

        lan_walker_ip, lan_walker_port = self._struct_4SH.unpack_from(
            packet, offset)
        lan_walker_address = (inet_ntoa(lan_walker_ip), lan_walker_port)
        print("lan_walker_address is: " + str(lan_walker_address))
        offset += 6

        wan_walker_ip, wan_walker_port = self._struct_4SH.unpack_from(
            packet, offset)
        wan_walker_address = (inet_ntoa(wan_walker_ip), wan_walker_port)
        print("wan_walker_address is: " + str(wan_walker_address))
        offset += 6

        identifier, = self._struct_H.unpack_from(packet, offset)
        offset += 2

        signiture = packet[offset:]
        prefix = packet[0:offset]

        #message = Message.puncture_request()

        #message.lan_walker_addr = lan_walker_address
        #message.wan_walker_addr = wan_walker_address
        #message.identifier = identifier
        #message.global_time = global_time
        #message.signiture = signiture
        #message.prefix = self.prefix
        #message.packet = packet

        message = Message.message(message_type=250,
                                  lan_walker_address=lan_walker_address,
                                  wan_walker_address=wan_walker_address,
                                  identifier=identifier,
                                  global_time=global_time,
                                  signiture=signiture,
                                  prefix=self.prefix,
                                  packet=packet)
        return message

    def decode_puncture(self, packet):
        pass

    #some untility functions listed below

    #get a proper candidate to introduce
    def get_candidate_to_introduce(self, candidate):
        candidate_to_introduce = self.candidate_group.get_candidate_to_introduce(
            candidate)
        return candidate_to_introduce

    #get a proper candidate to walk
    def get_candidate_to_walk(self):
        candidate_to_walk = self.candidate_group.get_candidate_to_walk()
        return candidate_to_walk

    def get_lan_IP(self, addr):
        #try to connect to tracker to determine the ip we used
        #because a device may have multiple network interfaces (e.g. a Wifi and wire network while one of them
        #is not connected to public network)
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(addr)
        sock_IP = s.getsockname()[0]
        s.close()
        return sock_IP

    #@staticmethod
    #def get_addr_from_string(address):
    #convert a string to (IP,PORT) tuple
    #addr = address.split(":")
    #addr_tuple = (addr[0],addr[1])
    #return addr_tuple

    #get the majority votes
    def get_majority_vote(self):
        max_vote = 0
        majority = self.wan_ip + ":" + str(self.wan_port)
        for key in self.WAN_VOTE:
            num_vote = len(self.WAN_VOTE[key])
            if num_vote > max_vote:
                majority = key
        majority_list = majority.split(":")
        majority_IP = majority_list[0]
        majority_PORT = int(majority_list[1])
        return (majority_IP, majority_PORT)

    #take a wan vote, possible to change the wan address basing on the votes
    def wan_address_vote(self, address, candidate_addr):
        assert isinstance(address, tuple), type(address)
        assert isinstance(candidate_addr, tuple), type(candidate_addr)
        #@param:addr my address which is perceived by the voter
        #@param:candidate_addr the candidate's (voter) addr
        change_flag = 0
        IP = address[0]
        PORT = address[1]
        ADDR = IP + ":" + str(PORT)
        if ADDR in self.WAN_VOTE:
            candidate_vote_list = self.WAN_VOTE[ADDR]
            if candidate_addr not in candidate_vote_list:
                self.WAN_VOTE[ADDR].append(candidate_addr)
                change_flag = 1
        else:
            self.WAN_VOTE[ADDR] = [candidate_addr]
            change_flag = 1
        #if there is any update in WAN_VOTE
        if (change_flag == 1):
            new_WAN_ADDR = self.get_majority_vote()
            self.wan_ip = new_WAN_ADDR[0]
            self.wan_port = new_WAN_ADDR[1]
            self.wan_addr = new_WAN_ADDR

    def get_netmask(self, address):
        interfaces = Walker._get_interface_addresses()
        for interface in interfaces:
            if (interface.address == address):
                return interface.netmask
        return None

    def run(self):
        self.reactor.run()

    def stop(self):
        self.reactor.stop()

    @staticmethod
    def _get_interface_addresses():
        """
        Yields Interface instances for each available AF_INET interface found.

        An Interface instance has the following properties:
        - name          (i.e. "eth0")
        - address       (i.e. "10.148.3.254")
        - netmask       (i.e. "255.255.255.0")
        - broadcast     (i.e. "10.148.3.255")
        """
        class Interface(object):
            def __init__(self, name, address, netmask, broadcast):
                self.name = name
                self.address = address
                self.netmask = netmask
                self.broadcast = broadcast
                self._l_address, = unpack_from(">L", inet_aton(address))
                self._l_netmask, = unpack_from(">L", inet_aton(netmask))

            def __contains__(self, address):
                assert isinstance(address, str), type(address)
                l_address, = unpack_from(">L", inet_aton(address))
                return (l_address & self._l_netmask) == (self._l_address
                                                         & self._l_netmask)

            def __str__(self):
                return "<{self.__class__.__name__} \"{self.name}\" addr:{self.address} mask:{self.netmask}>".format(
                    self=self)

            def __repr__(self):
                return "<{self.__class__.__name__} \"{self.name}\" addr:{self.address} mask:{self.netmask}>".format(
                    self=self)

        try:
            for interface in netifaces.interfaces():
                try:
                    addresses = netifaces.ifaddresses(interface)

                except ValueError:
                    # some interfaces are given that are invalid, we encountered one called ppp0
                    pass

                else:
                    for option in addresses.get(netifaces.AF_INET, []):
                        try:
                            yield Interface(interface, option.get("addr"),
                                            option.get("netmask"),
                                            option.get("broadcast"))

                        except TypeError:
                            # some interfaces have no netmask configured, causing a TypeError when
                            # trying to unpack _l_netmask
                            pass
        except OSError, e:
            #logger = logging.getLogger("dispersy")
            #logger.warning("failed to check network interfaces, error was: %r", e)
            print("OSError")
Ejemplo n.º 9
0
class Test_Message:
    def setup(self):
        print("TestUM:setup() before each test method")
        self.crypto = ECCrypto()
        self.my_key1 = self.crypto.generate_key(u"medium")
        self.my_key2 = self.crypto.generate_key(u"medium")
        self.my_key3 = self.crypto.generate_key(u"medium")
        self.my_key4 = self.crypto.generate_key(u"medium")
        self.my_key5 = self.crypto.generate_key(u"medium")
        self.my_identity1 = self.crypto.key_to_hash(self.my_key1.pub())
        self.my_identity2 = self.crypto.key_to_hash(self.my_key2.pub())
        self.my_identity3 = self.crypto.key_to_hash(self.my_key3.pub())
        self.my_identity4 = self.crypto.key_to_hash(self.my_key4.pub())
        self.my_identity5 = self.crypto.key_to_hash(self.my_key5.pub())
        self.my_public_key1 = self.crypto.key_to_bin(self.my_key1.pub())
        self.my_public_key2 = self.crypto.key_to_bin(self.my_key2.pub())
        self.my_public_key3 = self.crypto.key_to_bin(self.my_key3.pub())
        self.my_public_key4 = self.crypto.key_to_bin(self.my_key4.pub())
        self.my_public_key5 = self.crypto.key_to_bin(self.my_key5.pub())
        if os.path.isfile('BlockDataBase.db'):
            os.remove('BlockDataBase.db')
        self.database = HalfBlockDatabase()

    def teardown(self):
        print("TestUM:teardown() after each test method")

    @classmethod
    def setup_class(cls):
        print("setup_class() before any methods in this class")
        #cls.walker = Walker(port=23334)

    @classmethod
    def teardown_class(cls):
        print("teardown_class() after any methods in this class")

    def test_add_and_get_member(self):
        self.database.add_member(identity=self.my_identity1,
                                 public_key=self.my_public_key1)
        result = self.database.get_member(public_key=self.my_public_key1)
        assert str(result[0]) == self.my_identity1
        assert str(result[1]) == self.my_public_key1

    def test_add_and_get_block(self):

        block1 = HalfBlock()
        block1.public_key = self.my_public_key1

        block2 = HalfBlock()
        block2.public_key = self.my_public_key2
        self.database.add_block(block1)
        self.database.add_block(block2)

        results = self.database.get_blocks_by_public_key(
            public_key=self.my_public_key1)
        for result in results:
            block = HalfBlock(result)
            if block.public_key == self.my_public_key1:
                block.insert_time = block1.insert_time
                assert block.insert_time == block1.insert_time
            if block.public_key == self.my_public_key2:
                block.insert_time = block2.insert_time
                assert block == block2

    def test_has_block(self):
        block3 = HalfBlock()
        block3.public_key = self.my_public_key3

        block4 = HalfBlock()
        block4.public_key = self.my_public_key4
        self.database.add_block(block3)
        status1 = self.database.has_block(block3)
        status2 = self.database.has_block(block4)

        assert status1 == True
        assert status2 == False
class Test_HalfBlockDatabase:
    def setup(self):
        print("TestUM:setup() before each test method")
        self.crypto = ECCrypto()
        self.my_key1 = self.crypto.generate_key(u"medium")
        self.my_key2 = self.crypto.generate_key(u"medium")
        self.my_key3 = self.crypto.generate_key(u"medium")
        self.my_key4 = self.crypto.generate_key(u"medium")
        self.my_key5 = self.crypto.generate_key(u"medium")
        self.my_key6 = self.crypto.generate_key(u"medium")

        self.my_identity1 = self.crypto.key_to_hash(self.my_key1.pub())
        self.my_identity2 = self.crypto.key_to_hash(self.my_key2.pub())
        self.my_identity3 = self.crypto.key_to_hash(self.my_key3.pub())
        self.my_identity4 = self.crypto.key_to_hash(self.my_key4.pub())
        self.my_identity5 = self.crypto.key_to_hash(self.my_key5.pub())
        self.my_identity6 = self.crypto.key_to_hash(self.my_key6.pub())

        self.my_public_key1 = self.crypto.key_to_bin(self.my_key1.pub())
        self.my_public_key2 = self.crypto.key_to_bin(self.my_key2.pub())
        self.my_public_key3 = self.crypto.key_to_bin(self.my_key3.pub())
        self.my_public_key4 = self.crypto.key_to_bin(self.my_key4.pub())
        self.my_public_key5 = self.crypto.key_to_bin(self.my_key5.pub())
        self.my_public_key6 = self.crypto.key_to_bin(self.my_key6.pub())

        if os.path.isfile('BlockDataBase.db'):
            os.remove('BlockDataBase.db')
        self.database = HalfBlockDatabase(
            os.path.join(BASE, 'BlockDataBase.db'))

    def teardown(self):
        print("TestUM:teardown() after each test method")

    @classmethod
    def setup_class(cls):
        print("setup_class() before any methods in this class")
        #cls.walker = Walker(port=23334)

    @classmethod
    def teardown_class(cls):
        print("teardown_class() after any methods in this class")

    def test_add_and_get_member(self):
        self.database.add_member(identity=self.my_identity1,
                                 public_key=self.my_public_key1)
        result = self.database.get_member(public_key=self.my_public_key1)
        assert str(result[0]) == self.my_identity1
        assert str(result[1]) == self.my_public_key1

    def test_add_and_get_block(self):

        block1 = HalfBlock()
        block1.public_key = self.my_public_key1

        block2 = HalfBlock()
        block2.public_key = self.my_public_key2
        self.database.add_block(block1)
        self.database.add_block(block2)

        blocks = self.database.get_blocks_by_public_key(
            public_key=self.my_public_key1)
        for block in blocks:
            if block.public_key == self.my_public_key1:
                block.insert_time = block1.insert_time
                assert block.insert_time == block1.insert_time
            if block.public_key == self.my_public_key2:
                block.insert_time = block2.insert_time
                assert block == block2

    def test_has_block(self):
        block3 = HalfBlock()
        block3.public_key = self.my_public_key3

        block4 = HalfBlock()
        block4.public_key = self.my_public_key4
        self.database.add_block(block3)
        status1 = self.database.has_block(block3)
        status2 = self.database.has_block(block4)

        assert status1 == True
        assert status2 == False

    def test_get_all_member(self):
        self.database.add_member(identity=self.my_identity1,
                                 public_key=self.my_public_key1)
        self.database.add_member(identity=self.my_identity2,
                                 public_key=self.my_public_key2)
        members = self.database.get_all_member()
        assert members != None

    def test_get_latest_sequence_number(self):
        block3 = HalfBlock()
        block3.public_key = self.my_public_key3
        block3.sequence_number = 1

        block4 = HalfBlock()
        block4.public_key = self.my_public_key3
        block4.sequence_number = 2

        self.database.add_block(block3)
        self.database.add_block(block4)
        sequence_number = self.database.get_latest_sequence_number(
            public_key=self.my_public_key3)
        assert sequence_number == 2

    def test_get_blocks_since(self):
        block1 = HalfBlock()
        block1.public_key = self.my_public_key4
        block1.sequence_number = 1

        block2 = HalfBlock()
        block2.public_key = self.my_public_key4
        block2.sequence_number = 2

        self.database.add_block(block1)
        self.database.add_block(block2)
        blocks = self.database.get_blocks_since(sequence_number=2,
                                                public_key=self.my_public_key4)

        assert blocks[0].public_key == self.my_public_key4
        assert blocks[0].sequence_number == 2

    def test_get_blocks_by_public_key(self):
        block = HalfBlock()
        block.public_key = "haha"
        block.sequence_number = 80
        self.database.add_block(block)
        block_return = self.database.get_blocks_by_public_key(
            public_key="haha")
        assert block_return[0].public_key == "haha"
        assert block_return[0].sequence_number == 80

    def test_add_and_get_visit_record(self):
        self.database.add_visit_record(ip="6.6.6.6",
                                       port=6,
                                       public_key="haha2")
        results = self.database.get_all_visit_records()
        print("it is:")
        print str(results[0][0])
        assert str(results[0][0]) == "6.6.6.6"
        assert results[0][1] == 6
        assert str(results[0][2]) == "haha2"