예제 #1
0
    def HandleInvMessage(self, payload):
        """
        Process a block header inventory payload.

        Args:
            inventory (neo.Network.Payloads.InvPayload):
        """

        if self.sync_mode != MODE_MAINTAIN:
            return

        inventory = IOHelper.AsSerializableWithType(
            payload, 'neo.Network.Payloads.InvPayload.InvPayload')

        if inventory.Type == InventoryType.BlockInt:

            ok_hashes = []
            for hash in inventory.Hashes:
                hash = hash.encode('utf-8')
                if hash not in self.myblockrequests and hash not in BC.Default(
                ).BlockRequests:
                    ok_hashes.append(hash)
                    BC.Default().BlockRequests.add(hash)
                    self.myblockrequests.add(hash)
            if len(ok_hashes):
                #                logger.info("OK HASHES, get data %s " % ok_hashes)
                message = Message("getdata",
                                  InvPayload(InventoryType.Block, ok_hashes))
                self.SendSerializedMessage(message)

        elif inventory.Type == InventoryType.TXInt:
            pass
        elif inventory.Type == InventoryType.ConsensusInt:
            pass
예제 #2
0
    def HandleGetBlocksMessageReceived(self, payload):
        """
        Process a GetBlocksPayload payload.

        Args:
            payload (neo.Network.Payloads.GetBlocksPayload):
        """
        if not self.leader.ServiceEnabled:
            return

        inventory = IOHelper.AsSerializableWithType(
            payload, 'neo.Network.Payloads.GetBlocksPayload.GetBlocksPayload')

        if not BC.Default().GetHeader(inventory.HashStart):
            self.Log("Hash %s not found %s " % inventory.HashStart)
            return

        hashes = []
        hcount = 0
        hash = inventory.HashStart
        while hash != inventory.HashStop and hcount < 500:
            hash = BC.Default().GetNextBlockHash(hash)
            if hash is None:
                break
            hashes.append(hash)
            hcount += 1
        if hcount > 0:
            self.Log("sending inv hashes! %s " % hashes)
            self.SendSerializedMessage(
                Message('inv',
                        InvPayload(type=InventoryType.Block, hashes=hashes)))
예제 #3
0
    def DoAskForMoreBlocks(self):
        hashes = []
        hashstart = BC.Default().Height + 1
        current_header_height = BC.Default().HeaderHeight + 1

        do_go_ahead = False
        if BC.Default().BlockSearchTries > 100 and len(BC.Default().BlockRequests) > 0:
            do_go_ahead = True

        first = None
        while hashstart < current_header_height and len(hashes) < self.leader.BREQPART:
            hash = BC.Default().GetHeaderHash(hashstart)
            if not do_go_ahead:
                if hash is not None and hash not in BC.Default().BlockRequests \
                        and hash not in self.myblockrequests:

                    if not first:
                        first = hashstart
                    BC.Default().BlockRequests.add(hash)
                    self.myblockrequests.add(hash)
                    hashes.append(hash)
            else:
                if not first:
                    first = hashstart
                BC.Default().BlockRequests.add(hash)
                self.myblockrequests.add(hash)
                hashes.append(hash)

            hashstart += 1

        self.Log("asked for more blocks ... %s thru %s (%s blocks) stale count %s BCRLen: %s " % (first, hashstart, len(hashes), BC.Default().BlockSearchTries, len(BC.Default().BlockRequests)))

        if len(hashes) > 0:
            message = Message("getdata", InvPayload(InventoryType.Block, hashes))
            reactor.callInThread(self.SendSerializedMessage, message)
 def SendVersion(self):
     """Send our client version."""
     m = Message(
         "version",
         VersionPayload(settings.NODE_PORT, self.remote_nodeid,
                        settings.VERSION_NAME))
     self.SendSerializedMessage(m)
예제 #5
0
    def Relay(self, inventory):

        inventory = InvPayload(type=inventory.InventoryType, hashes=[inventory.Hash.ToBytes()])
        m = Message("inv", inventory)
        self.SendSerializedMessage(m)

        return True
