Пример #1
0
def test_callback():
    R = []

    def the_callback(blockchain, ops):
        R.extend(ops)

    parent_for_0 = b'\0' * 32
    # same as test_fork, above

    BC = BlockChain(parent_for_0)
    BC.add_change_callback(the_callback)

    ITEMS = dict((i, FakeBlock(i)) for i in range(7))
    ITEMS[0] = FakeBlock(0, parent_for_0)

    ITEMS.update(dict((i, FakeBlock(i)) for i in range(301, 306)))
    ITEMS[301] = FakeBlock(301, 3)

    # send them all except 302
    BC.add_headers((ITEMS[i] for i in ITEMS.keys() if i != 302))

    # now send 302
    BC.add_headers([ITEMS[302]])

    expected = [("add", ITEMS[i], i) for i in range(7)]
    expected += [("remove", ITEMS[i], i) for i in range(6, 3, -1)]
    expected += [("add", ITEMS[i], i+4-301) for i in range(301, 306)]

    assert R == expected
Пример #2
0
def test_callback():
    R = []

    def the_callback(blockchain, ops):
        R.extend(ops)

    parent_for_0 = b'\0' * 32
    # same as test_fork, above

    BC = BlockChain(parent_for_0)
    BC.add_change_callback(the_callback)

    ITEMS = dict((i, FakeBlock(i)) for i in range(7))
    ITEMS[0] = FakeBlock(0, parent_for_0)

    ITEMS.update(dict((i, FakeBlock(i)) for i in range(301, 306)))
    ITEMS[301] = FakeBlock(301, 3)

    # send them all except 302
    BC.add_headers((ITEMS[i] for i in ITEMS.keys() if i != 302))

    # now send 302
    BC.add_headers([ITEMS[302]])

    expected = [("add", ITEMS[i], i) for i in range(7)]
    expected += [("remove", ITEMS[i], i) for i in range(6, 3, -1)]
    expected += [("add", ITEMS[i], i + 4 - 301) for i in range(301, 306)]

    assert R == expected
Пример #3
0
def locked_blocks_iterator(blockfile,
                           start_info=(0, 0),
                           cached_headers=50,
                           batch_size=50):
    """
    This method loads blocks from disk, skipping any orphan blocks.
    """
    f = blockfile
    current_state = []

    def change_state(bc, ops):
        for op, bh, work in ops:
            if op == 'add':
                current_state.append(bh)
                pass
            else:
                current_state.pop()

    bc = BlockChain()
    bc.add_change_callback(change_state)
    bhs = []
    index = 0
    info_offset = start_info
    while 1:
        v = blockfile.next_offset(info_offset)
        if v is None:
            break
        block_offset, info_offset = v
        f.jump_to(block_offset)
        bh = Block.parse_as_header(f)
        bh.info = block_offset

        bhs.append(bh)
        if len(bhs) > batch_size:
            bc.add_headers(bhs)
            bhs = []
            if len(current_state) > cached_headers:
                for bh in current_state[:cached_headers]:
                    bh.index = index
                    yield bh
                    index += 1
                    bc.lock_to_index(index)
                current_state = current_state[cached_headers:]
Пример #4
0
def locked_blocks_iterator(start_info=(0, 0),
                           cached_headers=50,
                           batch_size=50,
                           base_dir=None,
                           headers_only=False):
    """
    This method loads blocks from disk, skipping any orphan blocks.
    """
    block_class = BlockHeader if headers_only else Block
    f = Blockfiles(base_dir, start_info)
    for initial_location in block_info_iterator(start_info, base_dir):
        f.jump_to(initial_location)
        initial_header = BlockHeader.parse(f)
        break
    current_state = []

    def change_state(bc, ops):
        for op, bh, work in ops:
            if op == 'add':
                current_state.append(bh)
                pass
            else:
                current_state.pop()

    bc = BlockChain()
    bc.add_change_callback(change_state)
    bhs = []
    index = 0
    for info in block_info_iterator(start_info, base_dir):
        bh = blockheader_for_offset_info(info, base_dir)
        bh.info = info
        bhs.append(bh)
        if len(bhs) > batch_size:
            bc.add_headers(bhs)
            bhs = []
            if len(current_state) > cached_headers:
                for bh in current_state[:cached_headers]:
                    f.jump_to(bh.info)
                    block = block_class.parse(f)
                    yield block
                    index += 1
                    bc.lock_to_index(index)
                current_state = current_state[cached_headers:]
