Esempio n. 1
0
 def test_create_from_json(self):
     p1 = PeerId()
     data1 = p1.to_json(include_private_key=True)
     p2 = PeerId.create_from_json(data1)
     data2 = p2.to_json(include_private_key=True)
     self.assertEqual(data1, data2)
     p2.validate()
Esempio n. 2
0
 def test_create_from_json_without_private_key(self):
     p1 = PeerId()
     data1 = p1.to_json()
     # Just to test a part of the code
     del data1['entrypoints']
     p2 = PeerId.create_from_json(data1)
     data2 = p2.to_json()
     self.assertEqual(data2['entrypoints'], [])
     data1['entrypoints'] = []
     self.assertEqual(data1, data2)
     p2.validate()
Esempio n. 3
0
 def handle_peers(self, payload: str) -> None:
     """ Executed when a PEERS command is received. It updates the list
     of known peers (and tries to connect to new ones).
     """
     received_peers = json.loads(payload)
     for data in received_peers:
         peer = PeerId.create_from_json(data)
         peer.validate()
         if self.protocol.connections:
             self.protocol.connections.on_receive_peer(peer, origin=self)
     remote = self.protocol.transport.getPeer()
     self.log.debug('received peers', remote=remote, payload=payload)
Esempio n. 4
0
    def handle_peer_id(self, payload: str) -> Generator[Any, Any, None]:
        """ Executed when a PEER-ID is received. It basically checks
        the identity of the peer. Only after this step, the peer connection
        is considered established and ready to communicate.
        """
        protocol = self.protocol
        data = json.loads(payload)

        peer = PeerId.create_from_json(data)
        peer.validate()
        assert peer.id is not None

        # If the connection URL had a peer-id parameter we need to check it's the same
        if protocol.expected_peer_id and peer.id != protocol.expected_peer_id:
            protocol.send_error_and_close_connection(
                'Peer id different from the requested one.')
            return

        # is it on the whitelist?
        if settings.ENABLE_PEER_WHITELIST and peer.id not in protocol.node.peers_whitelist:
            protocol.send_error_and_close_connection(
                'Blocked. Get in touch with Hathor team.')
            return

        if peer.id == protocol.my_peer.id:
            protocol.send_error_and_close_connection('Are you my clone?!')
            return

        if protocol.connections:
            if protocol.connections.is_peer_connected(peer.id):
                protocol.send_error_and_close_connection(
                    'We are already connected.')
                return

        entrypoint_valid = yield peer.validate_entrypoint(protocol)
        if not entrypoint_valid:
            protocol.send_error_and_close_connection(
                'Connection string is not in the entrypoints.')
            return

        if protocol.use_ssl:
            certificate_valid = peer.validate_certificate(protocol)
            if not certificate_valid:
                protocol.send_error_and_close_connection(
                    'Public keys from peer and certificate are not the same.')
                return

        # If it gets here, the peer is validated, and we are ready to start communicating.
        protocol.peer = peer

        self.send_ready()