예제 #6
0
    def HandleGetBlocksMessageReceived(self, payload):
        """
        Process a GetBlocksPayload payload.

        Args:
            payload (neo.Network.Payloads.GetBlocksPayload):
        """
        if not self.leader.ServiceEnabled:
            return

        inventory = IOHelper.AsSerializableWithType(
            payload, 'neo.Network.Payloads.GetBlocksPayload.GetBlocksPayload')
        if not inventory:
            return

        blockchain = BC.Default()
        hash = inventory.HashStart[0]
        if not blockchain.GetHeader(hash):
            return

        hashes = []
        hcount = 0
        while hash != inventory.HashStop and hcount < 500:
            hash = blockchain.GetNextBlockHash(hash)
            if hash is None:
                break
            hashes.append(hash)
            hcount += 1
        if hcount > 0:
            self.SendSerializedMessage(
                Message('inv',
                        InvPayload(type=InventoryType.Block, hashes=hashes)))
예제 #7
0
    def DoAskForMoreBlocks(self):

        hashes = []
        hashstart = BC.Default().Height + 1

        if BC.Default().BlockSearchTries > 400 and len(BC.Default().BlockRequests) > 0:
            self.leader.ResetBlockRequestsAndCache()

        first=None
        while hashstart < BC.Default().HeaderHeight and len(hashes) < self.leader.BREQPART:
            hash = BC.Default().GetHeaderHash(hashstart)
            if hash is not None and not hash in BC.Default().BlockRequests and not hash in self.myblockrequests:
                if not first:
                    first = hashstart
                BC.Default().BlockRequests.add(hash)
                self.myblockrequests.add(hash)
                hashes.append(hash)
            hashstart += 1

        self.Log("asked for more blocks ... %s thru %s stale count %s " % (first,hashstart, BC.Default().BlockSearchTries))


        if len(hashes) > 0:
            message = Message("getdata", InvPayload(InventoryType.Block, hashes))
            self.SendSerializedMessage(message)
        else:
            reactor.callLater(5, self.AskForMoreBlocks)
예제 #8
0
    def HandleGetDataMessageReceived(self, payload):
        """
        Process a InvPayload payload.

        Args:
            payload (neo.Network.Inventory):
        """
        inventory = IOHelper.AsSerializableWithType(payload, 'neo.Network.Payloads.InvPayload.InvPayload')

        for hash in inventory.Hashes:
            hash = hash.encode('utf-8')

            item = None
            # try to get the inventory to send from relay cache

            if hash in self.leader.RelayCache.keys():
                item = self.leader.RelayCache[hash]

            if item:
                if inventory.Type == int.from_bytes(InventoryType.TX, 'little'):
                    message = Message(command='tx', payload=item, print_payload=True)
                    self.SendSerializedMessage(message)

                elif inventory.Type == int.from_bytes(InventoryType.Block, 'little'):
                    logger.info("handle block!")

                elif inventory.Type == int.from_bytes(InventoryType.Consensus, 'little'):
                    logger.info("handle consensus")
예제 #9
0
    def HandleGetHeadersMessageReceived(self, payload):

        if not self.leader.ServiceEnabled:
            return

        inventory = IOHelper.AsSerializableWithType(payload, 'neo.Network.Payloads.GetBlocksPayload.GetBlocksPayload')

        if not inventory:
            return

        blockchain = BC.Default()

        hash = inventory.HashStart[0]

        if hash is None or hash == inventory.HashStop:
            self.Log("getheaders: Hash {} not found or hashstop reached".format(inventory.HashStart))
            return

        headers = []
        header_count = 0

        while hash != inventory.HashStop and header_count < 2000:
            hash = blockchain.GetNextBlockHash(hash)
            if not hash:
                break
            headers.append(blockchain.GetHeader(hash))
            header_count += 1

        if header_count > 0:
            self.SendSerializedMessage(Message('headers', HeadersPayload(headers=headers)))
