Example #1
0
class BlockchainManager(object):
    """Client to synchronise blockchain headers."""
    def __init__(self):
        """Initialise the blockchain manager."""
        self.bcs = BlockChainStore(data_dir)
        self.client = None

    def _blockchain_change_callback(self, blockchain, ops):
        pass

    def _sync_loop(self, timeout, length_change_callback):
        interval_time = 1
        current_length = 0
        time_elapsed_since_length_change = 0
        while True:
            new_length = self.blockchain().length()
            if current_length == new_length:
                time_elapsed_since_length_change += interval_time
                if time_elapsed_since_length_change > timeout:
                    self.event_loop.stop()
                    break
            else:
                time_elapsed_since_length_change = 0
                current_length = new_length
                if length_change_callback:
                    length_change_callback(current_length)

            time.sleep(interval_time)

    def sync(self, timeout, length_change_callback=None):
        """
        Synchronise the blockchain to the latest headers.

        Args:
            timeout: the timeout to stop after not receiving any new blocks.
            length_change_callback: a function to call with arg (length) when the blockchain length changes.
        """
        self.client = Client(
            network=MAINNET,
            host_port_q=dns_bootstrap_host_port_q(MAINNET),
            should_download_block_f=should_download_block_false,
            block_chain_store=self.bcs,
            blockchain_change_callback=self._blockchain_change_callback,
        )

        self.event_loop = asyncio.get_event_loop()
        t = threading.Thread(target=self._sync_loop,
                             args=(timeout, length_change_callback))
        t.start()
        self.event_loop.run_forever()

    def blockchain(self):
        """Returns the current Blockchain object."""
        if self.client:
            return self.client.blockhandler.block_chain
        else:
            blockchain = BlockChain(
                did_lock_to_index_f=self.bcs.did_lock_to_index)
            blockchain.preload_locked_blocks(self.bcs.headers())
            return blockchain
def test_BlockChainStore():
    with TemporaryDirectory() as the_dir:
        db = BlockChainStore(dir_path=the_dir, parent_to_0=h_f(-1))
        check_prepopulate(db)
        check_postpopulate(db)

        db1 = BlockChainStore(dir_path=the_dir, parent_to_0=h_f(-1))
        check_postpopulate(db1)

        BHOS1 = [FakeHeader(h_f(i), h_f(i-1)) for i in range(10000,10050)]

        db2 = BlockChainStore(dir_path=the_dir, parent_to_0=h_f(-1))
        check_postpopulate(db2)
        db2.did_lock_to_index(BHOS1, len(BHOS))
        assert list(db2.headers()) == BHOS + BHOS1

        db3 = BlockChainStore(dir_path=the_dir, parent_to_0=h_f(-1))
        assert list(db3.headers()) == BHOS + BHOS1
Example #3
0
def main():
    parser = argparse.ArgumentParser(description="Watch Bitcoin network for new blocks.")
    parser.add_argument('-s', "--state-dir", help='The directory where state files are stored.')
    parser.add_argument(
        '-f', "--fast-forward", type=int,
        help="block index to fast-forward to (ie. don't download full blocks prior to this one)", default=0
    )
    parser.add_argument(
        '-d', "--depth", type=int,
        help="Minimum depth blocks must be buried before being dropped in blockdir", default=1
    )
    parser.add_argument('-l', "--log-file", help="Path to log file", default=None)
    parser.add_argument("blockdir", help='The directory where new blocks are dropped.')

    args = parser.parse_args()

    asyncio.tasks._DEBUG = True
    logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT)
    logging.getLogger("asyncio").setLevel(logging.INFO)

    if args.log_file:
        log_file(args.log_file)

    state_dir = args.state_dir
    block_chain_store = BlockChainStore(state_dir)

    network = MAINNET

    if 1:
        host_port_q = dns_bootstrap_host_port_q(network)
    else:
        host_port_q = asyncio.Queue()
        host_port_q.put_nowait(("127.0.0.1", 8333))

    should_download_block_f = lambda block_hash, block_index: block_index >= args.fast_forward

    last_processed_block = max(get_last_processed_block(state_dir), args.fast_forward)
    update_last_processed_block(state_dir, last_processed_block)

    change_q = asyncio.Queue()
    from pycoin.blockchain.BlockChain import _update_q

    def do_update(blockchain, ops):
        _update_q(change_q, [list(o) for o in ops])

    client = Client(
        network, host_port_q, should_download_block_f, block_chain_store, do_update)

    blockfetcher = client.blockfetcher

    block_processor_task = asyncio.Task(
        block_processor(
            change_q, blockfetcher, state_dir, args.blockdir, args.depth))

    asyncio.get_event_loop().run_forever()