Пример #5
0
def locked_blocks_iterator(start_info=(0, 0), cached_headers=50, batch_size=50, base_dir=None,
                           headers_only=False):
    """
    This method loads blocks from disk, skipping any orphan blocks.
    """
    parse_method = Block.parse_as_header if headers_only else Block.parse
    f = Blockfiles(base_dir, start_info)
    for initial_location in block_info_iterator(start_info, base_dir):
        f.jump_to(initial_location)
        parse_method(f)
        break
    current_state = []

    def change_state(bc, ops):
        for op, bh, work in ops:
            if op == 'add':
                current_state.append(bh)
                pass
            else:
                current_state.pop()
    bc = BlockChain()
    bc.add_change_callback(change_state)
    bhs = []
    index = 0
    for info in block_info_iterator(start_info, base_dir):
        bh = blockheader_for_offset_info(info, base_dir)
        bh.info = info
        bhs.append(bh)
        if len(bhs) > batch_size:
            bc.add_headers(bhs)
            bhs = []
            if len(current_state) > cached_headers:
                for bh in current_state[:cached_headers]:
                    f.jump_to(bh.info)
                    block = parse_method(f)
                    yield block
                    index += 1
                    bc.lock_to_index(index)
                current_state = current_state[cached_headers:]
Пример #6
0
    def __init__(self,
                 network,
                 host_port_q,
                 should_download_block_f,
                 block_chain_store,
                 blockchain_change_callback,
                 server_port=9999):
        """
        network:
            a value from pycoinnet.helpers.networks
        host_port_q:
            a Queue that is being fed potential places to connect
        should_download_block_f:
            a function that accepting(block_hash, block_index) and returning a boolean
            indicating whether that block should be downloaded. Only used during fast-forward.
        block_chain_store:
            usually a BlockChainStore instance
        blockchain_change_callback:
            a callback that expects (blockchain, list_of_ops) that is invoked whenever the
            block chain is updated; blockchain is a BlockChain object and list_of_ops is a pair
            of tuples of the form (op, block_hash, block_index) where op is one of "add" or "remove",
            block_hash is a binary block hash, and block_index is an integer index number.
        """

        block_chain = BlockChain(
            did_lock_to_index_f=block_chain_store.did_lock_to_index)

        block_chain.preload_locked_blocks(block_chain_store.headers())

        block_chain.add_change_callback(block_chain_locker_callback)

        self.blockfetcher = Blockfetcher()
        self.inv_collector = InvCollector()

        self.block_store = TwoLevelDict()

        @asyncio.coroutine
        def _rotate(block_store):
            while True:
                block_store.rotate()
                yield from asyncio.sleep(1800)

        self.rotate_task = asyncio.Task(_rotate(self.block_store))

        self.blockhandler = BlockHandler(
            self.inv_collector,
            block_chain,
            self.block_store,
            should_download_f=should_download_block_f)

        block_chain.add_change_callback(blockchain_change_callback)

        self.fast_forward_add_peer = fast_forwarder_add_peer_f(block_chain)
        self.fetcher_task = asyncio.Task(
            new_block_fetcher(self.inv_collector, block_chain))

        self.nonce = int.from_bytes(os.urandom(8), byteorder="big")
        self.subversion = "/Notoshi/".encode("utf8")

        @asyncio.coroutine
        def run_peer(peer, fetcher, fast_forward_add_peer, blockfetcher,
                     inv_collector, blockhandler):
            yield from asyncio.wait_for(peer.connection_made_future,
                                        timeout=None)
            version_parameters = version_data_for_peer(
                peer,
                local_port=(server_port or 0),
                last_block_index=block_chain.length(),
                nonce=self.nonce,
                subversion=self.subversion)
            version_data = yield from initial_handshake(
                peer, version_parameters)
            last_block_index = version_data["last_block_index"]
            fast_forward_add_peer(peer, last_block_index)
            blockfetcher.add_peer(peer, fetcher, last_block_index)
            inv_collector.add_peer(peer)
            blockhandler.add_peer(peer)

        def create_protocol_callback():
            peer = BitcoinPeerProtocol(network["MAGIC_HEADER"])
            install_pingpong_manager(peer)
            fetcher = Fetcher(peer)
            peer.add_task(
                run_peer(peer, fetcher, self.fast_forward_add_peer,
                         self.blockfetcher, self.inv_collector,
                         self.blockhandler))
            return peer

        self.connection_info_q = manage_connection_count(
            host_port_q, create_protocol_callback, 8)
        self.show_task = asyncio.Task(
            show_connection_info(self.connection_info_q))

        # listener
        @asyncio.coroutine
        def run_listener():
            abstract_server = None
            future_peer = asyncio.Future()
            try:
                abstract_server = yield from asyncio.get_event_loop(
                ).create_server(protocol_factory=create_protocol_callback,
                                port=server_port)
                return abstract_server
            except OSError as ex:
                logging.info("can't listen on port %d", server_port)

        if server_port:
            self.server_task = asyncio.Task(run_listener())