예제 #10
0
    def HandleGetDataMessageReceived(self, payload):
        """
        Process a InvPayload payload.

        Args:
            payload (neo.Network.Inventory):
        """
        inventory = IOHelper.AsSerializableWithType(
            payload, 'neo.Network.Payloads.InvPayload.InvPayload')
        if not inventory:
            return

        for hash in inventory.Hashes:
            hash = hash.encode('utf-8')

            item = None
            # try to get the inventory to send from relay cache

            if hash in self.leader.RelayCache.keys():
                item = self.leader.RelayCache[hash]

            if inventory.Type == InventoryType.TXInt:
                if not item:
                    item, index = BC.Default().GetTransaction(hash)
                if not item:
                    item = self.leader.GetTransaction(hash)
                if item:
                    message = Message(command='tx',
                                      payload=item,
                                      print_payload=False)
                    self.SendSerializedMessage(message)

            elif inventory.Type == InventoryType.BlockInt:
                if not item:
                    item = BC.Default().GetBlock(hash)
                if item:
                    message = Message(command='block',
                                      payload=item,
                                      print_payload=False)
                    self.SendSerializedMessage(message)

            elif inventory.Type == InventoryType.ConsensusInt:
                if item:
                    self.SendSerializedMessage(
                        Message(command='consensus',
                                payload=item,
                                print_payload=False))
예제 #11
0
    def test_data_received(self, mock):
        node = NeoNode()
        node.endpoint = Endpoint('hello.com', 1234)
        node.host = node.endpoint.host
        node.port = node.endpoint.port
        payload = VersionPayload(10234, 1234, 'version')
        message = Message('version', payload=payload)
        stream = StreamManager.GetStream()
        writer = BinaryWriter(stream)
        message.Serialize(writer)

        out = stream.getvalue()
        node.dataReceived(out)

        mock.assert_called_once()

        self.assertEqual(node.Version.Nonce, payload.Nonce)
예제 #12
0
 def HandleVerack(self):
     """Handle the `verack` response."""
     m = Message('verack')
     self.SendSerializedMessage(m)
     self.leader.NodeCount += 1
     self.identifier = self.leader.NodeCount
     logger.debug(f"{self.prefix} Handshake complete!")
     self.handshake_complete = True
     self.ProtocolReady()
예제 #13
0
 def AskForMoreHeaders(self):
     logger.debug(
         f"{self.prefix} asking for more headers, starting from {BC.Default().HeaderHeight}"
     )
     self.health_check(HEARTBEAT_HEADERS)
     get_headers_message = Message(
         "getheaders",
         GetBlocksPayload(hash_start=[BC.Default().CurrentHeaderHash]))
     self.SendSerializedMessage(get_headers_message)
예제 #14
0
    def test_handle_message(self, mock):

        node = NeoNode()
        node.endpoint = Endpoint('hello.com', 1234)
        node.host = node.endpoint.host
        node.port = node.endpoint.port

        payload = VersionPayload(10234, 1234, 'version')

        message = Message('version', payload=payload)

        stream = StreamManager.GetStream()
        writer = BinaryWriter(stream)

        message.Serialize(writer)

        out = stream.getvalue()

        print("OUT %s " % out)

        out1 = out[0:10]
        out2 = out[10:20]
        out3 = out[20:]

        node.dataReceived(out1)
        node.dataReceived(out2)

        self.assertEqual(node.buffer_in, out1 + out2)
        #        import pdb
        #        pdb.set_trace()

        self.assertEqual(node.bytes_in, 20)

        mock.assert_not_called()

        node.dataReceived(out3)

        self.assertEqual(node.bytes_in, len(out))
        #        mock.assert_called_with(message)

        mock.assert_called_once()
