Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ TOPOLOGY_GEN_DIR = topology/gen
GOSSIPSUB_DIR = gossipsub
TOPOLOGY_FILE = topology.json
SIMCONFIG_FILE = simconfig.yaml
PLOT_DIR = updated-plots
PLOT_OUTPUT_FILE = output.png

# Check dependencies
check-deps:
Expand Down Expand Up @@ -49,7 +51,7 @@ build: check-deps
@echo "Build successful"

# Generate network graph and Shadow configuration
generate-config: generate-topology
generate-config: build generate-topology
@echo "Generating Shadow network configuration for $(NODE_COUNT) nodes with $(MESH_NODE_COUNT) mesh nodes, $(MESH_ATTESTER_COUNT) mesh attesters nodes, $(NON_MESH_ATTESTER_COUNT) non mesh attesters nodes..."
uv run network_graph.py $(NODE_COUNT) $(TOPOLOGY_FILE) $(SIMCONFIG_FILE)
@test -f shadow-gossipsub.yaml && test -f graph.gml || (echo "Config generation failed" && exit 1)
Expand All @@ -62,8 +64,8 @@ generate-config-only:
@echo "Configuration generated"

# Run the complete Shadow simulation
run-sim: build generate-config
@echo "Starting GossipSub Shadow simulation ($(NODE_COUNT) nodes, $(MESH_NODE_COUNT) mesh nodes, $(MESH_ATTESTER_COUNT) mesh attesters nodes, $(NON_MESH_ATTESTER_COUNT) non mesh attesters nodes, $(MSG_SIZE) byte message)..."
run-shadow: build
@echo "Starting GossipSub Shadow simulation"
@rm -rf shadow.data/
shadow --progress $(PROGRESS) shadow-gossipsub.yaml
@echo "GossipSub simulation completed"
Expand All @@ -76,8 +78,11 @@ test:
# Plot message propagation
plot:
@echo "Plotting message propagation..."
uv run plot_propagation.py $(NODE_COUNT) --topology-file $(TOPOLOGY_FILE) --peer-count $(PEER_COUNT) --non-mesh-node-peer-count $(NON_MESH_NODE_PEER_COUNT) --simconfig-file $(SIMCONFIG_FILE) -o some-plots/30slots_batch_5ms_node$(NODE_COUNT)_mesh_nodes$(MESH_NODE_COUNT)_mesh_attesters$(MESH_ATTESTER_COUNT)_non_mesh_attesters$(NON_MESH_ATTESTER_COUNT).png
@test -f some-plots/30slots_batch_5ms_node$(NODE_COUNT)_mesh_nodes$(MESH_NODE_COUNT)_mesh_attesters$(MESH_ATTESTER_COUNT)_non_mesh_attesters$(NON_MESH_ATTESTER_COUNT).png && echo "Plot generated: some-plots/30slots_batch_5ms_node$(NODE_COUNT)_mesh_nodes$(MESH_NODE_COUNT)_mesh_attesters$(MESH_ATTESTER_COUNT)_non_mesh_attesters$(NON_MESH_ATTESTER_COUNT).png" || echo "Plot generation failed"
@mkdir -p $(PLOT_DIR)
uv run plot_propagation.py $(NODE_COUNT) --topology-file $(TOPOLOGY_FILE) --peer-count $(PEER_COUNT) --non-mesh-node-peer-count $(NON_MESH_NODE_PEER_COUNT) --simconfig-file $(SIMCONFIG_FILE) -o $(PLOT_DIR)/$(PLOT_OUTPUT_FILE)
@test -f $(PLOT_DIR)/$(PLOT_OUTPUT_FILE) && echo "Plot generated: $(PLOT_DIR)/$(PLOT_OUTPUT_FILE)" || echo "Plot generation failed"

run-sim: run-shadow test plot