Esempio n. 5
0
    def prepare(self, args: Namespace) -> None:
        import hathor
        from hathor.conf import HathorSettings
        from hathor.manager import HathorManager, TestMode
        from hathor.p2p.peer_discovery import BootstrapPeerDiscovery, DNSPeerDiscovery
        from hathor.p2p.peer_id import PeerId
        from hathor.p2p.utils import discover_hostname
        from hathor.transaction import genesis
        from hathor.transaction.storage import (
            TransactionStorage,
            TransactionCacheStorage,
            TransactionCompactStorage,
            TransactionMemoryStorage,
        )
        from hathor.wallet import HDWallet, Wallet

        settings = HathorSettings()

        if args.recursion_limit:
            sys.setrecursionlimit(args.recursion_limit)

        if not args.peer:
            peer_id = PeerId()
        else:
            data = json.load(open(args.peer, 'r'))
            peer_id = PeerId.create_from_json(data)

        print('Hathor v{} (genesis {})'.format(hathor.__version__,
                                               genesis.GENESIS_HASH.hex()[:7]))
        print('My peer id is', peer_id.id)

        def create_wallet():
            if args.wallet == 'hd':
                print('Using HDWallet')
                kwargs = {
                    'words': args.words,
                }

                if args.passphrase:
                    wallet_passphrase = getpass.getpass(
                        prompt='HD Wallet passphrase:')
                    kwargs['passphrase'] = wallet_passphrase.encode()

                if args.data:
                    kwargs['directory'] = args.data

                return HDWallet(**kwargs)
            elif args.wallet == 'keypair':
                print('Using KeyPairWallet')
                if args.data:
                    wallet = Wallet(directory=args.data)
                else:
                    wallet = Wallet()

                wallet.flush_to_disk_interval = 5  # seconds

                if args.unlock_wallet:
                    wallet_passwd = getpass.getpass(prompt='Wallet password:'******'Invalid type for wallet')

        tx_storage: TransactionStorage
        if args.data:
            wallet_dir = args.data
            print('Using Wallet at {}'.format(wallet_dir))
            if args.rocksdb_storage:
                from hathor.transaction.storage import TransactionRocksDBStorage
                tx_dir = os.path.join(args.data, 'tx.db')
                tx_storage = TransactionRocksDBStorage(
                    path=tx_dir, with_index=(not args.cache))
                print('Using TransactionRocksDBStorage at {}'.format(tx_dir))
            else:
                tx_dir = os.path.join(args.data, 'tx')
                tx_storage = TransactionCompactStorage(
                    path=tx_dir, with_index=(not args.cache))
                print('Using TransactionCompactStorage at {}'.format(tx_dir))
            if args.cache:
                tx_storage = TransactionCacheStorage(tx_storage, reactor)
                if args.cache_size:
                    tx_storage.capacity = args.cache_size
                if args.cache_interval:
                    tx_storage.interval = args.cache_interval
                print(
                    'Using TransactionCacheStorage, capacity {}, interval {}s'.
                    format(tx_storage.capacity, tx_storage.interval))
                tx_storage.start()
        else:
            # if using MemoryStorage, no need to have cache
            tx_storage = TransactionMemoryStorage()
            print('Using TransactionMemoryStorage')
        self.tx_storage = tx_storage

        if args.wallet:
            self.wallet = create_wallet()
        else:
            self.wallet = None

        if args.hostname and args.auto_hostname:
            print('You cannot use --hostname and --auto-hostname together.')
            sys.exit(-1)

        if not args.auto_hostname:
            hostname = args.hostname
        else:
            print('Trying to discover your hostname...')
            hostname = discover_hostname()
            if not hostname:
                print('Aborting because we could not discover your hostname.')
                print('Try again or run without --auto-hostname.')
                sys.exit(-1)
            print('Hostname discovered and set to {}'.format(hostname))

        network = settings.NETWORK_NAME
        self.manager = HathorManager(reactor,
                                     peer_id=peer_id,
                                     network=network,
                                     hostname=hostname,
                                     tx_storage=self.tx_storage,
                                     wallet=self.wallet,
                                     wallet_index=args.wallet_index,
                                     stratum_port=args.stratum,
                                     min_block_weight=args.min_block_weight,
                                     ssl=True)
        if args.allow_mining_without_peers:
            self.manager.allow_mining_without_peers()

        dns_hosts = []
        if settings.BOOTSTRAP_DNS:
            dns_hosts.extend(settings.BOOTSTRAP_DNS)

        if args.dns:
            dns_hosts.extend(args.dns)

        if dns_hosts:
            self.manager.add_peer_discovery(DNSPeerDiscovery(dns_hosts))

        if args.bootstrap:
            self.manager.add_peer_discovery(
                BootstrapPeerDiscovery(args.bootstrap))

        if args.test_mode_tx_weight:
            self.manager.test_mode = TestMode.TEST_TX_WEIGHT
            if self.wallet:
                self.wallet.test_mode = True

        for description in args.listen:
            self.manager.add_listen_address(description)

        self.start_manager()
        self.register_resources(args)