예제 #15
0
    def CheckDataReceived(self):

        if len(self.buffer_in) >= 24:

            mstart = self.buffer_in[:24]
            ms = StreamManager.GetStream(mstart)
            reader = BinaryReader(ms)

            try:
                m = Message()
                m.Magic = reader.ReadUInt32()
                m.Command = reader.ReadFixedString(12).decode('utf-8')
                m.Length = reader.ReadUInt32()
                m.Checksum = reader.ReadUInt32()
                self.pm = m
            except Exception as e:
                self.Log('could not read initial bytes %s ' % e)
            finally:
                StreamManager.ReleaseStream(ms)
                del reader

            try:
                #make this threadsafe
                #                reactor.callFromThread(self.CheckMessageData)
                self.CheckMessageData()
            except RecursionError:
                self.Log("Recursion error!!!")
                self.Disconnect()
예제 #16
0
    def SendPeerInfo(self):
        if not self.leader.ServiceEnabled:
            return

        peerlist = []
        for peer in self.leader.Peers:
            addr = peer.GetNetworkAddressWithTime()
            if addr is not None:
                peerlist.append(addr)
        self.Log("Peer list %s " % list(map(lambda p: p.ToString(), peerlist)))

        addrpayload = AddrPayload(addresses=peerlist)
        message = Message('addr', addrpayload)
        self.SendSerializedMessage(message)
예제 #17
0
    def SendPeerInfo(self):

        self.Log("SENDING PEER INFO %s " % self)

        peerlist = []
        for peer in self.leader.Peers:
            #make sure peers rating is <= 90 by checking the banlist
            if (peer.getRating <= 90):
                peerlist.append(peer.GetNetworkAddressWithTime())
        self.Log("Peer list %s " % peerlist)

        addrpayload = AddrPayload(addresses=peerlist)
        message = Message('addr', addrpayload)
        self.SendSerializedMessage(message)
예제 #18
0
    def SendPeerInfo(self):
        # if not self.leader.ServiceEnabled:
        #     return

        peerlist = []
        for peer in self.leader.Peers:
            addr = peer.GetNetworkAddressWithTime()
            if addr is not None:
                peerlist.append(addr)
        peer_str_list = list(map(lambda p: p.ToString(), peerlist))
        logger.debug(f"{self.prefix} Sending Peer list {peer_str_list}")

        addrpayload = AddrPayload(addresses=peerlist)
        message = Message('addr', addrpayload)
        self.SendSerializedMessage(message)
예제 #19
0
    def Relay(self, inventory):
        """
        Wrap the inventory in a InvPayload object and send it over the write to the remote node.

        Args:
            inventory:

        Returns:
            bool: True (fixed)
        """
        inventory = InvPayload(type=inventory.InventoryType, hashes=[inventory.Hash.ToBytes()])
        m = Message("inv", inventory)
        self.SendSerializedMessage(m)

        return True
예제 #20
0
    def CheckMessageData(self):
        if not self.pm: return

        currentlength = len(self.buffer_in)
        messageExpectedLength = 24 + self.pm.Length
        #        percentcomplete = int(100 * (currentlength / messageExpectedLength))
        #        self.Log("Receiving %s data: %s percent complete" % (self.pm.Command, percentcomplete))

        if currentlength >= messageExpectedLength:
            mdata = self.buffer_in[:messageExpectedLength]
            stream = StreamManager.GetStream(mdata)
            reader = BinaryReader(stream)
            message = Message()
            message.Deserialize(reader)
            StreamManager.ReleaseStream(stream)
            self.buffer_in = self.buffer_in[messageExpectedLength:]
            self.pm = None
            self.MessageReceived(message)
            self.reset_counter = False
            while len(self.buffer_in) > 24 and not self.reset_counter:
                self.CheckDataReceived()

        else:
            self.reset_counter = True
