13
13
# limitations under the License.
14
14
15
15
from enum import IntFlag
16
- from typing import TYPE_CHECKING , Iterator , Optional , cast
16
+ from typing import TYPE_CHECKING , Iterable , Iterator , Optional , Union , cast
17
17
18
18
from structlog import get_logger
19
19
from twisted .internet .interfaces import IConsumer , IDelayedCall , IPushProducer
@@ -39,6 +39,7 @@ class StreamEnd(IntFlag):
39
39
LIMIT_EXCEEDED = 2
40
40
STREAM_BECAME_VOIDED = 3 # this will happen when the current chain becomes voided while it is being sent
41
41
TX_NOT_CONFIRMED = 4
42
+ INVALID_PARAMS = 5
42
43
43
44
def __str__ (self ):
44
45
if self is StreamEnd .END_HASH_REACHED :
@@ -191,6 +192,10 @@ def send_next(self) -> None:
191
192
192
193
class TransactionsStreamingServer (_StreamingServerBase ):
193
194
"""Streams all transactions confirmed by the given block, from right to left (decreasing timestamp).
195
+
196
+ If the start_from parameter is not empty, the BFS (Breadth-First Search) for the first block will commence
197
+ using the provided hashes. This mechanism enables streaming requests to continue from a specific point
198
+ should there be interruptions or issues.
194
199
"""
195
200
196
201
def __init__ (self ,
@@ -206,28 +211,39 @@ def __init__(self,
206
211
207
212
self .first_block : Block = cast (Block , self .tx_storage .get_transaction (first_block_hash ))
208
213
self .last_block : Block = cast (Block , self .tx_storage .get_transaction (last_block_hash ))
214
+ self .start_from = start_from
209
215
210
216
assert isinstance (self .first_block , Block )
211
217
assert isinstance (self .last_block , Block )
212
218
213
- self .current_block : Optional [Block ] = self .first_block
214
-
215
219
# TODO Validated start_from and use it when it's not empty.
216
220
221
+ self .current_block : Optional [Block ] = self .first_block
217
222
self .bfs = BFSOrderWalk (self .tx_storage , is_dag_verifications = True , is_dag_funds = True , is_left_to_right = False )
218
223
self .iter = self .get_iter ()
219
224
220
225
def get_iter (self ) -> Iterator [BaseTransaction ]:
221
226
"""Return an iterator that yields all transactions confirmed by each block in sequence."""
227
+ root : Union [BaseTransaction , Iterable [BaseTransaction ]]
228
+ skip_root : bool
222
229
while self .current_block :
230
+ if not self .start_from :
231
+ root = self .current_block
232
+ skip_root = True
233
+ else :
234
+ root = self .start_from
235
+ skip_root = False
223
236
self .log .debug ('sending transactions from block' ,
224
237
block = not_none (self .current_block .hash ).hex (),
225
- height = self .current_block .get_height ())
226
- it = self .bfs .run (self .current_block , skip_root = True )
238
+ height = self .current_block .get_height (),
239
+ start_from = self .start_from ,
240
+ skip_root = skip_root )
241
+ it = self .bfs .run (root , skip_root = skip_root )
227
242
yield from it
228
243
if self .current_block == self .last_block :
229
244
break
230
245
self .current_block = self .current_block .get_next_block_best_chain ()
246
+ self .start_from .clear ()
231
247
232
248
def send_next (self ) -> None :
233
249
"""Push next transaction to peer."""
0 commit comments