Esempio n. 6
0
    def prepare(self, args: Namespace) -> None:
        import hathor
        from hathor.cli.util import check_or_exit
        from hathor.conf import HathorSettings
        from hathor.conf.get_settings import get_settings_module
        from hathor.daa import TestMode, _set_test_mode
        from hathor.manager import HathorManager
        from hathor.p2p.peer_discovery import BootstrapPeerDiscovery, DNSPeerDiscovery
        from hathor.p2p.peer_id import PeerId
        from hathor.p2p.utils import discover_hostname
        from hathor.transaction import genesis
        from hathor.transaction.storage import (
            TransactionCacheStorage,
            TransactionCompactStorage,
            TransactionMemoryStorage,
            TransactionRocksDBStorage,
            TransactionStorage,
        )
        from hathor.wallet import HDWallet, Wallet

        settings = HathorSettings()
        settings_module = get_settings_module()  # only used for logging its location
        self.log = logger.new()

        from setproctitle import setproctitle
        setproctitle('{}hathor-core'.format(args.procname_prefix))

        if args.recursion_limit:
            sys.setrecursionlimit(args.recursion_limit)
        else:
            sys.setrecursionlimit(5000)

        try:
            import resource
        except ModuleNotFoundError:
            pass
        else:
            (nofile_soft, _) = resource.getrlimit(resource.RLIMIT_NOFILE)
            if nofile_soft < 256:
                print('Maximum number of open file descriptors is too low. Minimum required is 256.')
                sys.exit(-2)

        if not args.peer:
            peer_id = PeerId()
        else:
            data = json.load(open(args.peer, 'r'))
            peer_id = PeerId.create_from_json(data)

        python = f'{platform.python_version()}-{platform.python_implementation()}'

        self.check_unsafe_arguments(args)

        self.log.info(
            'hathor-core v{hathor}',
            hathor=hathor.__version__,
            pid=os.getpid(),
            genesis=genesis.GENESIS_HASH.hex()[:7],
            my_peer_id=str(peer_id.id),
            python=python,
            platform=platform.platform(),
            settings=settings_module.__file__,
        )

        def create_wallet():
            if args.wallet == 'hd':
                kwargs = {
                    'words': args.words,
                }

                if args.passphrase:
                    wallet_passphrase = getpass.getpass(prompt='HD Wallet passphrase:')
                    kwargs['passphrase'] = wallet_passphrase.encode()

                if args.data:
                    kwargs['directory'] = args.data

                return HDWallet(**kwargs)
            elif args.wallet == 'keypair':
                print('Using KeyPairWallet')
                if args.data:
                    wallet = Wallet(directory=args.data)
                else:
                    wallet = Wallet()

                wallet.flush_to_disk_interval = 5  # seconds

                if args.unlock_wallet:
                    wallet_passwd = getpass.getpass(prompt='Wallet password:'******'Invalid type for wallet')

        tx_storage: TransactionStorage
        if args.memory_storage:
            check_or_exit(not args.data, '--data should not be used with --memory-storage')
            # if using MemoryStorage, no need to have cache
            tx_storage = TransactionMemoryStorage()
            assert not args.x_rocksdb_indexes, 'RocksDB indexes require RocksDB data'
            self.log.info('with storage', storage_class=type(tx_storage).__name__)
        elif args.json_storage:
            check_or_exit(args.data, '--data is expected')
            assert not args.x_rocksdb_indexes, 'RocksDB indexes require RocksDB data'
            tx_storage = TransactionCompactStorage(path=args.data, with_index=(not args.cache))
        else:
            check_or_exit(args.data, '--data is expected')
            if args.rocksdb_storage:
                self.log.warn('--rocksdb-storage is now implied, no need to specify it')
            cache_capacity = args.rocksdb_cache
            use_memory_indexes = not args.x_rocksdb_indexes
            tx_storage = TransactionRocksDBStorage(path=args.data, with_index=(not args.cache),
                                                   cache_capacity=cache_capacity,
                                                   use_memory_indexes=use_memory_indexes)
        self.log.info('with storage', storage_class=type(tx_storage).__name__, path=args.data)
        if args.cache:
            check_or_exit(not args.memory_storage, '--cache should not be used with --memory-storage')
            tx_storage = TransactionCacheStorage(tx_storage, reactor)
            if args.cache_size:
                tx_storage.capacity = args.cache_size
            if args.cache_interval:
                tx_storage.interval = args.cache_interval
            self.log.info('with cache', capacity=tx_storage.capacity, interval=tx_storage.interval)
        self.tx_storage = tx_storage
        self.log.info('with indexes', indexes_class=type(tx_storage.indexes).__name__)

        if args.wallet:
            self.wallet = create_wallet()
            self.log.info('with wallet', wallet=self.wallet, path=args.data)
        else:
            self.wallet = None

        if args.hostname and args.auto_hostname:
            print('You cannot use --hostname and --auto-hostname together.')
            sys.exit(-1)

        if not args.auto_hostname:
            hostname = args.hostname
        else:
            print('Trying to discover your hostname...')
            hostname = discover_hostname()
            if not hostname:
                print('Aborting because we could not discover your hostname.')
                print('Try again or run without --auto-hostname.')
                sys.exit(-1)
            print('Hostname discovered and set to {}'.format(hostname))

        network = settings.NETWORK_NAME
        enable_sync_v1 = not args.x_sync_v2_only
        enable_sync_v2 = args.x_sync_v2_only or args.x_sync_bridge

        self.manager = HathorManager(
            reactor,
            peer_id=peer_id,
            network=network,
            hostname=hostname,
            tx_storage=self.tx_storage,
            wallet=self.wallet,
            wallet_index=args.wallet_index,
            stratum_port=args.stratum,
            ssl=True,
            checkpoints=settings.CHECKPOINTS,
            enable_sync_v1=enable_sync_v1,
            enable_sync_v2=enable_sync_v2,
            soft_voided_tx_ids=set(settings.SOFT_VOIDED_TX_IDS),
        )
        if args.allow_mining_without_peers:
            self.manager.allow_mining_without_peers()

        if args.x_localhost_only:
            self.manager.connections.localhost_only = True

        dns_hosts = []
        if settings.BOOTSTRAP_DNS:
            dns_hosts.extend(settings.BOOTSTRAP_DNS)

        if args.dns:
            dns_hosts.extend(args.dns)

        if dns_hosts:
            self.manager.add_peer_discovery(DNSPeerDiscovery(dns_hosts))

        if args.bootstrap:
            self.manager.add_peer_discovery(BootstrapPeerDiscovery(args.bootstrap))

        if args.test_mode_tx_weight:
            _set_test_mode(TestMode.TEST_TX_WEIGHT)
            if self.wallet:
                self.wallet.test_mode = True

        if args.x_full_verification:
            self.manager._full_verification = True
        if args.x_fast_init_beta:
            self.log.warn('--x-fast-init-beta is now the default, no need to specify it')

        for description in args.listen:
            self.manager.add_listen_address(description)

        self.start_manager(args)
        self.register_resources(args)
