async def alice_and_bob(alice_chain, bob_chain): pair_factory = ETHPeerPairFactory( alice_client_version='alice', alice_peer_context=ChainContextFactory(headerdb=AsyncHeaderDB(alice_chain.headerdb.db)), bob_client_version='bob', bob_peer_context=ChainContextFactory(headerdb=AsyncHeaderDB(bob_chain.headerdb.db)), ) async with pair_factory as (alice, bob): yield alice, bob
async def alice_and_bob(common_base_chain, request): pair_factory = request.param( alice_client_version='alice', alice_peer_context=ChainContextFactory(headerdb=AsyncHeaderDB( common_base_chain.headerdb.db)), # noqa: E501 bob_client_version='bob', bob_peer_context=ChainContextFactory( headerdb=AsyncHeaderDB(common_base_chain.headerdb.db)), ) async with pair_factory as (alice, bob): yield alice, bob
def make_eth1_request_server(cls, app_config: Eth1AppConfig, base_db: BaseAtomicDB, event_bus: EndpointAPI) -> Service: server: Service if app_config.database_mode is Eth1DbMode.LIGHT: header_db = AsyncHeaderDB(base_db) server = LightRequestServer( event_bus, TO_NETWORKING_BROADCAST_CONFIG, header_db ) elif app_config.database_mode is Eth1DbMode.FULL: chain_db = AsyncChainDB(base_db) server = ETHRequestServer( event_bus, TO_NETWORKING_BROADCAST_CONFIG, chain_db ) else: raise Exception(f"Unsupported Database Mode: {app_config.database_mode}") return server
async def test_generate_eth_cap_enr_field(): base_db = AtomicDB() ChainDB(base_db).persist_header(ROPSTEN_GENESIS_HEADER) enr_field = await generate_eth_cap_enr_field(ROPSTEN_VM_CONFIGURATION, AsyncHeaderDB(base_db)) enr = ENRFactory(custom_kv_pairs={enr_field[0]: enr_field[1]}) assert extract_forkid(enr) == ForkID(hash=to_bytes(hexstr='0x30c7ddbc'), next=10)
async def test_handshake_with_incompatible_fork_id(alice_chain, bob_chain): alice_chain = build(alice_chain, mine_block()) pair_factory = ETHPeerPairFactory(alice_peer_context=ChainContextFactory( headerdb=AsyncHeaderDB(alice_chain.headerdb.db), vm_configuration=((1, PetersburgVM), (2, MuirGlacierVM))), ) with pytest.raises(WrongForkIDFailure): async with pair_factory as (alice, bob): pass
def __init__(self, event_bus: EndpointAPI, trinity_config: TrinityConfig) -> None: super().__init__() self.trinity_config = trinity_config self._base_db = DBClient.connect(trinity_config.database_ipc_path) self._headerdb = AsyncHeaderDB(self._base_db) self._jsonrpc_ipc_path: Path = trinity_config.jsonrpc_ipc_path self._network_id = trinity_config.network_id self.event_bus = event_bus
def __init__(self, event_bus: EndpointAPI, trinity_config: TrinityConfig) -> None: self.trinity_config = trinity_config self._base_db = DBClient.connect(trinity_config.database_ipc_path) self._headerdb = AsyncHeaderDB(self._base_db) self._jsonrpc_ipc_path: Path = trinity_config.jsonrpc_ipc_path self._network_id = trinity_config.network_id self.event_bus = event_bus self.master_cancel_token = CancelToken(type(self).__name__)
async def sync(self, args: Namespace, logger: Logger, chain: AsyncChainAPI, base_db: AtomicDatabaseAPI, peer_pool: BasePeerPool, event_bus: EndpointAPI, cancel_token: CancelToken) -> None: syncer = LightChainSyncer( chain, AsyncHeaderDB(base_db), cast(LESPeerPool, peer_pool), cancel_token, ) await syncer.run()
async def sync(self, args: Namespace, logger: logging.Logger, chain: AsyncChainAPI, base_db: AtomicDatabaseAPI, peer_pool: BasePeerPool, event_bus: EndpointAPI) -> None: syncer = LightChainSyncer( chain, AsyncHeaderDB(base_db), cast(LESPeerPool, peer_pool), ) async with background_asyncio_service(syncer) as manager: await manager.wait_finished()
def get_eth1_chain_with_remote_db( boot_info: BootInfo, event_bus: EndpointAPI) -> Iterator[ChainAPI]: app_config = boot_info.trinity_config.get_app_config(Eth1AppConfig) chain_config = app_config.get_chain_config() chain: ChainAPI base_db = DBClient.connect(boot_info.trinity_config.database_ipc_path) with base_db: if boot_info.args.sync_mode == SYNC_LIGHT: header_db = AsyncHeaderDB(base_db) chain = chain_config.light_chain_class( header_db, peer_chain=EventBusLightPeerChain(event_bus)) else: chain = chain_config.full_chain_class(base_db) yield chain
def get_server(privkey, address, event_bus): base_db = AtomicDB() headerdb = AsyncHeaderDB(base_db) chaindb = ChainDB(base_db) chaindb.persist_header(ROPSTEN_GENESIS_HEADER) chain = RopstenChain(base_db) server = ParagonServer( privkey=privkey, port=address.tcp_port, chain=chain, chaindb=chaindb, headerdb=headerdb, base_db=base_db, network_id=NETWORK_ID, event_bus=event_bus, ) return server
def get_chain(self) -> ChainAPI: app_config = self.boot_info.trinity_config.get_app_config( Eth1AppConfig) chain_config = app_config.get_chain_config() chain: ChainAPI base_db = DBClient.connect( self.boot_info.trinity_config.database_ipc_path) if self.boot_info.args.sync_mode == SYNC_LIGHT: header_db = AsyncHeaderDB(base_db) chain = chain_config.light_chain_class( header_db, peer_chain=EventBusLightPeerChain(self.event_bus)) else: chain = chain_config.full_chain_class(base_db) return chain
async def _main() -> None: parser = argparse.ArgumentParser() parser.add_argument('-enode', type=str, help="The enode we should connect to", required=True) parser.add_argument('-mainnet', action='store_true') parser.add_argument('-light', action='store_true', help="Connect as a light node") parser.add_argument('-debug', action="store_true") args = parser.parse_args() log_level = logging.INFO if args.debug: log_level = DEBUG2_LEVEL_NUM logging.basicConfig(level=log_level, format='%(asctime)s %(levelname)s: %(message)s', datefmt='%H:%M:%S') peer_class: Union[Type[ETHPeer], Type[LESPeer]] pool_class: Union[Type[ETHPeerPool], Type[LESPeerPool]] if args.light: peer_class = LESPeer pool_class = LESPeerPool else: peer_class = ETHPeer pool_class = ETHPeerPool bootnodes: Tuple[str, ...] if args.mainnet: bootnodes = MAINNET_BOOTNODES chain_id = MainnetChain.chain_id vm_config = MAINNET_VM_CONFIGURATION genesis = MAINNET_GENESIS_HEADER else: bootnodes = ROPSTEN_BOOTNODES chain_id = RopstenChain.chain_id vm_config = ROPSTEN_VM_CONFIGURATION genesis = ROPSTEN_GENESIS_HEADER headerdb = AsyncHeaderDB(AtomicDB(MemoryDB())) headerdb.persist_header(genesis) loop = asyncio.get_event_loop() if args.enode == "bootnodes": nodes = [Node.from_uri(enode) for enode in bootnodes] else: nodes = [Node.from_uri(args.enode)] context = ChainContext( headerdb=headerdb, network_id=chain_id, vm_configuration=vm_config, client_version_string=construct_trinity_client_identifier(), listen_port=30309, p2p_version=DEVP2P_V5, ) peer_pool = pool_class(privkey=ecies.generate_privkey(), context=context) async def request_stuff() -> None: nonlocal peer_pool # Request some stuff from ropsten's block 2440319 # (https://ropsten.etherscan.io/block/2440319), just as a basic test. peer = peer_pool.highest_td_peer if peer_class == ETHPeer: peer = cast(ETHPeer, peer) headers = await peer.eth_api.get_block_headers( BlockNumber(2440319), max_headers=100) hashes = tuple(header.hash for header in headers) peer.eth_api.send_get_block_bodies(hashes) peer.eth_api.send_get_receipts(hashes) else: peer = cast(LESPeer, peer) headers = await peer.les_api.get_block_headers( BlockNumber(2440319), max_headers=100) peer.les_api.send_get_block_bodies(list(hashes)) peer.les_api.send_get_receipts(hashes[:1]) async with background_asyncio_service(peer_pool) as manager: for sig in [signal.SIGINT, signal.SIGTERM]: loop.add_signal_handler(sig, manager.cancel) await peer_pool.connect_to_nodes(nodes) await asyncio.sleep(1) if len(peer_pool) == 0: peer_pool.logger.error(f"Unable to connect to any of {nodes}") return try: await asyncio.wait_for(request_stuff(), timeout=2) except asyncio.TimeoutError: peer_pool.logger.error("Timeout waiting for replies") await manager.wait_finished()
async def test_sync_integration(request, caplog, geth_ipc_path, enode, geth_process): """Test a regular chain sync against a running geth instance. In order to run this manually, you can use `tox -e py37-sync_integration` or: pytest --integration --capture=no tests/integration/test_sync.py The fixture for this test was generated with: geth --ropsten --syncmode full It only needs the first 11 blocks for this test to succeed. """ if not request.config.getoption("--integration"): pytest.skip("Not asked to run integration tests") # will almost certainly want verbose logging in a failure caplog.set_level(logging.DEBUG) # make sure geth has been launched wait_for_socket(geth_ipc_path) remote = Node.from_uri(enode) base_db = AtomicDB() chaindb = AsyncChainDB(base_db) chaindb.persist_header(ROPSTEN_GENESIS_HEADER) headerdb = AsyncHeaderDB(base_db) chain_config = Eth1ChainConfig.from_preconfigured_network( ROPSTEN_NETWORK_ID) chain = chain_config.initialize_chain(base_db) context = ChainContext( headerdb=headerdb, network_id=ROPSTEN_NETWORK_ID, vm_configuration=ROPSTEN_VM_CONFIGURATION, client_version_string='trinity-test', listen_port=30303, p2p_version=DEVP2P_V5, ) peer_pool = ETHPeerPool(privkey=ecies.generate_privkey(), context=context) syncer = RegularChainSyncer(chain, chaindb, peer_pool) async with background_asyncio_service(peer_pool) as manager: await manager.wait_started() await peer_pool.connect_to_nodes([remote]) assert len(peer_pool) == 1 async with background_asyncio_service(syncer) as syncer_manager: await syncer_manager.wait_started() n = 11 manager.logger.info(f"Waiting for the chain to sync {n} blocks") async def wait_for_header_sync(block_number): while chaindb.get_canonical_head().block_number < block_number: await asyncio.sleep(0.1) await asyncio.wait_for(wait_for_header_sync(n), 5) # https://ropsten.etherscan.io/block/11 header = chaindb.get_canonical_block_header_by_number(n) transactions = chaindb.get_block_transactions( header, BaseTransactionFields) assert len(transactions) == 15 receipts = chaindb.get_receipts(header, Receipt) assert len(receipts) == 15 assert encode_hex(keccak(rlp.encode(receipts[0]))) == ( '0xf709ed2c57efc18a1675e8c740f3294c9e2cb36ba7bb3b89d3ab4c8fef9d8860' )
async def test_lightchain_integration(request, event_loop, caplog, geth_ipc_path, enode, geth_process): """Test LightChainSyncer/LightPeerChain against a running geth instance. In order to run this manually, you can use `tox -e py36-lightchain_integration` or: pytest --integration --capture=no tests/integration/test_lightchain_integration.py The fixture for this test was generated with: geth --testnet --syncmode full It only needs the first 11 blocks for this test to succeed. """ if not request.config.getoption("--integration"): pytest.skip("Not asked to run integration tests") # will almost certainly want verbose logging in a failure caplog.set_level(logging.DEBUG) # make sure geth has been launched wait_for_socket(geth_ipc_path) remote = Node.from_uri(enode) base_db = AtomicDB() chaindb = AsyncChainDB(base_db) chaindb.persist_header(ROPSTEN_GENESIS_HEADER) headerdb = AsyncHeaderDB(base_db) context = ChainContext( headerdb=headerdb, network_id=ROPSTEN_NETWORK_ID, vm_configuration=ROPSTEN_VM_CONFIGURATION, client_version_string='trinity-test', listen_port=30303, p2p_version=DEVP2P_V5, ) peer_pool = LESPeerPool( privkey=ecies.generate_privkey(), context=context, ) chain = AsyncRopstenChain(base_db) syncer = LightChainSyncer(chain, chaindb, peer_pool) syncer.min_peers_to_sync = 1 peer_chain = LightPeerChain(headerdb, peer_pool) asyncio.ensure_future(peer_pool.run()) asyncio.ensure_future(connect_to_peers_loop(peer_pool, tuple([remote]))) asyncio.ensure_future(peer_chain.run()) asyncio.ensure_future(syncer.run()) await asyncio.sleep( 0) # Yield control to give the LightChainSyncer a chance to start def finalizer(): event_loop.run_until_complete(peer_pool.cancel()) event_loop.run_until_complete(peer_chain.cancel()) event_loop.run_until_complete(syncer.cancel()) request.addfinalizer(finalizer) n = 11 # Wait for the chain to sync a few headers. async def wait_for_header_sync(block_number): while headerdb.get_canonical_head().block_number < block_number: await asyncio.sleep(0.1) await asyncio.wait_for(wait_for_header_sync(n), 5) # https://ropsten.etherscan.io/block/11 header = headerdb.get_canonical_block_header_by_number(n) body = await peer_chain.coro_get_block_body_by_hash(header.hash) assert len(body['transactions']) == 15 receipts = await peer_chain.coro_get_receipts(header.hash) assert len(receipts) == 15 assert encode_hex(keccak(rlp.encode(receipts[0]))) == ( '0xf709ed2c57efc18a1675e8c740f3294c9e2cb36ba7bb3b89d3ab4c8fef9d8860') assert len(peer_pool) == 1 peer = peer_pool.highest_td_peer head = await peer_chain.coro_get_block_header_by_hash( peer.head_info.head_hash) # In order to answer queries for contract code, geth needs the state trie entry for the block # we specify in the query, but because of fast sync we can only assume it has that for recent # blocks, so we use the current head to lookup the code for the contract below. # https://ropsten.etherscan.io/address/0x95a48dca999c89e4e284930d9b9af973a7481287 contract_addr = decode_hex('0x8B09D9ac6A4F7778fCb22852e879C7F3B2bEeF81') contract_code = await peer_chain.coro_get_contract_code( head.hash, contract_addr) assert encode_hex(contract_code) == '0x600060006000600060006000356000f1' account = await peer_chain.coro_get_account(head.hash, contract_addr) assert account.code_hash == keccak(contract_code) assert account.balance == 0
async def _main() -> None: parser = argparse.ArgumentParser() parser.add_argument('-db', type=str, required=True) parser.add_argument('-light', action="store_true") parser.add_argument('-nodekey', type=str) parser.add_argument('-enode', type=str, required=False, help="The enode we should connect to") parser.add_argument('-debug', action="store_true") args = parser.parse_args() logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s: %(message)s', datefmt='%H:%M:%S') log_level = logging.INFO if args.debug: log_level = logging.DEBUG loop = asyncio.get_event_loop() base_db = LevelDB(args.db) headerdb = AsyncHeaderDB(AtomicDB(base_db)) chaindb = AsyncChainDB(AtomicDB(base_db)) try: genesis = chaindb.get_canonical_block_header_by_number(BlockNumber(0)) except HeaderNotFound: genesis = ROPSTEN_GENESIS_HEADER chaindb.persist_header(genesis) peer_pool_class: Type[Union[ETHPeerPool, LESPeerPool]] = ETHPeerPool if args.light: peer_pool_class = LESPeerPool chain_class: Union[Type[AsyncRopstenChain], Type[AsyncMainnetChain]] if genesis.hash == ROPSTEN_GENESIS_HEADER.hash: chain_id = RopstenChain.chain_id vm_config = ROPSTEN_VM_CONFIGURATION chain_class = AsyncRopstenChain elif genesis.hash == MAINNET_GENESIS_HEADER.hash: chain_id = MainnetChain.chain_id vm_config = MAINNET_VM_CONFIGURATION # type: ignore chain_class = AsyncMainnetChain else: raise RuntimeError("Unknown genesis: %s", genesis) if args.nodekey: privkey = load_nodekey(Path(args.nodekey)) else: privkey = ecies.generate_privkey() context = ChainContext( headerdb=headerdb, network_id=chain_id, vm_configuration=vm_config, client_version_string=construct_trinity_client_identifier(), listen_port=30309, p2p_version=DEVP2P_V5, ) peer_pool = peer_pool_class(privkey=privkey, context=context) if args.enode: nodes = tuple([Node.from_uri(args.enode)]) else: nodes = DEFAULT_PREFERRED_NODES[chain_id] async with background_asyncio_service(peer_pool) as manager: manager.run_task(connect_to_peers_loop(peer_pool, nodes)) # type: ignore chain = chain_class(base_db) syncer: Service = None if args.light: syncer = LightChainSyncer(chain, headerdb, cast(LESPeerPool, peer_pool)) else: syncer = RegularChainSyncer(chain, chaindb, cast(ETHPeerPool, peer_pool)) logging.getLogger().setLevel(log_level) sigint_received = asyncio.Event() for sig in [signal.SIGINT, signal.SIGTERM]: loop.add_signal_handler(sig, sigint_received.set) async def exit_on_sigint() -> None: await sigint_received.wait() syncer.get_manager().cancel() asyncio.ensure_future(exit_on_sigint()) async with background_asyncio_service(syncer) as syncer_manager: await syncer_manager.wait_finished()
def _main() -> None: logging.basicConfig(level=DEBUG2_LEVEL_NUM, format='%(asctime)s %(levelname)s: %(message)s') parser = argparse.ArgumentParser() parser.add_argument('-enode', type=str, help="The enode we should connect to", required=True) parser.add_argument('-mainnet', action='store_true') parser.add_argument('-light', action='store_true', help="Connect as a light node") args = parser.parse_args() peer_class: Union[Type[ETHPeer], Type[LESPeer]] pool_class: Union[Type[ETHPeerPool], Type[LESPeerPool]] if args.light: peer_class = LESPeer pool_class = LESPeerPool else: peer_class = ETHPeer pool_class = ETHPeerPool if args.mainnet: chain_id = MainnetChain.chain_id vm_config = MAINNET_VM_CONFIGURATION genesis = MAINNET_GENESIS_HEADER else: chain_id = RopstenChain.chain_id vm_config = ROPSTEN_VM_CONFIGURATION genesis = ROPSTEN_GENESIS_HEADER headerdb = AsyncHeaderDB(AtomicDB(MemoryDB())) headerdb.persist_header(genesis) loop = asyncio.get_event_loop() nodes = [Node.from_uri(args.enode)] context = ChainContext( headerdb=headerdb, network_id=chain_id, vm_configuration=vm_config, client_version_string=construct_trinity_client_identifier(), listen_port=30309, p2p_version=DEVP2P_V5, ) peer_pool = pool_class( privkey=ecies.generate_privkey(), context=context, ) asyncio.ensure_future(peer_pool.run()) peer_pool.run_task(connect_to_peers_loop(peer_pool, nodes)) async def request_stuff() -> None: # Request some stuff from ropsten's block 2440319 # (https://ropsten.etherscan.io/block/2440319), just as a basic test. nonlocal peer_pool while not peer_pool.connected_nodes: peer_pool.logger.info("Waiting for peer connection...") await asyncio.sleep(0.2) peer = peer_pool.highest_td_peer headers = await cast(ETHPeer, peer).eth_api.get_block_headers( BlockNumber(2440319), max_headers=100 ) hashes = tuple(header.hash for header in headers) if peer_class == ETHPeer: peer = cast(ETHPeer, peer) peer.eth_api.send_get_block_bodies(hashes) peer.eth_api.send_get_receipts(hashes) else: peer = cast(LESPeer, peer) peer.les_api.send_get_block_bodies(list(hashes)) peer.les_api.send_get_receipts(hashes[0]) sigint_received = asyncio.Event() for sig in [signal.SIGINT, signal.SIGTERM]: loop.add_signal_handler(sig, sigint_received.set) async def exit_on_sigint() -> None: await sigint_received.wait() await peer_pool.cancel() loop.stop() asyncio.ensure_future(exit_on_sigint()) asyncio.ensure_future(request_stuff()) loop.set_debug(True) loop.run_forever() loop.close()