Пример #7
0
    def __init__(self, network, host_port_q, should_download_block_f, block_chain_store,
                 blockchain_change_callback, server_port=9999):
        """
        network:
            a value from pycoinnet.helpers.networks
        host_port_q:
            a Queue that is being fed potential places to connect
        should_download_block_f:
            a function that accepting(block_hash, block_index) and returning a boolean
            indicating whether that block should be downloaded. Only used during fast-forward.
        block_chain_store:
            usually a BlockChainStore instance
        blockchain_change_callback:
            a callback that expects (blockchain, list_of_ops) that is invoked whenever the
            block chain is updated; blockchain is a BlockChain object and list_of_ops is a pair
            of tuples of the form (op, block_hash, block_index) where op is one of "add" or "remove",
            block_hash is a binary block hash, and block_index is an integer index number.
        """

        block_chain = BlockChain(did_lock_to_index_f=block_chain_store.did_lock_to_index)

        block_chain.preload_locked_blocks(block_chain_store.headers())

        block_chain.add_change_callback(block_chain_locker_callback)

        self.blockfetcher = Blockfetcher()
        self.inv_collector = InvCollector()

        self.block_store = TwoLevelDict()

        @asyncio.coroutine
        def _rotate(block_store):
            while True:
                block_store.rotate()
                yield from asyncio.sleep(1800)
        self.rotate_task = asyncio.Task(_rotate(self.block_store))

        self.blockhandler = BlockHandler(self.inv_collector, block_chain, self.block_store,
                                         should_download_f=should_download_block_f)

        block_chain.add_change_callback(blockchain_change_callback)

        self.fast_forward_add_peer = fast_forwarder_add_peer_f(block_chain)
        self.fetcher_task = asyncio.Task(new_block_fetcher(self.inv_collector, block_chain))

        self.nonce = int.from_bytes(os.urandom(8), byteorder="big")
        self.subversion = "/Notoshi/".encode("utf8")

        @asyncio.coroutine
        def run_peer(peer, fetcher, fast_forward_add_peer, blockfetcher, inv_collector, blockhandler):
            yield from asyncio.wait_for(peer.connection_made_future, timeout=None)
            version_parameters = version_data_for_peer(
                peer, local_port=(server_port or 0), last_block_index=block_chain.length(),
                nonce=self.nonce, subversion=self.subversion)
            version_data = yield from initial_handshake(peer, version_parameters)
            last_block_index = version_data["last_block_index"]
            fast_forward_add_peer(peer, last_block_index)
            blockfetcher.add_peer(peer, fetcher, last_block_index)
            inv_collector.add_peer(peer)
            blockhandler.add_peer(peer)

        def create_protocol_callback():
            peer = BitcoinPeerProtocol(network["MAGIC_HEADER"])
            install_pingpong_manager(peer)
            fetcher = Fetcher(peer)
            peer.add_task(run_peer(
                peer, fetcher, self.fast_forward_add_peer,
                self.blockfetcher, self.inv_collector, self.blockhandler))
            return peer

        self.connection_info_q = manage_connection_count(host_port_q, create_protocol_callback, 8)
        self.show_task = asyncio.Task(show_connection_info(self.connection_info_q))

        # listener
        @asyncio.coroutine
        def run_listener():
            abstract_server = None
            try:
                abstract_server = yield from asyncio.get_event_loop().create_server(
                    protocol_factory=create_protocol_callback, port=server_port)
                return abstract_server
            except OSError:
                logging.info("can't listen on port %d", server_port)

        if server_port:
            self.server_task = asyncio.Task(run_listener())