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, (i, i-1, 1)) for i in range(7)) ITEMS[0] = (0, parent_for_0, 1) ITEMS.update(dict((i, (i, i-1, 1)) for i in range(301, 306))) ITEMS[301] = (301, 3, 1) # send them all except 302 ops = BC.add_nodes((ITEMS[i] for i in ITEMS.keys() if i != 302)) # now send 302 ops = BC.add_nodes([ITEMS[302]]) expected = [("add", i, i) for i in range(7)] expected += [("remove", i, i) for i in range(6, 3, -1)] expected += [("add", i, i+4-301) for i in range(301,306)] assert R == expected
def test_fork(): parent_for_0 = b'\0' * 32 # 0 <= 1 <= ... <= 5 <= 6 # 3 <= 301 <= 302 <= 303 <= 304 <= 305 #parent_for_0 = "motherless" BC = BlockChain(parent_for_0) ITEMS = dict((i, (i, i-1, 1)) for i in range(7)) ITEMS[0] = (0, parent_for_0, 1) ITEMS.update(dict((i, (i, i-1, 1)) for i in range(301, 306))) ITEMS[301] = (301, 3, 1) assert longest_block_chain(BC) == [] assert BC.locked_length() == 0 assert BC.length() == 0 assert set(BC.chain_finder.missing_parents()) == set() # send them all except 302 ops = BC.add_nodes((ITEMS[i] for i in ITEMS.keys() if i != 302)) assert ops == [("add", i, i) for i in range(7)] assert set(BC.chain_finder.missing_parents()) == set([parent_for_0, 302]) # now send 302 ops = BC.add_nodes([ITEMS[302]]) # we should see a change expected = [("remove", i, i) for i in range(6, 3, -1)] expected += [("add", i, i+4-301) for i in range(301,306)] assert ops == expected assert set(BC.chain_finder.missing_parents()) == set([parent_for_0])
def items_for_client(initial_blocks=[]): block_store = {} block_chain = BlockChain() blockfetcher = Blockfetcher() inv_collector = InvCollector() block_handler = BlockHandler(inv_collector, block_chain, block_store) fast_forward_add_peer = fast_forwarder_add_peer_f(block_chain) for block in initial_blocks: inv_collector.advertise_item(InvItem(ITEM_TYPE_BLOCK, block.hash())) block_store[block.hash()] = block block_chain.add_headers(initial_blocks) inv_q = inv_collector.new_inv_item_queue() ap = make_add_peer(fast_forward_add_peer, blockfetcher, block_handler, inv_collector, block_chain, block_store) ap.block_getter_task = asyncio.Task(block_getter(inv_q, inv_collector, block_handler, block_chain, block_store)) return block_handler, block_chain, block_store, ap
def items_for_client(initial_blocks=[]): block_store = {} block_chain = BlockChain() blockfetcher = Blockfetcher() inv_collector = InvCollector() block_handler = BlockHandler(inv_collector, block_chain, block_store) fast_forward_add_peer = fast_forwarder_add_peer_f(block_chain) for block in initial_blocks: inv_collector.advertise_item(InvItem(ITEM_TYPE_BLOCK, block.hash())) block_store[block.hash()] = block block_chain.add_headers(initial_blocks) inv_q = inv_collector.new_inv_item_queue() ap = make_add_peer(fast_forward_add_peer, blockfetcher, block_handler, inv_collector, block_chain, block_store) ap.block_getter_task = asyncio.Task( block_getter(inv_q, inv_collector, block_handler, block_chain, block_store)) return block_handler, block_chain, block_store, ap
def test_fork(): parent_for_0 = b'\0' * 32 # 0 <= 1 <= ... <= 5 <= 6 # 3 <= 301 <= 302 <= 303 <= 304 <= 305 #parent_for_0 = "motherless" BC = BlockChain(parent_for_0) ITEMS = dict((i, (i, i - 1, 1)) for i in range(7)) ITEMS[0] = (0, parent_for_0, 1) ITEMS.update(dict((i, (i, i - 1, 1)) for i in range(301, 306))) ITEMS[301] = (301, 3, 1) assert longest_block_chain(BC) == [] assert BC.locked_length() == 0 assert BC.length() == 0 assert set(BC.chain_finder.missing_parents()) == set() # send them all except 302 ops = BC.add_nodes((ITEMS[i] for i in ITEMS.keys() if i != 302)) assert ops == [("add", i, i) for i in range(7)] assert set(BC.chain_finder.missing_parents()) == set([parent_for_0, 302]) # now send 302 ops = BC.add_nodes([ITEMS[302]]) # we should see a change expected = [("remove", i, i) for i in range(6, 3, -1)] expected += [("add", i, i + 4 - 301) for i in range(301, 306)] assert ops == expected assert set(BC.chain_finder.missing_parents()) == set([parent_for_0])
def run_client(peer_list, block_list): block_chain = BlockChain() block_store = {} inv_collector = InvCollector() block_handler = BlockHandler(inv_collector, block_chain, block_store) for peer in peer_list: inv_collector.add_peer(peer) block_handler.add_peer(peer) for block in block_list: inv_collector.advertise_item(InvItem(ITEM_TYPE_BLOCK, block.hash())) block_store[block.hash()] = block while len(block_store) < 2: yield from asyncio.sleep(0.1) return block_store
def test_large(): SIZE = 3000 ITEMS = [(i, i - 1, 1) for i in range(SIZE)] ITEMS[0] = (0, parent_for_0, 1) BC = BlockChain(parent_for_0) assert longest_block_chain(BC) == [] assert BC.locked_length() == 0 assert BC.length() == 0 assert set(BC.chain_finder.missing_parents()) == set() ops = BC.add_nodes(ITEMS) assert ops == [("add", i, i) for i in range(SIZE)] assert longest_block_chain(BC) == list(range(SIZE)) assert set(BC.chain_finder.missing_parents()) == {parent_for_0} assert BC.parent_hash == parent_for_0 assert BC.locked_length() == 0 assert BC.length() == SIZE for i in range(SIZE): v = BC.tuple_for_index(i) assert v[0] == i assert v[1] == parent_for_0 if i == 0 else i assert BC.index_for_hash(-1) is None
def test_large(): SIZE = 3000 ITEMS = [(i, i-1, 1) for i in range(SIZE)] ITEMS[0] = (0, parent_for_0, 1) BC = BlockChain(parent_for_0) assert longest_block_chain(BC) == [] assert BC.locked_length() == 0 assert BC.length() == 0 assert set(BC.chain_finder.missing_parents()) == set() ops = BC.add_nodes(ITEMS) assert ops == [("add", i, i) for i in range(SIZE)] assert longest_block_chain(BC) == list(range(SIZE)) assert set(BC.chain_finder.missing_parents()) == {parent_for_0} assert BC.parent_hash == parent_for_0 assert BC.locked_length() == 0 assert BC.length() == SIZE for i in range(SIZE): v = BC.tuple_for_index(i) assert v[0] == i assert v[1] == parent_for_0 if i == 0 else i assert BC.index_for_hash(-1) is None
def test_simple_getheader(): BLOCKS = make_blocks(20) blockchain1 = BlockChain() blockchain1.add_headers(BLOCKS) block_store = dict((b.hash(), b) for b in BLOCKS) peer1, peer2 = create_handshaked_peers() block_store = {} block_chain = BlockChain() inv_collector = InvCollector() block_handler = BlockHandler(inv_collector, block_chain, block_store) for block in BLOCKS: inv_collector.advertise_item(InvItem(ITEM_TYPE_BLOCK, block.hash())) block_store[block.hash()] = block block_chain.add_headers(BLOCKS) inv_collector.add_peer(peer1) block_handler.add_peer(peer1) @asyncio.coroutine def run_peer2(): r = [] headers = yield from standards.get_headers_hashes( peer2, after_block_hash=b'\0' * 32) r.append(headers) return r f2 = asyncio.Task(run_peer2()) asyncio.get_event_loop().run_until_complete(asyncio.wait([f2])) r = f2.result() assert len(r) == 1 assert [b.hash() for b in r[0]] == [b.hash() for b in BLOCKS]
def test_simple_getheader(): BLOCKS = make_blocks(20) blockchain1 = BlockChain() blockchain1.add_headers(BLOCKS) block_store = dict((b.hash(), b) for b in BLOCKS) peer1, peer2 = create_handshaked_peers() block_store = {} block_chain = BlockChain() inv_collector = InvCollector() block_handler = BlockHandler(inv_collector, block_chain, block_store) for block in BLOCKS: inv_collector.advertise_item(InvItem(ITEM_TYPE_BLOCK, block.hash())) block_store[block.hash()] = block block_chain.add_headers(BLOCKS) inv_collector.add_peer(peer1) block_handler.add_peer(peer1) @asyncio.coroutine def run_peer2(): r = [] headers = yield from standards.get_headers_hashes(peer2, after_block_hash=b"\0" * 32) r.append(headers) return r f2 = asyncio.Task(run_peer2()) asyncio.get_event_loop().run_until_complete(asyncio.wait([f2])) r = f2.result() assert len(r) == 1 assert [b.hash() for b in r[0]] == [b.hash() for b in BLOCKS]
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 test_chain_locking(): SIZE = 2000 COUNT = 200 ITEMS = [(i, i-1, 1) for i in range(SIZE*COUNT)] ITEMS[0] = (0, parent_for_0, 1) BC = BlockChain(parent_for_0) assert longest_block_chain(BC) == [] assert BC.locked_length() == 0 assert BC.length() == 0 assert set(BC.chain_finder.missing_parents()) == set() for i in range(COUNT): start, end = i*SIZE, (i+1)*SIZE lock_start = max(0, start-10) expected_parent = lock_start-1 if lock_start else parent_for_0 assert BC.length() == start assert BC.locked_length() == lock_start ops = BC.add_nodes(ITEMS[start:end]) assert ops == [("add", i, i) for i in range(start, end)] assert longest_locked_block_chain(BC) == list(range(lock_start, end)) assert set(BC.chain_finder.missing_parents()) == {expected_parent} assert BC.parent_hash == expected_parent assert BC.locked_length() == lock_start assert BC.length() == end for i in range(start, end): v = BC.tuple_for_index(i) assert v[0] == i assert v[1] == parent_for_0 if i == 0 else i assert BC.index_for_hash(-1) is None assert BC.locked_length() == max(0, lock_start) BC.lock_to_index(end-10) assert BC.locked_length() == end-10
def test_basic(): BC = BlockChain(parent_for_0) ITEMS = [(i, i-1, 1) for i in range(100)] ITEMS[0] = (0, parent_for_0, 1) assert longest_block_chain(BC) == [] assert BC.length() == 0 assert BC.locked_length() == 0 assert set(BC.chain_finder.missing_parents()) == set() assert BC.parent_hash == parent_for_0 assert BC.index_for_hash(0) is None assert BC.index_for_hash(-1) is None ops = BC.add_nodes(ITEMS[:5]) assert ops == [("add", i, i) for i in range(5)] assert BC.parent_hash == parent_for_0 assert longest_block_chain(BC) == list(range(5)) assert BC.length() == 5 assert BC.locked_length() == 0 assert set(BC.chain_finder.missing_parents()) == {parent_for_0} for i in range(5): v = BC.tuple_for_index(i) assert v[0] == i assert v[1] == parent_for_0 if i == 0 else i assert BC.index_for_hash(-1) is None ops = BC.add_nodes(ITEMS[:7]) assert ops == [("add", i, i) for i in range(5,7)] assert BC.parent_hash == parent_for_0 assert longest_block_chain(BC) == list(range(7)) assert BC.length() == 7 assert BC.locked_length() == 0 assert set(BC.chain_finder.missing_parents()) == {parent_for_0} for i in range(7): v = BC.tuple_for_index(i) assert v[0] == i assert v[1] == parent_for_0 if i == 0 else i assert BC.index_for_hash(-1) is None ops = BC.add_nodes(ITEMS[10:14]) assert ops == [] assert BC.parent_hash == parent_for_0 assert longest_block_chain(BC) == [0, 1, 2, 3, 4, 5, 6] assert BC.locked_length() == 0 assert BC.locked_length() == 0 assert BC.length() == 7 assert set(BC.chain_finder.missing_parents()) == {parent_for_0, 9} for i in range(7): v = BC.tuple_for_index(i) assert v[0] == i assert v[1] == parent_for_0 if i == 0 else i assert BC.index_for_hash(-1) is None ops = BC.add_nodes(ITEMS[7:10]) assert ops == [("add", i, i) for i in range(7,14)] assert longest_block_chain(BC) == list(range(14)) assert set(BC.chain_finder.missing_parents()) == {parent_for_0} assert BC.parent_hash == parent_for_0 assert BC.locked_length() == 0 assert BC.length() == 14 for i in range(14): v = BC.tuple_for_index(i) assert v[0] == i assert v[1] == parent_for_0 if i == 0 else i assert BC.index_for_hash(-1) is None ops = BC.add_nodes(ITEMS[90:]) assert ops == [] assert longest_block_chain(BC) == list(range(14)) assert set(BC.chain_finder.missing_parents()) == {parent_for_0, 89} assert BC.parent_hash == parent_for_0 assert BC.locked_length() == 0 assert BC.length() == 14 for i in range(14): v = BC.tuple_for_index(i) assert v[0] == i assert v[1] == parent_for_0 if i == 0 else i assert BC.index_for_hash(-1) is None ops = BC.add_nodes(ITEMS[14:90]) assert ops == [("add", i, i) for i in range(14,100)] assert longest_block_chain(BC) == list(range(100)) assert set(BC.chain_finder.missing_parents()) == {parent_for_0} assert BC.parent_hash == parent_for_0 assert BC.locked_length() == 0 assert BC.length() == 100 for i in range(100): v = BC.tuple_for_index(i) assert v[0] == i assert v[1] == parent_for_0 if i == 0 else i assert BC.index_for_hash(-1) is None
def test_basic(): BC = BlockChain(parent_for_0) ITEMS = [(i, i - 1, 1) for i in range(100)] ITEMS[0] = (0, parent_for_0, 1) assert longest_block_chain(BC) == [] assert BC.length() == 0 assert BC.locked_length() == 0 assert set(BC.chain_finder.missing_parents()) == set() assert BC.parent_hash == parent_for_0 assert BC.index_for_hash(0) is None assert BC.index_for_hash(-1) is None ops = BC.add_nodes(ITEMS[:5]) assert ops == [("add", i, i) for i in range(5)] assert BC.parent_hash == parent_for_0 assert longest_block_chain(BC) == list(range(5)) assert BC.length() == 5 assert BC.locked_length() == 0 assert set(BC.chain_finder.missing_parents()) == {parent_for_0} for i in range(5): v = BC.tuple_for_index(i) assert v[0] == i assert v[1] == parent_for_0 if i == 0 else i assert BC.index_for_hash(-1) is None ops = BC.add_nodes(ITEMS[:7]) assert ops == [("add", i, i) for i in range(5, 7)] assert BC.parent_hash == parent_for_0 assert longest_block_chain(BC) == list(range(7)) assert BC.length() == 7 assert BC.locked_length() == 0 assert set(BC.chain_finder.missing_parents()) == {parent_for_0} for i in range(7): v = BC.tuple_for_index(i) assert v[0] == i assert v[1] == parent_for_0 if i == 0 else i assert BC.index_for_hash(-1) is None ops = BC.add_nodes(ITEMS[10:14]) assert ops == [] assert BC.parent_hash == parent_for_0 assert longest_block_chain(BC) == [0, 1, 2, 3, 4, 5, 6] assert BC.locked_length() == 0 assert BC.locked_length() == 0 assert BC.length() == 7 assert set(BC.chain_finder.missing_parents()) == {parent_for_0, 9} for i in range(7): v = BC.tuple_for_index(i) assert v[0] == i assert v[1] == parent_for_0 if i == 0 else i assert BC.index_for_hash(-1) is None ops = BC.add_nodes(ITEMS[7:10]) assert ops == [("add", i, i) for i in range(7, 14)] assert longest_block_chain(BC) == list(range(14)) assert set(BC.chain_finder.missing_parents()) == {parent_for_0} assert BC.parent_hash == parent_for_0 assert BC.locked_length() == 0 assert BC.length() == 14 for i in range(14): v = BC.tuple_for_index(i) assert v[0] == i assert v[1] == parent_for_0 if i == 0 else i assert BC.index_for_hash(-1) is None ops = BC.add_nodes(ITEMS[90:]) assert ops == [] assert longest_block_chain(BC) == list(range(14)) assert set(BC.chain_finder.missing_parents()) == {parent_for_0, 89} assert BC.parent_hash == parent_for_0 assert BC.locked_length() == 0 assert BC.length() == 14 for i in range(14): v = BC.tuple_for_index(i) assert v[0] == i assert v[1] == parent_for_0 if i == 0 else i assert BC.index_for_hash(-1) is None ops = BC.add_nodes(ITEMS[14:90]) assert ops == [("add", i, i) for i in range(14, 100)] assert longest_block_chain(BC) == list(range(100)) assert set(BC.chain_finder.missing_parents()) == {parent_for_0} assert BC.parent_hash == parent_for_0 assert BC.locked_length() == 0 assert BC.length() == 100 for i in range(100): v = BC.tuple_for_index(i) assert v[0] == i assert v[1] == parent_for_0 if i == 0 else i assert BC.index_for_hash(-1) is None
def test_chain_locking(): SIZE = 2000 COUNT = 200 ITEMS = [(i, i - 1, 1) for i in range(SIZE * COUNT)] ITEMS[0] = (0, parent_for_0, 1) BC = BlockChain(parent_for_0) assert longest_block_chain(BC) == [] assert BC.locked_length() == 0 assert BC.length() == 0 assert set(BC.chain_finder.missing_parents()) == set() for i in range(COUNT): start, end = i * SIZE, (i + 1) * SIZE lock_start = max(0, start - 10) expected_parent = lock_start - 1 if lock_start else parent_for_0 assert BC.length() == start assert BC.locked_length() == lock_start ops = BC.add_nodes(ITEMS[start:end]) assert ops == [("add", i, i) for i in range(start, end)] assert longest_locked_block_chain(BC) == list(range(lock_start, end)) assert set(BC.chain_finder.missing_parents()) == {expected_parent} assert BC.parent_hash == expected_parent assert BC.locked_length() == lock_start assert BC.length() == end for i in range(start, end): v = BC.tuple_for_index(i) assert v[0] == i assert v[1] == parent_for_0 if i == 0 else i assert BC.index_for_hash(-1) is None assert BC.locked_length() == max(0, lock_start) BC.lock_to_index(end - 10) assert BC.locked_length() == end - 10