Esempio n. 7
0
def _load_peer_id_pool(
        file_path: str = 'tests/peer_id_pool.json') -> Iterator[PeerId]:
    with open(file_path) as peer_id_pool_file:
        peer_id_pool_dict = json.load(peer_id_pool_file)
        for peer_id_dict in peer_id_pool_dict:
            yield PeerId.create_from_json(peer_id_dict)
Esempio n. 8
0
    def handle_peer_id(self, payload: str) -> Generator[Any, Any, None]:
        """ Executed when a PEER-ID is received. It basically checks
        the identity of the peer. Only after this step, the peer connection
        is considered established and ready to communicate.
        """
        protocol = self.protocol
        data = json.loads(payload)

        peer = PeerId.create_from_json(data)
        peer.validate()
        assert peer.id is not None

        # If the connection URL had a peer-id parameter we need to check it's the same
        if protocol.expected_peer_id and peer.id != protocol.expected_peer_id:
            protocol.send_error_and_close_connection(
                'Peer id different from the requested one.')
            return

        # is it on the whitelist?
        if peer.id and self._should_block_peer(peer.id):
            if settings.WHITELIST_WARN_BLOCKED_PEERS:
                protocol.send_error_and_close_connection(
                    f'Blocked (by {peer.id}). Get in touch with Hathor team.')
            else:
                protocol.send_error_and_close_connection(
                    'Connection rejected.')
            return

        if peer.id == protocol.my_peer.id:
            protocol.send_error_and_close_connection('Are you my clone?!')
            return

        if protocol.connections is not None:
            if protocol.connections.is_peer_connected(peer.id):
                protocol.send_error_and_close_connection(
                    'We are already connected.')
                return

        entrypoint_valid = yield peer.validate_entrypoint(protocol)
        if not entrypoint_valid:
            protocol.send_error_and_close_connection(
                'Connection string is not in the entrypoints.')
            return

        if protocol.use_ssl:
            certificate_valid = peer.validate_certificate(protocol)
            if not certificate_valid:
                protocol.send_error_and_close_connection(
                    'Public keys from peer and certificate are not the same.')
                return

        # If it gets here, the peer is validated, and we are ready to start communicating.
        protocol.peer = peer

        from hathor.p2p.netfilter import get_table
        from hathor.p2p.netfilter.context import NetfilterContext
        context = NetfilterContext(
            protocol=self.protocol,
            connections=self.protocol.connections,
            addr=self.protocol.transport.getPeer(),
        )
        verdict = get_table('filter').get_chain('post_peerid').process(context)
        if not bool(verdict):
            self.protocol.disconnect(
                'rejected by netfilter: filter post_peerid', force=True)
            return

        self.send_ready()