예제 #21
0
    def DoAskForMoreBlocks(self):
        hashes = []
        hashstart = BC.Default().Height + 1
        current_header_height = BC.Default().HeaderHeight + 1

        do_go_ahead = False
        if BC.Default().BlockSearchTries > 100 and len(
                BC.Default().BlockRequests) > 0:
            do_go_ahead = True

        first = None
        while hashstart <= current_header_height and len(
                hashes) < self.leader.BREQPART:
            hash = BC.Default().GetHeaderHash(hashstart)
            if not do_go_ahead:
                if hash is not None and hash not in BC.Default().BlockRequests \
                        and hash not in self.myblockrequests:

                    if not first:
                        first = hashstart
                    BC.Default().BlockRequests.add(hash)
                    self.myblockrequests.add(hash)
                    hashes.append(hash)
            else:
                if hash is not None:
                    if not first:
                        first = hashstart
                    BC.Default().BlockRequests.add(hash)
                    self.myblockrequests.add(hash)
                    hashes.append(hash)

            hashstart += 1

        if len(hashes) > 0:
            logger.debug(
                f"{self.prefix} asking for more blocks {first} - {hashstart} ({len(hashes)}) stale count: {BC.Default().BlockSearchTries} "
                f"BCRLen: {len(BC.Default().BlockRequests)}")
            self.health_check(HEARTBEAT_BLOCKS)
            message = Message("getdata", InvPayload(InventoryType.Block,
                                                    hashes))
            self.SendSerializedMessage(message)
예제 #22
0
    def test_message_serialization(self):

        message = Message('version', payload=self.payload)

        self.assertEqual(message.Command, 'version')

        ms = StreamManager.GetStream()
        writer = BinaryWriter(ms)

        message.Serialize(writer)


        result = binascii.unhexlify( ms.ToArray())
        StreamManager.ReleaseStream(ms)



        ms = StreamManager.GetStream(result)
        reader = BinaryReader(ms)

        deserialized_message = Message()
        deserialized_message.Deserialize( reader )

        StreamManager.ReleaseStream(ms)

        dm = deserialized_message

        self.assertEqual(dm.Command, 'version')

        self.assertEqual(dm.Magic, Settings.MAGIC)

        checksum = Message.GetChecksum(dm.Payload)

        self.assertEqual(checksum, dm.Checksum)


        deserialized_version = IOHelper.AsSerializableWithType(dm.Payload, 'neo.Network.Payloads.VersionPayload.VersionPayload')


        self.assertEqual(deserialized_version.Port, self.port)
        self.assertEqual(deserialized_version.UserAgent, self.ua)

        self.assertEqual(deserialized_version.Timestamp, self.payload.Timestamp)
예제 #23
0
    def AskForMoreBlocks(self):

        hashes = []
        hashstart = BC.Default().Height + 1


        self.Log("asking for more blocks ... %s " % hashstart)

        while hashstart < BC.Default().HeaderHeight and len(hashes) < self.leader.BREQPART:
            hash = BC.Default().GetHeaderHash(hashstart)
            if not hash in BC.Default().BlockRequests and not hash in self.myblockrequests:
                BC.Default().BlockRequests.add(hash)
                self.myblockrequests.add(hash)
                hashes.append(hash)
            hashstart += 1

        if len(hashes) > 0:
            message = Message("getdata", InvPayload(InventoryType.Block, hashes))
            self.SendSerializedMessage(message)
        else:
            reactor.callLater(5, self.AskForMoreBlocks)
예제 #24
0
    def CheckDataReceived(self):
        """Tries to extract a Message from the data buffer and process it."""
        currentLength = len(self.buffer_in)
        if currentLength < 24:
            return

        # Extract the message header from the buffer, and return if not enough
        # buffer to fully deserialize the message object.
        try:
            # Construct message
            mstart = self.buffer_in[:24]
            ms = StreamManager.GetStream(mstart)
            reader = BinaryReader(ms)
            m = Message()

            # Extract message metadata
            m.Magic = reader.ReadUInt32()
            m.Command = reader.ReadFixedString(12).decode('utf-8')
            m.Length = reader.ReadUInt32()
            m.Checksum = reader.ReadUInt32()

            # Return if not enough buffer to fully deserialize object.
            messageExpectedLength = 24 + m.Length
            # percentcomplete = int(100 * (currentLength / messageExpectedLength))
            # self.Log("Receiving %s data: %s percent complete" % (m.Command, percentcomplete))
            if currentLength < messageExpectedLength:
                return

        except Exception as e:
            self.Log('Error: Could not read initial bytes %s ' % e)
            return

        finally:
            StreamManager.ReleaseStream(ms)
            del reader

        # The message header was successfully extracted, and we have enough enough buffer
        # to extract the full payload
        try:
            # Extract message bytes from buffer and truncate buffer
            mdata = self.buffer_in[:messageExpectedLength]
            self.buffer_in = self.buffer_in[messageExpectedLength:]

            # Deserialize message with payload
            stream = StreamManager.GetStream(mdata)
            reader = BinaryReader(stream)
            message = Message()
            message.Deserialize(reader)

            # Propagate new message
            self.MessageReceived(message)

        except Exception as e:
            self.Log('Error: Could not extract message: %s ' % e)
            return

        finally:
            StreamManager.ReleaseStream(stream)

        # Finally, after a message has been fully deserialized and propagated,
        # check if another message can be extracted with the current buffer:
        if len(self.buffer_in) >= 24:
            self.CheckDataReceived()
