yellowstone-fumarole-client 0.1.0rc2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,324 @@
1
+ from typing import Optional, List, Dict, Set, Deque, Tuple, Any
2
+ from collections import deque, defaultdict
3
+ from yellowstone_fumarole_proto.fumarole_v2_pb2 import (
4
+ CommitmentLevel,
5
+ BlockchainEvent,
6
+ )
7
+ import heapq
8
+ import uuid
9
+ from enum import Enum
10
+
11
+ __all__ = [
12
+ "DEFAULT_SLOT_MEMORY_RETENTION",
13
+ "FumeBlockchainId",
14
+ "FumeBlockUID",
15
+ "FumeNumShards",
16
+ "FumeShardIdx",
17
+ "FumeOffset",
18
+ "FumeSessionSequence",
19
+ "Slot",
20
+ "FumeDownloadRequest",
21
+ "FumeSlotStatus",
22
+ "SlotCommitmentProgression",
23
+ "SlotDownloadProgress",
24
+ "SlotDownloadState",
25
+ "FumaroleSM",
26
+ ]
27
+
28
+ # Constants
29
+ DEFAULT_SLOT_MEMORY_RETENTION = 10000
30
+
31
+ # Type aliases
32
+ FumeBlockchainId = bytes # Equivalent to [u8; 16]
33
+ FumeBlockUID = bytes # Equivalent to [u8; 16]
34
+ FumeNumShards = int # Equivalent to u32
35
+ FumeShardIdx = int # Equivalent to u32
36
+ FumeOffset = int # Equivalent to i64
37
+ FumeSessionSequence = int # Equivalent to u64
38
+ Slot = int # From solana_sdk::clock::Slot
39
+
40
+
41
+ # Data structures
42
+ class FumeDownloadRequest:
43
+ def __init__(
44
+ self,
45
+ slot: Slot,
46
+ blockchain_id: FumeBlockchainId,
47
+ block_uid: FumeBlockUID,
48
+ num_shards: FumeNumShards,
49
+ commitment_level: CommitmentLevel,
50
+ ):
51
+ self.slot = slot
52
+ self.blockchain_id = blockchain_id
53
+ self.block_uid = block_uid
54
+ self.num_shards = num_shards
55
+ self.commitment_level = commitment_level
56
+
57
+
58
+ class FumeSlotStatus:
59
+ def __init__(
60
+ self,
61
+ session_sequence: FumeSessionSequence,
62
+ offset: FumeOffset,
63
+ slot: Slot,
64
+ parent_slot: Optional[Slot],
65
+ commitment_level: CommitmentLevel,
66
+ dead_error: Optional[str],
67
+ ):
68
+ self.session_sequence = session_sequence
69
+ self.offset = offset
70
+ self.slot = slot
71
+ self.parent_slot = parent_slot
72
+ self.commitment_level = commitment_level
73
+ self.dead_error = dead_error
74
+
75
+
76
+ class SlotCommitmentProgression:
77
+ def __init__(self):
78
+ self.processed_commitment_levels: Set[CommitmentLevel] = set()
79
+
80
+
81
+ class SlotDownloadProgress:
82
+ def __init__(self, num_shards: FumeNumShards):
83
+ self.num_shards = num_shards
84
+ self.shard_remaining = [False] * num_shards
85
+
86
+ def do_progress(self, shard_idx: FumeShardIdx) -> "SlotDownloadState":
87
+ self.shard_remaining[shard_idx % self.num_shards] = True
88
+ return (
89
+ SlotDownloadState.Done
90
+ if all(self.shard_remaining)
91
+ else SlotDownloadState.Downloading
92
+ )
93
+
94
+
95
+ class SlotDownloadState(Enum):
96
+ Downloading = "Downloading"
97
+ Done = "Done"
98
+
99
+
100
+ class FumaroleSM:
101
+ """
102
+ Sans-IO Fumarole State Machine
103
+
104
+ Manages in-flight slot downloads and ensures correct ordering of slot statuses without performing I/O.
105
+ """
106
+
107
+ def __init__(self, last_committed_offset: FumeOffset, slot_memory_retention: int):
108
+ self.last_committed_offset = last_committed_offset
109
+ self.slot_commitment_progression = dict() # Slot -> SlotCommitmentProgression
110
+ self.downloaded_slot = set() # Set of downloaded slots
111
+ self.inflight_slot_shard_download = {} # Slot -> SlotDownloadProgress
112
+ self.blocked_slot_status_update = defaultdict(
113
+ deque
114
+ ) # Slot -> Deque[FumeSlotStatus]
115
+ self.slot_status_update_queue = deque() # Deque[FumeSlotStatus]
116
+ self.processed_offset = [] # Min-heap for (sequence, offset)
117
+ self.committable_offset = last_committed_offset
118
+ self.max_slot_detected = 0
119
+ self.unprocessed_blockchain_event: Deque[
120
+ (FumeSessionSequence, BlockchainEvent)
121
+ ] = deque()
122
+ self.sequence = 1
123
+ self.last_processed_fume_sequence = 0
124
+ self.sequence_to_offset = {} # FumeSessionSequence -> FumeOffset
125
+ self.slot_memory_retention = slot_memory_retention
126
+
127
+ def update_committed_offset(self, offset: FumeOffset) -> None:
128
+ assert (
129
+ offset >= self.last_committed_offset
130
+ ), "Offset must be >= last committed offset"
131
+ self.last_committed_offset = offset
132
+
133
+ def next_sequence(self) -> int:
134
+ ret = self.sequence
135
+ self.sequence += 1
136
+ return ret
137
+
138
+ def gc(self) -> None:
139
+ """Garbage collect old slots to respect memory retention limit."""
140
+ while len(self.downloaded_slot) > self.slot_memory_retention:
141
+ slot = self.downloaded_slot.pop(0) if self.downloaded_slot else None
142
+ if slot is None:
143
+ break
144
+ self.slot_commitment_progression.pop(slot, None)
145
+ self.inflight_slot_shard_download.pop(slot, None)
146
+ self.blocked_slot_status_update.pop(slot, None)
147
+
148
+ def queue_blockchain_event(self, events: List[BlockchainEvent]) -> None:
149
+ """Queue blockchain events for processing."""
150
+ for event in events:
151
+
152
+ if event.offset < self.last_committed_offset:
153
+ continue
154
+
155
+ if event.slot > self.max_slot_detected:
156
+ self.max_slot_detected = event.slot
157
+
158
+ sequence = self.next_sequence()
159
+ self.sequence_to_offset[sequence] = event.offset
160
+
161
+ if event.slot in self.downloaded_slot:
162
+ fume_status = FumeSlotStatus(
163
+ session_sequence=sequence,
164
+ offset=event.offset,
165
+ slot=event.slot,
166
+ parent_slot=event.parent_slot,
167
+ commitment_level=event.commitment_level,
168
+ dead_error=event.dead_error,
169
+ )
170
+
171
+ if event.slot in self.inflight_slot_shard_download:
172
+ self.blocked_slot_status_update[event.slot].append(fume_status)
173
+ else:
174
+ self.slot_status_update_queue.append(fume_status)
175
+ else:
176
+ self.unprocessed_blockchain_event.append((sequence, event))
177
+
178
+ def make_slot_download_progress(
179
+ self, slot: Slot, shard_idx: FumeShardIdx
180
+ ) -> SlotDownloadState:
181
+ """Update download progress for a given slot."""
182
+ download_progress = self.inflight_slot_shard_download.get(slot)
183
+ if not download_progress:
184
+ raise ValueError("Slot not in download")
185
+
186
+ download_state = download_progress.do_progress(shard_idx)
187
+
188
+ if download_state == SlotDownloadState.Done:
189
+ self.inflight_slot_shard_download.pop(slot)
190
+ self.downloaded_slot.add(slot)
191
+ self.slot_commitment_progression.setdefault(
192
+ slot, SlotCommitmentProgression()
193
+ )
194
+ blocked_statuses = self.blocked_slot_status_update.pop(slot, deque())
195
+ self.slot_status_update_queue.extend(blocked_statuses)
196
+
197
+ return download_state
198
+
199
+ def pop_next_slot_status(self) -> Optional[FumeSlotStatus]:
200
+ """Pop the next slot status to process."""
201
+ while self.slot_status_update_queue:
202
+ slot_status = self.slot_status_update_queue.popleft()
203
+ commitment_history = self.slot_commitment_progression.get(slot_status.slot)
204
+ if (
205
+ commitment_history
206
+ and slot_status.commitment_level
207
+ not in commitment_history.processed_commitment_levels
208
+ ):
209
+ commitment_history.processed_commitment_levels.add(
210
+ slot_status.commitment_level
211
+ )
212
+ return slot_status
213
+ elif not commitment_history:
214
+ raise RuntimeError("Slot status should not be available here")
215
+ return None
216
+
217
+ def make_sure_slot_commitment_progression_exists(
218
+ self, slot: Slot
219
+ ) -> SlotCommitmentProgression:
220
+ """Ensure a slot has a commitment progression entry."""
221
+ return self.slot_commitment_progression.setdefault(
222
+ slot, SlotCommitmentProgression()
223
+ )
224
+
225
+ def pop_slot_to_download(self, commitment=None) -> Optional[FumeDownloadRequest]:
226
+ """Pop the next slot to download."""
227
+ min_commitment = commitment or CommitmentLevel.PROCESSED
228
+ while self.unprocessed_blockchain_event:
229
+ session_sequence, blockchain_event = (
230
+ self.unprocessed_blockchain_event.popleft()
231
+ )
232
+ blockchain_event: BlockchainEvent = blockchain_event
233
+ event_cl = blockchain_event.commitment_level
234
+
235
+ if event_cl < min_commitment:
236
+ self.slot_status_update_queue.append(
237
+ FumeSlotStatus(
238
+ session_sequence=session_sequence,
239
+ offset=blockchain_event.offset,
240
+ slot=blockchain_event.slot,
241
+ parent_slot=blockchain_event.parent_slot,
242
+ commitment_level=event_cl,
243
+ dead_error=blockchain_event.dead_error,
244
+ )
245
+ )
246
+ self.make_sure_slot_commitment_progression_exists(blockchain_event.slot)
247
+ continue
248
+
249
+ if blockchain_event.slot in self.downloaded_slot:
250
+ self.make_sure_slot_commitment_progression_exists(blockchain_event.slot)
251
+ progression = self.slot_commitment_progression[blockchain_event.slot]
252
+ if event_cl in progression.processed_commitment_levels:
253
+ self.mark_event_as_processed(session_sequence)
254
+ continue
255
+
256
+ self.slot_status_update_queue.append(
257
+ FumeSlotStatus(
258
+ session_sequence=session_sequence,
259
+ offset=blockchain_event.offset,
260
+ slot=blockchain_event.slot,
261
+ parent_slot=blockchain_event.parent_slot,
262
+ commitment_level=event_cl,
263
+ dead_error=blockchain_event.dead_error,
264
+ )
265
+ )
266
+ else:
267
+ blockchain_id = bytes(blockchain_event.blockchain_id)
268
+ block_uid = bytes(blockchain_event.block_uid)
269
+ if blockchain_event.slot not in self.inflight_slot_shard_download:
270
+ download_request = FumeDownloadRequest(
271
+ slot=blockchain_event.slot,
272
+ blockchain_id=blockchain_id,
273
+ block_uid=block_uid,
274
+ num_shards=blockchain_event.num_shards,
275
+ commitment_level=event_cl,
276
+ )
277
+ download_progress = SlotDownloadProgress(
278
+ num_shards=blockchain_event.num_shards
279
+ )
280
+ self.inflight_slot_shard_download[blockchain_event.slot] = (
281
+ download_progress
282
+ )
283
+ self.blocked_slot_status_update[blockchain_event.slot].append(
284
+ FumeSlotStatus(
285
+ session_sequence=session_sequence,
286
+ offset=blockchain_event.offset,
287
+ slot=blockchain_event.slot,
288
+ parent_slot=blockchain_event.parent_slot,
289
+ commitment_level=event_cl,
290
+ dead_error=blockchain_event.dead_error,
291
+ )
292
+ )
293
+ return download_request
294
+ return None
295
+
296
+ def mark_event_as_processed(self, event_seq_number: FumeSessionSequence) -> None:
297
+ """Mark an event as processed and update committable offset."""
298
+ fume_offset = self.sequence_to_offset.pop(event_seq_number, None)
299
+ if fume_offset is None:
300
+ raise ValueError("Event sequence number not found")
301
+ heapq.heappush(
302
+ self.processed_offset, (-event_seq_number, -fume_offset)
303
+ ) # Negate for min-heap
304
+
305
+ while self.processed_offset:
306
+ seq, offset = self.processed_offset[0]
307
+ seq, offset = -seq, -offset # Convert back to positive
308
+ if seq != self.last_processed_fume_sequence + 1:
309
+ break
310
+ heapq.heappop(self.processed_offset)
311
+ self.committable_offset = offset
312
+ self.last_processed_fume_sequence = seq
313
+
314
+ def slot_status_update_queue_len(self) -> int:
315
+ """Return the length of the slot status update queue."""
316
+ return len(self.slot_status_update_queue)
317
+
318
+ def processed_offset_queue_len(self) -> int:
319
+ """Return the length of the processed offset queue."""
320
+ return len(self.processed_offset)
321
+
322
+ def need_new_blockchain_events(self) -> bool:
323
+ """Check if new blockchain events are needed."""
324
+ return not self.slot_status_update_queue and not self.blocked_slot_status_update
File without changes
@@ -0,0 +1,30 @@
1
+ import asyncio
2
+ import logging
3
+ from typing import Any, Coroutine
4
+
5
+ LOGGER = logging.getLogger(__name__)
6
+
7
+
8
+ async def never():
9
+ """
10
+ Create a forever pending future. This future is not set and will never be set.
11
+ This is useful for testing purposes.
12
+ """
13
+ loop = asyncio.get_running_loop()
14
+ return await loop.create_future()
15
+
16
+
17
+ class Interval:
18
+
19
+ def __init__(self, interval: float):
20
+ """
21
+ Create an interval that will run the given factory every `interval` seconds.
22
+
23
+ Args:
24
+ interval: The interval in seconds.
25
+ factory: A factory that returns a coroutine to be run at the interval.
26
+ """
27
+ self.interval = interval
28
+
29
+ async def tick(self):
30
+ await asyncio.sleep(self.interval)
@@ -0,0 +1,115 @@
1
+ Metadata-Version: 2.1
2
+ Name: yellowstone-fumarole-client
3
+ Version: 0.1.0rc2
4
+ Summary: Yellowstone Fumarole Python Client
5
+ Home-page: https://github.com/rpcpool/yellowstone-fumarole
6
+ Author: Louis-Vincent
7
+ Author-email: louis-vincent@triton.one
8
+ Requires-Python: >=3.13,<4.0
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.13
11
+ Requires-Dist: asyncio (>=3.4.3,<4.0.0)
12
+ Requires-Dist: base58 (>=2.1.1,<3.0.0)
13
+ Requires-Dist: click (>=8.1.7,<9.0.0)
14
+ Requires-Dist: grpcio (>=1.71.1,<2.0.0)
15
+ Requires-Dist: protobuf (>=5.29.1,<6.0.0)
16
+ Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
17
+ Requires-Dist: tabulate (>=0.9.0,<0.10.0)
18
+ Requires-Dist: toml (>=0.10.2,<0.11.0)
19
+ Project-URL: Repository, https://github.com/rpcpool/yellowstone-fumarole
20
+ Description-Content-Type: text/markdown
21
+
22
+ # Fumarole Python SDK
23
+
24
+ This module contains Fumarole SDK for `python` programming language.
25
+
26
+ ## Configuration
27
+
28
+ ```yaml
29
+ endpoint: <"https://fumarole.endpoint.rpcpool.com">
30
+ x-token: <YOUR X-TOKEN secret here>
31
+ ```
32
+
33
+ ## Manage consumer group
34
+
35
+ Refer to [fume CLI](https://crates.io/crates/yellowstone-fumarole-cli) to manage your consumer groups.
36
+
37
+ ## Examples
38
+
39
+ ```python
40
+
41
+ from typing import Optional
42
+ import uuid
43
+ import asyncio
44
+ import logging
45
+ from os import environ
46
+ from collections import defaultdict
47
+ from yellowstone_fumarole_client.config import FumaroleConfig
48
+ from yellowstone_fumarole_client import FumaroleClient
49
+ from yellowstone_fumarole_proto.fumarole_v2_pb2 import CreateConsumerGroupRequest
50
+ from yellowstone_fumarole_proto.geyser_pb2 import (
51
+ SubscribeRequest,
52
+ SubscribeRequestFilterAccounts,
53
+ SubscribeRequestFilterTransactions,
54
+ SubscribeRequestFilterBlocksMeta,
55
+ SubscribeRequestFilterEntry,
56
+ SubscribeRequestFilterSlots,
57
+ )
58
+ from yellowstone_fumarole_proto.geyser_pb2 import (
59
+ SubscribeUpdate,
60
+ SubscribeUpdateTransaction,
61
+ SubscribeUpdateBlockMeta,
62
+ SubscribeUpdateAccount,
63
+ SubscribeUpdateEntry,
64
+ SubscribeUpdateSlot,
65
+ )
66
+
67
+ async def dragonsmouth_like_session(fumarole_config):
68
+ with open("~/.fumarole/config.yaml") as f:
69
+ fumarole_config = FumaroleConfig.from_yaml(f)
70
+
71
+ client: FumaroleClient = await FumaroleClient.connect(fumarole_config)
72
+ await client.delete_all_consumer_groups()
73
+
74
+ # --- This is optional ---
75
+ resp = await client.create_consumer_group(
76
+ CreateConsumerGroupRequest(
77
+ consumer_group_name="test",
78
+ )
79
+ )
80
+ assert resp.consumer_group_id, "Failed to create consumer group"
81
+ # --- END OF OPTIONAL BLOCK ---
82
+
83
+ session = await client.dragonsmouth_subscribe(
84
+ consumer_group_name="test",
85
+ request=SubscribeRequest(
86
+ # accounts={"fumarole": SubscribeRequestFilterAccounts()},
87
+ transactions={"fumarole": SubscribeRequestFilterTransactions()},
88
+ blocks_meta={"fumarole": SubscribeRequestFilterBlocksMeta()},
89
+ entry={"fumarole": SubscribeRequestFilterEntry()},
90
+ slots={"fumarole": SubscribeRequestFilterSlots()},
91
+ ),
92
+ )
93
+ dragonsmouth_source = session.source
94
+ handle = session.fumarole_handle
95
+ block_map = defaultdict(BlockConstruction)
96
+ while True:
97
+ tasks = [asyncio.create_task(dragonsmouth_source.get()), handle]
98
+ done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
99
+ for t in done:
100
+ if tasks[0] == t:
101
+ result: SubscribeUpdate = t.result()
102
+ if result.HasField("block_meta"):
103
+ block_meta: SubscribeUpdateBlockMeta = result.block_meta
104
+ elif result.HasField("transaction"):
105
+ tx: SubscribeUpdateTransaction = result.transaction
106
+ elif result.HasField("account"):
107
+ account: SubscribeUpdateAccount = result.account
108
+ elif result.HasField("entry"):
109
+ entry: SubscribeUpdateEntry = result.entry
110
+ elif result.HasField("slot"):
111
+ result: SubscribeUpdateSlot = result.slot
112
+ else:
113
+ result = t.result()
114
+ raise RuntimeError("failed to get dragonsmouth source: %s" % result)
115
+ ```
@@ -0,0 +1,21 @@
1
+ yellowstone_fumarole_client/__init__.py,sha256=zaCqyRuSvI2GRalf8iorVBxVfs_Yr6jmihC6y_cAs_Y,10943
2
+ yellowstone_fumarole_client/config.py,sha256=MIFJ-HwzkbdzGMU5mw2GQ8NbUbE7QaBM2NH5WUukodg,788
3
+ yellowstone_fumarole_client/grpc_connectivity.py,sha256=4wjcLq1vWUBXbngEJG-NMbbNhUjX2IgIlh6s2sN-OFM,7446
4
+ yellowstone_fumarole_client/runtime/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ yellowstone_fumarole_client/runtime/aio.py,sha256=TZer114eylM33UgvnG3nyjM3wfGnSKMA78vHt-KtQeM,20829
6
+ yellowstone_fumarole_client/runtime/state_machine.py,sha256=8mrCLd-DpCDdHsbOAhgYgzcb96Nrv4ToYxGAiSaqVcQ,12668
7
+ yellowstone_fumarole_client/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ yellowstone_fumarole_client/utils/aio.py,sha256=sm2q95CBumZGpRPQtD7QykCKgIxiP1te_dLVsFQ13hk,756
9
+ yellowstone_fumarole_proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ yellowstone_fumarole_proto/fumarole_v2_pb2.py,sha256=lbNwmOo03dwGvfOmEjgAQyUZH8Ym8iNEHN17aqbdIy0,12680
11
+ yellowstone_fumarole_proto/fumarole_v2_pb2.pyi,sha256=qxLRRROIAh0aLoR7_plq8Xhxw5GntLnefIi5dxCgPD4,17904
12
+ yellowstone_fumarole_proto/fumarole_v2_pb2_grpc.py,sha256=j_d9D2zecnNrmR3cP7XIzyq1y4R0_XHTnzv7RKsGxM0,15954
13
+ yellowstone_fumarole_proto/geyser_pb2.py,sha256=IyxdSjUgl5iNK_bG1ZESOLL2Z_t8b1VA_R1nD1n7Sho,19624
14
+ yellowstone_fumarole_proto/geyser_pb2.pyi,sha256=TJTvxms9xNxAjyKNUd6Z0KP7yNPqXaAv--lYLtzE4RU,26776
15
+ yellowstone_fumarole_proto/geyser_pb2_grpc.py,sha256=H70Rfun8udwbFh1hOAURjBk6KNIu4XEGIgFw1yJ46nc,13555
16
+ yellowstone_fumarole_proto/solana_storage_pb2.py,sha256=0LHBWc-hKY76rES8U2ak7niaJ_pgr0HiusJD7-NqtiM,8366
17
+ yellowstone_fumarole_proto/solana_storage_pb2.pyi,sha256=lRee-OWbvwFIdPs9IhW4U5VvDFeNBcq6ErbSDiO-G6E,12901
18
+ yellowstone_fumarole_proto/solana_storage_pb2_grpc.py,sha256=W_FjTN0_TEToXDu9eHWi4wRFkiq6zT7hJjL0cApXW80,895
19
+ yellowstone_fumarole_client-0.1.0rc2.dist-info/METADATA,sha256=M_7SMyyT5BTEeaiJd4S5cw0G0I1gEg4tLWlWNCOslKU,4148
20
+ yellowstone_fumarole_client-0.1.0rc2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
21
+ yellowstone_fumarole_client-0.1.0rc2.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 1.9.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
File without changes
@@ -0,0 +1,122 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # NO CHECKED-IN PROTOBUF GENCODE
4
+ # source: fumarole_v2.proto
5
+ # Protobuf Python Version: 5.29.0
6
+ """Generated protocol buffer code."""
7
+ from google.protobuf import descriptor as _descriptor
8
+ from google.protobuf import descriptor_pool as _descriptor_pool
9
+ from google.protobuf import runtime_version as _runtime_version
10
+ from google.protobuf import symbol_database as _symbol_database
11
+ from google.protobuf.internal import builder as _builder
12
+ _runtime_version.ValidateProtobufRuntimeVersion(
13
+ _runtime_version.Domain.PUBLIC,
14
+ 5,
15
+ 29,
16
+ 0,
17
+ '',
18
+ 'fumarole_v2.proto'
19
+ )
20
+ # @@protoc_insertion_point(imports)
21
+
22
+ _sym_db = _symbol_database.Default()
23
+
24
+
25
+ import yellowstone_fumarole_proto.geyser_pb2 as geyser__pb2
26
+ try:
27
+ solana__storage__pb2 = geyser__pb2.solana__storage__pb2
28
+ except AttributeError:
29
+ solana__storage__pb2 = geyser__pb2.solana_storage_pb2
30
+
31
+ from yellowstone_fumarole_proto.geyser_pb2 import *
32
+
33
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11\x66umarole_v2.proto\x12\x0b\x66umarole_v2\x1a\x0cgeyser.proto\"\x10\n\x0eVersionRequest\"\"\n\x0fVersionResponse\x12\x0f\n\x07version\x18\x01 \x01(\t\":\n\x1bGetConsumerGroupInfoRequest\x12\x1b\n\x13\x63onsumer_group_name\x18\x01 \x01(\t\"9\n\x1a\x44\x65leteConsumerGroupRequest\x12\x1b\n\x13\x63onsumer_group_name\x18\x01 \x01(\t\".\n\x1b\x44\x65leteConsumerGroupResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\x1b\n\x19ListConsumerGroupsRequest\"U\n\x1aListConsumerGroupsResponse\x12\x37\n\x0f\x63onsumer_groups\x18\x01 \x03(\x0b\x32\x1e.fumarole_v2.ConsumerGroupInfo\"N\n\x11\x43onsumerGroupInfo\x12\n\n\x02id\x18\x01 \x01(\t\x12\x1b\n\x13\x63onsumer_group_name\x18\x02 \x01(\t\x12\x10\n\x08is_stale\x18\x03 \x01(\x08\"4\n\x15GetSlotLagInfoRequest\x12\x1b\n\x13\x63onsumer_group_name\x18\x01 \x01(\t\"\xf1\x04\n\x0c\x42lockFilters\x12\x39\n\x08\x61\x63\x63ounts\x18\x01 \x03(\x0b\x32\'.fumarole_v2.BlockFilters.AccountsEntry\x12\x41\n\x0ctransactions\x18\x02 \x03(\x0b\x32+.fumarole_v2.BlockFilters.TransactionsEntry\x12\x37\n\x07\x65ntries\x18\x03 \x03(\x0b\x32&.fumarole_v2.BlockFilters.EntriesEntry\x12>\n\x0b\x62locks_meta\x18\x04 \x03(\x0b\x32).fumarole_v2.BlockFilters.BlocksMetaEntry\x1aW\n\rAccountsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x35\n\x05value\x18\x02 \x01(\x0b\x32&.geyser.SubscribeRequestFilterAccounts:\x02\x38\x01\x1a_\n\x11TransactionsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x39\n\x05value\x18\x02 \x01(\x0b\x32*.geyser.SubscribeRequestFilterTransactions:\x02\x38\x01\x1aS\n\x0c\x45ntriesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x32\n\x05value\x18\x02 \x01(\x0b\x32#.geyser.SubscribeRequestFilterEntry:\x02\x38\x01\x1a[\n\x0f\x42locksMetaEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x37\n\x05value\x18\x02 \x01(\x0b\x32(.geyser.SubscribeRequestFilterBlocksMeta:\x02\x38\x01\"\x98\x01\n\x12\x44ownloadBlockShard\x12\x15\n\rblockchain_id\x18\x01 \x01(\x0c\x12\x11\n\tblock_uid\x18\x02 \x01(\x0c\x12\x11\n\tshard_idx\x18\x03 \x01(\x05\x12\x34\n\x0c\x62lockFilters\x18\x04 \x01(\x0b\x32\x19.fumarole_v2.BlockFiltersH\x00\x88\x01\x01\x42\x0f\n\r_blockFilters\"\x17\n\x04Ping\x12\x0f\n\x07ping_id\x18\x01 \x01(\r\"\x17\n\x04Pong\x12\x0f\n\x07ping_id\x18\x01 \x01(\r\"\x8d\x01\n\x0b\x44\x61taCommand\x12?\n\x14\x64ownload_block_shard\x18\x01 \x01(\x0b\x32\x1f.fumarole_v2.DownloadBlockShardH\x00\x12\x32\n\rfilter_update\x18\x02 \x01(\x0b\x32\x19.fumarole_v2.BlockFiltersH\x00\x42\t\n\x07\x63ommand\"\x1a\n\x18\x42lockShardDownloadFinish\"L\n\rBlockNotFound\x12\x15\n\rblockchain_id\x18\x01 \x01(\x0c\x12\x11\n\tblock_uid\x18\x02 \x01(\x0c\x12\x11\n\tshard_idx\x18\x03 \x01(\x05\"E\n\tDataError\x12/\n\tnot_found\x18\x01 \x01(\x0b\x32\x1a.fumarole_v2.BlockNotFoundH\x00\x42\x07\n\x05\x65rror\"\x93\x01\n\x0c\x44\x61taResponse\x12)\n\x06update\x18\x01 \x01(\x0b\x32\x17.geyser.SubscribeUpdateH\x00\x12L\n\x1b\x62lock_shard_download_finish\x18\x02 \x01(\x0b\x32%.fumarole_v2.BlockShardDownloadFinishH\x00\x42\n\n\x08response\"0\n\x0c\x43ommitOffset\x12\x0e\n\x06offset\x18\x01 \x01(\x03\x12\x10\n\x08shard_id\x18\x02 \x01(\x05\"c\n\x15PollBlockchainHistory\x12\x10\n\x08shard_id\x18\x01 \x01(\x05\x12\x11\n\x04\x66rom\x18\x02 \x01(\x03H\x00\x88\x01\x01\x12\x12\n\x05limit\x18\x03 \x01(\x03H\x01\x88\x01\x01\x42\x07\n\x05_fromB\x08\n\x06_limit\"\x8f\x02\n\x0f\x42lockchainEvent\x12\x0e\n\x06offset\x18\x01 \x01(\x03\x12\x15\n\rblockchain_id\x18\x02 \x01(\x0c\x12\x11\n\tblock_uid\x18\x03 \x01(\x0c\x12\x12\n\nnum_shards\x18\x04 \x01(\r\x12\x0c\n\x04slot\x18\x05 \x01(\x04\x12\x18\n\x0bparent_slot\x18\x06 \x01(\x04H\x00\x88\x01\x01\x12\x31\n\x10\x63ommitment_level\x18\x07 \x01(\x0e\x32\x17.geyser.CommitmentLevel\x12\x1b\n\x13\x62lockchain_shard_id\x18\x08 \x01(\x05\x12\x17\n\ndead_error\x18\t \x01(\tH\x01\x88\x01\x01\x42\x0e\n\x0c_parent_slotB\r\n\x0b_dead_error\"A\n\x11\x42lockchainHistory\x12,\n\x06\x65vents\x18\x01 \x03(\x0b\x32\x1c.fumarole_v2.BlockchainEvent\"L\n\x10JoinControlPlane\x12 \n\x13\x63onsumer_group_name\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x16\n\x14_consumer_group_name\"\xe2\x01\n\x0e\x43ontrolCommand\x12\x35\n\x0cinitial_join\x18\x01 \x01(\x0b\x32\x1d.fumarole_v2.JoinControlPlaneH\x00\x12\x32\n\rcommit_offset\x18\x02 \x01(\x0b\x32\x19.fumarole_v2.CommitOffsetH\x00\x12\x37\n\tpoll_hist\x18\x03 \x01(\x0b\x32\".fumarole_v2.PollBlockchainHistoryH\x00\x12!\n\x04ping\x18\x04 \x01(\x0b\x32\x11.fumarole_v2.PingH\x00\x42\t\n\x07\x63ommand\"\xe7\x01\n\x0f\x43ontrolResponse\x12\x36\n\x04init\x18\x01 \x01(\x0b\x32&.fumarole_v2.InitialConsumerGroupStateH\x00\x12\x38\n\rcommit_offset\x18\x02 \x01(\x0b\x32\x1f.fumarole_v2.CommitOffsetResultH\x00\x12\x33\n\tpoll_hist\x18\x03 \x01(\x0b\x32\x1e.fumarole_v2.BlockchainHistoryH\x00\x12!\n\x04pong\x18\x04 \x01(\x0b\x32\x11.fumarole_v2.PongH\x00\x42\n\n\x08response\"6\n\x12\x43ommitOffsetResult\x12\x0e\n\x06offset\x18\x01 \x01(\x03\x12\x10\n\x08shard_id\x18\x02 \x01(\x05\"\xd1\x01\n\x19InitialConsumerGroupState\x12\x15\n\rblockchain_id\x18\x01 \x01(\x0c\x12`\n\x16last_committed_offsets\x18\x02 \x03(\x0b\x32@.fumarole_v2.InitialConsumerGroupState.LastCommittedOffsetsEntry\x1a;\n\x19LastCommittedOffsetsEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x03:\x02\x38\x01\"8\n\x1b\x43reateConsumerGroupResponse\x12\x19\n\x11\x63onsumer_group_id\x18\x01 \x01(\t\"z\n\x1a\x43reateConsumerGroupRequest\x12\x1b\n\x13\x63onsumer_group_name\x18\x01 \x01(\t\x12?\n\x15initial_offset_policy\x18\x02 \x01(\x0e\x32 .fumarole_v2.InitialOffsetPolicy*!\n\x13InitialOffsetPolicy\x12\n\n\x06LATEST\x10\x00\x32\xe2\x05\n\x08\x46umarole\x12\x62\n\x14GetConsumerGroupInfo\x12(.fumarole_v2.GetConsumerGroupInfoRequest\x1a\x1e.fumarole_v2.ConsumerGroupInfo\"\x00\x12g\n\x12ListConsumerGroups\x12&.fumarole_v2.ListConsumerGroupsRequest\x1a\'.fumarole_v2.ListConsumerGroupsResponse\"\x00\x12j\n\x13\x44\x65leteConsumerGroup\x12\'.fumarole_v2.DeleteConsumerGroupRequest\x1a(.fumarole_v2.DeleteConsumerGroupResponse\"\x00\x12j\n\x13\x43reateConsumerGroup\x12\'.fumarole_v2.CreateConsumerGroupRequest\x1a(.fumarole_v2.CreateConsumerGroupResponse\"\x00\x12O\n\rDownloadBlock\x12\x1f.fumarole_v2.DownloadBlockShard\x1a\x19.fumarole_v2.DataResponse\"\x00\x30\x01\x12J\n\rSubscribeData\x12\x18.fumarole_v2.DataCommand\x1a\x19.fumarole_v2.DataResponse\"\x00(\x01\x30\x01\x12L\n\tSubscribe\x12\x1b.fumarole_v2.ControlCommand\x1a\x1c.fumarole_v2.ControlResponse\"\x00(\x01\x30\x01\x12\x46\n\x07Version\x12\x1b.fumarole_v2.VersionRequest\x1a\x1c.fumarole_v2.VersionResponse\"\x00P\x00\x62\x06proto3')
34
+
35
+ _globals = globals()
36
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
37
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'fumarole_v2_pb2', _globals)
38
+ if not _descriptor._USE_C_DESCRIPTORS:
39
+ DESCRIPTOR._loaded_options = None
40
+ _globals['_BLOCKFILTERS_ACCOUNTSENTRY']._loaded_options = None
41
+ _globals['_BLOCKFILTERS_ACCOUNTSENTRY']._serialized_options = b'8\001'
42
+ _globals['_BLOCKFILTERS_TRANSACTIONSENTRY']._loaded_options = None
43
+ _globals['_BLOCKFILTERS_TRANSACTIONSENTRY']._serialized_options = b'8\001'
44
+ _globals['_BLOCKFILTERS_ENTRIESENTRY']._loaded_options = None
45
+ _globals['_BLOCKFILTERS_ENTRIESENTRY']._serialized_options = b'8\001'
46
+ _globals['_BLOCKFILTERS_BLOCKSMETAENTRY']._loaded_options = None
47
+ _globals['_BLOCKFILTERS_BLOCKSMETAENTRY']._serialized_options = b'8\001'
48
+ _globals['_INITIALCONSUMERGROUPSTATE_LASTCOMMITTEDOFFSETSENTRY']._loaded_options = None
49
+ _globals['_INITIALCONSUMERGROUPSTATE_LASTCOMMITTEDOFFSETSENTRY']._serialized_options = b'8\001'
50
+ _globals['_INITIALOFFSETPOLICY']._serialized_start=3306
51
+ _globals['_INITIALOFFSETPOLICY']._serialized_end=3339
52
+ _globals['_VERSIONREQUEST']._serialized_start=48
53
+ _globals['_VERSIONREQUEST']._serialized_end=64
54
+ _globals['_VERSIONRESPONSE']._serialized_start=66
55
+ _globals['_VERSIONRESPONSE']._serialized_end=100
56
+ _globals['_GETCONSUMERGROUPINFOREQUEST']._serialized_start=102
57
+ _globals['_GETCONSUMERGROUPINFOREQUEST']._serialized_end=160
58
+ _globals['_DELETECONSUMERGROUPREQUEST']._serialized_start=162
59
+ _globals['_DELETECONSUMERGROUPREQUEST']._serialized_end=219
60
+ _globals['_DELETECONSUMERGROUPRESPONSE']._serialized_start=221
61
+ _globals['_DELETECONSUMERGROUPRESPONSE']._serialized_end=267
62
+ _globals['_LISTCONSUMERGROUPSREQUEST']._serialized_start=269
63
+ _globals['_LISTCONSUMERGROUPSREQUEST']._serialized_end=296
64
+ _globals['_LISTCONSUMERGROUPSRESPONSE']._serialized_start=298
65
+ _globals['_LISTCONSUMERGROUPSRESPONSE']._serialized_end=383
66
+ _globals['_CONSUMERGROUPINFO']._serialized_start=385
67
+ _globals['_CONSUMERGROUPINFO']._serialized_end=463
68
+ _globals['_GETSLOTLAGINFOREQUEST']._serialized_start=465
69
+ _globals['_GETSLOTLAGINFOREQUEST']._serialized_end=517
70
+ _globals['_BLOCKFILTERS']._serialized_start=520
71
+ _globals['_BLOCKFILTERS']._serialized_end=1145
72
+ _globals['_BLOCKFILTERS_ACCOUNTSENTRY']._serialized_start=783
73
+ _globals['_BLOCKFILTERS_ACCOUNTSENTRY']._serialized_end=870
74
+ _globals['_BLOCKFILTERS_TRANSACTIONSENTRY']._serialized_start=872
75
+ _globals['_BLOCKFILTERS_TRANSACTIONSENTRY']._serialized_end=967
76
+ _globals['_BLOCKFILTERS_ENTRIESENTRY']._serialized_start=969
77
+ _globals['_BLOCKFILTERS_ENTRIESENTRY']._serialized_end=1052
78
+ _globals['_BLOCKFILTERS_BLOCKSMETAENTRY']._serialized_start=1054
79
+ _globals['_BLOCKFILTERS_BLOCKSMETAENTRY']._serialized_end=1145
80
+ _globals['_DOWNLOADBLOCKSHARD']._serialized_start=1148
81
+ _globals['_DOWNLOADBLOCKSHARD']._serialized_end=1300
82
+ _globals['_PING']._serialized_start=1302
83
+ _globals['_PING']._serialized_end=1325
84
+ _globals['_PONG']._serialized_start=1327
85
+ _globals['_PONG']._serialized_end=1350
86
+ _globals['_DATACOMMAND']._serialized_start=1353
87
+ _globals['_DATACOMMAND']._serialized_end=1494
88
+ _globals['_BLOCKSHARDDOWNLOADFINISH']._serialized_start=1496
89
+ _globals['_BLOCKSHARDDOWNLOADFINISH']._serialized_end=1522
90
+ _globals['_BLOCKNOTFOUND']._serialized_start=1524
91
+ _globals['_BLOCKNOTFOUND']._serialized_end=1600
92
+ _globals['_DATAERROR']._serialized_start=1602
93
+ _globals['_DATAERROR']._serialized_end=1671
94
+ _globals['_DATARESPONSE']._serialized_start=1674
95
+ _globals['_DATARESPONSE']._serialized_end=1821
96
+ _globals['_COMMITOFFSET']._serialized_start=1823
97
+ _globals['_COMMITOFFSET']._serialized_end=1871
98
+ _globals['_POLLBLOCKCHAINHISTORY']._serialized_start=1873
99
+ _globals['_POLLBLOCKCHAINHISTORY']._serialized_end=1972
100
+ _globals['_BLOCKCHAINEVENT']._serialized_start=1975
101
+ _globals['_BLOCKCHAINEVENT']._serialized_end=2246
102
+ _globals['_BLOCKCHAINHISTORY']._serialized_start=2248
103
+ _globals['_BLOCKCHAINHISTORY']._serialized_end=2313
104
+ _globals['_JOINCONTROLPLANE']._serialized_start=2315
105
+ _globals['_JOINCONTROLPLANE']._serialized_end=2391
106
+ _globals['_CONTROLCOMMAND']._serialized_start=2394
107
+ _globals['_CONTROLCOMMAND']._serialized_end=2620
108
+ _globals['_CONTROLRESPONSE']._serialized_start=2623
109
+ _globals['_CONTROLRESPONSE']._serialized_end=2854
110
+ _globals['_COMMITOFFSETRESULT']._serialized_start=2856
111
+ _globals['_COMMITOFFSETRESULT']._serialized_end=2910
112
+ _globals['_INITIALCONSUMERGROUPSTATE']._serialized_start=2913
113
+ _globals['_INITIALCONSUMERGROUPSTATE']._serialized_end=3122
114
+ _globals['_INITIALCONSUMERGROUPSTATE_LASTCOMMITTEDOFFSETSENTRY']._serialized_start=3063
115
+ _globals['_INITIALCONSUMERGROUPSTATE_LASTCOMMITTEDOFFSETSENTRY']._serialized_end=3122
116
+ _globals['_CREATECONSUMERGROUPRESPONSE']._serialized_start=3124
117
+ _globals['_CREATECONSUMERGROUPRESPONSE']._serialized_end=3180
118
+ _globals['_CREATECONSUMERGROUPREQUEST']._serialized_start=3182
119
+ _globals['_CREATECONSUMERGROUPREQUEST']._serialized_end=3304
120
+ _globals['_FUMAROLE']._serialized_start=3342
121
+ _globals['_FUMAROLE']._serialized_end=4080
122
+ # @@protoc_insertion_point(module_scope)