def test_BlockChainStore():
    with TemporaryDirectory() as the_dir:
        db = BlockChainStore(dir_path=the_dir, parent_to_0=h_f(-1))
        check_prepopulate(db)
        check_postpopulate(db)

        db1 = BlockChainStore(dir_path=the_dir, parent_to_0=h_f(-1))
        check_postpopulate(db1)

        BHOS1 = [(h_f(i), h_f(i-1), 1) for i in range(10000,10050)]

        db2 = BlockChainStore(dir_path=the_dir, parent_to_0=h_f(-1))
        check_postpopulate(db2)
        db2.did_lock_to_index(BHOS1, len(BHOS))
        assert list(db2.block_tuple_iterator()) == BHOS + BHOS1

        db3 = BlockChainStore(dir_path=the_dir, parent_to_0=h_f(-1))
        assert list(db3.block_tuple_iterator()) == BHOS + BHOS1
Example #5
0
def main():
    parser = argparse.ArgumentParser(description="Watch Bitcoin network for new blocks.")
    parser.add_argument('-c', "--config-dir", help='The directory where config files are stored.')
    parser.add_argument(
        '-f', "--fast-forward", type=int,
        help="block index to fast-forward to (ie. don't download full blocks prior to this one)", default=0
    )
    parser.add_argument(
        '-d', "--depth", type=int,
        help="Minimum depth blocks must be buried before being dropped in blockdir", default=2
    )
    parser.add_argument( '-l', "--log-file", help="Path to log file", default=None)
    parser.add_argument("blockdir", help='The directory where new blocks are dropped.')

    asyncio.tasks._DEBUG = True
    logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT)
    logging.getLogger("asyncio").setLevel(logging.INFO)

    if 1:
        host_port_q = dns_bootstrap_host_port_q(MAINNET)
    else:
        host_port_q = asyncio.Queue()
        host_port_q.put_nowait(("127.0.0.1", 8333))

    args = parser.parse_args()

    if args.log_file:
        log_file(args.log_file)

    block_chain_store = BlockChainStore(args.config_dir)
    block_chain = BlockChain(did_lock_to_index_f=block_chain_store.did_lock_to_index)

    locker_task = block_chain_locker(block_chain)
    block_chain.add_nodes(block_chain_store.block_tuple_iterator())

    blockfetcher = Blockfetcher()
    inv_collector = InvCollector()

    block_store = TwoLevelDict()

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

    blockhandler = BlockHandler(inv_collector, block_chain, block_store,
        should_download_f=lambda block_hash, block_index: block_index >= args.fast_forward)

    last_processed_block = max(get_last_processed_block(config_dir), args.fast_forward)
    update_last_processed_block(config_dir, last_processed_block)

    change_q = asyncio.Queue()
    from pycoinnet.util.BlockChain import _update_q
    block_chain.add_change_callback(lambda blockchain, ops: _update_q(change_q, ops))

    block_processor_task = asyncio.Task(
        block_processor(
            change_q, blockfetcher, args.config_dir, args.blockdir, args.depth)))

    fast_forward_add_peer = fast_forwarder_add_peer_f(block_chain)

    fetcher_task = asyncio.Task(new_block_fetcher(inv_collector, block_chain))

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

    connection_info_q = manage_connection_count(host_port_q, create_protocol_callback, 8)
    show_task = asyncio.Task(show_connection_info(connection_info_q))
    asyncio.get_event_loop().run_forever()
Example #6
0
 def __init__(self):
     """Initialise the blockchain manager."""
     self.bcs = BlockChainStore(data_dir)
     self.client = None