├── .github └── workflows │ └── ci-pip.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── jito_geyser ├── README.md ├── jito_geyser │ ├── __init__.py │ └── generated │ │ ├── __init__.py │ │ ├── confirmed_block_pb2.py │ │ ├── confirmed_block_pb2.pyi │ │ ├── confirmed_block_pb2_grpc.py │ │ ├── confirmed_block_pb2_grpc.pyi │ │ ├── geyser_pb2.py │ │ ├── geyser_pb2.pyi │ │ ├── geyser_pb2_grpc.py │ │ ├── geyser_pb2_grpc.pyi │ │ ├── transaction_by_addr_pb2.py │ │ ├── transaction_by_addr_pb2.pyi │ │ ├── transaction_by_addr_pb2_grpc.py │ │ └── transaction_by_addr_pb2_grpc.pyi ├── poetry.lock └── pyproject.toml └── jito_searcher_client ├── README.md ├── examples ├── async-searcher-cli.py └── searcher-cli.py ├── jito_searcher_client ├── __init__.py ├── async_searcher.py ├── convert.py ├── generated │ ├── __init__.py │ ├── auth_pb2.py │ ├── auth_pb2.pyi │ ├── auth_pb2_grpc.py │ ├── auth_pb2_grpc.pyi │ ├── block_engine_pb2.py │ ├── block_engine_pb2.pyi │ ├── block_engine_pb2_grpc.py │ ├── block_engine_pb2_grpc.pyi │ ├── block_pb2.py │ ├── block_pb2.pyi │ ├── block_pb2_grpc.py │ ├── block_pb2_grpc.pyi │ ├── bundle_pb2.py │ ├── bundle_pb2.pyi │ ├── bundle_pb2_grpc.py │ ├── bundle_pb2_grpc.pyi │ ├── packet_pb2.py │ ├── packet_pb2.pyi │ ├── packet_pb2_grpc.py │ ├── packet_pb2_grpc.pyi │ ├── relayer_pb2.py │ ├── relayer_pb2.pyi │ ├── relayer_pb2_grpc.py │ ├── relayer_pb2_grpc.pyi │ ├── searcher_pb2.py │ ├── searcher_pb2.pyi │ ├── searcher_pb2_grpc.py │ ├── searcher_pb2_grpc.pyi │ ├── shared_pb2.py │ ├── shared_pb2.pyi │ ├── shared_pb2_grpc.py │ ├── shared_pb2_grpc.pyi │ ├── shredstream_pb2.py │ ├── shredstream_pb2.pyi │ ├── shredstream_pb2_grpc.py │ └── shredstream_pb2_grpc.pyi ├── searcher.py └── token.py ├── poetry.lock └── pyproject.toml /.github/workflows/ci-pip.yml: -------------------------------------------------------------------------------- 1 | name: Publish Python Package 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | environment: PyPi 12 | permissions: 13 | id-token: write # IMPORTANT: this permission is mandatory for trusted publishing 14 | 15 | defaults: 16 | run: 17 | working-directory: ./jito_searcher_client 18 | 19 | steps: 20 | - uses: actions/checkout@v3 21 | with: 22 | submodules: 'recursive' 23 | 24 | - name: Set up Python 25 | uses: actions/setup-python@v4 26 | with: 27 | python-version: '3.11' 28 | 29 | - name: Install Poetry 30 | uses: snok/install-poetry@v1 31 | with: 32 | version: latest 33 | virtualenvs-create: true 34 | virtualenvs-in-project: true 35 | 36 | - name: Install dependencies 37 | run: | 38 | poetry install --no-interaction 39 | 40 | - name: Build package 41 | run: | 42 | poetry build 43 | 44 | - name: Publish package 45 | uses: pypa/gh-action-pypi-publish@v1.12.4 46 | with: 47 | password: ${{ secrets.PYPITOKEN }} 48 | packages-dir: jito_searcher_client/dist/ 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | .idea/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "mev-protos"] 2 | path = mev-protos 3 | url = git@github.com:jito-labs/mev-protos.git 4 | [submodule "geyser-grpc-plugin"] 5 | path = geyser-grpc-plugin 6 | url = git@github.com:jito-foundation/geyser-grpc-plugin.git 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright (c) 2025 Jito Labs 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /jito_geyser/README.md: -------------------------------------------------------------------------------- 1 | # About 2 | This library contains python code to interact with [Jito's Geyser Plugin](https://github.com/jito-foundation/geyser-grpc-plugin). 3 | 4 | # Downloading 5 | ```bash 6 | $ pip install jito_geyser 7 | ``` 8 | 9 | # Access Token 10 | We no longer support access to geyser. Please use 3rd party providers. 11 | 12 | # Examples 13 | 14 | ### Printing slot updates 15 | ```python 16 | from grpc import ssl_channel_credentials, secure_channel 17 | 18 | from jito_geyser.generated.geyser_pb2 import SubscribeSlotUpdateRequest 19 | from jito_geyser.generated.geyser_pb2_grpc import GeyserStub 20 | 21 | GEYSER_URL = "mainnet.rpc.jito.wtf" 22 | ACCESS_TOKEN = "ACCESS_TOKEN_HERE" 23 | 24 | channel = secure_channel(GEYSER_URL, ssl_channel_credentials()) 25 | client = GeyserStub(channel) 26 | for msg in client.SubscribeSlotUpdates(SubscribeSlotUpdateRequest(), metadata=[("access-token", ACCESS_TOKEN)]): 27 | print(msg) 28 | ``` 29 | 30 | ### Listening to program account updates 31 | This example listens to pyth-owned accounts 32 | ```python 33 | from grpc import ssl_channel_credentials, secure_channel 34 | from solders.pubkey import Pubkey # note: probably need to install solders for this import 35 | 36 | from jito_geyser.generated.geyser_pb2 import SubscribeProgramsUpdatesRequest 37 | from jito_geyser.generated.geyser_pb2_grpc import GeyserStub 38 | 39 | GEYSER_URL = "mainnet.rpc.jito.wtf" 40 | ACCESS_TOKEN = "ACCESS_TOKEN_HERE" 41 | ACCOUNTS = [bytes(Pubkey.from_string("FsJ3A3u2vn5cTVofAjvy6y5kwABJAqYWpe4975bi2epH"))] 42 | 43 | channel = secure_channel(GEYSER_URL, ssl_channel_credentials()) 44 | client = GeyserStub(channel) 45 | for msg in client.SubscribeProgramUpdates(SubscribeProgramsUpdatesRequest(programs=ACCOUNTS), metadata=[("access-token", ACCESS_TOKEN)]): 46 | print(msg) 47 | ``` 48 | 49 | ### Functions available 50 | - There are many functions available including: 51 | - GetHeartbeatInterval 52 | - SubscribeAccountUpdates 53 | - SubscribeProgramUpdates 54 | - SubscribePartialAccountUpdates 55 | - SubscribeSlotUpdates 56 | - SubscribeTransactionUpdates 57 | - SubscribeBlockUpdates 58 | 59 | # Development 60 | 61 | Install pip 62 | ```bash 63 | $ curl -sSL https://bootstrap.pypa.io/get-pip.py | python 3 - 64 | ``` 65 | 66 | Install poetry 67 | ```bash 68 | $ curl -sSL https://install.python-poetry.org | python3 - 69 | ``` 70 | 71 | Setup environment and build protobufs 72 | ```bash 73 | $ poetry install 74 | $ poetry shell 75 | $ poetry protoc 76 | ``` 77 | 78 | Linting 79 | ```bash 80 | $ poetry run black . 81 | $ poetry run isort . 82 | ``` 83 | 84 | Publishing package 85 | ```bash 86 | $ poetry protoc && poetry build && poetry publish 87 | ``` 88 | -------------------------------------------------------------------------------- /jito_geyser/jito_geyser/__init__.py: -------------------------------------------------------------------------------- 1 | from . import generated 2 | -------------------------------------------------------------------------------- /jito_geyser/jito_geyser/generated/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | # ugh https://stackoverflow.com/a/55258233 5 | sys.path.insert(0, os.path.abspath(os.path.dirname(__file__))) 6 | -------------------------------------------------------------------------------- /jito_geyser/jito_geyser/generated/confirmed_block_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: confirmed_block.proto 4 | """Generated protocol buffer code.""" 5 | from google.protobuf.internal import builder as _builder 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | 15 | 16 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x63onfirmed_block.proto\x12\x1dsolana.storage.ConfirmedBlock\"\xdb\x02\n\x0e\x43onfirmedBlock\x12\x1a\n\x12previous_blockhash\x18\x01 \x01(\t\x12\x11\n\tblockhash\x18\x02 \x01(\t\x12\x13\n\x0bparent_slot\x18\x03 \x01(\x04\x12I\n\x0ctransactions\x18\x04 \x03(\x0b\x32\x33.solana.storage.ConfirmedBlock.ConfirmedTransaction\x12\x36\n\x07rewards\x18\x05 \x03(\x0b\x32%.solana.storage.ConfirmedBlock.Reward\x12@\n\nblock_time\x18\x06 \x01(\x0b\x32,.solana.storage.ConfirmedBlock.UnixTimestamp\x12@\n\x0c\x62lock_height\x18\x07 \x01(\x0b\x32*.solana.storage.ConfirmedBlock.BlockHeight\"\x9b\x01\n\x14\x43onfirmedTransaction\x12?\n\x0btransaction\x18\x01 \x01(\x0b\x32*.solana.storage.ConfirmedBlock.Transaction\x12\x42\n\x04meta\x18\x02 \x01(\x0b\x32\x34.solana.storage.ConfirmedBlock.TransactionStatusMeta\"Z\n\x0bTransaction\x12\x12\n\nsignatures\x18\x01 \x03(\x0c\x12\x37\n\x07message\x18\x02 \x01(\x0b\x32&.solana.storage.ConfirmedBlock.Message\"\xad\x02\n\x07Message\x12<\n\x06header\x18\x01 \x01(\x0b\x32,.solana.storage.ConfirmedBlock.MessageHeader\x12\x14\n\x0c\x61\x63\x63ount_keys\x18\x02 \x03(\x0c\x12\x18\n\x10recent_blockhash\x18\x03 \x01(\x0c\x12H\n\x0cinstructions\x18\x04 \x03(\x0b\x32\x32.solana.storage.ConfirmedBlock.CompiledInstruction\x12\x11\n\tversioned\x18\x05 \x01(\x08\x12W\n\x15\x61\x64\x64ress_table_lookups\x18\x06 \x03(\x0b\x32\x38.solana.storage.ConfirmedBlock.MessageAddressTableLookup\"~\n\rMessageHeader\x12\x1f\n\x17num_required_signatures\x18\x01 \x01(\r\x12$\n\x1cnum_readonly_signed_accounts\x18\x02 \x01(\r\x12&\n\x1enum_readonly_unsigned_accounts\x18\x03 \x01(\r\"d\n\x19MessageAddressTableLookup\x12\x13\n\x0b\x61\x63\x63ount_key\x18\x01 \x01(\x0c\x12\x18\n\x10writable_indexes\x18\x02 \x01(\x0c\x12\x18\n\x10readonly_indexes\x18\x03 \x01(\x0c\"\xda\x05\n\x15TransactionStatusMeta\x12<\n\x03\x65rr\x18\x01 \x01(\x0b\x32/.solana.storage.ConfirmedBlock.TransactionError\x12\x0b\n\x03\x66\x65\x65\x18\x02 \x01(\x04\x12\x14\n\x0cpre_balances\x18\x03 \x03(\x04\x12\x15\n\rpost_balances\x18\x04 \x03(\x04\x12L\n\x12inner_instructions\x18\x05 \x03(\x0b\x32\x30.solana.storage.ConfirmedBlock.InnerInstructions\x12\x1f\n\x17inner_instructions_none\x18\n \x01(\x08\x12\x14\n\x0clog_messages\x18\x06 \x03(\t\x12\x19\n\x11log_messages_none\x18\x0b \x01(\x08\x12G\n\x12pre_token_balances\x18\x07 \x03(\x0b\x32+.solana.storage.ConfirmedBlock.TokenBalance\x12H\n\x13post_token_balances\x18\x08 \x03(\x0b\x32+.solana.storage.ConfirmedBlock.TokenBalance\x12\x36\n\x07rewards\x18\t \x03(\x0b\x32%.solana.storage.ConfirmedBlock.Reward\x12!\n\x19loaded_writable_addresses\x18\x0c \x03(\x0c\x12!\n\x19loaded_readonly_addresses\x18\r \x03(\x0c\x12>\n\x0breturn_data\x18\x0e \x01(\x0b\x32).solana.storage.ConfirmedBlock.ReturnData\x12\x18\n\x10return_data_none\x18\x0f \x01(\x08\x12#\n\x16\x63ompute_units_consumed\x18\x10 \x01(\x04H\x00\x88\x01\x01\x42\x19\n\x17_compute_units_consumed\"\x1f\n\x10TransactionError\x12\x0b\n\x03\x65rr\x18\x01 \x01(\x0c\"l\n\x11InnerInstructions\x12\r\n\x05index\x18\x01 \x01(\r\x12H\n\x0cinstructions\x18\x02 \x03(\x0b\x32\x32.solana.storage.ConfirmedBlock.CompiledInstruction\"O\n\x13\x43ompiledInstruction\x12\x18\n\x10program_id_index\x18\x01 \x01(\r\x12\x10\n\x08\x61\x63\x63ounts\x18\x02 \x01(\x0c\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\"\x9d\x01\n\x0cTokenBalance\x12\x15\n\raccount_index\x18\x01 \x01(\r\x12\x0c\n\x04mint\x18\x02 \x01(\t\x12\x45\n\x0fui_token_amount\x18\x03 \x01(\x0b\x32,.solana.storage.ConfirmedBlock.UiTokenAmount\x12\r\n\x05owner\x18\x04 \x01(\t\x12\x12\n\nprogram_id\x18\x05 \x01(\t\"^\n\rUiTokenAmount\x12\x11\n\tui_amount\x18\x01 \x01(\x01\x12\x10\n\x08\x64\x65\x63imals\x18\x02 \x01(\r\x12\x0e\n\x06\x61mount\x18\x03 \x01(\t\x12\x18\n\x10ui_amount_string\x18\x04 \x01(\t\".\n\nReturnData\x12\x12\n\nprogram_id\x18\x01 \x01(\x0c\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"\x94\x01\n\x06Reward\x12\x0e\n\x06pubkey\x18\x01 \x01(\t\x12\x10\n\x08lamports\x18\x02 \x01(\x03\x12\x14\n\x0cpost_balance\x18\x03 \x01(\x04\x12>\n\x0breward_type\x18\x04 \x01(\x0e\x32).solana.storage.ConfirmedBlock.RewardType\x12\x12\n\ncommission\x18\x05 \x01(\t\"A\n\x07Rewards\x12\x36\n\x07rewards\x18\x01 \x03(\x0b\x32%.solana.storage.ConfirmedBlock.Reward\"\"\n\rUnixTimestamp\x12\x11\n\ttimestamp\x18\x01 \x01(\x03\"#\n\x0b\x42lockHeight\x12\x14\n\x0c\x62lock_height\x18\x01 \x01(\x04*I\n\nRewardType\x12\x0f\n\x0bUnspecified\x10\x00\x12\x07\n\x03\x46\x65\x65\x10\x01\x12\x08\n\x04Rent\x10\x02\x12\x0b\n\x07Staking\x10\x03\x12\n\n\x06Voting\x10\x04\x62\x06proto3') 17 | 18 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 19 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'confirmed_block_pb2', globals()) 20 | if _descriptor._USE_C_DESCRIPTORS == False: 21 | 22 | DESCRIPTOR._options = None 23 | _REWARDTYPE._serialized_start=2742 24 | _REWARDTYPE._serialized_end=2815 25 | _CONFIRMEDBLOCK._serialized_start=57 26 | _CONFIRMEDBLOCK._serialized_end=404 27 | _CONFIRMEDTRANSACTION._serialized_start=407 28 | _CONFIRMEDTRANSACTION._serialized_end=562 29 | _TRANSACTION._serialized_start=564 30 | _TRANSACTION._serialized_end=654 31 | _MESSAGE._serialized_start=657 32 | _MESSAGE._serialized_end=958 33 | _MESSAGEHEADER._serialized_start=960 34 | _MESSAGEHEADER._serialized_end=1086 35 | _MESSAGEADDRESSTABLELOOKUP._serialized_start=1088 36 | _MESSAGEADDRESSTABLELOOKUP._serialized_end=1188 37 | _TRANSACTIONSTATUSMETA._serialized_start=1191 38 | _TRANSACTIONSTATUSMETA._serialized_end=1921 39 | _TRANSACTIONERROR._serialized_start=1923 40 | _TRANSACTIONERROR._serialized_end=1954 41 | _INNERINSTRUCTIONS._serialized_start=1956 42 | _INNERINSTRUCTIONS._serialized_end=2064 43 | _COMPILEDINSTRUCTION._serialized_start=2066 44 | _COMPILEDINSTRUCTION._serialized_end=2145 45 | _TOKENBALANCE._serialized_start=2148 46 | _TOKENBALANCE._serialized_end=2305 47 | _UITOKENAMOUNT._serialized_start=2307 48 | _UITOKENAMOUNT._serialized_end=2401 49 | _RETURNDATA._serialized_start=2403 50 | _RETURNDATA._serialized_end=2449 51 | _REWARD._serialized_start=2452 52 | _REWARD._serialized_end=2600 53 | _REWARDS._serialized_start=2602 54 | _REWARDS._serialized_end=2667 55 | _UNIXTIMESTAMP._serialized_start=2669 56 | _UNIXTIMESTAMP._serialized_end=2703 57 | _BLOCKHEIGHT._serialized_start=2705 58 | _BLOCKHEIGHT._serialized_end=2740 59 | # @@protoc_insertion_point(module_scope) 60 | -------------------------------------------------------------------------------- /jito_geyser/jito_geyser/generated/confirmed_block_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /jito_geyser/jito_geyser/generated/confirmed_block_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | -------------------------------------------------------------------------------- /jito_geyser/jito_geyser/generated/geyser_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: geyser.proto 4 | """Generated protocol buffer code.""" 5 | from google.protobuf.internal import builder as _builder 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 15 | import confirmed_block_pb2 as confirmed__block__pb2 16 | 17 | 18 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cgeyser.proto\x12\rsolana.geyser\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x15\x63onfirmed_block.proto\"\xa9\x01\n\x14PartialAccountUpdate\x12\x0c\n\x04slot\x18\x01 \x01(\x04\x12\x0e\n\x06pubkey\x18\x02 \x01(\x0c\x12\r\n\x05owner\x18\x03 \x01(\x0c\x12\x12\n\nis_startup\x18\x04 \x01(\x08\x12\x0b\n\x03seq\x18\x05 \x01(\x04\x12\x19\n\x0ctx_signature\x18\x06 \x01(\tH\x00\x88\x01\x01\x12\x17\n\x0freplica_version\x18\x07 \x01(\rB\x0f\n\r_tx_signature\"\xed\x01\n\rAccountUpdate\x12\x0c\n\x04slot\x18\x01 \x01(\x04\x12\x0e\n\x06pubkey\x18\x02 \x01(\x0c\x12\x10\n\x08lamports\x18\x03 \x01(\x04\x12\r\n\x05owner\x18\x04 \x01(\x0c\x12\x15\n\ris_executable\x18\x05 \x01(\x08\x12\x12\n\nrent_epoch\x18\x06 \x01(\x04\x12\x0c\n\x04\x64\x61ta\x18\x07 \x01(\x0c\x12\x0b\n\x03seq\x18\x08 \x01(\x04\x12\x12\n\nis_startup\x18\t \x01(\x08\x12\x19\n\x0ctx_signature\x18\n \x01(\tH\x00\x88\x01\x01\x12\x17\n\x0freplica_version\x18\x0b \x01(\rB\x0f\n\r_tx_signature\"u\n\nSlotUpdate\x12\x0c\n\x04slot\x18\x01 \x01(\x04\x12\x18\n\x0bparent_slot\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12/\n\x06status\x18\x03 \x01(\x0e\x32\x1f.solana.geyser.SlotUpdateStatusB\x0e\n\x0c_parent_slot\"o\n\x15TimestampedSlotUpdate\x12&\n\x02ts\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\x0bslot_update\x18\x02 \x01(\x0b\x32\x19.solana.geyser.SlotUpdate\"x\n\x18TimestampedAccountUpdate\x12&\n\x02ts\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x34\n\x0e\x61\x63\x63ount_update\x18\x02 \x01(\x0b\x32\x1c.solana.geyser.AccountUpdate\"$\n\"SubscribeTransactionUpdatesRequest\"\x1e\n\x1cSubscribeBlockUpdatesRequest\"\x91\x01\n\x19MaybePartialAccountUpdate\x12\x45\n\x16partial_account_update\x18\x01 \x01(\x0b\x32#.solana.geyser.PartialAccountUpdateH\x00\x12&\n\x02hb\x18\x02 \x01(\x0b\x32\x18.solana.geyser.HeartbeatH\x00\x42\x05\n\x03msg\"\x0b\n\tHeartbeat\"\x0e\n\x0c\x45mptyRequest\"\xc2\x01\n\x0b\x42lockUpdate\x12\x0c\n\x04slot\x18\x01 \x01(\x04\x12\x11\n\tblockhash\x18\x02 \x01(\t\x12\x36\n\x07rewards\x18\x03 \x03(\x0b\x32%.solana.storage.ConfirmedBlock.Reward\x12.\n\nblock_time\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x19\n\x0c\x62lock_height\x18\x05 \x01(\x04H\x00\x88\x01\x01\x42\x0f\n\r_block_height\"r\n\x16TimestampedBlockUpdate\x12&\n\x02ts\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x30\n\x0c\x62lock_update\x18\x02 \x01(\x0b\x32\x1a.solana.geyser.BlockUpdate\"\x96\x01\n\x11TransactionUpdate\x12\x0c\n\x04slot\x18\x01 \x01(\x04\x12\x11\n\tsignature\x18\x02 \x01(\t\x12\x0f\n\x07is_vote\x18\x03 \x01(\x08\x12\x0e\n\x06tx_idx\x18\x04 \x01(\x04\x12?\n\x02tx\x18\x05 \x01(\x0b\x32\x33.solana.storage.ConfirmedBlock.ConfirmedTransaction\"}\n\x1cTimestampedTransactionUpdate\x12&\n\x02ts\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x35\n\x0btransaction\x18\x02 \x01(\x0b\x32 .solana.geyser.TransactionUpdate\"\x1c\n\x1aSubscribeSlotUpdateRequest\"2\n\x1eSubscribeAccountUpdatesRequest\x12\x10\n\x08\x61\x63\x63ounts\x18\x01 \x03(\x0c\"3\n\x1fSubscribeProgramsUpdatesRequest\x12\x10\n\x08programs\x18\x01 \x03(\x0c\"C\n%SubscribePartialAccountUpdatesRequest\x12\x1a\n\x12skip_vote_accounts\x18\x01 \x01(\x08\"=\n\x1cGetHeartbeatIntervalResponse\x12\x1d\n\x15heartbeat_interval_ms\x18\x01 \x01(\x04*<\n\x10SlotUpdateStatus\x12\r\n\tCONFIRMED\x10\x00\x12\r\n\tPROCESSED\x10\x01\x12\n\n\x06ROOTED\x10\x02\x32\xc4\x06\n\x06Geyser\x12\x62\n\x14GetHeartbeatInterval\x12\x1b.solana.geyser.EmptyRequest\x1a+.solana.geyser.GetHeartbeatIntervalResponse\"\x00\x12u\n\x17SubscribeAccountUpdates\x12-.solana.geyser.SubscribeAccountUpdatesRequest\x1a\'.solana.geyser.TimestampedAccountUpdate\"\x00\x30\x01\x12v\n\x17SubscribeProgramUpdates\x12..solana.geyser.SubscribeProgramsUpdatesRequest\x1a\'.solana.geyser.TimestampedAccountUpdate\"\x00\x30\x01\x12\x84\x01\n\x1eSubscribePartialAccountUpdates\x12\x34.solana.geyser.SubscribePartialAccountUpdatesRequest\x1a(.solana.geyser.MaybePartialAccountUpdate\"\x00\x30\x01\x12k\n\x14SubscribeSlotUpdates\x12).solana.geyser.SubscribeSlotUpdateRequest\x1a$.solana.geyser.TimestampedSlotUpdate\"\x00\x30\x01\x12\x81\x01\n\x1bSubscribeTransactionUpdates\x12\x31.solana.geyser.SubscribeTransactionUpdatesRequest\x1a+.solana.geyser.TimestampedTransactionUpdate\"\x00\x30\x01\x12o\n\x15SubscribeBlockUpdates\x12+.solana.geyser.SubscribeBlockUpdatesRequest\x1a%.solana.geyser.TimestampedBlockUpdate\"\x00\x30\x01\x62\x06proto3') 19 | 20 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 21 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'geyser_pb2', globals()) 22 | if _descriptor._USE_C_DESCRIPTORS == False: 23 | 24 | DESCRIPTOR._options = None 25 | _SLOTUPDATESTATUS._serialized_start=1960 26 | _SLOTUPDATESTATUS._serialized_end=2020 27 | _PARTIALACCOUNTUPDATE._serialized_start=88 28 | _PARTIALACCOUNTUPDATE._serialized_end=257 29 | _ACCOUNTUPDATE._serialized_start=260 30 | _ACCOUNTUPDATE._serialized_end=497 31 | _SLOTUPDATE._serialized_start=499 32 | _SLOTUPDATE._serialized_end=616 33 | _TIMESTAMPEDSLOTUPDATE._serialized_start=618 34 | _TIMESTAMPEDSLOTUPDATE._serialized_end=729 35 | _TIMESTAMPEDACCOUNTUPDATE._serialized_start=731 36 | _TIMESTAMPEDACCOUNTUPDATE._serialized_end=851 37 | _SUBSCRIBETRANSACTIONUPDATESREQUEST._serialized_start=853 38 | _SUBSCRIBETRANSACTIONUPDATESREQUEST._serialized_end=889 39 | _SUBSCRIBEBLOCKUPDATESREQUEST._serialized_start=891 40 | _SUBSCRIBEBLOCKUPDATESREQUEST._serialized_end=921 41 | _MAYBEPARTIALACCOUNTUPDATE._serialized_start=924 42 | _MAYBEPARTIALACCOUNTUPDATE._serialized_end=1069 43 | _HEARTBEAT._serialized_start=1071 44 | _HEARTBEAT._serialized_end=1082 45 | _EMPTYREQUEST._serialized_start=1084 46 | _EMPTYREQUEST._serialized_end=1098 47 | _BLOCKUPDATE._serialized_start=1101 48 | _BLOCKUPDATE._serialized_end=1295 49 | _TIMESTAMPEDBLOCKUPDATE._serialized_start=1297 50 | _TIMESTAMPEDBLOCKUPDATE._serialized_end=1411 51 | _TRANSACTIONUPDATE._serialized_start=1414 52 | _TRANSACTIONUPDATE._serialized_end=1564 53 | _TIMESTAMPEDTRANSACTIONUPDATE._serialized_start=1566 54 | _TIMESTAMPEDTRANSACTIONUPDATE._serialized_end=1691 55 | _SUBSCRIBESLOTUPDATEREQUEST._serialized_start=1693 56 | _SUBSCRIBESLOTUPDATEREQUEST._serialized_end=1721 57 | _SUBSCRIBEACCOUNTUPDATESREQUEST._serialized_start=1723 58 | _SUBSCRIBEACCOUNTUPDATESREQUEST._serialized_end=1773 59 | _SUBSCRIBEPROGRAMSUPDATESREQUEST._serialized_start=1775 60 | _SUBSCRIBEPROGRAMSUPDATESREQUEST._serialized_end=1826 61 | _SUBSCRIBEPARTIALACCOUNTUPDATESREQUEST._serialized_start=1828 62 | _SUBSCRIBEPARTIALACCOUNTUPDATESREQUEST._serialized_end=1895 63 | _GETHEARTBEATINTERVALRESPONSE._serialized_start=1897 64 | _GETHEARTBEATINTERVALRESPONSE._serialized_end=1958 65 | _GEYSER._serialized_start=2023 66 | _GEYSER._serialized_end=2859 67 | # @@protoc_insertion_point(module_scope) 68 | -------------------------------------------------------------------------------- /jito_geyser/jito_geyser/generated/geyser_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | import abc 6 | import collections.abc 7 | import geyser_pb2 8 | import grpc 9 | 10 | class GeyserStub: 11 | """The following __must__ be assumed: 12 | - Clients may receive data for slots out of order. 13 | - Clients may receive account updates for a given slot out of order. 14 | """ 15 | 16 | def __init__(self, channel: grpc.Channel) -> None: ... 17 | GetHeartbeatInterval: grpc.UnaryUnaryMultiCallable[ 18 | geyser_pb2.EmptyRequest, 19 | geyser_pb2.GetHeartbeatIntervalResponse, 20 | ] 21 | """Invoke to get the expected heartbeat interval.""" 22 | SubscribeAccountUpdates: grpc.UnaryStreamMultiCallable[ 23 | geyser_pb2.SubscribeAccountUpdatesRequest, 24 | geyser_pb2.TimestampedAccountUpdate, 25 | ] 26 | """Subscribes to account updates in the accounts database; additionally pings clients with empty heartbeats. 27 | Upon initially connecting the client can expect a `highest_write_slot` set in the http headers. 28 | Subscribe to account updates 29 | """ 30 | SubscribeProgramUpdates: grpc.UnaryStreamMultiCallable[ 31 | geyser_pb2.SubscribeProgramsUpdatesRequest, 32 | geyser_pb2.TimestampedAccountUpdate, 33 | ] 34 | """Subscribes to updates given a list of program IDs. When an account update comes in that's owned by a provided 35 | program id, one will receive an update 36 | """ 37 | SubscribePartialAccountUpdates: grpc.UnaryStreamMultiCallable[ 38 | geyser_pb2.SubscribePartialAccountUpdatesRequest, 39 | geyser_pb2.MaybePartialAccountUpdate, 40 | ] 41 | """Functions similarly to `SubscribeAccountUpdates`, but consumes less bandwidth. 42 | Returns the highest slot seen thus far in the http headers named `highest-write-slot`. 43 | """ 44 | SubscribeSlotUpdates: grpc.UnaryStreamMultiCallable[ 45 | geyser_pb2.SubscribeSlotUpdateRequest, 46 | geyser_pb2.TimestampedSlotUpdate, 47 | ] 48 | """Subscribes to slot updates. 49 | Returns the highest slot seen thus far in the http headers named `highest-write-slot`. 50 | """ 51 | SubscribeTransactionUpdates: grpc.UnaryStreamMultiCallable[ 52 | geyser_pb2.SubscribeTransactionUpdatesRequest, 53 | geyser_pb2.TimestampedTransactionUpdate, 54 | ] 55 | """Subscribes to transaction updates.""" 56 | SubscribeBlockUpdates: grpc.UnaryStreamMultiCallable[ 57 | geyser_pb2.SubscribeBlockUpdatesRequest, 58 | geyser_pb2.TimestampedBlockUpdate, 59 | ] 60 | """Subscribes to block updates.""" 61 | 62 | class GeyserServicer(metaclass=abc.ABCMeta): 63 | """The following __must__ be assumed: 64 | - Clients may receive data for slots out of order. 65 | - Clients may receive account updates for a given slot out of order. 66 | """ 67 | 68 | @abc.abstractmethod 69 | def GetHeartbeatInterval( 70 | self, 71 | request: geyser_pb2.EmptyRequest, 72 | context: grpc.ServicerContext, 73 | ) -> geyser_pb2.GetHeartbeatIntervalResponse: 74 | """Invoke to get the expected heartbeat interval.""" 75 | @abc.abstractmethod 76 | def SubscribeAccountUpdates( 77 | self, 78 | request: geyser_pb2.SubscribeAccountUpdatesRequest, 79 | context: grpc.ServicerContext, 80 | ) -> collections.abc.Iterator[geyser_pb2.TimestampedAccountUpdate]: 81 | """Subscribes to account updates in the accounts database; additionally pings clients with empty heartbeats. 82 | Upon initially connecting the client can expect a `highest_write_slot` set in the http headers. 83 | Subscribe to account updates 84 | """ 85 | @abc.abstractmethod 86 | def SubscribeProgramUpdates( 87 | self, 88 | request: geyser_pb2.SubscribeProgramsUpdatesRequest, 89 | context: grpc.ServicerContext, 90 | ) -> collections.abc.Iterator[geyser_pb2.TimestampedAccountUpdate]: 91 | """Subscribes to updates given a list of program IDs. When an account update comes in that's owned by a provided 92 | program id, one will receive an update 93 | """ 94 | @abc.abstractmethod 95 | def SubscribePartialAccountUpdates( 96 | self, 97 | request: geyser_pb2.SubscribePartialAccountUpdatesRequest, 98 | context: grpc.ServicerContext, 99 | ) -> collections.abc.Iterator[geyser_pb2.MaybePartialAccountUpdate]: 100 | """Functions similarly to `SubscribeAccountUpdates`, but consumes less bandwidth. 101 | Returns the highest slot seen thus far in the http headers named `highest-write-slot`. 102 | """ 103 | @abc.abstractmethod 104 | def SubscribeSlotUpdates( 105 | self, 106 | request: geyser_pb2.SubscribeSlotUpdateRequest, 107 | context: grpc.ServicerContext, 108 | ) -> collections.abc.Iterator[geyser_pb2.TimestampedSlotUpdate]: 109 | """Subscribes to slot updates. 110 | Returns the highest slot seen thus far in the http headers named `highest-write-slot`. 111 | """ 112 | @abc.abstractmethod 113 | def SubscribeTransactionUpdates( 114 | self, 115 | request: geyser_pb2.SubscribeTransactionUpdatesRequest, 116 | context: grpc.ServicerContext, 117 | ) -> collections.abc.Iterator[geyser_pb2.TimestampedTransactionUpdate]: 118 | """Subscribes to transaction updates.""" 119 | @abc.abstractmethod 120 | def SubscribeBlockUpdates( 121 | self, 122 | request: geyser_pb2.SubscribeBlockUpdatesRequest, 123 | context: grpc.ServicerContext, 124 | ) -> collections.abc.Iterator[geyser_pb2.TimestampedBlockUpdate]: 125 | """Subscribes to block updates.""" 126 | 127 | def add_GeyserServicer_to_server(servicer: GeyserServicer, server: grpc.Server) -> None: ... 128 | -------------------------------------------------------------------------------- /jito_geyser/jito_geyser/generated/transaction_by_addr_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: transaction_by_addr.proto 4 | """Generated protocol buffer code.""" 5 | from google.protobuf.internal import builder as _builder 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | 15 | 16 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19transaction_by_addr.proto\x12 solana.storage.TransactionByAddr\"a\n\x11TransactionByAddr\x12L\n\x0btx_by_addrs\x18\x01 \x03(\x0b\x32\x37.solana.storage.TransactionByAddr.TransactionByAddrInfo\"\xf5\x01\n\x15TransactionByAddrInfo\x12\x11\n\tsignature\x18\x01 \x01(\x0c\x12?\n\x03\x65rr\x18\x02 \x01(\x0b\x32\x32.solana.storage.TransactionByAddr.TransactionError\x12\r\n\x05index\x18\x03 \x01(\r\x12\x34\n\x04memo\x18\x04 \x01(\x0b\x32&.solana.storage.TransactionByAddr.Memo\x12\x43\n\nblock_time\x18\x05 \x01(\x0b\x32/.solana.storage.TransactionByAddr.UnixTimestamp\"\x14\n\x04Memo\x12\x0c\n\x04memo\x18\x01 \x01(\t\"\x87\x02\n\x10TransactionError\x12Q\n\x11transaction_error\x18\x01 \x01(\x0e\x32\x36.solana.storage.TransactionByAddr.TransactionErrorType\x12M\n\x11instruction_error\x18\x02 \x01(\x0b\x32\x32.solana.storage.TransactionByAddr.InstructionError\x12Q\n\x13transaction_details\x18\x03 \x01(\x0b\x32\x34.solana.storage.TransactionByAddr.TransactionDetails\"\xa7\x01\n\x10InstructionError\x12\r\n\x05index\x18\x01 \x01(\r\x12\x45\n\x05\x65rror\x18\x02 \x01(\x0e\x32\x36.solana.storage.TransactionByAddr.InstructionErrorType\x12=\n\x06\x63ustom\x18\x03 \x01(\x0b\x32-.solana.storage.TransactionByAddr.CustomError\"#\n\x12TransactionDetails\x12\r\n\x05index\x18\x01 \x01(\r\"\"\n\rUnixTimestamp\x12\x11\n\ttimestamp\x18\x01 \x01(\x03\"\x1d\n\x0b\x43ustomError\x12\x0e\n\x06\x63ustom\x18\x01 \x01(\r*\xa6\x08\n\x14TransactionErrorType\x12\x12\n\x0e\x41\x43\x43OUNT_IN_USE\x10\x00\x12\x18\n\x14\x41\x43\x43OUNT_LOADED_TWICE\x10\x01\x12\x15\n\x11\x41\x43\x43OUNT_NOT_FOUND\x10\x02\x12\x1d\n\x19PROGRAM_ACCOUNT_NOT_FOUND\x10\x03\x12\x1e\n\x1aINSUFFICIENT_FUNDS_FOR_FEE\x10\x04\x12\x1b\n\x17INVALID_ACCOUNT_FOR_FEE\x10\x05\x12\x15\n\x11\x41LREADY_PROCESSED\x10\x06\x12\x17\n\x13\x42LOCKHASH_NOT_FOUND\x10\x07\x12\x15\n\x11INSTRUCTION_ERROR\x10\x08\x12\x17\n\x13\x43\x41LL_CHAIN_TOO_DEEP\x10\t\x12\x1d\n\x19MISSING_SIGNATURE_FOR_FEE\x10\n\x12\x19\n\x15INVALID_ACCOUNT_INDEX\x10\x0b\x12\x15\n\x11SIGNATURE_FAILURE\x10\x0c\x12!\n\x1dINVALID_PROGRAM_FOR_EXECUTION\x10\r\x12\x14\n\x10SANITIZE_FAILURE\x10\x0e\x12\x17\n\x13\x43LUSTER_MAINTENANCE\x10\x0f\x12!\n\x1d\x41\x43\x43OUNT_BORROW_OUTSTANDING_TX\x10\x10\x12%\n!WOULD_EXCEED_MAX_BLOCK_COST_LIMIT\x10\x11\x12\x17\n\x13UNSUPPORTED_VERSION\x10\x12\x12\x1c\n\x18INVALID_WRITABLE_ACCOUNT\x10\x13\x12\'\n#WOULD_EXCEED_MAX_ACCOUNT_COST_LIMIT\x10\x14\x12)\n%WOULD_EXCEED_ACCOUNT_DATA_BLOCK_LIMIT\x10\x15\x12\x1a\n\x16TOO_MANY_ACCOUNT_LOCKS\x10\x16\x12\"\n\x1e\x41\x44\x44RESS_LOOKUP_TABLE_NOT_FOUND\x10\x17\x12&\n\"INVALID_ADDRESS_LOOKUP_TABLE_OWNER\x10\x18\x12%\n!INVALID_ADDRESS_LOOKUP_TABLE_DATA\x10\x19\x12&\n\"INVALID_ADDRESS_LOOKUP_TABLE_INDEX\x10\x1a\x12\x1f\n\x1bINVALID_RENT_PAYING_ACCOUNT\x10\x1b\x12$\n WOULD_EXCEED_MAX_VOTE_COST_LIMIT\x10\x1c\x12)\n%WOULD_EXCEED_ACCOUNT_DATA_TOTAL_LIMIT\x10\x1d\x12\x19\n\x15\x44UPLICATE_INSTRUCTION\x10\x1e\x12\x1f\n\x1bINSUFFICIENT_FUNDS_FOR_RENT\x10\x1f\x12\x19\n\x15\x42UNDLE_NOT_CONTINUOUS\x10 \x12\x15\n\x11SKIPPED_EXECUTION\x10!*\x9e\x0b\n\x14InstructionErrorType\x12\x11\n\rGENERIC_ERROR\x10\x00\x12\x14\n\x10INVALID_ARGUMENT\x10\x01\x12\x1c\n\x18INVALID_INSTRUCTION_DATA\x10\x02\x12\x18\n\x14INVALID_ACCOUNT_DATA\x10\x03\x12\x1a\n\x16\x41\x43\x43OUNT_DATA_TOO_SMALL\x10\x04\x12\x16\n\x12INSUFFICIENT_FUNDS\x10\x05\x12\x18\n\x14INCORRECT_PROGRAM_ID\x10\x06\x12\x1e\n\x1aMISSING_REQUIRED_SIGNATURE\x10\x07\x12\x1f\n\x1b\x41\x43\x43OUNT_ALREADY_INITIALIZED\x10\x08\x12\x19\n\x15UNINITIALIZED_ACCOUNT\x10\t\x12\x1a\n\x16UNBALANCED_INSTRUCTION\x10\n\x12\x17\n\x13MODIFIED_PROGRAM_ID\x10\x0b\x12\"\n\x1e\x45XTERNAL_ACCOUNT_LAMPORT_SPEND\x10\x0c\x12\"\n\x1e\x45XTERNAL_ACCOUNT_DATA_MODIFIED\x10\r\x12\x1b\n\x17READONLY_LAMPORT_CHANGE\x10\x0e\x12\x1a\n\x16READONLY_DATA_MODIFIED\x10\x0f\x12\x1b\n\x17\x44UPLICATE_ACCOUNT_INDEX\x10\x10\x12\x17\n\x13\x45XECUTABLE_MODIFIED\x10\x11\x12\x17\n\x13RENT_EPOCH_MODIFIED\x10\x12\x12\x1b\n\x17NOT_ENOUGH_ACCOUNT_KEYS\x10\x13\x12\x1d\n\x19\x41\x43\x43OUNT_DATA_SIZE_CHANGED\x10\x14\x12\x1a\n\x16\x41\x43\x43OUNT_NOT_EXECUTABLE\x10\x15\x12\x19\n\x15\x41\x43\x43OUNT_BORROW_FAILED\x10\x16\x12\x1e\n\x1a\x41\x43\x43OUNT_BORROW_OUTSTANDING\x10\x17\x12!\n\x1d\x44UPLICATE_ACCOUNT_OUT_OF_SYNC\x10\x18\x12\n\n\x06\x43USTOM\x10\x19\x12\x11\n\rINVALID_ERROR\x10\x1a\x12\x1c\n\x18\x45XECUTABLE_DATA_MODIFIED\x10\x1b\x12\x1d\n\x19\x45XECUTABLE_LAMPORT_CHANGE\x10\x1c\x12&\n\"EXECUTABLE_ACCOUNT_NOT_RENT_EXEMPT\x10\x1d\x12\x1a\n\x16UNSUPPORTED_PROGRAM_ID\x10\x1e\x12\x0e\n\nCALL_DEPTH\x10\x1f\x12\x13\n\x0fMISSING_ACCOUNT\x10 \x12\x1a\n\x16REENTRANCY_NOT_ALLOWED\x10!\x12\x1c\n\x18MAX_SEED_LENGTH_EXCEEDED\x10\"\x12\x11\n\rINVALID_SEEDS\x10#\x12\x13\n\x0fINVALID_REALLOC\x10$\x12!\n\x1d\x43OMPUTATIONAL_BUDGET_EXCEEDED\x10%\x12\x18\n\x14PRIVILEGE_ESCALATION\x10&\x12%\n!PROGRAM_ENVIRONMENT_SETUP_FAILURE\x10\'\x12\x1e\n\x1aPROGRAM_FAILED_TO_COMPLETE\x10(\x12\x1d\n\x19PROGRAM_FAILED_TO_COMPILE\x10)\x12\r\n\tIMMUTABLE\x10*\x12\x17\n\x13INCORRECT_AUTHORITY\x10+\x12\x12\n\x0e\x42ORSH_IO_ERROR\x10,\x12\x1b\n\x17\x41\x43\x43OUNT_NOT_RENT_EXEMPT\x10-\x12\x19\n\x15INVALID_ACCOUNT_OWNER\x10.\x12\x17\n\x13\x41RITHMETIC_OVERFLOW\x10/\x12\x16\n\x12UNSUPPORTED_SYSVAR\x10\x30\x12\x11\n\rILLEGAL_OWNER\x10\x31\x12#\n\x1fMAX_ACCOUNTS_DATA_SIZE_EXCEEDED\x10\x32\x12\x19\n\x15MAX_ACCOUNTS_EXCEEDED\x10\x33\x62\x06proto3') 17 | 18 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 19 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'transaction_by_addr_pb2', globals()) 20 | if _descriptor._USE_C_DESCRIPTORS == False: 21 | 22 | DESCRIPTOR._options = None 23 | _TRANSACTIONERRORTYPE._serialized_start=973 24 | _TRANSACTIONERRORTYPE._serialized_end=2035 25 | _INSTRUCTIONERRORTYPE._serialized_start=2038 26 | _INSTRUCTIONERRORTYPE._serialized_end=3476 27 | _TRANSACTIONBYADDR._serialized_start=63 28 | _TRANSACTIONBYADDR._serialized_end=160 29 | _TRANSACTIONBYADDRINFO._serialized_start=163 30 | _TRANSACTIONBYADDRINFO._serialized_end=408 31 | _MEMO._serialized_start=410 32 | _MEMO._serialized_end=430 33 | _TRANSACTIONERROR._serialized_start=433 34 | _TRANSACTIONERROR._serialized_end=696 35 | _INSTRUCTIONERROR._serialized_start=699 36 | _INSTRUCTIONERROR._serialized_end=866 37 | _TRANSACTIONDETAILS._serialized_start=868 38 | _TRANSACTIONDETAILS._serialized_end=903 39 | _UNIXTIMESTAMP._serialized_start=905 40 | _UNIXTIMESTAMP._serialized_end=939 41 | _CUSTOMERROR._serialized_start=941 42 | _CUSTOMERROR._serialized_end=970 43 | # @@protoc_insertion_point(module_scope) 44 | -------------------------------------------------------------------------------- /jito_geyser/jito_geyser/generated/transaction_by_addr_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /jito_geyser/jito_geyser/generated/transaction_by_addr_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | -------------------------------------------------------------------------------- /jito_geyser/poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "grpcio" 5 | version = "1.51.1" 6 | description = "HTTP/2-based RPC framework" 7 | category = "main" 8 | optional = false 9 | python-versions = ">=3.7" 10 | files = [ 11 | {file = "grpcio-1.51.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:cc2bece1737b44d878cc1510ea04469a8073dbbcdd762175168937ae4742dfb3"}, 12 | {file = "grpcio-1.51.1-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:e223a9793522680beae44671b9ed8f6d25bbe5ddf8887e66aebad5e0686049ef"}, 13 | {file = "grpcio-1.51.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:24ac1154c4b2ab4a0c5326a76161547e70664cd2c39ba75f00fc8a2170964ea2"}, 14 | {file = "grpcio-1.51.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4ef09f8997c4be5f3504cefa6b5c6cc3cf648274ce3cede84d4342a35d76db6"}, 15 | {file = "grpcio-1.51.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8a0b77e992c64880e6efbe0086fe54dfc0bbd56f72a92d9e48264dcd2a3db98"}, 16 | {file = "grpcio-1.51.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:eacad297ea60c72dd280d3353d93fb1dcca952ec11de6bb3c49d12a572ba31dd"}, 17 | {file = "grpcio-1.51.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:16c71740640ba3a882f50b01bf58154681d44b51f09a5728180a8fdc66c67bd5"}, 18 | {file = "grpcio-1.51.1-cp310-cp310-win32.whl", hash = "sha256:29cb97d41a4ead83b7bcad23bdb25bdd170b1e2cba16db6d3acbb090bc2de43c"}, 19 | {file = "grpcio-1.51.1-cp310-cp310-win_amd64.whl", hash = "sha256:9ff42c5620b4e4530609e11afefa4a62ca91fa0abb045a8957e509ef84e54d30"}, 20 | {file = "grpcio-1.51.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:bc59f7ba87972ab236f8669d8ca7400f02a0eadf273ca00e02af64d588046f02"}, 21 | {file = "grpcio-1.51.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:3c2b3842dcf870912da31a503454a33a697392f60c5e2697c91d133130c2c85d"}, 22 | {file = "grpcio-1.51.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22b011674090594f1f3245960ced7386f6af35485a38901f8afee8ad01541dbd"}, 23 | {file = "grpcio-1.51.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49d680356a975d9c66a678eb2dde192d5dc427a7994fb977363634e781614f7c"}, 24 | {file = "grpcio-1.51.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:094e64236253590d9d4075665c77b329d707b6fca864dd62b144255e199b4f87"}, 25 | {file = "grpcio-1.51.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:257478300735ce3c98d65a930bbda3db172bd4e00968ba743e6a1154ea6edf10"}, 26 | {file = "grpcio-1.51.1-cp311-cp311-win32.whl", hash = "sha256:5a6ebcdef0ef12005d56d38be30f5156d1cb3373b52e96f147f4a24b0ddb3a9d"}, 27 | {file = "grpcio-1.51.1-cp311-cp311-win_amd64.whl", hash = "sha256:3f9b0023c2c92bebd1be72cdfca23004ea748be1813a66d684d49d67d836adde"}, 28 | {file = "grpcio-1.51.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:cd3baccea2bc5c38aeb14e5b00167bd4e2373a373a5e4d8d850bd193edad150c"}, 29 | {file = "grpcio-1.51.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:17ec9b13cec4a286b9e606b48191e560ca2f3bbdf3986f91e480a95d1582e1a7"}, 30 | {file = "grpcio-1.51.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:fbdbe9a849854fe484c00823f45b7baab159bdd4a46075302281998cb8719df5"}, 31 | {file = "grpcio-1.51.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31bb6bc7ff145e2771c9baf612f4b9ebbc9605ccdc5f3ff3d5553de7fc0e0d79"}, 32 | {file = "grpcio-1.51.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e473525c28251558337b5c1ad3fa969511e42304524a4e404065e165b084c9e4"}, 33 | {file = "grpcio-1.51.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6f0b89967ee11f2b654c23b27086d88ad7bf08c0b3c2a280362f28c3698b2896"}, 34 | {file = "grpcio-1.51.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7942b32a291421460d6a07883033e392167d30724aa84987e6956cd15f1a21b9"}, 35 | {file = "grpcio-1.51.1-cp37-cp37m-win32.whl", hash = "sha256:f96ace1540223f26fbe7c4ebbf8a98e3929a6aa0290c8033d12526847b291c0f"}, 36 | {file = "grpcio-1.51.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f1fec3abaf274cdb85bf3878167cfde5ad4a4d97c68421afda95174de85ba813"}, 37 | {file = "grpcio-1.51.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:0e1a9e1b4a23808f1132aa35f968cd8e659f60af3ffd6fb00bcf9a65e7db279f"}, 38 | {file = "grpcio-1.51.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:6df3b63538c362312bc5fa95fb965069c65c3ea91d7ce78ad9c47cab57226f54"}, 39 | {file = "grpcio-1.51.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:172405ca6bdfedd6054c74c62085946e45ad4d9cec9f3c42b4c9a02546c4c7e9"}, 40 | {file = "grpcio-1.51.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:506b9b7a4cede87d7219bfb31014d7b471cfc77157da9e820a737ec1ea4b0663"}, 41 | {file = "grpcio-1.51.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fb93051331acbb75b49a2a0fd9239c6ba9528f6bdc1dd400ad1cb66cf864292"}, 42 | {file = "grpcio-1.51.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5dca372268c6ab6372d37d6b9f9343e7e5b4bc09779f819f9470cd88b2ece3c3"}, 43 | {file = "grpcio-1.51.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:471d39d3370ca923a316d49c8aac66356cea708a11e647e3bdc3d0b5de4f0a40"}, 44 | {file = "grpcio-1.51.1-cp38-cp38-win32.whl", hash = "sha256:75e29a90dc319f0ad4d87ba6d20083615a00d8276b51512e04ad7452b5c23b04"}, 45 | {file = "grpcio-1.51.1-cp38-cp38-win_amd64.whl", hash = "sha256:f1158bccbb919da42544a4d3af5d9296a3358539ffa01018307337365a9a0c64"}, 46 | {file = "grpcio-1.51.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:59dffade859f157bcc55243714d57b286da6ae16469bf1ac0614d281b5f49b67"}, 47 | {file = "grpcio-1.51.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:dad6533411d033b77f5369eafe87af8583178efd4039c41d7515d3336c53b4f1"}, 48 | {file = "grpcio-1.51.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:4c4423ea38a7825b8fed8934d6d9aeebdf646c97e3c608c3b0bcf23616f33877"}, 49 | {file = "grpcio-1.51.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0dc5354e38e5adf2498312f7241b14c7ce3484eefa0082db4297189dcbe272e6"}, 50 | {file = "grpcio-1.51.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97d67983189e2e45550eac194d6234fc38b8c3b5396c153821f2d906ed46e0ce"}, 51 | {file = "grpcio-1.51.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:538d981818e49b6ed1e9c8d5e5adf29f71c4e334e7d459bf47e9b7abb3c30e09"}, 52 | {file = "grpcio-1.51.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9235dcd5144a83f9ca6f431bd0eccc46b90e2c22fe27b7f7d77cabb2fb515595"}, 53 | {file = "grpcio-1.51.1-cp39-cp39-win32.whl", hash = "sha256:aacb54f7789ede5cbf1d007637f792d3e87f1c9841f57dd51abf89337d1b8472"}, 54 | {file = "grpcio-1.51.1-cp39-cp39-win_amd64.whl", hash = "sha256:2b170eaf51518275c9b6b22ccb59450537c5a8555326fd96ff7391b5dd75303c"}, 55 | {file = "grpcio-1.51.1.tar.gz", hash = "sha256:e6dfc2b6567b1c261739b43d9c59d201c1b89e017afd9e684d85aa7a186c9f7a"}, 56 | ] 57 | 58 | [package.extras] 59 | protobuf = ["grpcio-tools (>=1.51.1)"] 60 | 61 | [[package]] 62 | name = "isort" 63 | version = "5.12.0" 64 | description = "A Python utility / library to sort Python imports." 65 | category = "main" 66 | optional = false 67 | python-versions = ">=3.8.0" 68 | files = [ 69 | {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, 70 | {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, 71 | ] 72 | 73 | [package.extras] 74 | colors = ["colorama (>=0.4.3)"] 75 | pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] 76 | plugins = ["setuptools"] 77 | requirements-deprecated-finder = ["pip-api", "pipreqs"] 78 | 79 | [[package]] 80 | name = "protobuf" 81 | version = "4.21.12" 82 | description = "" 83 | category = "main" 84 | optional = false 85 | python-versions = ">=3.7" 86 | files = [ 87 | {file = "protobuf-4.21.12-cp310-abi3-win32.whl", hash = "sha256:b135410244ebe777db80298297a97fbb4c862c881b4403b71bac9d4107d61fd1"}, 88 | {file = "protobuf-4.21.12-cp310-abi3-win_amd64.whl", hash = "sha256:89f9149e4a0169cddfc44c74f230d7743002e3aa0b9472d8c28f0388102fc4c2"}, 89 | {file = "protobuf-4.21.12-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:299ea899484ee6f44604deb71f424234f654606b983cb496ea2a53e3c63ab791"}, 90 | {file = "protobuf-4.21.12-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:d1736130bce8cf131ac7957fa26880ca19227d4ad68b4888b3be0dea1f95df97"}, 91 | {file = "protobuf-4.21.12-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:78a28c9fa223998472886c77042e9b9afb6fe4242bd2a2a5aced88e3f4422aa7"}, 92 | {file = "protobuf-4.21.12-cp37-cp37m-win32.whl", hash = "sha256:3d164928ff0727d97022957c2b849250ca0e64777ee31efd7d6de2e07c494717"}, 93 | {file = "protobuf-4.21.12-cp37-cp37m-win_amd64.whl", hash = "sha256:f45460f9ee70a0ec1b6694c6e4e348ad2019275680bd68a1d9314b8c7e01e574"}, 94 | {file = "protobuf-4.21.12-cp38-cp38-win32.whl", hash = "sha256:6ab80df09e3208f742c98443b6166bcb70d65f52cfeb67357d52032ea1ae9bec"}, 95 | {file = "protobuf-4.21.12-cp38-cp38-win_amd64.whl", hash = "sha256:1f22ac0ca65bb70a876060d96d914dae09ac98d114294f77584b0d2644fa9c30"}, 96 | {file = "protobuf-4.21.12-cp39-cp39-win32.whl", hash = "sha256:27f4d15021da6d2b706ddc3860fac0a5ddaba34ab679dc182b60a8bb4e1121cc"}, 97 | {file = "protobuf-4.21.12-cp39-cp39-win_amd64.whl", hash = "sha256:237216c3326d46808a9f7c26fd1bd4b20015fb6867dc5d263a493ef9a539293b"}, 98 | {file = "protobuf-4.21.12-py2.py3-none-any.whl", hash = "sha256:a53fd3f03e578553623272dc46ac2f189de23862e68565e83dde203d41b76fc5"}, 99 | {file = "protobuf-4.21.12-py3-none-any.whl", hash = "sha256:b98d0148f84e3a3c569e19f52103ca1feacdac0d2df8d6533cf983d1fda28462"}, 100 | {file = "protobuf-4.21.12.tar.gz", hash = "sha256:7cd532c4566d0e6feafecc1059d04c7915aec8e182d1cf7adee8b24ef1e2e6ab"}, 101 | ] 102 | 103 | [metadata] 104 | lock-version = "2.0" 105 | python-versions = "^3.10" 106 | content-hash = "19341507778eb2959e1c09893aacf08e18b4664155c82787743a20691172d295" 107 | -------------------------------------------------------------------------------- /jito_geyser/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "jito_geyser" 3 | version = "0.1.0" 4 | description = "Jito Labs Geyser Client" 5 | authors = ["Jito Labs "] 6 | readme = "README.md" 7 | packages = [{ include = "jito_geyser" }] 8 | 9 | [tool.poetry.dependencies] 10 | python = "^3.10" 11 | grpcio = "^1.51.1" 12 | protobuf = "^4.21.12" 13 | isort = "^5.11.4" 14 | 15 | [build-system] 16 | requires = ["poetry-core"] 17 | build-backend = "poetry.core.masonry.api" 18 | 19 | [tool.poetry-grpc-plugin] 20 | proto_path = "../geyser-grpc-plugin/proto/proto" 21 | python_out = "./jito_geyser/generated" 22 | 23 | [tool.black] 24 | line-length = 120 25 | target-version = ['py37'] 26 | include = '\.pyi?$' 27 | extend-exclude = '''generated''' 28 | 29 | [tool.isort] 30 | profile = "black" 31 | extend_skip_glob = ["jito_geyser/generated/*"] 32 | -------------------------------------------------------------------------------- /jito_searcher_client/README.md: -------------------------------------------------------------------------------- 1 | # About 2 | [![PyPI](https://img.shields.io/pypi/v/jito_searcher_client?label=PyPI&logo=python)](https://pypi.org/project/jito_searcher_client/) 3 | 4 | This library contains tooling to interact with Jito Lab's Block Engine as a searcher. 5 | 6 | # Downloading 7 | ```bash 8 | $ pip install jito_searcher_client 9 | ``` 10 | 11 | # Keypair Authentication 12 | Basic access(5 req/second per region) no longer requires approval. Please visit our [Discord](https://discord.gg/jito) dev channel, if you have other questions. 13 | If your application requires higher rate limits, please complete this [form](https://forms.gle/8jZmKX1KZA71jXp38) 14 | 15 | # Examples 16 | 17 | ## Sync Client 18 | 19 | ```python 20 | from jito_searcher_client import get_searcher_client 21 | from jito_searcher_client.generated.searcher_pb2 import ConnectedLeadersRequest 22 | 23 | from solders.keypair import Keypair 24 | 25 | KEYPAIR_PATH = "/path/to/authenticated/keypair.json" 26 | BLOCK_ENGINE_URL = "mainnet.block-engine.jito.wtf" 27 | 28 | with open(KEYPAIR_PATH) as kp_path: 29 | kp = Keypair.from_json(kp_path.read()) 30 | 31 | client = get_searcher_client(BLOCK_ENGINE_URL, kp) 32 | leaders = client.GetConnectedLeaders(ConnectedLeadersRequest()) 33 | print(f"{leaders=}") 34 | ``` 35 | 36 | ## Sync Client (No Auth) 37 | 38 | ```python 39 | from jito_searcher_client import get_searcher_client 40 | from jito_searcher_client.generated.searcher_pb2 import ConnectedLeadersRequest 41 | 42 | from solders.keypair import Keypair 43 | 44 | BLOCK_ENGINE_URL = "mainnet.block-engine.jito.wtf" 45 | 46 | client = get_searcher_client(BLOCK_ENGINE_URL) 47 | leaders = client.GetConnectedLeaders(ConnectedLeadersRequest()) 48 | print(f"{leaders=}") 49 | ``` 50 | 51 | ## Async Client 52 | 53 | ```python 54 | import asyncio 55 | 56 | from jito_searcher_client import get_async_searcher_client 57 | from jito_searcher_client.generated.searcher_pb2 import ConnectedLeadersRequest 58 | 59 | from solders.keypair import Keypair 60 | 61 | KEYPAIR_PATH = "/path/to/authenticated/keypair.json" 62 | BLOCK_ENGINE_URL = "mainnet.block-engine.jito.wtf" 63 | 64 | async def main(): 65 | with open(KEYPAIR_PATH) as kp_path: 66 | kp = Keypair.from_json(kp_path.read()) 67 | client = await get_async_searcher_client(BLOCK_ENGINE_URL, kp) 68 | leaders = await client.GetConnectedLeaders(ConnectedLeadersRequest()) 69 | print(f"{leaders=}") 70 | 71 | asyncio.run(main()) 72 | ``` 73 | 74 | ## Async Client (No Auth) 75 | 76 | ```python 77 | import asyncio 78 | 79 | from jito_searcher_client import get_async_searcher_client 80 | from jito_searcher_client.generated.searcher_pb2 import ConnectedLeadersRequest 81 | 82 | from solders.keypair import Keypair 83 | 84 | BLOCK_ENGINE_URL = "mainnet.block-engine.jito.wtf" 85 | 86 | async def main(): 87 | client = await get_async_searcher_client(BLOCK_ENGINE_URL) 88 | leaders = await client.GetConnectedLeaders(ConnectedLeadersRequest()) 89 | print(f"{leaders=}") 90 | 91 | asyncio.run(main()) 92 | ``` 93 | 94 | # Development 95 | 96 | Install pip 97 | ```bash 98 | $ curl -sSL https://bootstrap.pypa.io/get-pip.py | python 3 - 99 | ``` 100 | 101 | Install poetry 102 | ```bash 103 | $ curl -sSL https://install.python-poetry.org | python3 - 104 | ``` 105 | 106 | Setup environment and build protobufs 107 | ```bash 108 | $ poetry install 109 | $ poetry shell 110 | $ poetry protoc 111 | ``` 112 | 113 | Linting 114 | ```bash 115 | $ poetry run black . 116 | $ poetry run isort . 117 | ``` 118 | 119 | Linting: 120 | ```bash 121 | poetry run isort . 122 | poetry run black . 123 | ``` 124 | 125 | Publishing package 126 | ```bash 127 | $ poetry protoc && poetry build && poetry publish 128 | ``` 129 | Publishing package 130 | ```bash 131 | $ poetry protoc && poetry build && poetry publish 132 | ``` 133 | -------------------------------------------------------------------------------- /jito_searcher_client/examples/async-searcher-cli.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import time 3 | from typing import List 4 | 5 | import click 6 | from grpc._cython.cygrpc import _AioCall 7 | from grpc.aio import UnaryStreamCall 8 | from solana.rpc.api import Client 9 | from solana.rpc.commitment import Processed 10 | from solders.keypair import Keypair 11 | from solders.pubkey import Pubkey 12 | from solders.system_program import TransferParams, transfer 13 | from solders.transaction import Transaction, VersionedTransaction 14 | from spl.memo.instructions import MemoParams, create_memo 15 | 16 | from jito_searcher_client.async_searcher import get_async_searcher_client 17 | from jito_searcher_client.convert import tx_to_protobuf_packet 18 | from jito_searcher_client.generated.bundle_pb2 import Bundle 19 | from jito_searcher_client.generated.searcher_pb2 import ( 20 | ConnectedLeadersRequest, 21 | GetTipAccountsRequest, 22 | MempoolSubscription, 23 | NextScheduledLeaderRequest, 24 | NextScheduledLeaderResponse, 25 | PendingTxSubscriptionRequest, 26 | ProgramSubscriptionV0, 27 | SendBundleRequest, 28 | WriteLockedAccountSubscriptionV0, 29 | ) 30 | from jito_searcher_client.generated.searcher_pb2_grpc import SearcherServiceStub 31 | 32 | event_loop = asyncio.new_event_loop() 33 | 34 | 35 | @click.group("cli") 36 | @click.pass_context 37 | @click.option( 38 | "--keypair-path", 39 | help="Path to a keypair that is authenticated with the block engine.", 40 | required=True, 41 | ) 42 | @click.option( 43 | "--block-engine-url", 44 | help="Block Engine URL", 45 | required=True, 46 | ) 47 | def cli( 48 | ctx, 49 | keypair_path: str, 50 | block_engine_url: str, 51 | ): 52 | """ 53 | This script can be used to interface with the block engine as a jito_searcher_client. 54 | """ 55 | with open(keypair_path) as kp_path: 56 | kp = Keypair.from_json(kp_path.read()) 57 | ctx.obj = event_loop.run_until_complete(get_async_searcher_client(block_engine_url, kp)) 58 | 59 | 60 | @click.command("mempool-accounts") 61 | @click.pass_obj 62 | @click.argument("accounts", required=True, nargs=-1) 63 | def mempool_accounts(client: SearcherServiceStub, accounts: List[str]): 64 | """ 65 | Stream mempool transactions that write lock any of the provided accounts 66 | """ 67 | leader: NextScheduledLeaderResponse = event_loop.run_until_complete( 68 | client.GetNextScheduledLeader(NextScheduledLeaderRequest()) 69 | ) 70 | print( 71 | f"next scheduled leader is {leader.next_leader_identity} in {leader.next_leader_slot - leader.current_slot} slots" 72 | ) 73 | 74 | stream = client.SubscribeMempool( 75 | MempoolSubscription(wla_v0_sub=WriteLockedAccountSubscriptionV0(accounts=accounts)) 76 | ) 77 | while True: 78 | response = event_loop.run_until_complete(stream.read()) 79 | print(response) 80 | 81 | 82 | @click.command("mempool-programs") 83 | @click.pass_obj 84 | @click.argument("programs", required=True, nargs=-1) 85 | def mempool_programs(client: SearcherServiceStub, programs: List[str]): 86 | """ 87 | Stream mempool transactions that mention any of the provided programs 88 | """ 89 | leader: NextScheduledLeaderResponse = event_loop.run_until_complete( 90 | client.GetNextScheduledLeader(NextScheduledLeaderRequest()) 91 | ) 92 | print( 93 | f"next scheduled leader is {leader.next_leader_identity} in {leader.next_leader_slot - leader.current_slot} slots" 94 | ) 95 | 96 | stream = client.SubscribeMempool(MempoolSubscription(program_v0_sub=ProgramSubscriptionV0(programs=programs))) 97 | while True: 98 | response = event_loop.run_until_complete(stream.read()) 99 | print(response) 100 | 101 | 102 | @click.command("next-scheduled-leader") 103 | @click.pass_obj 104 | def next_scheduled_leader(client: SearcherServiceStub): 105 | """ 106 | Find information on the next scheduled leader. 107 | """ 108 | next_leader = event_loop.run_until_complete(client.GetNextScheduledLeader(NextScheduledLeaderRequest())) 109 | print(f"{next_leader=}") 110 | 111 | 112 | @click.command("connected-leaders") 113 | @click.pass_obj 114 | def connected_leaders(client: SearcherServiceStub): 115 | """ 116 | Get leaders connected to this block engine. 117 | """ 118 | leaders = event_loop.run_until_complete(client.GetConnectedLeaders(ConnectedLeadersRequest())) 119 | print(f"{leaders=}") 120 | 121 | 122 | @click.command("tip-accounts") 123 | @click.pass_obj 124 | def tip_accounts(client: SearcherServiceStub): 125 | """ 126 | Get the tip accounts from the block engine. 127 | """ 128 | accounts = event_loop.run_until_complete(client.GetTipAccounts(GetTipAccountsRequest())) 129 | print(f"{accounts=}") 130 | 131 | 132 | if __name__ == "__main__": 133 | cli.add_command(mempool_accounts) 134 | cli.add_command(mempool_programs) 135 | cli.add_command(next_scheduled_leader) 136 | cli.add_command(connected_leaders) 137 | cli.add_command(tip_accounts) 138 | cli() 139 | -------------------------------------------------------------------------------- /jito_searcher_client/examples/searcher-cli.py: -------------------------------------------------------------------------------- 1 | import time 2 | from typing import List 3 | 4 | import click 5 | from solana.rpc.api import Client 6 | from solana.rpc.commitment import Processed 7 | from solders.keypair import Keypair 8 | from solders.pubkey import Pubkey 9 | from solders.system_program import TransferParams, transfer 10 | from solders.transaction import Transaction, VersionedTransaction 11 | from spl.memo.instructions import MemoParams, create_memo 12 | 13 | from jito_searcher_client.convert import tx_to_protobuf_packet 14 | from jito_searcher_client.generated.bundle_pb2 import Bundle 15 | from jito_searcher_client.generated.searcher_pb2 import ( 16 | ConnectedLeadersRequest, 17 | MempoolSubscription, 18 | NextScheduledLeaderRequest, 19 | NextScheduledLeaderResponse, 20 | ProgramSubscriptionV0, 21 | SendBundleRequest, 22 | WriteLockedAccountSubscriptionV0, 23 | ) 24 | from jito_searcher_client.generated.searcher_pb2_grpc import SearcherServiceStub 25 | from jito_searcher_client.searcher import get_searcher_client 26 | 27 | 28 | @click.group("cli") 29 | @click.pass_context 30 | @click.option( 31 | "--keypair-path", 32 | help="Path to a keypair that is authenticated with the block engine.", 33 | required=True, 34 | ) 35 | @click.option( 36 | "--block-engine-url", 37 | help="Block Engine URL", 38 | required=True, 39 | ) 40 | def cli( 41 | ctx, 42 | keypair_path: str, 43 | block_engine_url: str, 44 | ): 45 | """ 46 | This script can be used to interface with the block engine as a jito_searcher_client. 47 | """ 48 | with open(keypair_path) as kp_path: 49 | kp = Keypair.from_json(kp_path.read()) 50 | ctx.obj = get_searcher_client(block_engine_url, kp) 51 | 52 | 53 | @click.command("mempool-accounts") 54 | @click.pass_obj 55 | @click.argument("accounts", required=True, nargs=-1) 56 | def mempool_accounts(client: SearcherServiceStub, accounts: List[str]): 57 | """ 58 | Stream transactions from the mempool if they write-lock one of the provided accounts 59 | """ 60 | leader: NextScheduledLeaderResponse = client.GetNextScheduledLeader(NextScheduledLeaderRequest()) 61 | print( 62 | f"next scheduled leader is {leader.next_leader_identity} in {leader.next_leader_slot - leader.current_slot} slots" 63 | ) 64 | 65 | for notification in client.SubscribeMempool( 66 | MempoolSubscription(wla_v0_sub=WriteLockedAccountSubscriptionV0(accounts=accounts)) 67 | ): 68 | for packet in notification.transactions: 69 | print(VersionedTransaction.from_bytes(packet.data)) 70 | 71 | 72 | @click.command("mempool-programs") 73 | @click.pass_obj 74 | @click.argument("programs", required=True, nargs=-1) 75 | def mempool_programs(client: SearcherServiceStub, programs: List[str]): 76 | """ 77 | Stream transactions from the mempool if they mention one of the provided programs 78 | """ 79 | leader: NextScheduledLeaderResponse = client.GetNextScheduledLeader(NextScheduledLeaderRequest()) 80 | print( 81 | f"next scheduled leader is {leader.next_leader_identity} in {leader.next_leader_slot - leader.current_slot} slots" 82 | ) 83 | 84 | for notification in client.SubscribeMempool( 85 | MempoolSubscription(program_v0_sub=ProgramSubscriptionV0(programs=programs)) 86 | ): 87 | for packet in notification.transactions: 88 | print(VersionedTransaction.from_bytes(packet.data)) 89 | 90 | 91 | @click.command("next-scheduled-leader") 92 | @click.pass_obj 93 | def next_scheduled_leader(client: SearcherServiceStub): 94 | """ 95 | Find information on the next scheduled leader. 96 | """ 97 | next_leader = client.GetNextScheduledLeader(NextScheduledLeaderRequest()) 98 | print(f"{next_leader=}") 99 | 100 | 101 | @click.command("connected-leaders") 102 | @click.pass_obj 103 | def connected_leaders(client: SearcherServiceStub): 104 | """ 105 | Get leaders connected to this block engine. 106 | """ 107 | leaders = client.GetConnectedLeaders(ConnectedLeadersRequest()) 108 | print(f"{leaders=}") 109 | 110 | 111 | @click.command("tip-accounts") 112 | @click.pass_obj 113 | def tip_accounts(client: SearcherServiceStub): 114 | """ 115 | Get the tip accounts from the block engine. 116 | """ 117 | accounts = client.GetNextScheduledLeader(NextScheduledLeaderRequest()) 118 | print(f"{accounts=}") 119 | 120 | 121 | @click.command("send-bundle") 122 | @click.pass_obj 123 | @click.option( 124 | "--rpc-url", 125 | help="RPC URL path", 126 | type=str, 127 | required=True, 128 | ) 129 | @click.option( 130 | "--payer", 131 | help="Path to payer keypair", 132 | type=str, 133 | required=True, 134 | ) 135 | @click.option( 136 | "--message", 137 | help="Message in the bundle", 138 | type=str, 139 | required=True, 140 | ) 141 | @click.option( 142 | "--num_txs", 143 | help="Number of transactions in the bundle (max is 5)", 144 | type=int, 145 | required=True, 146 | ) 147 | @click.option( 148 | "--lamports", 149 | help="Number of lamports to tip in each transaction", 150 | type=int, 151 | required=True, 152 | ) 153 | @click.option( 154 | "--tip_account", 155 | help="Tip account to tip", 156 | type=str, 157 | required=True, 158 | ) 159 | def send_bundle( 160 | client: SearcherServiceStub, 161 | rpc_url: str, 162 | payer: str, 163 | message: str, 164 | num_txs: int, 165 | lamports: int, 166 | tip_account: str, 167 | ): 168 | """ 169 | Send a bundle! 170 | """ 171 | with open(payer) as kp_path: 172 | payer_kp = Keypair.from_json(kp_path.read()) 173 | tip_account = Pubkey.from_string(tip_account) 174 | 175 | rpc_client = Client(rpc_url) 176 | balance = rpc_client.get_balance(payer_kp.pubkey()).value 177 | print(f"payer public key: {payer_kp.pubkey()} {balance=}") 178 | 179 | # This check is not needed since jito-sol is on the majority of validators 180 | # It is useful if jito-sol is on less than 50% of the validators 181 | is_leader_slot = False 182 | print("waiting for jito leader...") 183 | while not is_leader_slot: 184 | time.sleep(0.5) 185 | next_leader: NextScheduledLeaderResponse = client.GetNextScheduledLeader(NextScheduledLeaderRequest()) 186 | num_slots_to_leader = next_leader.next_leader_slot - next_leader.current_slot 187 | print(f"waiting {num_slots_to_leader} slots to jito leader") 188 | is_leader_slot = num_slots_to_leader <= 2 189 | 190 | blockhash = rpc_client.get_latest_blockhash().value.blockhash 191 | block_height = rpc_client.get_block_height(Processed).value 192 | 193 | # Build bundle 194 | txs: List[Transaction] = [] 195 | for idx in range(num_txs): 196 | ixs = [ 197 | create_memo( 198 | MemoParams( 199 | program_id=Pubkey.from_string("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"), 200 | signer=payer_kp.pubkey(), 201 | message=bytes(f"jito bundle {idx}: {message}", "utf-8"), 202 | ) 203 | ) 204 | ] 205 | if idx == num_txs - 1: 206 | # Adds searcher tip on last tx 207 | ixs.append( 208 | transfer(TransferParams(from_pubkey=payer_kp.pubkey(), to_pubkey=tip_account, lamports=lamports)) 209 | ) 210 | tx = Transaction.new_signed_with_payer( 211 | instructions=ixs, payer=payer_kp.pubkey(), signing_keypairs=[payer_kp], recent_blockhash=blockhash 212 | ) 213 | print(f"{idx=} signature={tx.signatures[0]}") 214 | txs.append(tx) 215 | 216 | # Note: setting meta.size here is important so the block engine can deserialize the packet 217 | packets = [tx_to_protobuf_packet(tx) for tx in txs] 218 | 219 | uuid_response = client.SendBundle(SendBundleRequest(bundle=Bundle(header=None, packets=packets))) 220 | print(f"bundle uuid: {uuid_response.uuid}") 221 | 222 | for tx in txs: 223 | print( 224 | rpc_client.confirm_transaction( 225 | tx.signatures[0], Processed, sleep_seconds=0.5, last_valid_block_height=block_height + 10 226 | ) 227 | ) 228 | 229 | 230 | if __name__ == "__main__": 231 | cli.add_command(mempool_accounts) 232 | cli.add_command(mempool_programs) 233 | cli.add_command(next_scheduled_leader) 234 | cli.add_command(connected_leaders) 235 | cli.add_command(tip_accounts) 236 | cli.add_command(send_bundle) 237 | cli() 238 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/__init__.py: -------------------------------------------------------------------------------- 1 | from .async_searcher import AsyncSearcherInterceptor, get_async_searcher_client 2 | from .convert import tx_to_protobuf_packet 3 | from .generated import * 4 | from .searcher import SearcherInterceptor, get_searcher_client 5 | from .token import JwtToken 6 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/async_searcher.py: -------------------------------------------------------------------------------- 1 | import time 2 | from typing import List, Optional, Tuple 3 | 4 | from grpc import ssl_channel_credentials 5 | from grpc.aio import ( 6 | ClientCallDetails, 7 | UnaryStreamClientInterceptor, 8 | UnaryUnaryClientInterceptor, 9 | secure_channel, 10 | ) 11 | from solders.keypair import Keypair 12 | 13 | from jito_searcher_client.generated.auth_pb2 import ( 14 | GenerateAuthChallengeRequest, 15 | GenerateAuthTokensRequest, 16 | GenerateAuthTokensResponse, 17 | RefreshAccessTokenRequest, 18 | RefreshAccessTokenResponse, 19 | Role, 20 | ) 21 | from jito_searcher_client.generated.auth_pb2_grpc import AuthServiceStub 22 | from jito_searcher_client.generated.searcher_pb2_grpc import SearcherServiceStub 23 | from jito_searcher_client.token import JwtToken 24 | 25 | 26 | class AsyncSearcherInterceptor( 27 | UnaryUnaryClientInterceptor, 28 | UnaryStreamClientInterceptor, 29 | ): 30 | """ 31 | AsyncSearcherInterceptor is responsible for authenticating with the block engine. 32 | Authentication happens in a challenge-response handshake. 33 | 1. Request a challenge and provide your public key. 34 | 2. Get challenge and sign a message "{pubkey}-{challenge}". 35 | 3. Get back a refresh token and access token. 36 | 37 | When the access token expires, use the refresh token to get a new one. 38 | When the refresh token expires, perform the challenge-response handshake again. 39 | """ 40 | 41 | def __init__(self, url: str, kp: Keypair): 42 | """ 43 | 44 | :param url: url of the Block Engine without http or https. 45 | :param kp: block engine authentication keypair 46 | """ 47 | self._url = url 48 | self._kp = kp 49 | 50 | self._access_token: Optional[JwtToken] = None 51 | self._refresh_token: Optional[JwtToken] = None 52 | 53 | async def intercept_unary_stream( 54 | self, 55 | continuation, 56 | client_call_details, 57 | request, 58 | ): 59 | if self._kp != None: 60 | await self.authenticate_if_needed() 61 | 62 | client_call_details = self._insert_headers( 63 | [("authorization", f"Bearer {self._access_token.token}")], 64 | client_call_details, 65 | ) 66 | 67 | call = await continuation(client_call_details, request) 68 | 69 | return call 70 | 71 | async def intercept_unary_unary( 72 | self, 73 | continuation, 74 | client_call_details, 75 | request, 76 | ): 77 | if self._kp != None: 78 | await self.authenticate_if_needed() 79 | 80 | client_call_details = self._insert_headers( 81 | [("authorization", f"Bearer {self._access_token.token}")], 82 | client_call_details, 83 | ) 84 | 85 | undone_call = await continuation(client_call_details, request) 86 | response = await undone_call 87 | return response 88 | 89 | @staticmethod 90 | def _insert_headers(new_metadata: List[Tuple[str, str]], client_call_details) -> ClientCallDetails: 91 | metadata = [] 92 | if client_call_details.metadata is not None: 93 | metadata = list(client_call_details.metadata) 94 | metadata.extend(new_metadata) 95 | 96 | return ClientCallDetails( 97 | client_call_details.method, 98 | client_call_details.timeout, 99 | metadata, 100 | client_call_details.credentials, 101 | False, 102 | ) 103 | 104 | async def authenticate_if_needed(self): 105 | """ 106 | Maybe authenticates depending on state of access + refresh tokens 107 | """ 108 | now = int(time.time()) 109 | if self._access_token is None or self._refresh_token is None or now >= self._refresh_token.expiration: 110 | await self.full_authentication() 111 | elif now >= self._access_token.expiration: 112 | await self.refresh_authentication() 113 | 114 | async def refresh_authentication(self): 115 | """ 116 | Performs an authentication refresh with the block engine, which involves using the refresh token to get a new 117 | access token. 118 | """ 119 | credentials = ssl_channel_credentials() 120 | channel = secure_channel(self._url, credentials) 121 | auth_client = AuthServiceStub(channel) 122 | 123 | new_access_token: RefreshAccessTokenResponse = await auth_client.RefreshAccessToken( 124 | RefreshAccessTokenRequest(refresh_token=self._refresh_token.token) 125 | ) 126 | self._access_token = JwtToken( 127 | token=new_access_token.access_token.value, expiration=new_access_token.access_token.expires_at_utc.seconds 128 | ) 129 | 130 | async def full_authentication(self): 131 | """ 132 | Performs full authentication with the block engine 133 | """ 134 | credentials = ssl_channel_credentials() 135 | channel = secure_channel(self._url, credentials) 136 | auth_client = AuthServiceStub(channel) 137 | 138 | challenge = ( 139 | await auth_client.GenerateAuthChallenge( 140 | GenerateAuthChallengeRequest(role=Role.SEARCHER, pubkey=bytes(self._kp.pubkey())) 141 | ) 142 | ).challenge 143 | 144 | challenge_to_sign = f"{str(self._kp.pubkey())}-{challenge}" 145 | 146 | signed = self._kp.sign_message(bytes(challenge_to_sign, "utf8")) 147 | 148 | auth_tokens_response: GenerateAuthTokensResponse = await auth_client.GenerateAuthTokens( 149 | GenerateAuthTokensRequest( 150 | challenge=challenge_to_sign, 151 | client_pubkey=bytes(self._kp.pubkey()), 152 | signed_challenge=bytes(signed), 153 | ) 154 | ) 155 | 156 | self._access_token = JwtToken( 157 | token=auth_tokens_response.access_token.value, 158 | expiration=auth_tokens_response.access_token.expires_at_utc.seconds, 159 | ) 160 | 161 | self._refresh_token = JwtToken( 162 | token=auth_tokens_response.refresh_token.value, 163 | expiration=auth_tokens_response.refresh_token.expires_at_utc.seconds, 164 | ) 165 | 166 | 167 | async def get_async_searcher_client(url: str, kp: Keypair=None) -> SearcherServiceStub: 168 | """ 169 | Returns a Searcher Service client that intercepts requests and authenticates with the block engine. 170 | :param url: url of the block engine without http/https 171 | :param kp: keypair of the block engine 172 | :return: SearcherServiceStub which handles authentication on requests 173 | """ 174 | # Authenticate immediately 175 | searcher_interceptor = AsyncSearcherInterceptor(url, kp) 176 | await searcher_interceptor.authenticate_if_needed() 177 | 178 | credentials = ssl_channel_credentials() 179 | channel = secure_channel(url, credentials, interceptors=[searcher_interceptor]) 180 | channel._unary_stream_interceptors.append(searcher_interceptor) 181 | 182 | return SearcherServiceStub(channel) 183 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/convert.py: -------------------------------------------------------------------------------- 1 | from solana.transaction import Transaction 2 | from solders.transaction import VersionedTransaction 3 | 4 | from jito_searcher_client.generated.packet_pb2 import Meta, Packet 5 | 6 | 7 | def versioned_tx_to_protobuf_packet(tx: VersionedTransaction) -> Packet: 8 | """ 9 | Converts a versioned transaction to a packet 10 | Note: setting packet.meta.size is required, the rest are optional 11 | """ 12 | return Packet( 13 | data=bytes(tx), 14 | meta=Meta(size=len(bytes(tx)), addr="0.0.0.0", port=0, flags=None, sender_stake=0), 15 | ) 16 | 17 | 18 | def tx_to_protobuf_packet(tx: Transaction) -> Packet: 19 | """ 20 | Converts a transaction to a packet 21 | Note: setting packet.meta.size is required, the rest are optional 22 | """ 23 | return Packet( 24 | data=tx.serialize(), 25 | meta=Meta(size=len(tx.serialize()), addr="0.0.0.0", port=0, flags=None, sender_stake=0), 26 | ) 27 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | # ugh https://stackoverflow.com/a/55258233 4 | sys.path.insert(0, os.path.abspath(os.path.dirname(__file__))) 5 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/auth_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: auth.proto 4 | """Generated protocol buffer code.""" 5 | from google.protobuf.internal import builder as _builder 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 15 | 16 | 17 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\nauth.proto\x12\x04\x61uth\x1a\x1fgoogle/protobuf/timestamp.proto\"H\n\x1cGenerateAuthChallengeRequest\x12\x18\n\x04role\x18\x01 \x01(\x0e\x32\n.auth.Role\x12\x0e\n\x06pubkey\x18\x02 \x01(\x0c\"2\n\x1dGenerateAuthChallengeResponse\x12\x11\n\tchallenge\x18\x01 \x01(\t\"_\n\x19GenerateAuthTokensRequest\x12\x11\n\tchallenge\x18\x01 \x01(\t\x12\x15\n\rclient_pubkey\x18\x02 \x01(\x0c\x12\x18\n\x10signed_challenge\x18\x03 \x01(\x0c\"J\n\x05Token\x12\r\n\x05value\x18\x01 \x01(\t\x12\x32\n\x0e\x65xpires_at_utc\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"c\n\x1aGenerateAuthTokensResponse\x12!\n\x0c\x61\x63\x63\x65ss_token\x18\x01 \x01(\x0b\x32\x0b.auth.Token\x12\"\n\rrefresh_token\x18\x02 \x01(\x0b\x32\x0b.auth.Token\"2\n\x19RefreshAccessTokenRequest\x12\x15\n\rrefresh_token\x18\x01 \x01(\t\"?\n\x1aRefreshAccessTokenResponse\x12!\n\x0c\x61\x63\x63\x65ss_token\x18\x01 \x01(\x0b\x32\x0b.auth.Token*L\n\x04Role\x12\x0b\n\x07RELAYER\x10\x00\x12\x0c\n\x08SEARCHER\x10\x01\x12\r\n\tVALIDATOR\x10\x02\x12\x1a\n\x16SHREDSTREAM_SUBSCRIBER\x10\x03\x32\xa7\x02\n\x0b\x41uthService\x12\x62\n\x15GenerateAuthChallenge\x12\".auth.GenerateAuthChallengeRequest\x1a#.auth.GenerateAuthChallengeResponse\"\x00\x12Y\n\x12GenerateAuthTokens\x12\x1f.auth.GenerateAuthTokensRequest\x1a .auth.GenerateAuthTokensResponse\"\x00\x12Y\n\x12RefreshAccessToken\x12\x1f.auth.RefreshAccessTokenRequest\x1a .auth.RefreshAccessTokenResponse\"\x00\x62\x06proto3') 18 | 19 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 20 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'auth_pb2', globals()) 21 | if _descriptor._USE_C_DESCRIPTORS == False: 22 | 23 | DESCRIPTOR._options = None 24 | _ROLE._serialized_start=570 25 | _ROLE._serialized_end=646 26 | _GENERATEAUTHCHALLENGEREQUEST._serialized_start=53 27 | _GENERATEAUTHCHALLENGEREQUEST._serialized_end=125 28 | _GENERATEAUTHCHALLENGERESPONSE._serialized_start=127 29 | _GENERATEAUTHCHALLENGERESPONSE._serialized_end=177 30 | _GENERATEAUTHTOKENSREQUEST._serialized_start=179 31 | _GENERATEAUTHTOKENSREQUEST._serialized_end=274 32 | _TOKEN._serialized_start=276 33 | _TOKEN._serialized_end=350 34 | _GENERATEAUTHTOKENSRESPONSE._serialized_start=352 35 | _GENERATEAUTHTOKENSRESPONSE._serialized_end=451 36 | _REFRESHACCESSTOKENREQUEST._serialized_start=453 37 | _REFRESHACCESSTOKENREQUEST._serialized_end=503 38 | _REFRESHACCESSTOKENRESPONSE._serialized_start=505 39 | _REFRESHACCESSTOKENRESPONSE._serialized_end=568 40 | _AUTHSERVICE._serialized_start=649 41 | _AUTHSERVICE._serialized_end=944 42 | # @@protoc_insertion_point(module_scope) 43 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/auth_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | import builtins 6 | import google.protobuf.descriptor 7 | import google.protobuf.internal.enum_type_wrapper 8 | import google.protobuf.message 9 | import google.protobuf.timestamp_pb2 10 | import sys 11 | import typing 12 | 13 | if sys.version_info >= (3, 10): 14 | import typing as typing_extensions 15 | else: 16 | import typing_extensions 17 | 18 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 19 | 20 | class _Role: 21 | ValueType = typing.NewType("ValueType", builtins.int) 22 | V: typing_extensions.TypeAlias = ValueType 23 | 24 | class _RoleEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_Role.ValueType], builtins.type): 25 | DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor 26 | RELAYER: _Role.ValueType # 0 27 | SEARCHER: _Role.ValueType # 1 28 | VALIDATOR: _Role.ValueType # 2 29 | SHREDSTREAM_SUBSCRIBER: _Role.ValueType # 3 30 | 31 | class Role(_Role, metaclass=_RoleEnumTypeWrapper): ... 32 | 33 | RELAYER: Role.ValueType # 0 34 | SEARCHER: Role.ValueType # 1 35 | VALIDATOR: Role.ValueType # 2 36 | SHREDSTREAM_SUBSCRIBER: Role.ValueType # 3 37 | global___Role = Role 38 | 39 | @typing_extensions.final 40 | class GenerateAuthChallengeRequest(google.protobuf.message.Message): 41 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 42 | 43 | ROLE_FIELD_NUMBER: builtins.int 44 | PUBKEY_FIELD_NUMBER: builtins.int 45 | role: global___Role.ValueType 46 | """/ Role the client is attempting to generate tokens for.""" 47 | pubkey: builtins.bytes 48 | """/ Client's 32 byte pubkey.""" 49 | def __init__( 50 | self, 51 | *, 52 | role: global___Role.ValueType = ..., 53 | pubkey: builtins.bytes = ..., 54 | ) -> None: ... 55 | def ClearField(self, field_name: typing_extensions.Literal["pubkey", b"pubkey", "role", b"role"]) -> None: ... 56 | 57 | global___GenerateAuthChallengeRequest = GenerateAuthChallengeRequest 58 | 59 | @typing_extensions.final 60 | class GenerateAuthChallengeResponse(google.protobuf.message.Message): 61 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 62 | 63 | CHALLENGE_FIELD_NUMBER: builtins.int 64 | challenge: builtins.str 65 | def __init__( 66 | self, 67 | *, 68 | challenge: builtins.str = ..., 69 | ) -> None: ... 70 | def ClearField(self, field_name: typing_extensions.Literal["challenge", b"challenge"]) -> None: ... 71 | 72 | global___GenerateAuthChallengeResponse = GenerateAuthChallengeResponse 73 | 74 | @typing_extensions.final 75 | class GenerateAuthTokensRequest(google.protobuf.message.Message): 76 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 77 | 78 | CHALLENGE_FIELD_NUMBER: builtins.int 79 | CLIENT_PUBKEY_FIELD_NUMBER: builtins.int 80 | SIGNED_CHALLENGE_FIELD_NUMBER: builtins.int 81 | challenge: builtins.str 82 | """/ The pre-signed challenge.""" 83 | client_pubkey: builtins.bytes 84 | """/ The signing keypair's corresponding 32 byte pubkey.""" 85 | signed_challenge: builtins.bytes 86 | """/ The 64 byte signature of the challenge signed by the client's private key. The private key must correspond to 87 | the pubkey passed in the [GenerateAuthChallenge] method. The client is expected to sign the challenge token 88 | prepended with their pubkey. For example sign(pubkey, challenge). 89 | """ 90 | def __init__( 91 | self, 92 | *, 93 | challenge: builtins.str = ..., 94 | client_pubkey: builtins.bytes = ..., 95 | signed_challenge: builtins.bytes = ..., 96 | ) -> None: ... 97 | def ClearField(self, field_name: typing_extensions.Literal["challenge", b"challenge", "client_pubkey", b"client_pubkey", "signed_challenge", b"signed_challenge"]) -> None: ... 98 | 99 | global___GenerateAuthTokensRequest = GenerateAuthTokensRequest 100 | 101 | @typing_extensions.final 102 | class Token(google.protobuf.message.Message): 103 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 104 | 105 | VALUE_FIELD_NUMBER: builtins.int 106 | EXPIRES_AT_UTC_FIELD_NUMBER: builtins.int 107 | value: builtins.str 108 | """/ The token.""" 109 | @property 110 | def expires_at_utc(self) -> google.protobuf.timestamp_pb2.Timestamp: 111 | """/ When the token will expire.""" 112 | def __init__( 113 | self, 114 | *, 115 | value: builtins.str = ..., 116 | expires_at_utc: google.protobuf.timestamp_pb2.Timestamp | None = ..., 117 | ) -> None: ... 118 | def HasField(self, field_name: typing_extensions.Literal["expires_at_utc", b"expires_at_utc"]) -> builtins.bool: ... 119 | def ClearField(self, field_name: typing_extensions.Literal["expires_at_utc", b"expires_at_utc", "value", b"value"]) -> None: ... 120 | 121 | global___Token = Token 122 | 123 | @typing_extensions.final 124 | class GenerateAuthTokensResponse(google.protobuf.message.Message): 125 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 126 | 127 | ACCESS_TOKEN_FIELD_NUMBER: builtins.int 128 | REFRESH_TOKEN_FIELD_NUMBER: builtins.int 129 | @property 130 | def access_token(self) -> global___Token: 131 | """/ The token granting access to resources.""" 132 | @property 133 | def refresh_token(self) -> global___Token: 134 | """/ The token used to refresh the access_token. This has a longer TTL than the access_token.""" 135 | def __init__( 136 | self, 137 | *, 138 | access_token: global___Token | None = ..., 139 | refresh_token: global___Token | None = ..., 140 | ) -> None: ... 141 | def HasField(self, field_name: typing_extensions.Literal["access_token", b"access_token", "refresh_token", b"refresh_token"]) -> builtins.bool: ... 142 | def ClearField(self, field_name: typing_extensions.Literal["access_token", b"access_token", "refresh_token", b"refresh_token"]) -> None: ... 143 | 144 | global___GenerateAuthTokensResponse = GenerateAuthTokensResponse 145 | 146 | @typing_extensions.final 147 | class RefreshAccessTokenRequest(google.protobuf.message.Message): 148 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 149 | 150 | REFRESH_TOKEN_FIELD_NUMBER: builtins.int 151 | refresh_token: builtins.str 152 | """/ Non-expired refresh token obtained from the [GenerateAuthTokens] method.""" 153 | def __init__( 154 | self, 155 | *, 156 | refresh_token: builtins.str = ..., 157 | ) -> None: ... 158 | def ClearField(self, field_name: typing_extensions.Literal["refresh_token", b"refresh_token"]) -> None: ... 159 | 160 | global___RefreshAccessTokenRequest = RefreshAccessTokenRequest 161 | 162 | @typing_extensions.final 163 | class RefreshAccessTokenResponse(google.protobuf.message.Message): 164 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 165 | 166 | ACCESS_TOKEN_FIELD_NUMBER: builtins.int 167 | @property 168 | def access_token(self) -> global___Token: 169 | """/ Fresh access_token.""" 170 | def __init__( 171 | self, 172 | *, 173 | access_token: global___Token | None = ..., 174 | ) -> None: ... 175 | def HasField(self, field_name: typing_extensions.Literal["access_token", b"access_token"]) -> builtins.bool: ... 176 | def ClearField(self, field_name: typing_extensions.Literal["access_token", b"access_token"]) -> None: ... 177 | 178 | global___RefreshAccessTokenResponse = RefreshAccessTokenResponse 179 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/auth_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | import auth_pb2 as auth__pb2 6 | 7 | 8 | class AuthServiceStub(object): 9 | """/ This service is responsible for issuing auth tokens to clients for API access. 10 | """ 11 | 12 | def __init__(self, channel): 13 | """Constructor. 14 | 15 | Args: 16 | channel: A grpc.Channel. 17 | """ 18 | self.GenerateAuthChallenge = channel.unary_unary( 19 | '/auth.AuthService/GenerateAuthChallenge', 20 | request_serializer=auth__pb2.GenerateAuthChallengeRequest.SerializeToString, 21 | response_deserializer=auth__pb2.GenerateAuthChallengeResponse.FromString, 22 | ) 23 | self.GenerateAuthTokens = channel.unary_unary( 24 | '/auth.AuthService/GenerateAuthTokens', 25 | request_serializer=auth__pb2.GenerateAuthTokensRequest.SerializeToString, 26 | response_deserializer=auth__pb2.GenerateAuthTokensResponse.FromString, 27 | ) 28 | self.RefreshAccessToken = channel.unary_unary( 29 | '/auth.AuthService/RefreshAccessToken', 30 | request_serializer=auth__pb2.RefreshAccessTokenRequest.SerializeToString, 31 | response_deserializer=auth__pb2.RefreshAccessTokenResponse.FromString, 32 | ) 33 | 34 | 35 | class AuthServiceServicer(object): 36 | """/ This service is responsible for issuing auth tokens to clients for API access. 37 | """ 38 | 39 | def GenerateAuthChallenge(self, request, context): 40 | """/ Returns a challenge, client is expected to sign this challenge with an appropriate keypair in order to obtain access tokens. 41 | """ 42 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 43 | context.set_details('Method not implemented!') 44 | raise NotImplementedError('Method not implemented!') 45 | 46 | def GenerateAuthTokens(self, request, context): 47 | """/ Provides the client with the initial pair of auth tokens for API access. 48 | """ 49 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 50 | context.set_details('Method not implemented!') 51 | raise NotImplementedError('Method not implemented!') 52 | 53 | def RefreshAccessToken(self, request, context): 54 | """/ Call this method with a non-expired refresh token to obtain a new access token. 55 | """ 56 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 57 | context.set_details('Method not implemented!') 58 | raise NotImplementedError('Method not implemented!') 59 | 60 | 61 | def add_AuthServiceServicer_to_server(servicer, server): 62 | rpc_method_handlers = { 63 | 'GenerateAuthChallenge': grpc.unary_unary_rpc_method_handler( 64 | servicer.GenerateAuthChallenge, 65 | request_deserializer=auth__pb2.GenerateAuthChallengeRequest.FromString, 66 | response_serializer=auth__pb2.GenerateAuthChallengeResponse.SerializeToString, 67 | ), 68 | 'GenerateAuthTokens': grpc.unary_unary_rpc_method_handler( 69 | servicer.GenerateAuthTokens, 70 | request_deserializer=auth__pb2.GenerateAuthTokensRequest.FromString, 71 | response_serializer=auth__pb2.GenerateAuthTokensResponse.SerializeToString, 72 | ), 73 | 'RefreshAccessToken': grpc.unary_unary_rpc_method_handler( 74 | servicer.RefreshAccessToken, 75 | request_deserializer=auth__pb2.RefreshAccessTokenRequest.FromString, 76 | response_serializer=auth__pb2.RefreshAccessTokenResponse.SerializeToString, 77 | ), 78 | } 79 | generic_handler = grpc.method_handlers_generic_handler( 80 | 'auth.AuthService', rpc_method_handlers) 81 | server.add_generic_rpc_handlers((generic_handler,)) 82 | 83 | 84 | # This class is part of an EXPERIMENTAL API. 85 | class AuthService(object): 86 | """/ This service is responsible for issuing auth tokens to clients for API access. 87 | """ 88 | 89 | @staticmethod 90 | def GenerateAuthChallenge(request, 91 | target, 92 | options=(), 93 | channel_credentials=None, 94 | call_credentials=None, 95 | insecure=False, 96 | compression=None, 97 | wait_for_ready=None, 98 | timeout=None, 99 | metadata=None): 100 | return grpc.experimental.unary_unary(request, target, '/auth.AuthService/GenerateAuthChallenge', 101 | auth__pb2.GenerateAuthChallengeRequest.SerializeToString, 102 | auth__pb2.GenerateAuthChallengeResponse.FromString, 103 | options, channel_credentials, 104 | insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 105 | 106 | @staticmethod 107 | def GenerateAuthTokens(request, 108 | target, 109 | options=(), 110 | channel_credentials=None, 111 | call_credentials=None, 112 | insecure=False, 113 | compression=None, 114 | wait_for_ready=None, 115 | timeout=None, 116 | metadata=None): 117 | return grpc.experimental.unary_unary(request, target, '/auth.AuthService/GenerateAuthTokens', 118 | auth__pb2.GenerateAuthTokensRequest.SerializeToString, 119 | auth__pb2.GenerateAuthTokensResponse.FromString, 120 | options, channel_credentials, 121 | insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 122 | 123 | @staticmethod 124 | def RefreshAccessToken(request, 125 | target, 126 | options=(), 127 | channel_credentials=None, 128 | call_credentials=None, 129 | insecure=False, 130 | compression=None, 131 | wait_for_ready=None, 132 | timeout=None, 133 | metadata=None): 134 | return grpc.experimental.unary_unary(request, target, '/auth.AuthService/RefreshAccessToken', 135 | auth__pb2.RefreshAccessTokenRequest.SerializeToString, 136 | auth__pb2.RefreshAccessTokenResponse.FromString, 137 | options, channel_credentials, 138 | insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 139 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/auth_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | import abc 6 | import auth_pb2 7 | import grpc 8 | 9 | class AuthServiceStub: 10 | """/ This service is responsible for issuing auth tokens to clients for API access.""" 11 | 12 | def __init__(self, channel: grpc.Channel) -> None: ... 13 | GenerateAuthChallenge: grpc.UnaryUnaryMultiCallable[ 14 | auth_pb2.GenerateAuthChallengeRequest, 15 | auth_pb2.GenerateAuthChallengeResponse, 16 | ] 17 | """/ Returns a challenge, client is expected to sign this challenge with an appropriate keypair in order to obtain access tokens.""" 18 | GenerateAuthTokens: grpc.UnaryUnaryMultiCallable[ 19 | auth_pb2.GenerateAuthTokensRequest, 20 | auth_pb2.GenerateAuthTokensResponse, 21 | ] 22 | """/ Provides the client with the initial pair of auth tokens for API access.""" 23 | RefreshAccessToken: grpc.UnaryUnaryMultiCallable[ 24 | auth_pb2.RefreshAccessTokenRequest, 25 | auth_pb2.RefreshAccessTokenResponse, 26 | ] 27 | """/ Call this method with a non-expired refresh token to obtain a new access token.""" 28 | 29 | class AuthServiceServicer(metaclass=abc.ABCMeta): 30 | """/ This service is responsible for issuing auth tokens to clients for API access.""" 31 | 32 | @abc.abstractmethod 33 | def GenerateAuthChallenge( 34 | self, 35 | request: auth_pb2.GenerateAuthChallengeRequest, 36 | context: grpc.ServicerContext, 37 | ) -> auth_pb2.GenerateAuthChallengeResponse: 38 | """/ Returns a challenge, client is expected to sign this challenge with an appropriate keypair in order to obtain access tokens.""" 39 | @abc.abstractmethod 40 | def GenerateAuthTokens( 41 | self, 42 | request: auth_pb2.GenerateAuthTokensRequest, 43 | context: grpc.ServicerContext, 44 | ) -> auth_pb2.GenerateAuthTokensResponse: 45 | """/ Provides the client with the initial pair of auth tokens for API access.""" 46 | @abc.abstractmethod 47 | def RefreshAccessToken( 48 | self, 49 | request: auth_pb2.RefreshAccessTokenRequest, 50 | context: grpc.ServicerContext, 51 | ) -> auth_pb2.RefreshAccessTokenResponse: 52 | """/ Call this method with a non-expired refresh token to obtain a new access token.""" 53 | 54 | def add_AuthServiceServicer_to_server(servicer: AuthServiceServicer, server: grpc.Server) -> None: ... 55 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/block_engine_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: block_engine.proto 4 | """Generated protocol buffer code.""" 5 | from google.protobuf.internal import builder as _builder 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | import packet_pb2 as packet__pb2 15 | import shared_pb2 as shared__pb2 16 | import bundle_pb2 as bundle__pb2 17 | 18 | 19 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12\x62lock_engine.proto\x12\x0c\x62lock_engine\x1a\x0cpacket.proto\x1a\x0cshared.proto\x1a\x0c\x62undle.proto\"\x19\n\x17SubscribePacketsRequest\"^\n\x18SubscribePacketsResponse\x12\x1e\n\x06header\x18\x01 \x01(\x0b\x32\x0e.shared.Header\x12\"\n\x05\x62\x61tch\x18\x02 \x01(\x0b\x32\x13.packet.PacketBatch\"\x19\n\x17SubscribeBundlesRequest\"?\n\x18SubscribeBundlesResponse\x12#\n\x07\x62undles\x18\x01 \x03(\x0b\x32\x12.bundle.BundleUuid\"\x1c\n\x1a\x42lockBuilderFeeInfoRequest\"A\n\x1b\x42lockBuilderFeeInfoResponse\x12\x0e\n\x06pubkey\x18\x01 \x01(\t\x12\x12\n\ncommission\x18\x02 \x01(\x04\"&\n\x12\x41\x63\x63ountsOfInterest\x12\x10\n\x08\x61\x63\x63ounts\x18\x01 \x03(\t\"\x1b\n\x19\x41\x63\x63ountsOfInterestRequest\",\n\x18\x41\x63\x63ountsOfInterestUpdate\x12\x10\n\x08\x61\x63\x63ounts\x18\x01 \x03(\t\"\x1b\n\x19ProgramsOfInterestRequest\",\n\x18ProgramsOfInterestUpdate\x12\x10\n\x08programs\x18\x01 \x03(\t\"l\n\x13\x45xpiringPacketBatch\x12\x1e\n\x06header\x18\x01 \x01(\x0b\x32\x0e.shared.Header\x12\"\n\x05\x62\x61tch\x18\x02 \x01(\x0b\x32\x13.packet.PacketBatch\x12\x11\n\texpiry_ms\x18\x03 \x01(\r\"x\n\x11PacketBatchUpdate\x12\x34\n\x07\x62\x61tches\x18\x01 \x01(\x0b\x32!.block_engine.ExpiringPacketBatchH\x00\x12&\n\theartbeat\x18\x02 \x01(\x0b\x32\x11.shared.HeartbeatH\x00\x42\x05\n\x03msg\"I\n!StartExpiringPacketStreamResponse\x12$\n\theartbeat\x18\x01 \x01(\x0b\x32\x11.shared.Heartbeat2\xd5\x02\n\x14\x42lockEngineValidator\x12\x65\n\x10SubscribePackets\x12%.block_engine.SubscribePacketsRequest\x1a&.block_engine.SubscribePacketsResponse\"\x00\x30\x01\x12\x65\n\x10SubscribeBundles\x12%.block_engine.SubscribeBundlesRequest\x1a&.block_engine.SubscribeBundlesResponse\"\x00\x30\x01\x12o\n\x16GetBlockBuilderFeeInfo\x12(.block_engine.BlockBuilderFeeInfoRequest\x1a).block_engine.BlockBuilderFeeInfoResponse\"\x00\x32\xf1\x02\n\x12\x42lockEngineRelayer\x12r\n\x1bSubscribeAccountsOfInterest\x12\'.block_engine.AccountsOfInterestRequest\x1a&.block_engine.AccountsOfInterestUpdate\"\x00\x30\x01\x12r\n\x1bSubscribeProgramsOfInterest\x12\'.block_engine.ProgramsOfInterestRequest\x1a&.block_engine.ProgramsOfInterestUpdate\"\x00\x30\x01\x12s\n\x19StartExpiringPacketStream\x12\x1f.block_engine.PacketBatchUpdate\x1a/.block_engine.StartExpiringPacketStreamResponse\"\x00(\x01\x30\x01\x62\x06proto3') 20 | 21 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 22 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'block_engine_pb2', globals()) 23 | if _descriptor._USE_C_DESCRIPTORS == False: 24 | 25 | DESCRIPTOR._options = None 26 | _SUBSCRIBEPACKETSREQUEST._serialized_start=78 27 | _SUBSCRIBEPACKETSREQUEST._serialized_end=103 28 | _SUBSCRIBEPACKETSRESPONSE._serialized_start=105 29 | _SUBSCRIBEPACKETSRESPONSE._serialized_end=199 30 | _SUBSCRIBEBUNDLESREQUEST._serialized_start=201 31 | _SUBSCRIBEBUNDLESREQUEST._serialized_end=226 32 | _SUBSCRIBEBUNDLESRESPONSE._serialized_start=228 33 | _SUBSCRIBEBUNDLESRESPONSE._serialized_end=291 34 | _BLOCKBUILDERFEEINFOREQUEST._serialized_start=293 35 | _BLOCKBUILDERFEEINFOREQUEST._serialized_end=321 36 | _BLOCKBUILDERFEEINFORESPONSE._serialized_start=323 37 | _BLOCKBUILDERFEEINFORESPONSE._serialized_end=388 38 | _ACCOUNTSOFINTEREST._serialized_start=390 39 | _ACCOUNTSOFINTEREST._serialized_end=428 40 | _ACCOUNTSOFINTERESTREQUEST._serialized_start=430 41 | _ACCOUNTSOFINTERESTREQUEST._serialized_end=457 42 | _ACCOUNTSOFINTERESTUPDATE._serialized_start=459 43 | _ACCOUNTSOFINTERESTUPDATE._serialized_end=503 44 | _PROGRAMSOFINTERESTREQUEST._serialized_start=505 45 | _PROGRAMSOFINTERESTREQUEST._serialized_end=532 46 | _PROGRAMSOFINTERESTUPDATE._serialized_start=534 47 | _PROGRAMSOFINTERESTUPDATE._serialized_end=578 48 | _EXPIRINGPACKETBATCH._serialized_start=580 49 | _EXPIRINGPACKETBATCH._serialized_end=688 50 | _PACKETBATCHUPDATE._serialized_start=690 51 | _PACKETBATCHUPDATE._serialized_end=810 52 | _STARTEXPIRINGPACKETSTREAMRESPONSE._serialized_start=812 53 | _STARTEXPIRINGPACKETSTREAMRESPONSE._serialized_end=885 54 | _BLOCKENGINEVALIDATOR._serialized_start=888 55 | _BLOCKENGINEVALIDATOR._serialized_end=1229 56 | _BLOCKENGINERELAYER._serialized_start=1232 57 | _BLOCKENGINERELAYER._serialized_end=1601 58 | # @@protoc_insertion_point(module_scope) 59 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/block_engine_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | import builtins 6 | import bundle_pb2 7 | import collections.abc 8 | import google.protobuf.descriptor 9 | import google.protobuf.internal.containers 10 | import google.protobuf.message 11 | import packet_pb2 12 | import shared_pb2 13 | import sys 14 | 15 | if sys.version_info >= (3, 8): 16 | import typing as typing_extensions 17 | else: 18 | import typing_extensions 19 | 20 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 21 | 22 | @typing_extensions.final 23 | class SubscribePacketsRequest(google.protobuf.message.Message): 24 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 25 | 26 | def __init__( 27 | self, 28 | ) -> None: ... 29 | 30 | global___SubscribePacketsRequest = SubscribePacketsRequest 31 | 32 | @typing_extensions.final 33 | class SubscribePacketsResponse(google.protobuf.message.Message): 34 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 35 | 36 | HEADER_FIELD_NUMBER: builtins.int 37 | BATCH_FIELD_NUMBER: builtins.int 38 | @property 39 | def header(self) -> shared_pb2.Header: ... 40 | @property 41 | def batch(self) -> packet_pb2.PacketBatch: ... 42 | def __init__( 43 | self, 44 | *, 45 | header: shared_pb2.Header | None = ..., 46 | batch: packet_pb2.PacketBatch | None = ..., 47 | ) -> None: ... 48 | def HasField(self, field_name: typing_extensions.Literal["batch", b"batch", "header", b"header"]) -> builtins.bool: ... 49 | def ClearField(self, field_name: typing_extensions.Literal["batch", b"batch", "header", b"header"]) -> None: ... 50 | 51 | global___SubscribePacketsResponse = SubscribePacketsResponse 52 | 53 | @typing_extensions.final 54 | class SubscribeBundlesRequest(google.protobuf.message.Message): 55 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 56 | 57 | def __init__( 58 | self, 59 | ) -> None: ... 60 | 61 | global___SubscribeBundlesRequest = SubscribeBundlesRequest 62 | 63 | @typing_extensions.final 64 | class SubscribeBundlesResponse(google.protobuf.message.Message): 65 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 66 | 67 | BUNDLES_FIELD_NUMBER: builtins.int 68 | @property 69 | def bundles(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[bundle_pb2.BundleUuid]: ... 70 | def __init__( 71 | self, 72 | *, 73 | bundles: collections.abc.Iterable[bundle_pb2.BundleUuid] | None = ..., 74 | ) -> None: ... 75 | def ClearField(self, field_name: typing_extensions.Literal["bundles", b"bundles"]) -> None: ... 76 | 77 | global___SubscribeBundlesResponse = SubscribeBundlesResponse 78 | 79 | @typing_extensions.final 80 | class BlockBuilderFeeInfoRequest(google.protobuf.message.Message): 81 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 82 | 83 | def __init__( 84 | self, 85 | ) -> None: ... 86 | 87 | global___BlockBuilderFeeInfoRequest = BlockBuilderFeeInfoRequest 88 | 89 | @typing_extensions.final 90 | class BlockBuilderFeeInfoResponse(google.protobuf.message.Message): 91 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 92 | 93 | PUBKEY_FIELD_NUMBER: builtins.int 94 | COMMISSION_FIELD_NUMBER: builtins.int 95 | pubkey: builtins.str 96 | commission: builtins.int 97 | """commission (0-100)""" 98 | def __init__( 99 | self, 100 | *, 101 | pubkey: builtins.str = ..., 102 | commission: builtins.int = ..., 103 | ) -> None: ... 104 | def ClearField(self, field_name: typing_extensions.Literal["commission", b"commission", "pubkey", b"pubkey"]) -> None: ... 105 | 106 | global___BlockBuilderFeeInfoResponse = BlockBuilderFeeInfoResponse 107 | 108 | @typing_extensions.final 109 | class AccountsOfInterest(google.protobuf.message.Message): 110 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 111 | 112 | ACCOUNTS_FIELD_NUMBER: builtins.int 113 | @property 114 | def accounts(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: 115 | """use * for all accounts""" 116 | def __init__( 117 | self, 118 | *, 119 | accounts: collections.abc.Iterable[builtins.str] | None = ..., 120 | ) -> None: ... 121 | def ClearField(self, field_name: typing_extensions.Literal["accounts", b"accounts"]) -> None: ... 122 | 123 | global___AccountsOfInterest = AccountsOfInterest 124 | 125 | @typing_extensions.final 126 | class AccountsOfInterestRequest(google.protobuf.message.Message): 127 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 128 | 129 | def __init__( 130 | self, 131 | ) -> None: ... 132 | 133 | global___AccountsOfInterestRequest = AccountsOfInterestRequest 134 | 135 | @typing_extensions.final 136 | class AccountsOfInterestUpdate(google.protobuf.message.Message): 137 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 138 | 139 | ACCOUNTS_FIELD_NUMBER: builtins.int 140 | @property 141 | def accounts(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... 142 | def __init__( 143 | self, 144 | *, 145 | accounts: collections.abc.Iterable[builtins.str] | None = ..., 146 | ) -> None: ... 147 | def ClearField(self, field_name: typing_extensions.Literal["accounts", b"accounts"]) -> None: ... 148 | 149 | global___AccountsOfInterestUpdate = AccountsOfInterestUpdate 150 | 151 | @typing_extensions.final 152 | class ProgramsOfInterestRequest(google.protobuf.message.Message): 153 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 154 | 155 | def __init__( 156 | self, 157 | ) -> None: ... 158 | 159 | global___ProgramsOfInterestRequest = ProgramsOfInterestRequest 160 | 161 | @typing_extensions.final 162 | class ProgramsOfInterestUpdate(google.protobuf.message.Message): 163 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 164 | 165 | PROGRAMS_FIELD_NUMBER: builtins.int 166 | @property 167 | def programs(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... 168 | def __init__( 169 | self, 170 | *, 171 | programs: collections.abc.Iterable[builtins.str] | None = ..., 172 | ) -> None: ... 173 | def ClearField(self, field_name: typing_extensions.Literal["programs", b"programs"]) -> None: ... 174 | 175 | global___ProgramsOfInterestUpdate = ProgramsOfInterestUpdate 176 | 177 | @typing_extensions.final 178 | class ExpiringPacketBatch(google.protobuf.message.Message): 179 | """A series of packets with an expiration attached to them. 180 | The header contains a timestamp for when this packet was generated. 181 | The expiry is how long the packet batches have before they expire and are forwarded to the validator. 182 | This provides a more censorship resistant method to MEV than block engines receiving packets directly. 183 | """ 184 | 185 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 186 | 187 | HEADER_FIELD_NUMBER: builtins.int 188 | BATCH_FIELD_NUMBER: builtins.int 189 | EXPIRY_MS_FIELD_NUMBER: builtins.int 190 | @property 191 | def header(self) -> shared_pb2.Header: ... 192 | @property 193 | def batch(self) -> packet_pb2.PacketBatch: ... 194 | expiry_ms: builtins.int 195 | def __init__( 196 | self, 197 | *, 198 | header: shared_pb2.Header | None = ..., 199 | batch: packet_pb2.PacketBatch | None = ..., 200 | expiry_ms: builtins.int = ..., 201 | ) -> None: ... 202 | def HasField(self, field_name: typing_extensions.Literal["batch", b"batch", "header", b"header"]) -> builtins.bool: ... 203 | def ClearField(self, field_name: typing_extensions.Literal["batch", b"batch", "expiry_ms", b"expiry_ms", "header", b"header"]) -> None: ... 204 | 205 | global___ExpiringPacketBatch = ExpiringPacketBatch 206 | 207 | @typing_extensions.final 208 | class PacketBatchUpdate(google.protobuf.message.Message): 209 | """Packets and heartbeats are sent over the same stream. 210 | ExpiringPacketBatches have an expiration attached to them so the block engine can track 211 | how long it has until the relayer forwards the packets to the validator. 212 | Heartbeats contain a timestamp from the system and is used as a simple and naive time-sync mechanism 213 | so the block engine has some idea on how far their clocks are apart. 214 | """ 215 | 216 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 217 | 218 | BATCHES_FIELD_NUMBER: builtins.int 219 | HEARTBEAT_FIELD_NUMBER: builtins.int 220 | @property 221 | def batches(self) -> global___ExpiringPacketBatch: ... 222 | @property 223 | def heartbeat(self) -> shared_pb2.Heartbeat: ... 224 | def __init__( 225 | self, 226 | *, 227 | batches: global___ExpiringPacketBatch | None = ..., 228 | heartbeat: shared_pb2.Heartbeat | None = ..., 229 | ) -> None: ... 230 | def HasField(self, field_name: typing_extensions.Literal["batches", b"batches", "heartbeat", b"heartbeat", "msg", b"msg"]) -> builtins.bool: ... 231 | def ClearField(self, field_name: typing_extensions.Literal["batches", b"batches", "heartbeat", b"heartbeat", "msg", b"msg"]) -> None: ... 232 | def WhichOneof(self, oneof_group: typing_extensions.Literal["msg", b"msg"]) -> typing_extensions.Literal["batches", "heartbeat"] | None: ... 233 | 234 | global___PacketBatchUpdate = PacketBatchUpdate 235 | 236 | @typing_extensions.final 237 | class StartExpiringPacketStreamResponse(google.protobuf.message.Message): 238 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 239 | 240 | HEARTBEAT_FIELD_NUMBER: builtins.int 241 | @property 242 | def heartbeat(self) -> shared_pb2.Heartbeat: ... 243 | def __init__( 244 | self, 245 | *, 246 | heartbeat: shared_pb2.Heartbeat | None = ..., 247 | ) -> None: ... 248 | def HasField(self, field_name: typing_extensions.Literal["heartbeat", b"heartbeat"]) -> builtins.bool: ... 249 | def ClearField(self, field_name: typing_extensions.Literal["heartbeat", b"heartbeat"]) -> None: ... 250 | 251 | global___StartExpiringPacketStreamResponse = StartExpiringPacketStreamResponse 252 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/block_engine_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | import abc 6 | import block_engine_pb2 7 | import collections.abc 8 | import grpc 9 | 10 | class BlockEngineValidatorStub: 11 | """/ Validators can connect to Block Engines to receive packets and bundles.""" 12 | 13 | def __init__(self, channel: grpc.Channel) -> None: ... 14 | SubscribePackets: grpc.UnaryStreamMultiCallable[ 15 | block_engine_pb2.SubscribePacketsRequest, 16 | block_engine_pb2.SubscribePacketsResponse, 17 | ] 18 | """/ Validators can subscribe to the block engine to receive a stream of packets""" 19 | SubscribeBundles: grpc.UnaryStreamMultiCallable[ 20 | block_engine_pb2.SubscribeBundlesRequest, 21 | block_engine_pb2.SubscribeBundlesResponse, 22 | ] 23 | """/ Validators can subscribe to the block engine to receive a stream of simulated and profitable bundles""" 24 | GetBlockBuilderFeeInfo: grpc.UnaryUnaryMultiCallable[ 25 | block_engine_pb2.BlockBuilderFeeInfoRequest, 26 | block_engine_pb2.BlockBuilderFeeInfoResponse, 27 | ] 28 | """Block builders can optionally collect fees. This returns fee information if a block builder wants to 29 | collect one. 30 | """ 31 | 32 | class BlockEngineValidatorServicer(metaclass=abc.ABCMeta): 33 | """/ Validators can connect to Block Engines to receive packets and bundles.""" 34 | 35 | @abc.abstractmethod 36 | def SubscribePackets( 37 | self, 38 | request: block_engine_pb2.SubscribePacketsRequest, 39 | context: grpc.ServicerContext, 40 | ) -> collections.abc.Iterator[block_engine_pb2.SubscribePacketsResponse]: 41 | """/ Validators can subscribe to the block engine to receive a stream of packets""" 42 | @abc.abstractmethod 43 | def SubscribeBundles( 44 | self, 45 | request: block_engine_pb2.SubscribeBundlesRequest, 46 | context: grpc.ServicerContext, 47 | ) -> collections.abc.Iterator[block_engine_pb2.SubscribeBundlesResponse]: 48 | """/ Validators can subscribe to the block engine to receive a stream of simulated and profitable bundles""" 49 | @abc.abstractmethod 50 | def GetBlockBuilderFeeInfo( 51 | self, 52 | request: block_engine_pb2.BlockBuilderFeeInfoRequest, 53 | context: grpc.ServicerContext, 54 | ) -> block_engine_pb2.BlockBuilderFeeInfoResponse: 55 | """Block builders can optionally collect fees. This returns fee information if a block builder wants to 56 | collect one. 57 | """ 58 | 59 | def add_BlockEngineValidatorServicer_to_server(servicer: BlockEngineValidatorServicer, server: grpc.Server) -> None: ... 60 | 61 | class BlockEngineRelayerStub: 62 | """/ Relayers can forward packets to Block Engines. 63 | / Block Engines provide an AccountsOfInterest field to only send transactions that are of interest. 64 | """ 65 | 66 | def __init__(self, channel: grpc.Channel) -> None: ... 67 | SubscribeAccountsOfInterest: grpc.UnaryStreamMultiCallable[ 68 | block_engine_pb2.AccountsOfInterestRequest, 69 | block_engine_pb2.AccountsOfInterestUpdate, 70 | ] 71 | """/ The block engine feeds accounts of interest (AOI) updates to the relayer periodically. 72 | / For all transactions the relayer receives, it forwards transactions to the block engine which write-lock 73 | / any of the accounts in the AOI. 74 | """ 75 | SubscribeProgramsOfInterest: grpc.UnaryStreamMultiCallable[ 76 | block_engine_pb2.ProgramsOfInterestRequest, 77 | block_engine_pb2.ProgramsOfInterestUpdate, 78 | ] 79 | StartExpiringPacketStream: grpc.StreamStreamMultiCallable[ 80 | block_engine_pb2.PacketBatchUpdate, 81 | block_engine_pb2.StartExpiringPacketStreamResponse, 82 | ] 83 | """Validators can subscribe to packets from the relayer and receive a multiplexed signal that contains a mixture 84 | of packets and heartbeats. 85 | NOTE: This is a bi-directional stream due to a bug with how Envoy handles half closed client-side streams. 86 | The issue is being tracked here: https://github.com/envoyproxy/envoy/issues/22748. In the meantime, the 87 | server will stream heartbeats to clients at some reasonable cadence. 88 | """ 89 | 90 | class BlockEngineRelayerServicer(metaclass=abc.ABCMeta): 91 | """/ Relayers can forward packets to Block Engines. 92 | / Block Engines provide an AccountsOfInterest field to only send transactions that are of interest. 93 | """ 94 | 95 | @abc.abstractmethod 96 | def SubscribeAccountsOfInterest( 97 | self, 98 | request: block_engine_pb2.AccountsOfInterestRequest, 99 | context: grpc.ServicerContext, 100 | ) -> collections.abc.Iterator[block_engine_pb2.AccountsOfInterestUpdate]: 101 | """/ The block engine feeds accounts of interest (AOI) updates to the relayer periodically. 102 | / For all transactions the relayer receives, it forwards transactions to the block engine which write-lock 103 | / any of the accounts in the AOI. 104 | """ 105 | @abc.abstractmethod 106 | def SubscribeProgramsOfInterest( 107 | self, 108 | request: block_engine_pb2.ProgramsOfInterestRequest, 109 | context: grpc.ServicerContext, 110 | ) -> collections.abc.Iterator[block_engine_pb2.ProgramsOfInterestUpdate]: ... 111 | @abc.abstractmethod 112 | def StartExpiringPacketStream( 113 | self, 114 | request_iterator: collections.abc.Iterator[block_engine_pb2.PacketBatchUpdate], 115 | context: grpc.ServicerContext, 116 | ) -> collections.abc.Iterator[block_engine_pb2.StartExpiringPacketStreamResponse]: 117 | """Validators can subscribe to packets from the relayer and receive a multiplexed signal that contains a mixture 118 | of packets and heartbeats. 119 | NOTE: This is a bi-directional stream due to a bug with how Envoy handles half closed client-side streams. 120 | The issue is being tracked here: https://github.com/envoyproxy/envoy/issues/22748. In the meantime, the 121 | server will stream heartbeats to clients at some reasonable cadence. 122 | """ 123 | 124 | def add_BlockEngineRelayerServicer_to_server(servicer: BlockEngineRelayerServicer, server: grpc.Server) -> None: ... 125 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/block_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: block.proto 4 | """Generated protocol buffer code.""" 5 | from google.protobuf.internal import builder as _builder 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | import shared_pb2 as shared__pb2 15 | 16 | 17 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0b\x62lock.proto\x12\x05\x62lock\x1a\x0cshared.proto\"\xb6\x01\n\x0e\x43ondensedBlock\x12\x1e\n\x06header\x18\x01 \x01(\x0b\x32\x0e.shared.Header\x12\x1a\n\x12previous_blockhash\x18\x02 \x01(\t\x12\x11\n\tblockhash\x18\x03 \x01(\t\x12\x13\n\x0bparent_slot\x18\x04 \x01(\x04\x12\x1e\n\x16versioned_transactions\x18\x05 \x03(\x0c\x12\x0c\n\x04slot\x18\x06 \x01(\x04\x12\x12\n\ncommitment\x18\x07 \x01(\tb\x06proto3') 18 | 19 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 20 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'block_pb2', globals()) 21 | if _descriptor._USE_C_DESCRIPTORS == False: 22 | 23 | DESCRIPTOR._options = None 24 | _CONDENSEDBLOCK._serialized_start=37 25 | _CONDENSEDBLOCK._serialized_end=219 26 | # @@protoc_insertion_point(module_scope) 27 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/block_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | import builtins 6 | import collections.abc 7 | import google.protobuf.descriptor 8 | import google.protobuf.internal.containers 9 | import google.protobuf.message 10 | import shared_pb2 11 | import sys 12 | 13 | if sys.version_info >= (3, 8): 14 | import typing as typing_extensions 15 | else: 16 | import typing_extensions 17 | 18 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 19 | 20 | @typing_extensions.final 21 | class CondensedBlock(google.protobuf.message.Message): 22 | """Condensed block helpful for getting data around efficiently internal to our system.""" 23 | 24 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 25 | 26 | HEADER_FIELD_NUMBER: builtins.int 27 | PREVIOUS_BLOCKHASH_FIELD_NUMBER: builtins.int 28 | BLOCKHASH_FIELD_NUMBER: builtins.int 29 | PARENT_SLOT_FIELD_NUMBER: builtins.int 30 | VERSIONED_TRANSACTIONS_FIELD_NUMBER: builtins.int 31 | SLOT_FIELD_NUMBER: builtins.int 32 | COMMITMENT_FIELD_NUMBER: builtins.int 33 | @property 34 | def header(self) -> shared_pb2.Header: ... 35 | previous_blockhash: builtins.str 36 | blockhash: builtins.str 37 | parent_slot: builtins.int 38 | @property 39 | def versioned_transactions(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.bytes]: ... 40 | slot: builtins.int 41 | commitment: builtins.str 42 | def __init__( 43 | self, 44 | *, 45 | header: shared_pb2.Header | None = ..., 46 | previous_blockhash: builtins.str = ..., 47 | blockhash: builtins.str = ..., 48 | parent_slot: builtins.int = ..., 49 | versioned_transactions: collections.abc.Iterable[builtins.bytes] | None = ..., 50 | slot: builtins.int = ..., 51 | commitment: builtins.str = ..., 52 | ) -> None: ... 53 | def HasField(self, field_name: typing_extensions.Literal["header", b"header"]) -> builtins.bool: ... 54 | def ClearField(self, field_name: typing_extensions.Literal["blockhash", b"blockhash", "commitment", b"commitment", "header", b"header", "parent_slot", b"parent_slot", "previous_blockhash", b"previous_blockhash", "slot", b"slot", "versioned_transactions", b"versioned_transactions"]) -> None: ... 55 | 56 | global___CondensedBlock = CondensedBlock 57 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/block_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/block_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/bundle_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: bundle.proto 4 | """Generated protocol buffer code.""" 5 | from google.protobuf.internal import builder as _builder 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | import packet_pb2 as packet__pb2 15 | import shared_pb2 as shared__pb2 16 | 17 | 18 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x62undle.proto\x12\x06\x62undle\x1a\x0cpacket.proto\x1a\x0cshared.proto\"I\n\x06\x42undle\x12\x1e\n\x06header\x18\x02 \x01(\x0b\x32\x0e.shared.Header\x12\x1f\n\x07packets\x18\x03 \x03(\x0b\x32\x0e.packet.Packet\":\n\nBundleUuid\x12\x1e\n\x06\x62undle\x18\x01 \x01(\x0b\x32\x0e.bundle.Bundle\x12\x0c\n\x04uuid\x18\x02 \x01(\t\"4\n\x08\x41\x63\x63\x65pted\x12\x0c\n\x04slot\x18\x01 \x01(\x04\x12\x1a\n\x12validator_identity\x18\x02 \x01(\t\"\x8c\x02\n\x08Rejected\x12\x45\n\x1astate_auction_bid_rejected\x18\x01 \x01(\x0b\x32\x1f.bundle.StateAuctionBidRejectedH\x00\x12\x45\n\x1awinning_batch_bid_rejected\x18\x02 \x01(\x0b\x32\x1f.bundle.WinningBatchBidRejectedH\x00\x12\x37\n\x12simulation_failure\x18\x03 \x01(\x0b\x32\x19.bundle.SimulationFailureH\x00\x12/\n\x0einternal_error\x18\x04 \x01(\x0b\x32\x15.bundle.InternalErrorH\x00\x42\x08\n\x06reason\"g\n\x17WinningBatchBidRejected\x12\x12\n\nauction_id\x18\x01 \x01(\t\x12\x1e\n\x16simulated_bid_lamports\x18\x02 \x01(\x04\x12\x10\n\x03msg\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x06\n\x04_msg\"g\n\x17StateAuctionBidRejected\x12\x12\n\nauction_id\x18\x01 \x01(\t\x12\x1e\n\x16simulated_bid_lamports\x18\x02 \x01(\x04\x12\x10\n\x03msg\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x06\n\x04_msg\"C\n\x11SimulationFailure\x12\x14\n\x0ctx_signature\x18\x01 \x01(\t\x12\x10\n\x03msg\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x06\n\x04_msg\"\x1c\n\rInternalError\x12\x0b\n\x03msg\x18\x01 \x01(\t\"w\n\x0c\x42undleResult\x12\x11\n\tbundle_id\x18\x01 \x01(\t\x12$\n\x08\x61\x63\x63\x65pted\x18\x02 \x01(\x0b\x32\x10.bundle.AcceptedH\x00\x12$\n\x08rejected\x18\x03 \x01(\x0b\x32\x10.bundle.RejectedH\x00\x42\x08\n\x06resultb\x06proto3') 19 | 20 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 21 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'bundle_pb2', globals()) 22 | if _descriptor._USE_C_DESCRIPTORS == False: 23 | 24 | DESCRIPTOR._options = None 25 | _BUNDLE._serialized_start=52 26 | _BUNDLE._serialized_end=125 27 | _BUNDLEUUID._serialized_start=127 28 | _BUNDLEUUID._serialized_end=185 29 | _ACCEPTED._serialized_start=187 30 | _ACCEPTED._serialized_end=239 31 | _REJECTED._serialized_start=242 32 | _REJECTED._serialized_end=510 33 | _WINNINGBATCHBIDREJECTED._serialized_start=512 34 | _WINNINGBATCHBIDREJECTED._serialized_end=615 35 | _STATEAUCTIONBIDREJECTED._serialized_start=617 36 | _STATEAUCTIONBIDREJECTED._serialized_end=720 37 | _SIMULATIONFAILURE._serialized_start=722 38 | _SIMULATIONFAILURE._serialized_end=789 39 | _INTERNALERROR._serialized_start=791 40 | _INTERNALERROR._serialized_end=819 41 | _BUNDLERESULT._serialized_start=821 42 | _BUNDLERESULT._serialized_end=940 43 | # @@protoc_insertion_point(module_scope) 44 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/bundle_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | import builtins 6 | import collections.abc 7 | import google.protobuf.descriptor 8 | import google.protobuf.internal.containers 9 | import google.protobuf.message 10 | import packet_pb2 11 | import shared_pb2 12 | import sys 13 | 14 | if sys.version_info >= (3, 8): 15 | import typing as typing_extensions 16 | else: 17 | import typing_extensions 18 | 19 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 20 | 21 | @typing_extensions.final 22 | class Bundle(google.protobuf.message.Message): 23 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 24 | 25 | HEADER_FIELD_NUMBER: builtins.int 26 | PACKETS_FIELD_NUMBER: builtins.int 27 | @property 28 | def header(self) -> shared_pb2.Header: ... 29 | @property 30 | def packets(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[packet_pb2.Packet]: ... 31 | def __init__( 32 | self, 33 | *, 34 | header: shared_pb2.Header | None = ..., 35 | packets: collections.abc.Iterable[packet_pb2.Packet] | None = ..., 36 | ) -> None: ... 37 | def HasField(self, field_name: typing_extensions.Literal["header", b"header"]) -> builtins.bool: ... 38 | def ClearField(self, field_name: typing_extensions.Literal["header", b"header", "packets", b"packets"]) -> None: ... 39 | 40 | global___Bundle = Bundle 41 | 42 | @typing_extensions.final 43 | class BundleUuid(google.protobuf.message.Message): 44 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 45 | 46 | BUNDLE_FIELD_NUMBER: builtins.int 47 | UUID_FIELD_NUMBER: builtins.int 48 | @property 49 | def bundle(self) -> global___Bundle: ... 50 | uuid: builtins.str 51 | def __init__( 52 | self, 53 | *, 54 | bundle: global___Bundle | None = ..., 55 | uuid: builtins.str = ..., 56 | ) -> None: ... 57 | def HasField(self, field_name: typing_extensions.Literal["bundle", b"bundle"]) -> builtins.bool: ... 58 | def ClearField(self, field_name: typing_extensions.Literal["bundle", b"bundle", "uuid", b"uuid"]) -> None: ... 59 | 60 | global___BundleUuid = BundleUuid 61 | 62 | @typing_extensions.final 63 | class Accepted(google.protobuf.message.Message): 64 | """Bundle Result Types 65 | 66 | Indicates the bundle was accepted and forwarded to a validator. 67 | NOTE: A single bundle may have multiple events emitted if forwarded to many validators. 68 | """ 69 | 70 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 71 | 72 | SLOT_FIELD_NUMBER: builtins.int 73 | VALIDATOR_IDENTITY_FIELD_NUMBER: builtins.int 74 | slot: builtins.int 75 | """Slot at which bundle was forwarded.""" 76 | validator_identity: builtins.str 77 | """Validator identity bundle was forwarded to.""" 78 | def __init__( 79 | self, 80 | *, 81 | slot: builtins.int = ..., 82 | validator_identity: builtins.str = ..., 83 | ) -> None: ... 84 | def ClearField(self, field_name: typing_extensions.Literal["slot", b"slot", "validator_identity", b"validator_identity"]) -> None: ... 85 | 86 | global___Accepted = Accepted 87 | 88 | @typing_extensions.final 89 | class Rejected(google.protobuf.message.Message): 90 | """Indicates the bundle was dropped and therefore not forwarded to any validator.""" 91 | 92 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 93 | 94 | STATE_AUCTION_BID_REJECTED_FIELD_NUMBER: builtins.int 95 | WINNING_BATCH_BID_REJECTED_FIELD_NUMBER: builtins.int 96 | SIMULATION_FAILURE_FIELD_NUMBER: builtins.int 97 | INTERNAL_ERROR_FIELD_NUMBER: builtins.int 98 | @property 99 | def state_auction_bid_rejected(self) -> global___StateAuctionBidRejected: ... 100 | @property 101 | def winning_batch_bid_rejected(self) -> global___WinningBatchBidRejected: ... 102 | @property 103 | def simulation_failure(self) -> global___SimulationFailure: ... 104 | @property 105 | def internal_error(self) -> global___InternalError: ... 106 | def __init__( 107 | self, 108 | *, 109 | state_auction_bid_rejected: global___StateAuctionBidRejected | None = ..., 110 | winning_batch_bid_rejected: global___WinningBatchBidRejected | None = ..., 111 | simulation_failure: global___SimulationFailure | None = ..., 112 | internal_error: global___InternalError | None = ..., 113 | ) -> None: ... 114 | def HasField(self, field_name: typing_extensions.Literal["internal_error", b"internal_error", "reason", b"reason", "simulation_failure", b"simulation_failure", "state_auction_bid_rejected", b"state_auction_bid_rejected", "winning_batch_bid_rejected", b"winning_batch_bid_rejected"]) -> builtins.bool: ... 115 | def ClearField(self, field_name: typing_extensions.Literal["internal_error", b"internal_error", "reason", b"reason", "simulation_failure", b"simulation_failure", "state_auction_bid_rejected", b"state_auction_bid_rejected", "winning_batch_bid_rejected", b"winning_batch_bid_rejected"]) -> None: ... 116 | def WhichOneof(self, oneof_group: typing_extensions.Literal["reason", b"reason"]) -> typing_extensions.Literal["state_auction_bid_rejected", "winning_batch_bid_rejected", "simulation_failure", "internal_error"] | None: ... 117 | 118 | global___Rejected = Rejected 119 | 120 | @typing_extensions.final 121 | class WinningBatchBidRejected(google.protobuf.message.Message): 122 | """Indicates the bundle's bid was high enough to win its state auction. 123 | However, not high enough relative to other state auction winners and therefore excluded from being forwarded. 124 | """ 125 | 126 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 127 | 128 | AUCTION_ID_FIELD_NUMBER: builtins.int 129 | SIMULATED_BID_LAMPORTS_FIELD_NUMBER: builtins.int 130 | MSG_FIELD_NUMBER: builtins.int 131 | auction_id: builtins.str 132 | """Auction's unique identifier.""" 133 | simulated_bid_lamports: builtins.int 134 | """Bundle's simulated bid.""" 135 | msg: builtins.str 136 | def __init__( 137 | self, 138 | *, 139 | auction_id: builtins.str = ..., 140 | simulated_bid_lamports: builtins.int = ..., 141 | msg: builtins.str | None = ..., 142 | ) -> None: ... 143 | def HasField(self, field_name: typing_extensions.Literal["_msg", b"_msg", "msg", b"msg"]) -> builtins.bool: ... 144 | def ClearField(self, field_name: typing_extensions.Literal["_msg", b"_msg", "auction_id", b"auction_id", "msg", b"msg", "simulated_bid_lamports", b"simulated_bid_lamports"]) -> None: ... 145 | def WhichOneof(self, oneof_group: typing_extensions.Literal["_msg", b"_msg"]) -> typing_extensions.Literal["msg"] | None: ... 146 | 147 | global___WinningBatchBidRejected = WinningBatchBidRejected 148 | 149 | @typing_extensions.final 150 | class StateAuctionBidRejected(google.protobuf.message.Message): 151 | """Indicates the bundle's bid was __not__ high enough to be included in its state auction's set of winners.""" 152 | 153 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 154 | 155 | AUCTION_ID_FIELD_NUMBER: builtins.int 156 | SIMULATED_BID_LAMPORTS_FIELD_NUMBER: builtins.int 157 | MSG_FIELD_NUMBER: builtins.int 158 | auction_id: builtins.str 159 | """Auction's unique identifier.""" 160 | simulated_bid_lamports: builtins.int 161 | """Bundle's simulated bid.""" 162 | msg: builtins.str 163 | def __init__( 164 | self, 165 | *, 166 | auction_id: builtins.str = ..., 167 | simulated_bid_lamports: builtins.int = ..., 168 | msg: builtins.str | None = ..., 169 | ) -> None: ... 170 | def HasField(self, field_name: typing_extensions.Literal["_msg", b"_msg", "msg", b"msg"]) -> builtins.bool: ... 171 | def ClearField(self, field_name: typing_extensions.Literal["_msg", b"_msg", "auction_id", b"auction_id", "msg", b"msg", "simulated_bid_lamports", b"simulated_bid_lamports"]) -> None: ... 172 | def WhichOneof(self, oneof_group: typing_extensions.Literal["_msg", b"_msg"]) -> typing_extensions.Literal["msg"] | None: ... 173 | 174 | global___StateAuctionBidRejected = StateAuctionBidRejected 175 | 176 | @typing_extensions.final 177 | class SimulationFailure(google.protobuf.message.Message): 178 | """Bundle dropped due to simulation failure.""" 179 | 180 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 181 | 182 | TX_SIGNATURE_FIELD_NUMBER: builtins.int 183 | MSG_FIELD_NUMBER: builtins.int 184 | tx_signature: builtins.str 185 | """Signature of the offending transaction.""" 186 | msg: builtins.str 187 | def __init__( 188 | self, 189 | *, 190 | tx_signature: builtins.str = ..., 191 | msg: builtins.str | None = ..., 192 | ) -> None: ... 193 | def HasField(self, field_name: typing_extensions.Literal["_msg", b"_msg", "msg", b"msg"]) -> builtins.bool: ... 194 | def ClearField(self, field_name: typing_extensions.Literal["_msg", b"_msg", "msg", b"msg", "tx_signature", b"tx_signature"]) -> None: ... 195 | def WhichOneof(self, oneof_group: typing_extensions.Literal["_msg", b"_msg"]) -> typing_extensions.Literal["msg"] | None: ... 196 | 197 | global___SimulationFailure = SimulationFailure 198 | 199 | @typing_extensions.final 200 | class InternalError(google.protobuf.message.Message): 201 | """Bundle dropped due to an internal error.""" 202 | 203 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 204 | 205 | MSG_FIELD_NUMBER: builtins.int 206 | msg: builtins.str 207 | def __init__( 208 | self, 209 | *, 210 | msg: builtins.str = ..., 211 | ) -> None: ... 212 | def ClearField(self, field_name: typing_extensions.Literal["msg", b"msg"]) -> None: ... 213 | 214 | global___InternalError = InternalError 215 | 216 | @typing_extensions.final 217 | class BundleResult(google.protobuf.message.Message): 218 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 219 | 220 | BUNDLE_ID_FIELD_NUMBER: builtins.int 221 | ACCEPTED_FIELD_NUMBER: builtins.int 222 | REJECTED_FIELD_NUMBER: builtins.int 223 | bundle_id: builtins.str 224 | """Bundle's Uuid.""" 225 | @property 226 | def accepted(self) -> global___Accepted: ... 227 | @property 228 | def rejected(self) -> global___Rejected: ... 229 | def __init__( 230 | self, 231 | *, 232 | bundle_id: builtins.str = ..., 233 | accepted: global___Accepted | None = ..., 234 | rejected: global___Rejected | None = ..., 235 | ) -> None: ... 236 | def HasField(self, field_name: typing_extensions.Literal["accepted", b"accepted", "rejected", b"rejected", "result", b"result"]) -> builtins.bool: ... 237 | def ClearField(self, field_name: typing_extensions.Literal["accepted", b"accepted", "bundle_id", b"bundle_id", "rejected", b"rejected", "result", b"result"]) -> None: ... 238 | def WhichOneof(self, oneof_group: typing_extensions.Literal["result", b"result"]) -> typing_extensions.Literal["accepted", "rejected"] | None: ... 239 | 240 | global___BundleResult = BundleResult 241 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/bundle_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/bundle_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/packet_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: packet.proto 4 | """Generated protocol buffer code.""" 5 | from google.protobuf.internal import builder as _builder 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | 15 | 16 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cpacket.proto\x12\x06packet\".\n\x0bPacketBatch\x12\x1f\n\x07packets\x18\x01 \x03(\x0b\x32\x0e.packet.Packet\"2\n\x06Packet\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\x12\x1a\n\x04meta\x18\x02 \x01(\x0b\x32\x0c.packet.Meta\"j\n\x04Meta\x12\x0c\n\x04size\x18\x01 \x01(\x04\x12\x0c\n\x04\x61\x64\x64r\x18\x02 \x01(\t\x12\x0c\n\x04port\x18\x03 \x01(\r\x12\"\n\x05\x66lags\x18\x04 \x01(\x0b\x32\x13.packet.PacketFlags\x12\x14\n\x0csender_stake\x18\x05 \x01(\x04\"p\n\x0bPacketFlags\x12\x0f\n\x07\x64iscard\x18\x01 \x01(\x08\x12\x11\n\tforwarded\x18\x02 \x01(\x08\x12\x0e\n\x06repair\x18\x03 \x01(\x08\x12\x16\n\x0esimple_vote_tx\x18\x04 \x01(\x08\x12\x15\n\rtracer_packet\x18\x05 \x01(\x08\x62\x06proto3') 17 | 18 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 19 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'packet_pb2', globals()) 20 | if _descriptor._USE_C_DESCRIPTORS == False: 21 | 22 | DESCRIPTOR._options = None 23 | _PACKETBATCH._serialized_start=24 24 | _PACKETBATCH._serialized_end=70 25 | _PACKET._serialized_start=72 26 | _PACKET._serialized_end=122 27 | _META._serialized_start=124 28 | _META._serialized_end=230 29 | _PACKETFLAGS._serialized_start=232 30 | _PACKETFLAGS._serialized_end=344 31 | # @@protoc_insertion_point(module_scope) 32 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/packet_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | import builtins 6 | import collections.abc 7 | import google.protobuf.descriptor 8 | import google.protobuf.internal.containers 9 | import google.protobuf.message 10 | import sys 11 | 12 | if sys.version_info >= (3, 8): 13 | import typing as typing_extensions 14 | else: 15 | import typing_extensions 16 | 17 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 18 | 19 | @typing_extensions.final 20 | class PacketBatch(google.protobuf.message.Message): 21 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 22 | 23 | PACKETS_FIELD_NUMBER: builtins.int 24 | @property 25 | def packets(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___Packet]: ... 26 | def __init__( 27 | self, 28 | *, 29 | packets: collections.abc.Iterable[global___Packet] | None = ..., 30 | ) -> None: ... 31 | def ClearField(self, field_name: typing_extensions.Literal["packets", b"packets"]) -> None: ... 32 | 33 | global___PacketBatch = PacketBatch 34 | 35 | @typing_extensions.final 36 | class Packet(google.protobuf.message.Message): 37 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 38 | 39 | DATA_FIELD_NUMBER: builtins.int 40 | META_FIELD_NUMBER: builtins.int 41 | data: builtins.bytes 42 | @property 43 | def meta(self) -> global___Meta: ... 44 | def __init__( 45 | self, 46 | *, 47 | data: builtins.bytes = ..., 48 | meta: global___Meta | None = ..., 49 | ) -> None: ... 50 | def HasField(self, field_name: typing_extensions.Literal["meta", b"meta"]) -> builtins.bool: ... 51 | def ClearField(self, field_name: typing_extensions.Literal["data", b"data", "meta", b"meta"]) -> None: ... 52 | 53 | global___Packet = Packet 54 | 55 | @typing_extensions.final 56 | class Meta(google.protobuf.message.Message): 57 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 58 | 59 | SIZE_FIELD_NUMBER: builtins.int 60 | ADDR_FIELD_NUMBER: builtins.int 61 | PORT_FIELD_NUMBER: builtins.int 62 | FLAGS_FIELD_NUMBER: builtins.int 63 | SENDER_STAKE_FIELD_NUMBER: builtins.int 64 | size: builtins.int 65 | addr: builtins.str 66 | port: builtins.int 67 | @property 68 | def flags(self) -> global___PacketFlags: ... 69 | sender_stake: builtins.int 70 | def __init__( 71 | self, 72 | *, 73 | size: builtins.int = ..., 74 | addr: builtins.str = ..., 75 | port: builtins.int = ..., 76 | flags: global___PacketFlags | None = ..., 77 | sender_stake: builtins.int = ..., 78 | ) -> None: ... 79 | def HasField(self, field_name: typing_extensions.Literal["flags", b"flags"]) -> builtins.bool: ... 80 | def ClearField(self, field_name: typing_extensions.Literal["addr", b"addr", "flags", b"flags", "port", b"port", "sender_stake", b"sender_stake", "size", b"size"]) -> None: ... 81 | 82 | global___Meta = Meta 83 | 84 | @typing_extensions.final 85 | class PacketFlags(google.protobuf.message.Message): 86 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 87 | 88 | DISCARD_FIELD_NUMBER: builtins.int 89 | FORWARDED_FIELD_NUMBER: builtins.int 90 | REPAIR_FIELD_NUMBER: builtins.int 91 | SIMPLE_VOTE_TX_FIELD_NUMBER: builtins.int 92 | TRACER_PACKET_FIELD_NUMBER: builtins.int 93 | discard: builtins.bool 94 | forwarded: builtins.bool 95 | repair: builtins.bool 96 | simple_vote_tx: builtins.bool 97 | tracer_packet: builtins.bool 98 | def __init__( 99 | self, 100 | *, 101 | discard: builtins.bool = ..., 102 | forwarded: builtins.bool = ..., 103 | repair: builtins.bool = ..., 104 | simple_vote_tx: builtins.bool = ..., 105 | tracer_packet: builtins.bool = ..., 106 | ) -> None: ... 107 | def ClearField(self, field_name: typing_extensions.Literal["discard", b"discard", "forwarded", b"forwarded", "repair", b"repair", "simple_vote_tx", b"simple_vote_tx", "tracer_packet", b"tracer_packet"]) -> None: ... 108 | 109 | global___PacketFlags = PacketFlags 110 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/packet_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/packet_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/relayer_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: relayer.proto 4 | """Generated protocol buffer code.""" 5 | from google.protobuf.internal import builder as _builder 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | import packet_pb2 as packet__pb2 15 | import shared_pb2 as shared__pb2 16 | 17 | 18 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rrelayer.proto\x12\x07relayer\x1a\x0cpacket.proto\x1a\x0cshared.proto\"\x16\n\x14GetTpuConfigsRequest\"Y\n\x15GetTpuConfigsResponse\x12\x1b\n\x03tpu\x18\x01 \x01(\x0b\x32\x0e.shared.Socket\x12#\n\x0btpu_forward\x18\x02 \x01(\x0b\x32\x0e.shared.Socket\"\x19\n\x17SubscribePacketsRequest\"\x8f\x01\n\x18SubscribePacketsResponse\x12\x1e\n\x06header\x18\x01 \x01(\x0b\x32\x0e.shared.Header\x12&\n\theartbeat\x18\x02 \x01(\x0b\x32\x11.shared.HeartbeatH\x00\x12$\n\x05\x62\x61tch\x18\x03 \x01(\x0b\x32\x13.packet.PacketBatchH\x00\x42\x05\n\x03msg2\xb8\x01\n\x07Relayer\x12P\n\rGetTpuConfigs\x12\x1d.relayer.GetTpuConfigsRequest\x1a\x1e.relayer.GetTpuConfigsResponse\"\x00\x12[\n\x10SubscribePackets\x12 .relayer.SubscribePacketsRequest\x1a!.relayer.SubscribePacketsResponse\"\x00\x30\x01\x62\x06proto3') 19 | 20 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 21 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'relayer_pb2', globals()) 22 | if _descriptor._USE_C_DESCRIPTORS == False: 23 | 24 | DESCRIPTOR._options = None 25 | _GETTPUCONFIGSREQUEST._serialized_start=54 26 | _GETTPUCONFIGSREQUEST._serialized_end=76 27 | _GETTPUCONFIGSRESPONSE._serialized_start=78 28 | _GETTPUCONFIGSRESPONSE._serialized_end=167 29 | _SUBSCRIBEPACKETSREQUEST._serialized_start=169 30 | _SUBSCRIBEPACKETSREQUEST._serialized_end=194 31 | _SUBSCRIBEPACKETSRESPONSE._serialized_start=197 32 | _SUBSCRIBEPACKETSRESPONSE._serialized_end=340 33 | _RELAYER._serialized_start=343 34 | _RELAYER._serialized_end=527 35 | # @@protoc_insertion_point(module_scope) 36 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/relayer_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | import builtins 6 | import google.protobuf.descriptor 7 | import google.protobuf.message 8 | import packet_pb2 9 | import shared_pb2 10 | import sys 11 | 12 | if sys.version_info >= (3, 8): 13 | import typing as typing_extensions 14 | else: 15 | import typing_extensions 16 | 17 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 18 | 19 | @typing_extensions.final 20 | class GetTpuConfigsRequest(google.protobuf.message.Message): 21 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 22 | 23 | def __init__( 24 | self, 25 | ) -> None: ... 26 | 27 | global___GetTpuConfigsRequest = GetTpuConfigsRequest 28 | 29 | @typing_extensions.final 30 | class GetTpuConfigsResponse(google.protobuf.message.Message): 31 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 32 | 33 | TPU_FIELD_NUMBER: builtins.int 34 | TPU_FORWARD_FIELD_NUMBER: builtins.int 35 | @property 36 | def tpu(self) -> shared_pb2.Socket: ... 37 | @property 38 | def tpu_forward(self) -> shared_pb2.Socket: ... 39 | def __init__( 40 | self, 41 | *, 42 | tpu: shared_pb2.Socket | None = ..., 43 | tpu_forward: shared_pb2.Socket | None = ..., 44 | ) -> None: ... 45 | def HasField(self, field_name: typing_extensions.Literal["tpu", b"tpu", "tpu_forward", b"tpu_forward"]) -> builtins.bool: ... 46 | def ClearField(self, field_name: typing_extensions.Literal["tpu", b"tpu", "tpu_forward", b"tpu_forward"]) -> None: ... 47 | 48 | global___GetTpuConfigsResponse = GetTpuConfigsResponse 49 | 50 | @typing_extensions.final 51 | class SubscribePacketsRequest(google.protobuf.message.Message): 52 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 53 | 54 | def __init__( 55 | self, 56 | ) -> None: ... 57 | 58 | global___SubscribePacketsRequest = SubscribePacketsRequest 59 | 60 | @typing_extensions.final 61 | class SubscribePacketsResponse(google.protobuf.message.Message): 62 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 63 | 64 | HEADER_FIELD_NUMBER: builtins.int 65 | HEARTBEAT_FIELD_NUMBER: builtins.int 66 | BATCH_FIELD_NUMBER: builtins.int 67 | @property 68 | def header(self) -> shared_pb2.Header: ... 69 | @property 70 | def heartbeat(self) -> shared_pb2.Heartbeat: ... 71 | @property 72 | def batch(self) -> packet_pb2.PacketBatch: ... 73 | def __init__( 74 | self, 75 | *, 76 | header: shared_pb2.Header | None = ..., 77 | heartbeat: shared_pb2.Heartbeat | None = ..., 78 | batch: packet_pb2.PacketBatch | None = ..., 79 | ) -> None: ... 80 | def HasField(self, field_name: typing_extensions.Literal["batch", b"batch", "header", b"header", "heartbeat", b"heartbeat", "msg", b"msg"]) -> builtins.bool: ... 81 | def ClearField(self, field_name: typing_extensions.Literal["batch", b"batch", "header", b"header", "heartbeat", b"heartbeat", "msg", b"msg"]) -> None: ... 82 | def WhichOneof(self, oneof_group: typing_extensions.Literal["msg", b"msg"]) -> typing_extensions.Literal["heartbeat", "batch"] | None: ... 83 | 84 | global___SubscribePacketsResponse = SubscribePacketsResponse 85 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/relayer_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | import relayer_pb2 as relayer__pb2 6 | 7 | 8 | class RelayerStub(object): 9 | """/ Relayers offer a TPU and TPU forward proxy for Solana validators. 10 | / Validators can connect and fetch the TPU configuration for the relayer and start to advertise the 11 | / relayer's information in gossip. 12 | / They can also subscribe to packets which arrived on the TPU ports at the relayer 13 | """ 14 | 15 | def __init__(self, channel): 16 | """Constructor. 17 | 18 | Args: 19 | channel: A grpc.Channel. 20 | """ 21 | self.GetTpuConfigs = channel.unary_unary( 22 | '/relayer.Relayer/GetTpuConfigs', 23 | request_serializer=relayer__pb2.GetTpuConfigsRequest.SerializeToString, 24 | response_deserializer=relayer__pb2.GetTpuConfigsResponse.FromString, 25 | ) 26 | self.SubscribePackets = channel.unary_stream( 27 | '/relayer.Relayer/SubscribePackets', 28 | request_serializer=relayer__pb2.SubscribePacketsRequest.SerializeToString, 29 | response_deserializer=relayer__pb2.SubscribePacketsResponse.FromString, 30 | ) 31 | 32 | 33 | class RelayerServicer(object): 34 | """/ Relayers offer a TPU and TPU forward proxy for Solana validators. 35 | / Validators can connect and fetch the TPU configuration for the relayer and start to advertise the 36 | / relayer's information in gossip. 37 | / They can also subscribe to packets which arrived on the TPU ports at the relayer 38 | """ 39 | 40 | def GetTpuConfigs(self, request, context): 41 | """The relayer has TPU and TPU forward sockets that validators can leverage. 42 | A validator can fetch this config and change its TPU and TPU forward port in gossip. 43 | """ 44 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 45 | context.set_details('Method not implemented!') 46 | raise NotImplementedError('Method not implemented!') 47 | 48 | def SubscribePackets(self, request, context): 49 | """Validators can subscribe to packets from the relayer and receive a multiplexed signal that contains a mixture 50 | of packets and heartbeats 51 | """ 52 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 53 | context.set_details('Method not implemented!') 54 | raise NotImplementedError('Method not implemented!') 55 | 56 | 57 | def add_RelayerServicer_to_server(servicer, server): 58 | rpc_method_handlers = { 59 | 'GetTpuConfigs': grpc.unary_unary_rpc_method_handler( 60 | servicer.GetTpuConfigs, 61 | request_deserializer=relayer__pb2.GetTpuConfigsRequest.FromString, 62 | response_serializer=relayer__pb2.GetTpuConfigsResponse.SerializeToString, 63 | ), 64 | 'SubscribePackets': grpc.unary_stream_rpc_method_handler( 65 | servicer.SubscribePackets, 66 | request_deserializer=relayer__pb2.SubscribePacketsRequest.FromString, 67 | response_serializer=relayer__pb2.SubscribePacketsResponse.SerializeToString, 68 | ), 69 | } 70 | generic_handler = grpc.method_handlers_generic_handler( 71 | 'relayer.Relayer', rpc_method_handlers) 72 | server.add_generic_rpc_handlers((generic_handler,)) 73 | 74 | 75 | # This class is part of an EXPERIMENTAL API. 76 | class Relayer(object): 77 | """/ Relayers offer a TPU and TPU forward proxy for Solana validators. 78 | / Validators can connect and fetch the TPU configuration for the relayer and start to advertise the 79 | / relayer's information in gossip. 80 | / They can also subscribe to packets which arrived on the TPU ports at the relayer 81 | """ 82 | 83 | @staticmethod 84 | def GetTpuConfigs(request, 85 | target, 86 | options=(), 87 | channel_credentials=None, 88 | call_credentials=None, 89 | insecure=False, 90 | compression=None, 91 | wait_for_ready=None, 92 | timeout=None, 93 | metadata=None): 94 | return grpc.experimental.unary_unary(request, target, '/relayer.Relayer/GetTpuConfigs', 95 | relayer__pb2.GetTpuConfigsRequest.SerializeToString, 96 | relayer__pb2.GetTpuConfigsResponse.FromString, 97 | options, channel_credentials, 98 | insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 99 | 100 | @staticmethod 101 | def SubscribePackets(request, 102 | target, 103 | options=(), 104 | channel_credentials=None, 105 | call_credentials=None, 106 | insecure=False, 107 | compression=None, 108 | wait_for_ready=None, 109 | timeout=None, 110 | metadata=None): 111 | return grpc.experimental.unary_stream(request, target, '/relayer.Relayer/SubscribePackets', 112 | relayer__pb2.SubscribePacketsRequest.SerializeToString, 113 | relayer__pb2.SubscribePacketsResponse.FromString, 114 | options, channel_credentials, 115 | insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 116 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/relayer_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | import abc 6 | import collections.abc 7 | import grpc 8 | import relayer_pb2 9 | 10 | class RelayerStub: 11 | """/ Relayers offer a TPU and TPU forward proxy for Solana validators. 12 | / Validators can connect and fetch the TPU configuration for the relayer and start to advertise the 13 | / relayer's information in gossip. 14 | / They can also subscribe to packets which arrived on the TPU ports at the relayer 15 | """ 16 | 17 | def __init__(self, channel: grpc.Channel) -> None: ... 18 | GetTpuConfigs: grpc.UnaryUnaryMultiCallable[ 19 | relayer_pb2.GetTpuConfigsRequest, 20 | relayer_pb2.GetTpuConfigsResponse, 21 | ] 22 | """The relayer has TPU and TPU forward sockets that validators can leverage. 23 | A validator can fetch this config and change its TPU and TPU forward port in gossip. 24 | """ 25 | SubscribePackets: grpc.UnaryStreamMultiCallable[ 26 | relayer_pb2.SubscribePacketsRequest, 27 | relayer_pb2.SubscribePacketsResponse, 28 | ] 29 | """Validators can subscribe to packets from the relayer and receive a multiplexed signal that contains a mixture 30 | of packets and heartbeats 31 | """ 32 | 33 | class RelayerServicer(metaclass=abc.ABCMeta): 34 | """/ Relayers offer a TPU and TPU forward proxy for Solana validators. 35 | / Validators can connect and fetch the TPU configuration for the relayer and start to advertise the 36 | / relayer's information in gossip. 37 | / They can also subscribe to packets which arrived on the TPU ports at the relayer 38 | """ 39 | 40 | @abc.abstractmethod 41 | def GetTpuConfigs( 42 | self, 43 | request: relayer_pb2.GetTpuConfigsRequest, 44 | context: grpc.ServicerContext, 45 | ) -> relayer_pb2.GetTpuConfigsResponse: 46 | """The relayer has TPU and TPU forward sockets that validators can leverage. 47 | A validator can fetch this config and change its TPU and TPU forward port in gossip. 48 | """ 49 | @abc.abstractmethod 50 | def SubscribePackets( 51 | self, 52 | request: relayer_pb2.SubscribePacketsRequest, 53 | context: grpc.ServicerContext, 54 | ) -> collections.abc.Iterator[relayer_pb2.SubscribePacketsResponse]: 55 | """Validators can subscribe to packets from the relayer and receive a multiplexed signal that contains a mixture 56 | of packets and heartbeats 57 | """ 58 | 59 | def add_RelayerServicer_to_server(servicer: RelayerServicer, server: grpc.Server) -> None: ... 60 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/searcher_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: searcher.proto 4 | """Generated protocol buffer code.""" 5 | from google.protobuf.internal import builder as _builder 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | import bundle_pb2 as bundle__pb2 15 | import packet_pb2 as packet__pb2 16 | from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 17 | 18 | 19 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0esearcher.proto\x12\x08searcher\x1a\x0c\x62undle.proto\x1a\x0cpacket.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x19\n\x08SlotList\x12\r\n\x05slots\x18\x01 \x03(\x04\"3\n\x11SendBundleRequest\x12\x1e\n\x06\x62undle\x18\x01 \x01(\x0b\x32\x0e.bundle.Bundle\"\"\n\x12SendBundleResponse\x12\x0c\n\x04uuid\x18\x01 \x01(\t\")\n\x15ProgramSubscriptionV0\x12\x10\n\x08programs\x18\x01 \x03(\t\"4\n WriteLockedAccountSubscriptionV0\x12\x10\n\x08\x61\x63\x63ounts\x18\x01 \x03(\t\"\x99\x01\n\x13MempoolSubscription\x12\x39\n\x0eprogram_v0_sub\x18\x01 \x01(\x0b\x32\x1f.searcher.ProgramSubscriptionV0H\x00\x12@\n\nwla_v0_sub\x18\x02 \x01(\x0b\x32*.searcher.WriteLockedAccountSubscriptionV0H\x00\x42\x05\n\x03msg\"0\n\x1cPendingTxSubscriptionRequest\x12\x10\n\x08\x61\x63\x63ounts\x18\x01 \x03(\t\"\xa6\x01\n\x15PendingTxNotification\x12\x32\n\x0eserver_side_ts\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x33\n\x0f\x65xpiration_time\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12$\n\x0ctransactions\x18\x03 \x03(\x0b\x32\x0e.packet.Packet\"\x1c\n\x1aNextScheduledLeaderRequest\"k\n\x1bNextScheduledLeaderResponse\x12\x14\n\x0c\x63urrent_slot\x18\x01 \x01(\x04\x12\x18\n\x10next_leader_slot\x18\x02 \x01(\x04\x12\x1c\n\x14next_leader_identity\x18\x03 \x01(\t\"\x19\n\x17\x43onnectedLeadersRequest\"\xc5\x01\n\x18\x43onnectedLeadersResponse\x12Y\n\x14\x63onnected_validators\x18\x01 \x03(\x0b\x32;.searcher.ConnectedLeadersResponse.ConnectedValidatorsEntry\x1aN\n\x18\x43onnectedValidatorsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.searcher.SlotList:\x02\x38\x01\"\x17\n\x15GetTipAccountsRequest\"*\n\x16GetTipAccountsResponse\x12\x10\n\x08\x61\x63\x63ounts\x18\x01 \x03(\t\"\x1f\n\x1dSubscribeBundleResultsRequest2\x9e\x05\n\x0fSearcherService\x12[\n\x16SubscribeBundleResults\x12\'.searcher.SubscribeBundleResultsRequest\x1a\x14.bundle.BundleResult\"\x00\x30\x01\x12k\n\x1cSubscribePendingTransactions\x12&.searcher.PendingTxSubscriptionRequest\x1a\x1f.searcher.PendingTxNotification\"\x00\x30\x01\x12V\n\x10SubscribeMempool\x12\x1d.searcher.MempoolSubscription\x1a\x1f.searcher.PendingTxNotification\"\x00\x30\x01\x12I\n\nSendBundle\x12\x1b.searcher.SendBundleRequest\x1a\x1c.searcher.SendBundleResponse\"\x00\x12g\n\x16GetNextScheduledLeader\x12$.searcher.NextScheduledLeaderRequest\x1a%.searcher.NextScheduledLeaderResponse\"\x00\x12^\n\x13GetConnectedLeaders\x12!.searcher.ConnectedLeadersRequest\x1a\".searcher.ConnectedLeadersResponse\"\x00\x12U\n\x0eGetTipAccounts\x12\x1f.searcher.GetTipAccountsRequest\x1a .searcher.GetTipAccountsResponse\"\x00\x62\x06proto3') 20 | 21 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 22 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'searcher_pb2', globals()) 23 | if _descriptor._USE_C_DESCRIPTORS == False: 24 | 25 | DESCRIPTOR._options = None 26 | _CONNECTEDLEADERSRESPONSE_CONNECTEDVALIDATORSENTRY._options = None 27 | _CONNECTEDLEADERSRESPONSE_CONNECTEDVALIDATORSENTRY._serialized_options = b'8\001' 28 | _SLOTLIST._serialized_start=89 29 | _SLOTLIST._serialized_end=114 30 | _SENDBUNDLEREQUEST._serialized_start=116 31 | _SENDBUNDLEREQUEST._serialized_end=167 32 | _SENDBUNDLERESPONSE._serialized_start=169 33 | _SENDBUNDLERESPONSE._serialized_end=203 34 | _PROGRAMSUBSCRIPTIONV0._serialized_start=205 35 | _PROGRAMSUBSCRIPTIONV0._serialized_end=246 36 | _WRITELOCKEDACCOUNTSUBSCRIPTIONV0._serialized_start=248 37 | _WRITELOCKEDACCOUNTSUBSCRIPTIONV0._serialized_end=300 38 | _MEMPOOLSUBSCRIPTION._serialized_start=303 39 | _MEMPOOLSUBSCRIPTION._serialized_end=456 40 | _PENDINGTXSUBSCRIPTIONREQUEST._serialized_start=458 41 | _PENDINGTXSUBSCRIPTIONREQUEST._serialized_end=506 42 | _PENDINGTXNOTIFICATION._serialized_start=509 43 | _PENDINGTXNOTIFICATION._serialized_end=675 44 | _NEXTSCHEDULEDLEADERREQUEST._serialized_start=677 45 | _NEXTSCHEDULEDLEADERREQUEST._serialized_end=705 46 | _NEXTSCHEDULEDLEADERRESPONSE._serialized_start=707 47 | _NEXTSCHEDULEDLEADERRESPONSE._serialized_end=814 48 | _CONNECTEDLEADERSREQUEST._serialized_start=816 49 | _CONNECTEDLEADERSREQUEST._serialized_end=841 50 | _CONNECTEDLEADERSRESPONSE._serialized_start=844 51 | _CONNECTEDLEADERSRESPONSE._serialized_end=1041 52 | _CONNECTEDLEADERSRESPONSE_CONNECTEDVALIDATORSENTRY._serialized_start=963 53 | _CONNECTEDLEADERSRESPONSE_CONNECTEDVALIDATORSENTRY._serialized_end=1041 54 | _GETTIPACCOUNTSREQUEST._serialized_start=1043 55 | _GETTIPACCOUNTSREQUEST._serialized_end=1066 56 | _GETTIPACCOUNTSRESPONSE._serialized_start=1068 57 | _GETTIPACCOUNTSRESPONSE._serialized_end=1110 58 | _SUBSCRIBEBUNDLERESULTSREQUEST._serialized_start=1112 59 | _SUBSCRIBEBUNDLERESULTSREQUEST._serialized_end=1143 60 | _SEARCHERSERVICE._serialized_start=1146 61 | _SEARCHERSERVICE._serialized_end=1816 62 | # @@protoc_insertion_point(module_scope) 63 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/searcher_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | import builtins 6 | import bundle_pb2 7 | import collections.abc 8 | import google.protobuf.descriptor 9 | import google.protobuf.internal.containers 10 | import google.protobuf.message 11 | import google.protobuf.timestamp_pb2 12 | import packet_pb2 13 | import sys 14 | 15 | if sys.version_info >= (3, 8): 16 | import typing as typing_extensions 17 | else: 18 | import typing_extensions 19 | 20 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 21 | 22 | @typing_extensions.final 23 | class SlotList(google.protobuf.message.Message): 24 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 25 | 26 | SLOTS_FIELD_NUMBER: builtins.int 27 | @property 28 | def slots(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.int]: ... 29 | def __init__( 30 | self, 31 | *, 32 | slots: collections.abc.Iterable[builtins.int] | None = ..., 33 | ) -> None: ... 34 | def ClearField(self, field_name: typing_extensions.Literal["slots", b"slots"]) -> None: ... 35 | 36 | global___SlotList = SlotList 37 | 38 | @typing_extensions.final 39 | class SendBundleRequest(google.protobuf.message.Message): 40 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 41 | 42 | BUNDLE_FIELD_NUMBER: builtins.int 43 | @property 44 | def bundle(self) -> bundle_pb2.Bundle: ... 45 | def __init__( 46 | self, 47 | *, 48 | bundle: bundle_pb2.Bundle | None = ..., 49 | ) -> None: ... 50 | def HasField(self, field_name: typing_extensions.Literal["bundle", b"bundle"]) -> builtins.bool: ... 51 | def ClearField(self, field_name: typing_extensions.Literal["bundle", b"bundle"]) -> None: ... 52 | 53 | global___SendBundleRequest = SendBundleRequest 54 | 55 | @typing_extensions.final 56 | class SendBundleResponse(google.protobuf.message.Message): 57 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 58 | 59 | UUID_FIELD_NUMBER: builtins.int 60 | uuid: builtins.str 61 | """server uuid for the bundle""" 62 | def __init__( 63 | self, 64 | *, 65 | uuid: builtins.str = ..., 66 | ) -> None: ... 67 | def ClearField(self, field_name: typing_extensions.Literal["uuid", b"uuid"]) -> None: ... 68 | 69 | global___SendBundleResponse = SendBundleResponse 70 | 71 | @typing_extensions.final 72 | class ProgramSubscriptionV0(google.protobuf.message.Message): 73 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 74 | 75 | PROGRAMS_FIELD_NUMBER: builtins.int 76 | @property 77 | def programs(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... 78 | def __init__( 79 | self, 80 | *, 81 | programs: collections.abc.Iterable[builtins.str] | None = ..., 82 | ) -> None: ... 83 | def ClearField(self, field_name: typing_extensions.Literal["programs", b"programs"]) -> None: ... 84 | 85 | global___ProgramSubscriptionV0 = ProgramSubscriptionV0 86 | 87 | @typing_extensions.final 88 | class WriteLockedAccountSubscriptionV0(google.protobuf.message.Message): 89 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 90 | 91 | ACCOUNTS_FIELD_NUMBER: builtins.int 92 | @property 93 | def accounts(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... 94 | def __init__( 95 | self, 96 | *, 97 | accounts: collections.abc.Iterable[builtins.str] | None = ..., 98 | ) -> None: ... 99 | def ClearField(self, field_name: typing_extensions.Literal["accounts", b"accounts"]) -> None: ... 100 | 101 | global___WriteLockedAccountSubscriptionV0 = WriteLockedAccountSubscriptionV0 102 | 103 | @typing_extensions.final 104 | class MempoolSubscription(google.protobuf.message.Message): 105 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 106 | 107 | PROGRAM_V0_SUB_FIELD_NUMBER: builtins.int 108 | WLA_V0_SUB_FIELD_NUMBER: builtins.int 109 | @property 110 | def program_v0_sub(self) -> global___ProgramSubscriptionV0: ... 111 | @property 112 | def wla_v0_sub(self) -> global___WriteLockedAccountSubscriptionV0: ... 113 | def __init__( 114 | self, 115 | *, 116 | program_v0_sub: global___ProgramSubscriptionV0 | None = ..., 117 | wla_v0_sub: global___WriteLockedAccountSubscriptionV0 | None = ..., 118 | ) -> None: ... 119 | def HasField(self, field_name: typing_extensions.Literal["msg", b"msg", "program_v0_sub", b"program_v0_sub", "wla_v0_sub", b"wla_v0_sub"]) -> builtins.bool: ... 120 | def ClearField(self, field_name: typing_extensions.Literal["msg", b"msg", "program_v0_sub", b"program_v0_sub", "wla_v0_sub", b"wla_v0_sub"]) -> None: ... 121 | def WhichOneof(self, oneof_group: typing_extensions.Literal["msg", b"msg"]) -> typing_extensions.Literal["program_v0_sub", "wla_v0_sub"] | None: ... 122 | 123 | global___MempoolSubscription = MempoolSubscription 124 | 125 | @typing_extensions.final 126 | class PendingTxSubscriptionRequest(google.protobuf.message.Message): 127 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 128 | 129 | ACCOUNTS_FIELD_NUMBER: builtins.int 130 | @property 131 | def accounts(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: 132 | """list of accounts to subscribe to 133 | NOTE: the block-engine will only forward transactions that write lock the provided accounts here. 134 | """ 135 | def __init__( 136 | self, 137 | *, 138 | accounts: collections.abc.Iterable[builtins.str] | None = ..., 139 | ) -> None: ... 140 | def ClearField(self, field_name: typing_extensions.Literal["accounts", b"accounts"]) -> None: ... 141 | 142 | global___PendingTxSubscriptionRequest = PendingTxSubscriptionRequest 143 | 144 | @typing_extensions.final 145 | class PendingTxNotification(google.protobuf.message.Message): 146 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 147 | 148 | SERVER_SIDE_TS_FIELD_NUMBER: builtins.int 149 | EXPIRATION_TIME_FIELD_NUMBER: builtins.int 150 | TRANSACTIONS_FIELD_NUMBER: builtins.int 151 | @property 152 | def server_side_ts(self) -> google.protobuf.timestamp_pb2.Timestamp: 153 | """server-side timestamp the transactions were generated at (for debugging/profiling purposes)""" 154 | @property 155 | def expiration_time(self) -> google.protobuf.timestamp_pb2.Timestamp: 156 | """expiration time of the packet""" 157 | @property 158 | def transactions(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[packet_pb2.Packet]: 159 | """list of pending transactions""" 160 | def __init__( 161 | self, 162 | *, 163 | server_side_ts: google.protobuf.timestamp_pb2.Timestamp | None = ..., 164 | expiration_time: google.protobuf.timestamp_pb2.Timestamp | None = ..., 165 | transactions: collections.abc.Iterable[packet_pb2.Packet] | None = ..., 166 | ) -> None: ... 167 | def HasField(self, field_name: typing_extensions.Literal["expiration_time", b"expiration_time", "server_side_ts", b"server_side_ts"]) -> builtins.bool: ... 168 | def ClearField(self, field_name: typing_extensions.Literal["expiration_time", b"expiration_time", "server_side_ts", b"server_side_ts", "transactions", b"transactions"]) -> None: ... 169 | 170 | global___PendingTxNotification = PendingTxNotification 171 | 172 | @typing_extensions.final 173 | class NextScheduledLeaderRequest(google.protobuf.message.Message): 174 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 175 | 176 | def __init__( 177 | self, 178 | ) -> None: ... 179 | 180 | global___NextScheduledLeaderRequest = NextScheduledLeaderRequest 181 | 182 | @typing_extensions.final 183 | class NextScheduledLeaderResponse(google.protobuf.message.Message): 184 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 185 | 186 | CURRENT_SLOT_FIELD_NUMBER: builtins.int 187 | NEXT_LEADER_SLOT_FIELD_NUMBER: builtins.int 188 | NEXT_LEADER_IDENTITY_FIELD_NUMBER: builtins.int 189 | current_slot: builtins.int 190 | """the current slot the backend is on""" 191 | next_leader_slot: builtins.int 192 | """the slot and identity of the next leader""" 193 | next_leader_identity: builtins.str 194 | def __init__( 195 | self, 196 | *, 197 | current_slot: builtins.int = ..., 198 | next_leader_slot: builtins.int = ..., 199 | next_leader_identity: builtins.str = ..., 200 | ) -> None: ... 201 | def ClearField(self, field_name: typing_extensions.Literal["current_slot", b"current_slot", "next_leader_identity", b"next_leader_identity", "next_leader_slot", b"next_leader_slot"]) -> None: ... 202 | 203 | global___NextScheduledLeaderResponse = NextScheduledLeaderResponse 204 | 205 | @typing_extensions.final 206 | class ConnectedLeadersRequest(google.protobuf.message.Message): 207 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 208 | 209 | def __init__( 210 | self, 211 | ) -> None: ... 212 | 213 | global___ConnectedLeadersRequest = ConnectedLeadersRequest 214 | 215 | @typing_extensions.final 216 | class ConnectedLeadersResponse(google.protobuf.message.Message): 217 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 218 | 219 | @typing_extensions.final 220 | class ConnectedValidatorsEntry(google.protobuf.message.Message): 221 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 222 | 223 | KEY_FIELD_NUMBER: builtins.int 224 | VALUE_FIELD_NUMBER: builtins.int 225 | key: builtins.str 226 | @property 227 | def value(self) -> global___SlotList: ... 228 | def __init__( 229 | self, 230 | *, 231 | key: builtins.str = ..., 232 | value: global___SlotList | None = ..., 233 | ) -> None: ... 234 | def HasField(self, field_name: typing_extensions.Literal["value", b"value"]) -> builtins.bool: ... 235 | def ClearField(self, field_name: typing_extensions.Literal["key", b"key", "value", b"value"]) -> None: ... 236 | 237 | CONNECTED_VALIDATORS_FIELD_NUMBER: builtins.int 238 | @property 239 | def connected_validators(self) -> google.protobuf.internal.containers.MessageMap[builtins.str, global___SlotList]: ... 240 | def __init__( 241 | self, 242 | *, 243 | connected_validators: collections.abc.Mapping[builtins.str, global___SlotList] | None = ..., 244 | ) -> None: ... 245 | def ClearField(self, field_name: typing_extensions.Literal["connected_validators", b"connected_validators"]) -> None: ... 246 | 247 | global___ConnectedLeadersResponse = ConnectedLeadersResponse 248 | 249 | @typing_extensions.final 250 | class GetTipAccountsRequest(google.protobuf.message.Message): 251 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 252 | 253 | def __init__( 254 | self, 255 | ) -> None: ... 256 | 257 | global___GetTipAccountsRequest = GetTipAccountsRequest 258 | 259 | @typing_extensions.final 260 | class GetTipAccountsResponse(google.protobuf.message.Message): 261 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 262 | 263 | ACCOUNTS_FIELD_NUMBER: builtins.int 264 | @property 265 | def accounts(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... 266 | def __init__( 267 | self, 268 | *, 269 | accounts: collections.abc.Iterable[builtins.str] | None = ..., 270 | ) -> None: ... 271 | def ClearField(self, field_name: typing_extensions.Literal["accounts", b"accounts"]) -> None: ... 272 | 273 | global___GetTipAccountsResponse = GetTipAccountsResponse 274 | 275 | @typing_extensions.final 276 | class SubscribeBundleResultsRequest(google.protobuf.message.Message): 277 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 278 | 279 | def __init__( 280 | self, 281 | ) -> None: ... 282 | 283 | global___SubscribeBundleResultsRequest = SubscribeBundleResultsRequest 284 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/searcher_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | import bundle_pb2 as bundle__pb2 6 | import searcher_pb2 as searcher__pb2 7 | 8 | 9 | class SearcherServiceStub(object): 10 | """Missing associated documentation comment in .proto file.""" 11 | 12 | def __init__(self, channel): 13 | """Constructor. 14 | 15 | Args: 16 | channel: A grpc.Channel. 17 | """ 18 | self.SubscribeBundleResults = channel.unary_stream( 19 | '/searcher.SearcherService/SubscribeBundleResults', 20 | request_serializer=searcher__pb2.SubscribeBundleResultsRequest.SerializeToString, 21 | response_deserializer=bundle__pb2.BundleResult.FromString, 22 | ) 23 | self.SubscribePendingTransactions = channel.unary_stream( 24 | '/searcher.SearcherService/SubscribePendingTransactions', 25 | request_serializer=searcher__pb2.PendingTxSubscriptionRequest.SerializeToString, 26 | response_deserializer=searcher__pb2.PendingTxNotification.FromString, 27 | ) 28 | self.SubscribeMempool = channel.unary_stream( 29 | '/searcher.SearcherService/SubscribeMempool', 30 | request_serializer=searcher__pb2.MempoolSubscription.SerializeToString, 31 | response_deserializer=searcher__pb2.PendingTxNotification.FromString, 32 | ) 33 | self.SendBundle = channel.unary_unary( 34 | '/searcher.SearcherService/SendBundle', 35 | request_serializer=searcher__pb2.SendBundleRequest.SerializeToString, 36 | response_deserializer=searcher__pb2.SendBundleResponse.FromString, 37 | ) 38 | self.GetNextScheduledLeader = channel.unary_unary( 39 | '/searcher.SearcherService/GetNextScheduledLeader', 40 | request_serializer=searcher__pb2.NextScheduledLeaderRequest.SerializeToString, 41 | response_deserializer=searcher__pb2.NextScheduledLeaderResponse.FromString, 42 | ) 43 | self.GetConnectedLeaders = channel.unary_unary( 44 | '/searcher.SearcherService/GetConnectedLeaders', 45 | request_serializer=searcher__pb2.ConnectedLeadersRequest.SerializeToString, 46 | response_deserializer=searcher__pb2.ConnectedLeadersResponse.FromString, 47 | ) 48 | self.GetTipAccounts = channel.unary_unary( 49 | '/searcher.SearcherService/GetTipAccounts', 50 | request_serializer=searcher__pb2.GetTipAccountsRequest.SerializeToString, 51 | response_deserializer=searcher__pb2.GetTipAccountsResponse.FromString, 52 | ) 53 | 54 | 55 | class SearcherServiceServicer(object): 56 | """Missing associated documentation comment in .proto file.""" 57 | 58 | def SubscribeBundleResults(self, request, context): 59 | """Searchers can invoke this endpoint to subscribe to their respective bundle results. 60 | A success result would indicate the bundle won its state auction and was submitted to the validator. 61 | """ 62 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 63 | context.set_details('Method not implemented!') 64 | raise NotImplementedError('Method not implemented!') 65 | 66 | def SubscribePendingTransactions(self, request, context): 67 | """RPC endpoint to subscribe to pending transactions. Clients can provide a list of base58 encoded accounts. 68 | Any transactions that write-lock the provided accounts will be streamed to the searcher. 69 | NOTE: DEPRECATED SOON!!! 70 | """ 71 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 72 | context.set_details('Method not implemented!') 73 | raise NotImplementedError('Method not implemented!') 74 | 75 | def SubscribeMempool(self, request, context): 76 | """RPC endpoint to subscribe to mempool based on a few filters 77 | """ 78 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 79 | context.set_details('Method not implemented!') 80 | raise NotImplementedError('Method not implemented!') 81 | 82 | def SendBundle(self, request, context): 83 | """Missing associated documentation comment in .proto file.""" 84 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 85 | context.set_details('Method not implemented!') 86 | raise NotImplementedError('Method not implemented!') 87 | 88 | def GetNextScheduledLeader(self, request, context): 89 | """Returns the next scheduled leader connected to the block engine. 90 | """ 91 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 92 | context.set_details('Method not implemented!') 93 | raise NotImplementedError('Method not implemented!') 94 | 95 | def GetConnectedLeaders(self, request, context): 96 | """Returns information on connected leader slots 97 | """ 98 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 99 | context.set_details('Method not implemented!') 100 | raise NotImplementedError('Method not implemented!') 101 | 102 | def GetTipAccounts(self, request, context): 103 | """Returns the tip accounts searchers shall transfer funds to for the leader to claim. 104 | """ 105 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 106 | context.set_details('Method not implemented!') 107 | raise NotImplementedError('Method not implemented!') 108 | 109 | 110 | def add_SearcherServiceServicer_to_server(servicer, server): 111 | rpc_method_handlers = { 112 | 'SubscribeBundleResults': grpc.unary_stream_rpc_method_handler( 113 | servicer.SubscribeBundleResults, 114 | request_deserializer=searcher__pb2.SubscribeBundleResultsRequest.FromString, 115 | response_serializer=bundle__pb2.BundleResult.SerializeToString, 116 | ), 117 | 'SubscribePendingTransactions': grpc.unary_stream_rpc_method_handler( 118 | servicer.SubscribePendingTransactions, 119 | request_deserializer=searcher__pb2.PendingTxSubscriptionRequest.FromString, 120 | response_serializer=searcher__pb2.PendingTxNotification.SerializeToString, 121 | ), 122 | 'SubscribeMempool': grpc.unary_stream_rpc_method_handler( 123 | servicer.SubscribeMempool, 124 | request_deserializer=searcher__pb2.MempoolSubscription.FromString, 125 | response_serializer=searcher__pb2.PendingTxNotification.SerializeToString, 126 | ), 127 | 'SendBundle': grpc.unary_unary_rpc_method_handler( 128 | servicer.SendBundle, 129 | request_deserializer=searcher__pb2.SendBundleRequest.FromString, 130 | response_serializer=searcher__pb2.SendBundleResponse.SerializeToString, 131 | ), 132 | 'GetNextScheduledLeader': grpc.unary_unary_rpc_method_handler( 133 | servicer.GetNextScheduledLeader, 134 | request_deserializer=searcher__pb2.NextScheduledLeaderRequest.FromString, 135 | response_serializer=searcher__pb2.NextScheduledLeaderResponse.SerializeToString, 136 | ), 137 | 'GetConnectedLeaders': grpc.unary_unary_rpc_method_handler( 138 | servicer.GetConnectedLeaders, 139 | request_deserializer=searcher__pb2.ConnectedLeadersRequest.FromString, 140 | response_serializer=searcher__pb2.ConnectedLeadersResponse.SerializeToString, 141 | ), 142 | 'GetTipAccounts': grpc.unary_unary_rpc_method_handler( 143 | servicer.GetTipAccounts, 144 | request_deserializer=searcher__pb2.GetTipAccountsRequest.FromString, 145 | response_serializer=searcher__pb2.GetTipAccountsResponse.SerializeToString, 146 | ), 147 | } 148 | generic_handler = grpc.method_handlers_generic_handler( 149 | 'searcher.SearcherService', rpc_method_handlers) 150 | server.add_generic_rpc_handlers((generic_handler,)) 151 | 152 | 153 | # This class is part of an EXPERIMENTAL API. 154 | class SearcherService(object): 155 | """Missing associated documentation comment in .proto file.""" 156 | 157 | @staticmethod 158 | def SubscribeBundleResults(request, 159 | target, 160 | options=(), 161 | channel_credentials=None, 162 | call_credentials=None, 163 | insecure=False, 164 | compression=None, 165 | wait_for_ready=None, 166 | timeout=None, 167 | metadata=None): 168 | return grpc.experimental.unary_stream(request, target, '/searcher.SearcherService/SubscribeBundleResults', 169 | searcher__pb2.SubscribeBundleResultsRequest.SerializeToString, 170 | bundle__pb2.BundleResult.FromString, 171 | options, channel_credentials, 172 | insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 173 | 174 | @staticmethod 175 | def SubscribePendingTransactions(request, 176 | target, 177 | options=(), 178 | channel_credentials=None, 179 | call_credentials=None, 180 | insecure=False, 181 | compression=None, 182 | wait_for_ready=None, 183 | timeout=None, 184 | metadata=None): 185 | return grpc.experimental.unary_stream(request, target, '/searcher.SearcherService/SubscribePendingTransactions', 186 | searcher__pb2.PendingTxSubscriptionRequest.SerializeToString, 187 | searcher__pb2.PendingTxNotification.FromString, 188 | options, channel_credentials, 189 | insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 190 | 191 | @staticmethod 192 | def SubscribeMempool(request, 193 | target, 194 | options=(), 195 | channel_credentials=None, 196 | call_credentials=None, 197 | insecure=False, 198 | compression=None, 199 | wait_for_ready=None, 200 | timeout=None, 201 | metadata=None): 202 | return grpc.experimental.unary_stream(request, target, '/searcher.SearcherService/SubscribeMempool', 203 | searcher__pb2.MempoolSubscription.SerializeToString, 204 | searcher__pb2.PendingTxNotification.FromString, 205 | options, channel_credentials, 206 | insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 207 | 208 | @staticmethod 209 | def SendBundle(request, 210 | target, 211 | options=(), 212 | channel_credentials=None, 213 | call_credentials=None, 214 | insecure=False, 215 | compression=None, 216 | wait_for_ready=None, 217 | timeout=None, 218 | metadata=None): 219 | return grpc.experimental.unary_unary(request, target, '/searcher.SearcherService/SendBundle', 220 | searcher__pb2.SendBundleRequest.SerializeToString, 221 | searcher__pb2.SendBundleResponse.FromString, 222 | options, channel_credentials, 223 | insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 224 | 225 | @staticmethod 226 | def GetNextScheduledLeader(request, 227 | target, 228 | options=(), 229 | channel_credentials=None, 230 | call_credentials=None, 231 | insecure=False, 232 | compression=None, 233 | wait_for_ready=None, 234 | timeout=None, 235 | metadata=None): 236 | return grpc.experimental.unary_unary(request, target, '/searcher.SearcherService/GetNextScheduledLeader', 237 | searcher__pb2.NextScheduledLeaderRequest.SerializeToString, 238 | searcher__pb2.NextScheduledLeaderResponse.FromString, 239 | options, channel_credentials, 240 | insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 241 | 242 | @staticmethod 243 | def GetConnectedLeaders(request, 244 | target, 245 | options=(), 246 | channel_credentials=None, 247 | call_credentials=None, 248 | insecure=False, 249 | compression=None, 250 | wait_for_ready=None, 251 | timeout=None, 252 | metadata=None): 253 | return grpc.experimental.unary_unary(request, target, '/searcher.SearcherService/GetConnectedLeaders', 254 | searcher__pb2.ConnectedLeadersRequest.SerializeToString, 255 | searcher__pb2.ConnectedLeadersResponse.FromString, 256 | options, channel_credentials, 257 | insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 258 | 259 | @staticmethod 260 | def GetTipAccounts(request, 261 | target, 262 | options=(), 263 | channel_credentials=None, 264 | call_credentials=None, 265 | insecure=False, 266 | compression=None, 267 | wait_for_ready=None, 268 | timeout=None, 269 | metadata=None): 270 | return grpc.experimental.unary_unary(request, target, '/searcher.SearcherService/GetTipAccounts', 271 | searcher__pb2.GetTipAccountsRequest.SerializeToString, 272 | searcher__pb2.GetTipAccountsResponse.FromString, 273 | options, channel_credentials, 274 | insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 275 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/searcher_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | import abc 6 | import bundle_pb2 7 | import collections.abc 8 | import grpc 9 | import searcher_pb2 10 | 11 | class SearcherServiceStub: 12 | def __init__(self, channel: grpc.Channel) -> None: ... 13 | SubscribeBundleResults: grpc.UnaryStreamMultiCallable[ 14 | searcher_pb2.SubscribeBundleResultsRequest, 15 | bundle_pb2.BundleResult, 16 | ] 17 | """Searchers can invoke this endpoint to subscribe to their respective bundle results. 18 | A success result would indicate the bundle won its state auction and was submitted to the validator. 19 | """ 20 | SubscribePendingTransactions: grpc.UnaryStreamMultiCallable[ 21 | searcher_pb2.PendingTxSubscriptionRequest, 22 | searcher_pb2.PendingTxNotification, 23 | ] 24 | """RPC endpoint to subscribe to pending transactions. Clients can provide a list of base58 encoded accounts. 25 | Any transactions that write-lock the provided accounts will be streamed to the searcher. 26 | NOTE: DEPRECATED SOON!!! 27 | """ 28 | SubscribeMempool: grpc.UnaryStreamMultiCallable[ 29 | searcher_pb2.MempoolSubscription, 30 | searcher_pb2.PendingTxNotification, 31 | ] 32 | """RPC endpoint to subscribe to mempool based on a few filters""" 33 | SendBundle: grpc.UnaryUnaryMultiCallable[ 34 | searcher_pb2.SendBundleRequest, 35 | searcher_pb2.SendBundleResponse, 36 | ] 37 | GetNextScheduledLeader: grpc.UnaryUnaryMultiCallable[ 38 | searcher_pb2.NextScheduledLeaderRequest, 39 | searcher_pb2.NextScheduledLeaderResponse, 40 | ] 41 | """Returns the next scheduled leader connected to the block engine.""" 42 | GetConnectedLeaders: grpc.UnaryUnaryMultiCallable[ 43 | searcher_pb2.ConnectedLeadersRequest, 44 | searcher_pb2.ConnectedLeadersResponse, 45 | ] 46 | """Returns information on connected leader slots""" 47 | GetTipAccounts: grpc.UnaryUnaryMultiCallable[ 48 | searcher_pb2.GetTipAccountsRequest, 49 | searcher_pb2.GetTipAccountsResponse, 50 | ] 51 | """Returns the tip accounts searchers shall transfer funds to for the leader to claim.""" 52 | 53 | class SearcherServiceServicer(metaclass=abc.ABCMeta): 54 | @abc.abstractmethod 55 | def SubscribeBundleResults( 56 | self, 57 | request: searcher_pb2.SubscribeBundleResultsRequest, 58 | context: grpc.ServicerContext, 59 | ) -> collections.abc.Iterator[bundle_pb2.BundleResult]: 60 | """Searchers can invoke this endpoint to subscribe to their respective bundle results. 61 | A success result would indicate the bundle won its state auction and was submitted to the validator. 62 | """ 63 | @abc.abstractmethod 64 | def SubscribePendingTransactions( 65 | self, 66 | request: searcher_pb2.PendingTxSubscriptionRequest, 67 | context: grpc.ServicerContext, 68 | ) -> collections.abc.Iterator[searcher_pb2.PendingTxNotification]: 69 | """RPC endpoint to subscribe to pending transactions. Clients can provide a list of base58 encoded accounts. 70 | Any transactions that write-lock the provided accounts will be streamed to the searcher. 71 | NOTE: DEPRECATED SOON!!! 72 | """ 73 | @abc.abstractmethod 74 | def SubscribeMempool( 75 | self, 76 | request: searcher_pb2.MempoolSubscription, 77 | context: grpc.ServicerContext, 78 | ) -> collections.abc.Iterator[searcher_pb2.PendingTxNotification]: 79 | """RPC endpoint to subscribe to mempool based on a few filters""" 80 | @abc.abstractmethod 81 | def SendBundle( 82 | self, 83 | request: searcher_pb2.SendBundleRequest, 84 | context: grpc.ServicerContext, 85 | ) -> searcher_pb2.SendBundleResponse: ... 86 | @abc.abstractmethod 87 | def GetNextScheduledLeader( 88 | self, 89 | request: searcher_pb2.NextScheduledLeaderRequest, 90 | context: grpc.ServicerContext, 91 | ) -> searcher_pb2.NextScheduledLeaderResponse: 92 | """Returns the next scheduled leader connected to the block engine.""" 93 | @abc.abstractmethod 94 | def GetConnectedLeaders( 95 | self, 96 | request: searcher_pb2.ConnectedLeadersRequest, 97 | context: grpc.ServicerContext, 98 | ) -> searcher_pb2.ConnectedLeadersResponse: 99 | """Returns information on connected leader slots""" 100 | @abc.abstractmethod 101 | def GetTipAccounts( 102 | self, 103 | request: searcher_pb2.GetTipAccountsRequest, 104 | context: grpc.ServicerContext, 105 | ) -> searcher_pb2.GetTipAccountsResponse: 106 | """Returns the tip accounts searchers shall transfer funds to for the leader to claim.""" 107 | 108 | def add_SearcherServiceServicer_to_server(servicer: SearcherServiceServicer, server: grpc.Server) -> None: ... 109 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/shared_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: shared.proto 4 | """Generated protocol buffer code.""" 5 | from google.protobuf.internal import builder as _builder 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 15 | 16 | 17 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cshared.proto\x12\x06shared\x1a\x1fgoogle/protobuf/timestamp.proto\"0\n\x06Header\x12&\n\x02ts\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\x1a\n\tHeartbeat\x12\r\n\x05\x63ount\x18\x01 \x01(\x04\"\"\n\x06Socket\x12\n\n\x02ip\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x03\x62\x06proto3') 18 | 19 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 20 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'shared_pb2', globals()) 21 | if _descriptor._USE_C_DESCRIPTORS == False: 22 | 23 | DESCRIPTOR._options = None 24 | _HEADER._serialized_start=57 25 | _HEADER._serialized_end=105 26 | _HEARTBEAT._serialized_start=107 27 | _HEARTBEAT._serialized_end=133 28 | _SOCKET._serialized_start=135 29 | _SOCKET._serialized_end=169 30 | # @@protoc_insertion_point(module_scope) 31 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/shared_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | import builtins 6 | import google.protobuf.descriptor 7 | import google.protobuf.message 8 | import google.protobuf.timestamp_pb2 9 | import sys 10 | 11 | if sys.version_info >= (3, 8): 12 | import typing as typing_extensions 13 | else: 14 | import typing_extensions 15 | 16 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 17 | 18 | @typing_extensions.final 19 | class Header(google.protobuf.message.Message): 20 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 21 | 22 | TS_FIELD_NUMBER: builtins.int 23 | @property 24 | def ts(self) -> google.protobuf.timestamp_pb2.Timestamp: ... 25 | def __init__( 26 | self, 27 | *, 28 | ts: google.protobuf.timestamp_pb2.Timestamp | None = ..., 29 | ) -> None: ... 30 | def HasField(self, field_name: typing_extensions.Literal["ts", b"ts"]) -> builtins.bool: ... 31 | def ClearField(self, field_name: typing_extensions.Literal["ts", b"ts"]) -> None: ... 32 | 33 | global___Header = Header 34 | 35 | @typing_extensions.final 36 | class Heartbeat(google.protobuf.message.Message): 37 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 38 | 39 | COUNT_FIELD_NUMBER: builtins.int 40 | count: builtins.int 41 | def __init__( 42 | self, 43 | *, 44 | count: builtins.int = ..., 45 | ) -> None: ... 46 | def ClearField(self, field_name: typing_extensions.Literal["count", b"count"]) -> None: ... 47 | 48 | global___Heartbeat = Heartbeat 49 | 50 | @typing_extensions.final 51 | class Socket(google.protobuf.message.Message): 52 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 53 | 54 | IP_FIELD_NUMBER: builtins.int 55 | PORT_FIELD_NUMBER: builtins.int 56 | ip: builtins.str 57 | port: builtins.int 58 | def __init__( 59 | self, 60 | *, 61 | ip: builtins.str = ..., 62 | port: builtins.int = ..., 63 | ) -> None: ... 64 | def ClearField(self, field_name: typing_extensions.Literal["ip", b"ip", "port", b"port"]) -> None: ... 65 | 66 | global___Socket = Socket 67 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/shared_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/shared_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/shredstream_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: shredstream.proto 4 | """Generated protocol buffer code.""" 5 | from google.protobuf.internal import builder as _builder 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | import shared_pb2 as shared__pb2 15 | 16 | 17 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11shredstream.proto\x12\x0bshredstream\x1a\x0cshared.proto\"<\n\tHeartbeat\x12\x1e\n\x06socket\x18\x01 \x01(\x0b\x32\x0e.shared.Socket\x12\x0f\n\x07regions\x18\x02 \x03(\t\"#\n\x11HeartbeatResponse\x12\x0e\n\x06ttl_ms\x18\x01 \x01(\r2X\n\x0bShredstream\x12I\n\rSendHeartbeat\x12\x16.shredstream.Heartbeat\x1a\x1e.shredstream.HeartbeatResponse\"\x00\x62\x06proto3') 18 | 19 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 20 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'shredstream_pb2', globals()) 21 | if _descriptor._USE_C_DESCRIPTORS == False: 22 | 23 | DESCRIPTOR._options = None 24 | _HEARTBEAT._serialized_start=48 25 | _HEARTBEAT._serialized_end=108 26 | _HEARTBEATRESPONSE._serialized_start=110 27 | _HEARTBEATRESPONSE._serialized_end=145 28 | _SHREDSTREAM._serialized_start=147 29 | _SHREDSTREAM._serialized_end=235 30 | # @@protoc_insertion_point(module_scope) 31 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/shredstream_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | import builtins 6 | import collections.abc 7 | import google.protobuf.descriptor 8 | import google.protobuf.internal.containers 9 | import google.protobuf.message 10 | import shared_pb2 11 | import sys 12 | 13 | if sys.version_info >= (3, 8): 14 | import typing as typing_extensions 15 | else: 16 | import typing_extensions 17 | 18 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 19 | 20 | @typing_extensions.final 21 | class Heartbeat(google.protobuf.message.Message): 22 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 23 | 24 | SOCKET_FIELD_NUMBER: builtins.int 25 | REGIONS_FIELD_NUMBER: builtins.int 26 | @property 27 | def socket(self) -> shared_pb2.Socket: 28 | """don't trust IP:PORT from tcp header since it can be tampered over the wire 29 | `socket.ip` must match incoming packet's ip. this prevents spamming an unwitting destination 30 | """ 31 | @property 32 | def regions(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: 33 | """regions for shredstream proxy to receive shreds from 34 | list of valid regions: https://jito-labs.gitbook.io/mev/systems/connecting/mainnet 35 | """ 36 | def __init__( 37 | self, 38 | *, 39 | socket: shared_pb2.Socket | None = ..., 40 | regions: collections.abc.Iterable[builtins.str] | None = ..., 41 | ) -> None: ... 42 | def HasField(self, field_name: typing_extensions.Literal["socket", b"socket"]) -> builtins.bool: ... 43 | def ClearField(self, field_name: typing_extensions.Literal["regions", b"regions", "socket", b"socket"]) -> None: ... 44 | 45 | global___Heartbeat = Heartbeat 46 | 47 | @typing_extensions.final 48 | class HeartbeatResponse(google.protobuf.message.Message): 49 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 50 | 51 | TTL_MS_FIELD_NUMBER: builtins.int 52 | ttl_ms: builtins.int 53 | """client must respond within `ttl_ms` to keep stream alive""" 54 | def __init__( 55 | self, 56 | *, 57 | ttl_ms: builtins.int = ..., 58 | ) -> None: ... 59 | def ClearField(self, field_name: typing_extensions.Literal["ttl_ms", b"ttl_ms"]) -> None: ... 60 | 61 | global___HeartbeatResponse = HeartbeatResponse 62 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/shredstream_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | import shredstream_pb2 as shredstream__pb2 6 | 7 | 8 | class ShredstreamStub(object): 9 | """Missing associated documentation comment in .proto file.""" 10 | 11 | def __init__(self, channel): 12 | """Constructor. 13 | 14 | Args: 15 | channel: A grpc.Channel. 16 | """ 17 | self.SendHeartbeat = channel.unary_unary( 18 | '/shredstream.Shredstream/SendHeartbeat', 19 | request_serializer=shredstream__pb2.Heartbeat.SerializeToString, 20 | response_deserializer=shredstream__pb2.HeartbeatResponse.FromString, 21 | ) 22 | 23 | 24 | class ShredstreamServicer(object): 25 | """Missing associated documentation comment in .proto file.""" 26 | 27 | def SendHeartbeat(self, request, context): 28 | """RPC endpoint to send heartbeats to keep shreds flowing 29 | """ 30 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 31 | context.set_details('Method not implemented!') 32 | raise NotImplementedError('Method not implemented!') 33 | 34 | 35 | def add_ShredstreamServicer_to_server(servicer, server): 36 | rpc_method_handlers = { 37 | 'SendHeartbeat': grpc.unary_unary_rpc_method_handler( 38 | servicer.SendHeartbeat, 39 | request_deserializer=shredstream__pb2.Heartbeat.FromString, 40 | response_serializer=shredstream__pb2.HeartbeatResponse.SerializeToString, 41 | ), 42 | } 43 | generic_handler = grpc.method_handlers_generic_handler( 44 | 'shredstream.Shredstream', rpc_method_handlers) 45 | server.add_generic_rpc_handlers((generic_handler,)) 46 | 47 | 48 | # This class is part of an EXPERIMENTAL API. 49 | class Shredstream(object): 50 | """Missing associated documentation comment in .proto file.""" 51 | 52 | @staticmethod 53 | def SendHeartbeat(request, 54 | target, 55 | options=(), 56 | channel_credentials=None, 57 | call_credentials=None, 58 | insecure=False, 59 | compression=None, 60 | wait_for_ready=None, 61 | timeout=None, 62 | metadata=None): 63 | return grpc.experimental.unary_unary(request, target, '/shredstream.Shredstream/SendHeartbeat', 64 | shredstream__pb2.Heartbeat.SerializeToString, 65 | shredstream__pb2.HeartbeatResponse.FromString, 66 | options, channel_credentials, 67 | insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 68 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/generated/shredstream_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | import abc 6 | import grpc 7 | import shredstream_pb2 8 | 9 | class ShredstreamStub: 10 | def __init__(self, channel: grpc.Channel) -> None: ... 11 | SendHeartbeat: grpc.UnaryUnaryMultiCallable[ 12 | shredstream_pb2.Heartbeat, 13 | shredstream_pb2.HeartbeatResponse, 14 | ] 15 | """RPC endpoint to send heartbeats to keep shreds flowing""" 16 | 17 | class ShredstreamServicer(metaclass=abc.ABCMeta): 18 | @abc.abstractmethod 19 | def SendHeartbeat( 20 | self, 21 | request: shredstream_pb2.Heartbeat, 22 | context: grpc.ServicerContext, 23 | ) -> shredstream_pb2.HeartbeatResponse: 24 | """RPC endpoint to send heartbeats to keep shreds flowing""" 25 | 26 | def add_ShredstreamServicer_to_server(servicer: ShredstreamServicer, server: grpc.Server) -> None: ... 27 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/searcher.py: -------------------------------------------------------------------------------- 1 | import time 2 | from typing import List, Optional, Tuple 3 | 4 | from grpc import ( 5 | UnaryStreamClientInterceptor, 6 | UnaryUnaryClientInterceptor, 7 | intercept_channel, 8 | secure_channel, 9 | ssl_channel_credentials, 10 | ) 11 | from grpc.aio import ClientCallDetails 12 | from solders.keypair import Keypair 13 | 14 | from jito_searcher_client.generated.auth_pb2 import ( 15 | GenerateAuthChallengeRequest, 16 | GenerateAuthTokensRequest, 17 | GenerateAuthTokensResponse, 18 | RefreshAccessTokenRequest, 19 | RefreshAccessTokenResponse, 20 | Role, 21 | ) 22 | from jito_searcher_client.generated.auth_pb2_grpc import AuthServiceStub 23 | from jito_searcher_client.generated.searcher_pb2_grpc import SearcherServiceStub 24 | from jito_searcher_client.token import JwtToken 25 | 26 | 27 | class SearcherInterceptor( 28 | UnaryUnaryClientInterceptor, 29 | UnaryStreamClientInterceptor, 30 | ): 31 | """ 32 | SearcherInterceptor is responsible for authenticating with the block engine. 33 | Authentication happens in a challenge-response handshake. 34 | 1. Request a challenge and provide your public key. 35 | 2. Get challenge and sign a message "{pubkey}-{challenge}". 36 | 3. Get back a refresh token and access token. 37 | 38 | When the access token expires, use the refresh token to get a new one. 39 | When the refresh token expires, perform the challenge-response handshake again. 40 | """ 41 | 42 | def __init__(self, url: str, kp: Keypair): 43 | """ 44 | 45 | :param url: url of the Block Engine without http or https. 46 | :param kp: block engine authentication keypair 47 | """ 48 | self._url = url 49 | self._kp = kp 50 | 51 | self._access_token: Optional[JwtToken] = None 52 | self._refresh_token: Optional[JwtToken] = None 53 | 54 | def intercept_unary_stream(self, continuation, client_call_details, request): 55 | if self._kp != None: 56 | self.authenticate_if_needed() 57 | 58 | client_call_details = self._insert_headers( 59 | [("authorization", f"Bearer {self._access_token.token}")], 60 | client_call_details, 61 | ) 62 | 63 | return continuation(client_call_details, request) 64 | 65 | def intercept_unary_unary(self, continuation, client_call_details, request): 66 | if self._kp != None: 67 | self.authenticate_if_needed() 68 | 69 | client_call_details = self._insert_headers( 70 | [("authorization", f"Bearer {self._access_token.token}")], 71 | client_call_details, 72 | ) 73 | 74 | return continuation(client_call_details, request) 75 | 76 | @staticmethod 77 | def _insert_headers(new_metadata: List[Tuple[str, str]], client_call_details) -> ClientCallDetails: 78 | metadata = [] 79 | if client_call_details.metadata is not None: 80 | metadata = list(client_call_details.metadata) 81 | metadata.extend(new_metadata) 82 | 83 | return ClientCallDetails( 84 | client_call_details.method, 85 | client_call_details.timeout, 86 | metadata, 87 | client_call_details.credentials, 88 | False, 89 | ) 90 | 91 | def authenticate_if_needed(self): 92 | """ 93 | Maybe authenticates depending on state of access + refresh tokens 94 | """ 95 | now = int(time.time()) 96 | if self._access_token is None or self._refresh_token is None or now >= self._refresh_token.expiration: 97 | self.full_authentication() 98 | elif now >= self._access_token.expiration: 99 | self.refresh_authentication() 100 | 101 | def refresh_authentication(self): 102 | """ 103 | Performs an authentication refresh with the block engine, which involves using the refresh token to get a new 104 | access token. 105 | """ 106 | credentials = ssl_channel_credentials() 107 | channel = secure_channel(self._url, credentials) 108 | auth_client = AuthServiceStub(channel) 109 | 110 | new_access_token: RefreshAccessTokenResponse = auth_client.RefreshAccessToken( 111 | RefreshAccessTokenRequest(refresh_token=self._refresh_token.token) 112 | ) 113 | self._access_token = JwtToken( 114 | token=new_access_token.access_token.value, expiration=new_access_token.access_token.expires_at_utc.seconds 115 | ) 116 | 117 | def full_authentication(self): 118 | """ 119 | Performs full authentication with the block engine 120 | """ 121 | credentials = ssl_channel_credentials() 122 | channel = secure_channel(self._url, credentials) 123 | auth_client = AuthServiceStub(channel) 124 | 125 | challenge = auth_client.GenerateAuthChallenge( 126 | GenerateAuthChallengeRequest(role=Role.SEARCHER, pubkey=bytes(self._kp.pubkey())) 127 | ).challenge 128 | 129 | challenge_to_sign = f"{str(self._kp.pubkey())}-{challenge}" 130 | 131 | signed = self._kp.sign_message(bytes(challenge_to_sign, "utf8")) 132 | 133 | auth_tokens_response: GenerateAuthTokensResponse = auth_client.GenerateAuthTokens( 134 | GenerateAuthTokensRequest( 135 | challenge=challenge_to_sign, 136 | client_pubkey=bytes(self._kp.pubkey()), 137 | signed_challenge=bytes(signed), 138 | ) 139 | ) 140 | 141 | self._access_token = JwtToken( 142 | token=auth_tokens_response.access_token.value, 143 | expiration=auth_tokens_response.access_token.expires_at_utc.seconds, 144 | ) 145 | 146 | self._refresh_token = JwtToken( 147 | token=auth_tokens_response.refresh_token.value, 148 | expiration=auth_tokens_response.refresh_token.expires_at_utc.seconds, 149 | ) 150 | 151 | 152 | def get_searcher_client(url: str, kp: Keypair=None) -> SearcherServiceStub: 153 | """ 154 | Returns a Searcher Service client that intercepts requests and authenticates with the block engine. 155 | :param url: url of the block engine without http/https 156 | :param kp: keypair of the block engine 157 | :return: SearcherServiceStub which handles authentication on requests 158 | """ 159 | # Authenticate immediately only if it is required 160 | searcher_interceptor = SearcherInterceptor(url, kp) 161 | if kp != None: 162 | searcher_interceptor.authenticate_if_needed() 163 | 164 | credentials = ssl_channel_credentials() 165 | channel = secure_channel(url, credentials) 166 | intercepted_channel = intercept_channel(channel, searcher_interceptor) 167 | 168 | return SearcherServiceStub(intercepted_channel) 169 | -------------------------------------------------------------------------------- /jito_searcher_client/jito_searcher_client/token.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | 4 | @dataclass(frozen=True) 5 | class JwtToken: 6 | # jwt token string 7 | token: str 8 | # time in seconds since epoch when the token expires 9 | expiration: int 10 | -------------------------------------------------------------------------------- /jito_searcher_client/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "jito_searcher_client" 3 | version = "0.1.6" 4 | description = "Jito Labs Python Searcher Client" 5 | authors = ["Jito Labs "] 6 | urls = { "Support" = "https://discord.gg/jito" } 7 | readme = "README.md" 8 | packages = [{ include = "jito_searcher_client" }] 9 | 10 | [tool.poetry.dependencies] 11 | python = "^3.10" 12 | grpcio = "^1.62.1" 13 | protobuf = "^4.25.3" 14 | click = "^8.1.3" 15 | solana = "0.34.0" 16 | 17 | [build-system] 18 | requires = ["poetry-core"] 19 | build-backend = "poetry.core.masonry.api" 20 | 21 | [tool.poetry-grpc-plugin] 22 | proto_path = "../mev-protos" 23 | python_out = "./jito_searcher_client/generated" 24 | 25 | [tool.black] 26 | line-length = 120 27 | target-version = ['py37'] 28 | include = '\.pyi?$' 29 | extend-exclude = '''generated''' 30 | 31 | [tool.isort] 32 | profile = "black" 33 | extend_skip_glob = ["jito_searcher_client/generated/*"] 34 | 35 | [project] 36 | name = "jito_searcher_client" 37 | version = "0.1.6" 38 | description = "Jito Labs Python Searcher Client" 39 | authors = [ 40 | {name = "Jito Labs", email = "noreply@jito.wtf"}, 41 | ] 42 | --------------------------------------------------------------------------------