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
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
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()
def __init__(self): """Initialise the blockchain manager.""" self.bcs = BlockChainStore(data_dir) self.client = None