# Clean build artifacts and simulation results
clean:
Expand Down
104 changes: 78 additions & 26 deletions gossipsub/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,11 @@ const (

// BLSBatchVerifier simulates a BLS signature batch verifier queue
type BLSBatchVerifier struct {
queue chan *ValidationRequest
ctx context.Context
cancel context.CancelFunc
batchVerifierTime time.Duration
batchIntervalTime time.Duration
queue chan *ValidationRequest
ctx context.Context
cancel context.CancelFunc
batchIntervalTime time.Duration
prysmValidatorInfo *simconfig.PrysmValidatorInfo
}

// ValidationRequest represents a message waiting for batch verification
Expand All @@ -129,15 +129,15 @@ type ValidationRequest struct {
}

// NewBLSBatchVerifier creates a new batch verifier
func NewBLSBatchVerifier(batchVerifierTime time.Duration, batchIntervalTime time.Duration) *BLSBatchVerifier {
func NewBLSBatchVerifier(prysmValidatorInfo *simconfig.PrysmValidatorInfo, batchIntervalTime time.Duration) *BLSBatchVerifier {
ctx, cancel := context.WithCancel(context.Background())

bv := &BLSBatchVerifier{
queue: make(chan *ValidationRequest, 1000), // Buffer for high throughput
ctx: ctx,
cancel: cancel,
batchVerifierTime: batchVerifierTime,
batchIntervalTime: batchIntervalTime,
queue: make(chan *ValidationRequest, 1000), // Buffer for high throughput
ctx: ctx,
cancel: cancel,
batchIntervalTime: batchIntervalTime,
prysmValidatorInfo: prysmValidatorInfo,
}

// Start the batch processing goroutine
Expand Down Expand Up @@ -168,13 +168,37 @@ func (bv *BLSBatchVerifier) processBatches() {
}
}

// processBatch simulates batch verification taking 4.5ms
// processBatch simulates batch verification with percentile-based timing
func (bv *BLSBatchVerifier) processBatch(batch []*ValidationRequest) {
if len(batch) == 0 {
return
}

time.Sleep(bv.batchVerifierTime)
// Generate random number to determine which percentile batch verifier time to use
randNum := rand.Intn(101) // 0-100 inclusive
var batchVerifierTime time.Duration

if randNum >= 99 {
// Top 1%: values 99-100 → P99
batchVerifierTime = time.Duration(bv.prysmValidatorInfo.P99BatchVerifierTime) * time.Microsecond
} else if randNum >= 95 {
// 95-98: 4% of values → P95
batchVerifierTime = time.Duration(bv.prysmValidatorInfo.P95BatchVerifierTime) * time.Microsecond
} else if randNum >= 90 {
// 90-94: 5% of values → P90
batchVerifierTime = time.Duration(bv.prysmValidatorInfo.P90BatchVerifierTime) * time.Microsecond
} else if randNum >= 75 {
// 75-89: 15% of values → P75
batchVerifierTime = time.Duration(bv.prysmValidatorInfo.P75BatchVerifierTime) * time.Microsecond
} else if randNum >= 25 {
// 25-74: 50% of values → P50 (median range)
batchVerifierTime = time.Duration(bv.prysmValidatorInfo.P50BatchVerifierTime) * time.Microsecond
} else {
// 0-24: 25% of values → P25
batchVerifierTime = time.Duration(bv.prysmValidatorInfo.P25BatchVerifierTime) * time.Microsecond
}

time.Sleep(batchVerifierTime)

// Send results back to all requests in the batch
for _, req := range batch {
Expand Down Expand Up @@ -261,11 +285,11 @@ func main() {
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)

var (
nodeID = flag.Int("node-id", 0, "Node ID for this simulation instance")
nodeCount = flag.Int("node-count", 10, "Total number of nodes in simulation")
simConfigFile = flag.String("simconfig-file", "", "Path to simulation config file")
topologyFile = flag.String("topology-file", "", "Path to topology JSON file (required)")
logLevel = flag.String("log-level", "info", "Log level (debug, info, warn, error)")
nodeID = flag.Int("node-id", 0, "Node ID for this simulation instance")
nodeCount = flag.Int("node-count", 10, "Total number of nodes in simulation")
simConfigFile = flag.String("simconfig-file", "", "Path to simulation config file")
topologyFile = flag.String("topology-file", "", "Path to topology JSON file (required)")
logLevel = flag.String("log-level", "info", "Log level (debug, info, warn, error)")
)
flag.Parse()

Expand Down Expand Up @@ -388,24 +412,47 @@ func main() {
}

batchIntervalTimeDuration := time.Duration(simConfig.PrysmValidator.BatchInterval) * time.Millisecond
batchVerificationTimeDuration := time.Duration(simConfig.PrysmValidator.BatchVerifierTime) * time.Microsecond

// Create BLS batch verifier for Prysm clients
var batchVerifier *BLSBatchVerifier
if clientType == PrysmClient {
log.Printf("Creating BLS batch verifier for Prysm client with batch verification time %s and batch interval time %s", batchVerificationTimeDuration.String(), batchIntervalTimeDuration.String())
batchVerifier = NewBLSBatchVerifier(batchVerificationTimeDuration, batchIntervalTimeDuration)
log.Printf("Creating BLS batch verifier for Prysm client with percentile-based batch verification times and batch interval time %s", batchIntervalTimeDuration.String())
batchVerifier = NewBLSBatchVerifier(&simConfig.PrysmValidator, batchIntervalTimeDuration)
defer batchVerifier.Close()
} else {
log.Printf("Creating Lighthouse validator for Lighthouse client with validator time %s", time.Duration(simConfig.LighthouseValidator.ValidatorTime).String())
log.Printf("Creating Lighthouse validator for Lighthouse client with percentile-based validator times")
}
// Register topic validator with BLS batch verification
// Register topic validator with BLS batch verification. 47 byte topic
topicName := "gossipsub-simabcdefghijklmnopqrstuvwxyzabcdefgh"
err = ps.RegisterTopicValidator(topicName, func(ctx context.Context, pid peer.ID, msg *pubsub.Message) pubsub.ValidationResult {
if clientType == PrysmClient {
return batchVerifier.ValidateMessage(ctx, msg)
} else if clientType == LighthouseClient {
time.Sleep(time.Duration(simConfig.LighthouseValidator.ValidatorTime) * time.Microsecond)
// Generate random number to determine which percentile validation time to use
randNum := rand.Intn(101) // 0-100 inclusive
var validatorTime uint64

if randNum >= 99 {
// Top 1%: values 99-100 → P99
validatorTime = simConfig.LighthouseValidator.P99ValidatorTime
} else if randNum >= 95 {
// 95-98: 4% of values → P95
validatorTime = simConfig.LighthouseValidator.P95ValidatorTime
} else if randNum >= 90 {
// 90-94: 5% of values → P90
validatorTime = simConfig.LighthouseValidator.P90ValidatorTime
} else if randNum >= 75 {
// 75-89: 15% of values → P75
validatorTime = simConfig.LighthouseValidator.P75ValidatorTime
} else if randNum >= 25 {
// 25-74: 50% of values → P50 (median range)
validatorTime = simConfig.LighthouseValidator.P50ValidatorTime
} else {
// 0-24: 25% of values → P25
validatorTime = simConfig.LighthouseValidator.P25ValidatorTime
}

time.Sleep(time.Duration(validatorTime) * time.Microsecond)
return pubsub.ValidationAccept
}

Expand All @@ -414,7 +461,7 @@ func main() {
if err != nil {
log.Fatalf("Failed to register topic validator: %v", err)
}
log.Printf("Registered BLS batch verifier for %s (%s batching + %s verification)", topicName, batchIntervalTimeDuration.String(), batchVerificationTimeDuration.String())
log.Printf("Registered BLS batch verifier for %s (%s batching with percentile-based verification times)", topicName, batchIntervalTimeDuration.String())

// Join topic and conditionally subscribe
var topic *pubsub.Topic
Expand Down Expand Up @@ -502,7 +549,7 @@ func main() {
// Wait for network setup and peer discovery (important in Shadow)
// Synchronize all nodes to start at exactly 2000/01/01 00:02:00
targetTime := time.Date(2000, 1, 1, 0, 2, 0, 0, time.UTC)
waitDuration := targetTime.Sub(time.Now())
waitDuration := time.Until(targetTime)
log.Printf("Waiting for peer discovery and network stabilization until 2000/01/01 00:02:00 (%v)...", waitDuration)
if waitDuration > 0 {
time.Sleep(waitDuration)
Expand Down Expand Up @@ -581,6 +628,11 @@ func main() {
}
}

// Sleep for a random time between 10 and 20ms before publishing to account for publish delays.
// number is not scientifically chosen.
sleepDuration := time.Duration(10+rand.Intn(11)) * time.Millisecond
time.Sleep(sleepDuration)

err = topic.Publish(ctx, msg)
if err != nil {
log.Printf("Failed to publish message: %v", err)
Expand Down
Loading
Loading