44import logging , random
55import pandas as pd
66from functools import partial , partialmethod
7+ from collections import deque
78from datetime import datetime
89from DAS .tools import *
910from DAS .results import *
@@ -21,6 +22,7 @@ def __init__(self, shape, config, execID):
2122 self .format = {"entity" : "Simulator" }
2223 self .execID = execID
2324 self .result = Result (self .shape , self .execID )
25+ self .dhtResult = Result (self .shape , self .execID )
2426 self .validators = []
2527 self .logger = []
2628 self .logLevel = config .logLevel
@@ -31,6 +33,7 @@ def __init__(self, shape, config, execID):
3133 self .distC = []
3234 self .nodeRows = []
3335 self .nodeColumns = []
36+ self .dhtNetwork = DHTNetwork (0 , 0 , [0 ])
3437
3538 # In GossipSub the initiator might push messages without participating in the mesh.
3639 # proposerPublishOnly regulates this behavior. If set to true, the proposer is not
@@ -178,23 +181,6 @@ def initNetwork(self):
178181 self .logger .debug ("Val %d : rowN %s" , i , self .validators [i ].rowNeighbors , extra = self .format )
179182 self .logger .debug ("Val %d : colN %s" , i , self .validators [i ].columnNeighbors , extra = self .format )
180183
181- def initDHTNetwork (self ):
182- """ Compose the DHT network based on the pre-initialized Validators """
183- # compose the DHT networking layer
184- self .logger .info ("Initializing DHTNetwork... with %d nodes" % self .shape .numberNodes , extra = self .format )
185- self .DHTNetwork = DHTNetwork (self .execID , self .shape .failureRate , self .config .stepDuration )
186-
187- # initialize each of the routing tables
188- startTime = time .time ()
189- _ = self .DHTNetwork .init_with_random_peers (self .config .numJobs , self .shape .numberNodes ,
190- self .shape .k , self .shape .alpha , self .shape .k , self .config .nilStepsToStopLookup )
191- self .logger .info ("DHT fast-init (%d jobs) done in %.2f secs" , self .config .numJobs , time .time ()- startTime , extra = self .format )
192-
193- # add the initialized DHTClient back to the Validator
194- for val in self .validators :
195- val .addDHTClient (self .DHTNetwork .nodestore .get_node (val .ID ))
196- # the network should be ready to go :)
197-
198184 def initLogger (self ):
199185 """It initializes the logger."""
200186 logging .TRACE = 5
@@ -239,7 +225,7 @@ def runBlockBroadcasting(self):
239225 self .glob .checkRowsColumns (self .validators )
240226 for i in range (0 ,self .shape .numberNodes ):
241227 if i == self .proposerID :
242- self .validators [i ].initBlock ()
228+ self .block = self . validators [i ].initBlock () # Keep the OG block that we are broadcasting
243229 else :
244230 self .validators [i ].logIDs ()
245231 arrived , expected , ready , validatedall , validated = self .glob .checkStatus (self .validators )
@@ -253,7 +239,7 @@ def runBlockBroadcasting(self):
253239 oldMissingSamples = missingSamples
254240 self .logger .debug ("PHASE SEND %d" % steps , extra = self .format )
255241 for i in range (0 ,self .shape .numberNodes ):
256- self .validators [i ].send ()
242+ self .validators [i ].sendToNeigbors ()
257243 self .logger .debug ("PHASE RECEIVE %d" % steps , extra = self .format )
258244 for i in range (1 ,self .shape .numberNodes ):
259245 self .validators [i ].receiveRowsColumns ()
@@ -325,6 +311,89 @@ def runBlockBroadcasting(self):
325311 self .result .populate (self .shape , self .config , missingVector )
326312 return self .result
327313
328- def runBlockPublicationToDHT (self ):
329- """It runs the main DHT simulation, where the block proposer has to send the segments to the XOR close enough nodes."""
314+ def initDHTNetwork (self ):
315+ """ Compose the DHT network based on the pre-initialized Validators """
316+ # compose the DHT networking layer
317+ self .logger .info ("Initializing DHTNetwork... with %d nodes" % self .shape .numberNodes , extra = self .format )
318+ self .dhtNetwork = DHTNetwork (self .execID , self .shape .failureRate , [self .config .stepDuration ])
319+
320+ # initialize each of the routing tables
321+ startTime = time .time ()
322+ _ = self .dhtNetwork .init_with_random_peers (self .config .numJobs , self .shape .numberNodes ,
323+ self .shape .k , self .shape .alpha , self .shape .k , self .config .nilStepsToStopLookup )
324+ self .logger .info ("DHT fast-init (%d jobs) done in %.2f secs" , self .config .numJobs , time .time ()- startTime , extra = self .format )
325+
326+ # add the initialized DHTClient back to the Validator
327+ for val in self .validators :
328+ val .addDHTclient (self .dhtNetwork .nodestore .get_node (val .ID ))
329+ # the network should be ready to go :)
330+
331+ def runBlockPublicationToDHT (self , strategy ):
332+ """It runs the dht simulation to seed the DHT with blocks' info"""
333+
334+ if strategy == "builder-seeding-segments" :
335+ self .logger .info ("Seeding DHT with '%s' strategy" % strategy , extra = self .format )
336+ self .dhtBlockProposerSeedingDHTwithSegments ()
337+ else :
338+ self .logger .error ("unable to identify DHT seeding strategy '%s'" % strategy , extra = self .format )
339+
330340 return
341+
342+ def dhtBlockProposerSeedingDHTwithSegments (self ):
343+ """It runs the simulation where the block builder has to seed the DHT with all the block segments"""
344+ # check who is the block proposer
345+ blockProposer = self .dhtNetwork .nodestore .get_node (self .proposerID )
346+ self .logger .info ("Node %d will start providing the block to the DHT!" % self .proposerID , extra = self .format )
347+
348+ # make a dht lookup for each of the segments in the block
349+ # TODO: currently sequential, add randomness later
350+ # TODO: it is pretty hard to define the bandwidth usage of so many lookups,
351+ # a concurrency degree could help though (only XX lookups at the time)
352+ totalSegements = self .shape .blockSize * self .shape .blockSize
353+ segmentIDs = deque (maxlen = totalSegements )
354+ segmentHashes = deque (maxlen = totalSegements )
355+ segmentValues = deque (maxlen = totalSegements )
356+ closestNodes = deque (maxlen = totalSegements )
357+ lookupAggrDelays = deque (maxlen = totalSegements )
358+ lookupTotalAttempts = deque (maxlen = totalSegements )
359+ lookupConnectedNodes = deque (maxlen = totalSegements )
360+ lookupProcessExecTime = deque (maxlen = totalSegements )
361+
362+ lookupStartTime = time .time ()
363+ for rowID in range (self .shape .blockSize ):
364+ for columnID in range (self .shape .blockSize ):
365+ segmentID = self .block .getUniqueIDforSegment (rowID , columnID )
366+ segmentHash = self .block .getSegmentHash (rowID , columnID )
367+ segmentValue = self .block .getSegment (rowID , columnID )
368+ self .logger .debug (f"starting DHT lookup for segment { segmentID } with hash { segmentHash } " ,
369+ extra = self .format )
370+ nodes , _ , summary , aggrDelay = blockProposer .lookup_for_hash (segmentHash )
371+ self .logger .debug (
372+ f"finished DHT lookup for segment { segmentID } with hash { segmentHash } in { summary ['finishTime' ] - summary ['startTime' ]} secs" ,
373+ extra = self .format )
374+ segmentIDs .append (segmentID )
375+ segmentHashes .append (segmentHash )
376+ segmentValues .append (segmentValue )
377+ closestNodes .append (nodes )
378+ lookupAggrDelays .append (aggrDelay )
379+ lookupTotalAttempts .append (summary ["connectionAttempts" ])
380+ lookupConnectedNodes .append (summary ["successfulCons" ])
381+ lookupProcessExecTime .append (summary ["finishTime" ] - summary ["startTime" ])
382+ self .logger .info (f"lookup for the { totalSegements } segments done in { time .time () - lookupStartTime } secs" ,
383+ extra = self .format )
384+
385+ # make the provide operation of the segments to the closest nodes
386+ # TODO: at the moment, this only supports the standard Provide operation (mimicking IPFS' provide operation)
387+ # for each segment add the K closest nodes as neighbours
388+
389+ # start the dissemination of the segments based on avg latency windows,
390+ # track Tx and Rx stats
391+ # remember, opening a connection uses one latency step
392+
393+ # when there are no more segments to disseminate, get all the metrics
394+ # Avg successful provides vs failed ones on provide
395+ # avg time for the lookup
396+
397+ # TODO: do we want to check if the content would be retrievable?
398+
399+ return
0 commit comments