예제 #25
0
    def CheckDataReceived(self):
        """Tries to extract a Message from the data buffer and process it."""
        currentLength = len(self.buffer_in)
        if currentLength < 24:
            return

        # Extract the message header from the buffer, and return if not enough
        # buffer to fully deserialize the message object.
        try:
            # Construct message
            mstart = self.buffer_in[:24]
            ms = StreamManager.GetStream(mstart)
            reader = BinaryReader(ms)
            m = Message()

            # Extract message metadata
            m.Magic = reader.ReadUInt32()
            m.Command = reader.ReadFixedString(12).decode('utf-8')
            m.Length = reader.ReadUInt32()
            m.Checksum = reader.ReadUInt32()

            # Return if not enough buffer to fully deserialize object.
            messageExpectedLength = 24 + m.Length
            if currentLength < messageExpectedLength:
                return

        except Exception as e:
            self.Log('Error: Could not read initial bytes %s ' % e)
            return

        finally:
            StreamManager.ReleaseStream(ms)
            del reader

        # The message header was successfully extracted, and we have enough enough buffer
        # to extract the full payload
        try:
            # Extract message bytes from buffer and truncate buffer
            mdata = self.buffer_in[:messageExpectedLength]
            self.buffer_in = self.buffer_in[messageExpectedLength:]

            # Deserialize message with payload
            stream = StreamManager.GetStream(mdata)
            reader = BinaryReader(stream)
            message = Message()
            message.Deserialize(reader)

            # Propagate new message
            self.MessageReceived(message)

        except Exception as e:
            self.Log('Error: Could not extract message: %s ' % e)
            return

        finally:
            StreamManager.ReleaseStream(stream)

        # Finally, after a message has been fully deserialized and propagated,
        # check if another message can be extracted with the current buffer:
        if len(self.buffer_in) >= 24:
            self.CheckDataReceived()
 def RequestVersion(self):
     """Request the remote client version."""
     # self.Log("All caught up, requesting version")
     m = Message("getversion")
     self.SendSerializedMessage(m)
예제 #27
0
 def HandleVerack(self):
     """Handle the `verack` response."""
     m = Message('verack')
     self.SendSerializedMessage(m)
     self.ProtocolReady()
예제 #28
0
 def RequestVersion(self):
     """Request the remote client version."""
     m = Message("getversion")
     self.SendSerializedMessage(m)
예제 #29
0
 def RequestPeerInfo(self):
     """Request the peer address information from the remote client."""
     self.SendSerializedMessage(Message('getaddr'))
예제 #30
0
 def DoAskForSingleBlock(self, block_hash):
     if block_hash not in self.myblockrequests:
         message = Message("getdata", InvPayload(InventoryType.Block, [block_hash]))
         self.myblockrequests.add(block_hash)
         self.SendSerializedMessage(message)
예제 #31
0
 def AskForMoreHeaders(self):
     # self.Log("asking for more headers...")
     get_headers_message = Message("getheaders", GetBlocksPayload(hash_start=[BC.Default().CurrentHeaderHash]))
     self.SendSerializedMessage(get_headers_message)