From 8adc69efcb15f48ba8a35d37d1cf7250d2228d93 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Fri, 15 Sep 2023 10:46:40 +0200 Subject: [PATCH 01/98] back to sample assignment based on id --- simulator/config/dasprotocol.cfg | 47 ++++---- simulator/config/dasprotocoldht.cfg | 51 ++++----- .../kademlia/das/CustomDistributionDas.java | 103 +----------------- .../peersim/kademlia/das/DASProtocol.java | 5 +- .../kademlia/das/DASProtocolBuilder.java | 24 ++-- .../kademlia/das/DASProtocolValidator.java | 2 +- .../peersim/kademlia/das/SearchTable.java | 24 ++-- .../kademlia/das/TrafficGeneratorSample.java | 2 +- .../operations/RandomSamplingOperation.java | 7 +- .../das/operations/SamplingOperation.java | 5 +- 10 files changed, 88 insertions(+), 182 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 53125240..6abf328d 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 5000 +SIZE 20000 # Random seed K 5 @@ -14,16 +14,16 @@ MINDELAY 100 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*7 +SIM_TIME 1000*60*1 CHURN_RATE_HOUR 5 #Traffic generator is executed every TRAFFIC_STEP -TRAFFIC_STEP 300000 #10000000/SIZE +TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP -OBSERVER_STEP 100000 +OBSERVER_STEP 10000 #Turbulence module is executed every TURBULENCE_STEP enabling churning -TURBULENCE_STEP 3600000/(4*SIZE*CHURN_RATE_HOUR/100) #100000000/SIZE +TURBULENCE_STEP 120000000 #100000000/SIZE # add network config parameters to simulation @@ -101,27 +101,28 @@ control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 control.0traffic.block_dim_size 512 control.0traffic.kadprotocol 3kademlia + # turbulence non-validator -# control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas -# control.2turbolenceAdd.protocol 3kademlia -# control.2turbolenceAdd.protocoldas 4dasprotocol -# control.2turbolenceAdd.protocolevildas 7evildasprotocol -# control.2turbolenceAdd.transport 2unreltr -# control.2turbolenceAdd.step TURBULENCE_STEP -# control.2turbolenceAdd.p_idle 0.5 -# control.2turbolenceAdd.p_rem 0.25 -# control.2turbolenceAdd.p_add 0.25 +control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +control.2turbolenceAdd.protocol 3kademlia +control.2turbolenceAdd.protocoldas 4dasprotocol +control.2turbolenceAdd.protocolevildas 7evildasprotocol +control.2turbolenceAdd.transport 2unreltr +control.2turbolenceAdd.step TURBULENCE_STEP +control.2turbolenceAdd.p_idle 0.09 +control.2turbolenceAdd.p_rem 0.05 +control.2turbolenceAdd.p_add 0.05 # # turbulence validators -# control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator -# control.3turbolenceAdd.protocol 3kademlia -# control.3turbolenceAdd.protocoldas 4dasprotocol -# control.3turbolenceAdd.protocolevildas 7evildasprotocol -# control.3turbolenceAdd.transport 2unreltr -# control.3turbolenceAdd.step TURBULENCE_STEP -# control.3turbolenceAdd.p_idle 0.5 -# control.3turbolenceAdd.p_rem 0.25 -# control.3turbolenceAdd.p_add 0.25 +control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +control.3turbolenceAdd.protocol 3kademlia +control.3turbolenceAdd.protocoldas 4dasprotocol +control.3turbolenceAdd.protocolevildas 7evildasprotocol +control.3turbolenceAdd.transport 2unreltr +control.3turbolenceAdd.step TURBULENCE_STEP +control.3turbolenceAdd.p_idle 0.5 +control.3turbolenceAdd.p_rem 0.25 +control.3turbolenceAdd.p_add 0.25 # ::::: OBSERVER ::::: #The observer is executed every OBSERVER_STEP and will generate data traces diff --git a/simulator/config/dasprotocoldht.cfg b/simulator/config/dasprotocoldht.cfg index 9ed7afb7..9db480c8 100644 --- a/simulator/config/dasprotocoldht.cfg +++ b/simulator/config/dasprotocoldht.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 5000 +SIZE 20000 # Random seed K 5 @@ -14,16 +14,16 @@ MINDELAY 100 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*7 +SIM_TIME 1000*60*1 CHURN_RATE_HOUR 5 #Traffic generator is executed every TRAFFIC_STEP -TRAFFIC_STEP 300000 #10000000/SIZE +TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP -OBSERVER_STEP 100000 +OBSERVER_STEP 10000 #Turbulence module is executed every TURBULENCE_STEP enabling churning -TURBULENCE_STEP 3600000/(4*SIZE*CHURN_RATE_HOUR/100) #100000000/SIZE +TURBULENCE_STEP 120000000 #100000000/SIZE # add network config parameters to simulation @@ -102,27 +102,28 @@ control.0traffic.mapping_fn 1 control.0traffic.sample_copy_per_node 1 control.0traffic.block_dim_size 512 control.0traffic.kadprotocol 3kademlia + # turbulence non-validator -# control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas -# control.2turbolenceAdd.protocol 3kademlia -# control.2turbolenceAdd.protocoldas 4dasprotocol -# control.2turbolenceAdd.protocolevildas 7evildasprotocol -# control.2turbolenceAdd.transport 2unreltr -# control.2turbolenceAdd.step TURBULENCE_STEP -# control.2turbolenceAdd.p_idle 0.5 -# control.2turbolenceAdd.p_rem 0.25 -# control.2turbolenceAdd.p_add 0.25 - -# # turbulence validators -# control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator -# control.3turbolenceAdd.protocol 3kademlia -# control.3turbolenceAdd.protocoldas 4dasprotocol -# control.3turbolenceAdd.protocolevildas 7evildasprotocol -# control.3turbolenceAdd.transport 2unreltr -# control.3turbolenceAdd.step TURBULENCE_STEP -# control.3turbolenceAdd.p_idle 0.5 -# control.3turbolenceAdd.p_rem 0.25 -# control.3turbolenceAdd.p_add 0.25 +control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +control.2turbolenceAdd.protocol 3kademlia +control.2turbolenceAdd.protocoldas 4dasprotocol +control.2turbolenceAdd.protocolevildas 7evildasprotocol +control.2turbolenceAdd.transport 2unreltr +control.2turbolenceAdd.step TURBULENCE_STEP +control.2turbolenceAdd.p_idle 0.5 +control.2turbolenceAdd.p_rem 0.25 +control.2turbolenceAdd.p_add 0.25 + +# turbulence validators +control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +control.3turbolenceAdd.protocol 3kademlia +control.3turbolenceAdd.protocoldas 4dasprotocol +control.3turbolenceAdd.protocolevildas 7evildasprotocol +control.3turbolenceAdd.transport 2unreltr +control.3turbolenceAdd.step TURBULENCE_STEP +control.3turbolenceAdd.p_idle 0.5 +control.3turbolenceAdd.p_rem 0.25 +control.3turbolenceAdd.p_add 0.25 # ::::: OBSERVER ::::: #The observer is executed every OBSERVER_STEP and will generate data traces diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index 54f233da..f4d5b4f4 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -92,105 +92,6 @@ public boolean execute() { KademliaProtocol kadProt = null; DASProtocol dasProt = null; - /** Generate honest and evil nodes * */ - /*if (i == 0) { - kadProt = ((KademliaProtocol) (Network.get(i).getProtocol(protocolKadID))); - dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolDasBuilderID))); - System.out.println("Init builder " + i); - kadProt.setProtocolID(protocolKadID); - dasProt.setDASProtocolID(protocolDasBuilderID); - dasProt.setKademliaProtocol(kadProt); - kadProt.setEventsCallback(dasProt); - kadProt.setNode(node); - - builderAddress = dasProt.getKademliaProtocol().getKademliaNode().getId(); - - generalNode.setProtocol(protocolDasValidatorID, null); - generalNode.setProtocol(protocolDasNonValidatorID, null); - generalNode.setProtocol(protocolDasBuilderID, dasProt); - generalNode.setProtocol(protocolEvilDasID, null); - } else if ((i > 0) && (i < (numEvilValidatorNodes + 1))) { - System.out.println("Init evil validator " + i); - - kadProt = ((KademliaProtocol) (Network.get(i).getProtocol(protocolEvilKadID))); - dasProt = ((EvilDASProtocol) (Network.get(i).getProtocol(protocolEvilDasID))); - kadProt.setProtocolID(protocolEvilKadID); - dasProt.setDASProtocolID(protocolEvilDasID); - dasProt.setKademliaProtocol(kadProt); - kadProt.setEventsCallback(dasProt); - kadProt.setNode(node); - node.setEvil(true); - dasProt.setBuilderAddress(builderAddress); - - generalNode.setProtocol(protocolDasValidatorID, null); - generalNode.setProtocol(protocolDasNonValidatorID, null); - generalNode.setProtocol(protocolDasBuilderID, null); - generalNode.setProtocol(protocolEvilDasID, dasProt); - - validatorsIds.add(dasProt.getKademliaId()); - validators.add(dasProt); - } else if (i >= (numEvilValidatorNodes + 1) - && i < (numEvilValidatorNodes + numEvilNonValidatorNodes + 1)) { - System.out.println("Init evil non validator " + i); - kadProt = ((KademliaProtocol) (Network.get(i).getProtocol(protocolEvilKadID))); - dasProt = ((EvilDASProtocol) (Network.get(i).getProtocol(protocolEvilDasID))); - kadProt.setProtocolID(protocolEvilKadID); - dasProt.setDASProtocolID(protocolEvilDasID); - dasProt.setKademliaProtocol(kadProt); - kadProt.setEventsCallback(dasProt); - kadProt.setNode(node); - node.setEvil(true); - dasProt.setBuilderAddress(builderAddress); - - generalNode.setProtocol(protocolDasValidatorID, null); - generalNode.setProtocol(protocolDasNonValidatorID, null); - generalNode.setProtocol(protocolDasBuilderID, null); - generalNode.setProtocol(protocolEvilDasID, dasProt); - - } else if (i >= (numEvilValidatorNodes + numEvilNonValidatorNodes + 1) - && i - < (numEvilValidatorNodes - + numEvilNonValidatorNodes - + (numValidators - numEvilValidatorNodes) - + 1)) { - assert (!node.isEvil()); - System.out.println("Init validator " + i); - - kadProt = ((KademliaProtocol) (Network.get(i).getProtocol(protocolKadID))); - dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolDasValidatorID))); - kadProt.setProtocolID(protocolKadID); - dasProt.setDASProtocolID(protocolDasValidatorID); - dasProt.setBuilderAddress(builderAddress); - dasProt.setKademliaProtocol(kadProt); - kadProt.setEventsCallback(dasProt); - kadProt.setNode(node); - - validatorsIds.add(kadProt.getKademliaNode().getId()); - validators.add(dasProt); - - generalNode.setProtocol(protocolDasValidatorID, dasProt); - generalNode.setProtocol(protocolDasNonValidatorID, null); - generalNode.setProtocol(protocolDasBuilderID, null); - generalNode.setProtocol(protocolEvilDasID, null); - - } else { - assert (!node.isEvil()); - System.out.println("Init non-validator " + i); - kadProt = ((KademliaProtocol) (Network.get(i).getProtocol(protocolKadID))); - dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolDasNonValidatorID))); - kadProt.setProtocolID(protocolKadID); - dasProt.setDASProtocolID(protocolDasNonValidatorID); - dasProt.setBuilderAddress(builderAddress); - dasProt.setKademliaProtocol(kadProt); - kadProt.setEventsCallback(dasProt); - kadProt.setNode(node); - - generalNode.setProtocol(protocolDasValidatorID, null); - generalNode.setProtocol(protocolDasNonValidatorID, dasProt); - generalNode.setProtocol(protocolDasBuilderID, null); - generalNode.setProtocol(protocolEvilDasID, null); - }*/ - kadProt = ((KademliaProtocol) (Network.get(i).getProtocol(protocolKadID))); kadProt.setProtocolID(protocolKadID); kadProt.setNode(node); @@ -246,8 +147,8 @@ public boolean execute() { // for (DASProtocol validator : validators) { for (int i = 0; i < Network.size(); i++) { Node generalNode = Network.get(i); - if (i == 0) generalNode.getDASProtocol().setNonValidators(nonValidatorsIds); - generalNode.getDASProtocol().addKnownValidator(validatorsIds.toArray(new BigInteger[0])); + if (i == 0) // generalNode.getDASProtocol().setNonValidators(nonValidatorsIds); + generalNode.getDASProtocol().addKnownValidator(validatorsIds.toArray(new BigInteger[0])); } KademliaCommonConfigDas.networkSize = Network.size(); KademliaCommonConfigDas.validatorsSize = numValidators; diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 3edea34c..a73f38ba 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -549,7 +549,7 @@ protected void startRandomSampling() { currentBlock, searchTable, this.isValidator, - validatorsList.length, + KademliaCommonConfigDas.validatorsSize, this); op.elaborateResponse(kv.getAll().toArray(new Sample[0])); samplingOp.put(op.getId(), op); @@ -699,7 +699,8 @@ public void missing(BigInteger sample, Operation op) { searchTable.getValidatorNodesbySample( sample, currentBlock.computeRegionRadius( - KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, validatorsList.length)); + KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, + KademliaCommonConfigDas.validatorsSize)); for (BigInteger id : ids) { logger.warning("Found id " + id + " for sample " + sample); } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index a278b464..8390dd8f 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -35,13 +35,11 @@ protected void handleSeedSample(Message m, int myPid) { @Override protected void handleInitNewBlock(Message m, int myPid) { super.handleInitNewBlock(m, myPid); - logger.warning( - "Builder new block:" - + currentBlock.getBlockId() - + " " - + validatorsList.length - + " " - + nonValidatorsIndexed.size()); + logger.warning("Builder new block:" + currentBlock.getBlockId()); + /*+ " " + + validatorsList.length + + " " + + nonValidatorsIndexed.size());*/ int samplesWithinRegion = 0; // samples that are within at least one node's region int samplesValidators = 0; @@ -50,14 +48,18 @@ protected void handleInitNewBlock(Message m, int myPid) { while (currentBlock.hasNext()) { Sample s = currentBlock.next(); boolean inRegion = false; - + BigInteger radiusValidator = + currentBlock.computeRegionRadius( + KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, validatorsList.length); BigInteger radiusNonValidator = currentBlock.computeRegionRadius(KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); - List idsValidatorsRows = SearchTable.getNodesBySample(s.getIdByRow()); + // List idsValidatorsRows = SearchTable.getNodesBySample(s.getIdByRow()); + List idsValidatorsRows = + searchTable.getValidatorNodesbySample(s.getIdByRow(), radiusValidator); List idsValidatorsColumns = - // searchTable.getValidatorNodesbySample(s.getIdByColumn(), radiusValidator); - SearchTable.getNodesBySample(s.getIdByColumn()); + searchTable.getValidatorNodesbySample(s.getIdByColumn(), radiusValidator); + // SearchTable.getNodesBySample(s.getIdByColumn()); List idsNonValidatorsRows = getNonValidatorNodesbySample(s.getIdByRow(), radiusNonValidator); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index 1d1c16d2..61a91b6c 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -97,7 +97,7 @@ private void createValidatorSamplingOperation(int row, int column, long timestam row, column, this.isValidator, - validatorsList.length, + KademliaCommonConfigDas.validatorsSize, this); samplingOp.put(op.getId(), op); logger.warning("Sampling operation started validator " + op.getId()); diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index 7c1c4493..723fee92 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -3,10 +3,8 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Random; import java.util.Set; import java.util.TreeSet; // import peersim.kademlia.KademliaCommonConfig; @@ -25,7 +23,7 @@ public class SearchTable { private HashSet blackList; // , samplesIndexed; - private static HashMap> sampleMap = new HashMap<>(); + // private static HashMap> sampleMap = new HashMap<>(); private BigInteger builderAddress; public SearchTable(/*Block currentblock , BigInteger id*/ ) { @@ -169,7 +167,7 @@ public List getNodesbySample(Set samples, BigInteger rad return result; } - public static void createSampleMap(Block currentBlock) { + /*public static void createSampleMap(Block currentBlock) { int validatorParcelSize = (currentBlock.getSize() @@ -193,8 +191,7 @@ public static void createSampleMap(Block currentBlock) { // samples.put(node, sampleList); for (BigInteger sample : sampleList) { if (sampleMap.containsKey(sample)) { - /*System.out.println( - "assign samples to node " + node + " " + sampleMap.get(sample).size());*/ + sampleMap.get(sample).add(node); } else { List nList = new ArrayList<>(); @@ -232,8 +229,7 @@ public static void createSampleMap(Block currentBlock) { for (BigInteger sample : sampleList) { // System.out.println("assign samples to node " + node + " " + nodeMap.size()); if (sampleMap.containsKey(sample)) { - /*System.out.println( - "assign samples to node " + node + " " + sampleMap.get(sample).size());*/ + sampleMap.get(sample).add(node); } else { List nList = new ArrayList<>(); @@ -270,16 +266,16 @@ public static void createSampleMap(Block currentBlock) { + " " + currentBlock.getSize()); - /*for (List l : sampleMap.values()) { - System.out.println("samples " + l.size()); - }*/ - } + //for (List l : sampleMap.values()) { + // System.out.println("samples " + l.size()); + //} + }*/ - public static List getNodesBySample(BigInteger s) { + /*public static List getNodesBySample(BigInteger s) { return sampleMap.get(s); } - /*public BigInteger[] findKClosestValidators(BigInteger sampleId) { + public BigInteger[] findKClosestValidators(BigInteger sampleId) { return routingTable.getNeighbours(sampleId, sampleId); }*/ diff --git a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java index 179839e0..8075db3a 100755 --- a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java @@ -130,7 +130,7 @@ public boolean execute() { second = true; } else /*if (second)*/ { - SearchTable.createSampleMap(b); + // SearchTable.createSampleMap(b); for (int i = 0; i < Network.size(); i++) { Node n = Network.get(i); // b.initIterator(); diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index 9672e7fe..96dc8b16 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -108,9 +108,12 @@ protected void createNodes() { if (!samples.get(sample).isDownloaded()) { List validatorsBySampleRow = - SearchTable.getNodesBySample(samples.get(sample).getId()); + // SearchTable.getNodesBySample(samples.get(sample).getId()); + searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusValidator); List validatorsBySampleColumn = - SearchTable.getNodesBySample(samples.get(sample).getIdByColumn()); + // SearchTable.getNodesBySample(samples.get(sample).getIdByColumn()); + searchTable.getValidatorNodesbySample( + samples.get(sample).getIdByColumn(), radiusValidator); List validatorsBySample = new ArrayList<>(); diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index 354047bc..531f3307 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -107,7 +107,9 @@ protected void createNodes() { for (BigInteger sample : samples.keySet()) { if (!samples.get(sample).isDownloaded()) { - List validatorsBySample = SearchTable.getNodesBySample(sample); + // List validatorsBySample = SearchTable.getNodesBySample(sample); + List validatorsBySample = + searchTable.getValidatorNodesbySample(sample, radiusValidator); List nonValidatorsBySample = searchTable.getNonValidatorNodesbySample(sample, radiusNonValidator); @@ -144,7 +146,6 @@ public BigInteger[] doSampling() { aggressiveness += KademliaCommonConfigDas.aggressiveness_step; for (Node n : nodes.values()) n.setAgressiveness(aggressiveness); - List result = new ArrayList<>(); for (Node n : nodes.values()) { /*System.out.println( From 72b37c573bad1bec11e4227dd5a350c507646669 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Fri, 15 Sep 2023 11:00:33 +0200 Subject: [PATCH 02/98] dht fix --- .../kademlia/das/CustomDistributionDas.java | 2 +- .../das/DASDHTProtocolNonValidator.java | 2 +- .../kademlia/das/DASDHTProtocolValidator.java | 4 +-- .../kademlia/das/TrafficGeneratorSample.java | 29 +++++++++---------- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index f4d5b4f4..83651505 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -148,7 +148,7 @@ public boolean execute() { for (int i = 0; i < Network.size(); i++) { Node generalNode = Network.get(i); if (i == 0) // generalNode.getDASProtocol().setNonValidators(nonValidatorsIds); - generalNode.getDASProtocol().addKnownValidator(validatorsIds.toArray(new BigInteger[0])); + generalNode.getDASProtocol().addKnownValidator(validatorsIds.toArray(new BigInteger[0])); } KademliaCommonConfigDas.networkSize = Network.size(); KademliaCommonConfigDas.validatorsSize = numValidators; diff --git a/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolNonValidator.java index 28df26a0..d35155cb 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolNonValidator.java @@ -119,7 +119,7 @@ protected void startRandomSampling() { currentBlock, searchTable, this.isValidator, - validatorsList.length, + KademliaCommonConfigDas.validatorsSize, this); op.elaborateResponse(this.kadProtocol.kv.getAll().toArray(new Sample[0])); samplingOp.put(op.getId(), op); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolValidator.java index dd772f2d..fd129490 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolValidator.java @@ -73,7 +73,7 @@ private void createValidatorSamplingOperation(int row, int column, long timestam row, column, this.isValidator, - validatorsList.length, + KademliaCommonConfigDas.validatorsSize, this); op.elaborateResponse(this.kadProtocol.kv.getAll().toArray(new Sample[0])); @@ -158,7 +158,7 @@ protected void startRandomSampling() { currentBlock, searchTable, this.isValidator, - validatorsList.length, + KademliaCommonConfigDas.validatorsSize, this); op.elaborateResponse(this.kadProtocol.kv.getAll().toArray(new Sample[0])); samplingOp.put(op.getId(), op); diff --git a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java index 8075db3a..6825dc57 100755 --- a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java @@ -110,7 +110,7 @@ private Message generateFindNodeMessage(BigInteger id) { public boolean execute() { Block b = new Block(KademliaCommonConfigDas.BLOCK_DIM_SIZE, ID_GENERATOR); - if (first) { + /*if (first) { for (int i = 0; i < Network.size(); i++) { Node start = Network.get(i); if (start.isUp()) { @@ -128,21 +128,20 @@ public boolean execute() { } first = false; second = true; - } else /*if (second)*/ { - - // SearchTable.createSampleMap(b); - for (int i = 0; i < Network.size(); i++) { - Node n = Network.get(i); - // b.initIterator(); - // we add 1 ms delay to be sure the builder starts before validators. - if (n.getDASProtocol().isBuilder()) - EDSimulator.add(0, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); - else - EDSimulator.add(1, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); - } - ID_GENERATOR++; - second = false; + } else if (second) { */ + + // SearchTable.createSampleMap(b); + for (int i = 0; i < Network.size(); i++) { + Node n = Network.get(i); + // b.initIterator(); + // we add 1 ms delay to be sure the builder starts before validators. + if (n.getDASProtocol().isBuilder()) + EDSimulator.add(0, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); + else EDSimulator.add(1, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); } + ID_GENERATOR++; + second = false; + // } return false; } From c57f36c5a009dd33ec8eae7730ebe07eff7a9e58 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Fri, 15 Sep 2023 12:27:55 +0200 Subject: [PATCH 03/98] disable initial elaborate response dht --- .../das/DASDHTProtocolNonValidator.java | 2 +- .../kademlia/das/DASDHTProtocolValidator.java | 2 +- .../kademlia/das/TrafficGeneratorSample.java | 29 ++++++++++--------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolNonValidator.java index d35155cb..b5c659b3 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolNonValidator.java @@ -121,7 +121,7 @@ protected void startRandomSampling() { this.isValidator, KademliaCommonConfigDas.validatorsSize, this); - op.elaborateResponse(this.kadProtocol.kv.getAll().toArray(new Sample[0])); + // op.elaborateResponse(this.kadProtocol.kv.getAll().toArray(new Sample[0])); samplingOp.put(op.getId(), op); logger.warning("Sampling operation started random"); doSampling(op); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolValidator.java index fd129490..441dea22 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolValidator.java @@ -76,7 +76,7 @@ private void createValidatorSamplingOperation(int row, int column, long timestam KademliaCommonConfigDas.validatorsSize, this); - op.elaborateResponse(this.kadProtocol.kv.getAll().toArray(new Sample[0])); + // op.elaborateResponse(this.kadProtocol.kv.getAll().toArray(new Sample[0])); samplingOp.put(op.getId(), op); logger.warning("Sampling operation started validator " + op.getId() + " " + row + " " + column); diff --git a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java index 6825dc57..8075db3a 100755 --- a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java @@ -110,7 +110,7 @@ private Message generateFindNodeMessage(BigInteger id) { public boolean execute() { Block b = new Block(KademliaCommonConfigDas.BLOCK_DIM_SIZE, ID_GENERATOR); - /*if (first) { + if (first) { for (int i = 0; i < Network.size(); i++) { Node start = Network.get(i); if (start.isUp()) { @@ -128,20 +128,21 @@ public boolean execute() { } first = false; second = true; - } else if (second) { */ - - // SearchTable.createSampleMap(b); - for (int i = 0; i < Network.size(); i++) { - Node n = Network.get(i); - // b.initIterator(); - // we add 1 ms delay to be sure the builder starts before validators. - if (n.getDASProtocol().isBuilder()) - EDSimulator.add(0, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); - else EDSimulator.add(1, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); + } else /*if (second)*/ { + + // SearchTable.createSampleMap(b); + for (int i = 0; i < Network.size(); i++) { + Node n = Network.get(i); + // b.initIterator(); + // we add 1 ms delay to be sure the builder starts before validators. + if (n.getDASProtocol().isBuilder()) + EDSimulator.add(0, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); + else + EDSimulator.add(1, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); + } + ID_GENERATOR++; + second = false; } - ID_GENERATOR++; - second = false; - // } return false; } From 9ca67c99c933523754ebb887431816f79592cf0e Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Tue, 3 Oct 2023 13:33:38 +0200 Subject: [PATCH 04/98] fix starting multiple builder issue --- simulator/config/dasprotocol.cfg | 4 ++-- .../kademlia/das/CustomDistributionDas.java | 8 +++++--- .../java/peersim/kademlia/das/DASProtocol.java | 2 ++ .../peersim/kademlia/das/DASProtocolBuilder.java | 15 ++++++++++++++- .../kademlia/das/DASProtocolValidator.java | 2 -- .../kademlia/das/TrafficGeneratorSample.java | 13 +++++++++++-- .../das/operations/RandomSamplingOperation.java | 16 +++++++++++++--- 7 files changed, 47 insertions(+), 13 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 6abf328d..2b4a37bb 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 20000 +SIZE 50000 # Random seed K 5 @@ -109,7 +109,7 @@ control.2turbolenceAdd.protocoldas 4dasprotocol control.2turbolenceAdd.protocolevildas 7evildasprotocol control.2turbolenceAdd.transport 2unreltr control.2turbolenceAdd.step TURBULENCE_STEP -control.2turbolenceAdd.p_idle 0.09 +control.2turbolenceAdd.p_idle 0.9 control.2turbolenceAdd.p_rem 0.05 control.2turbolenceAdd.p_add 0.05 diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index 83651505..6eb1404a 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -97,8 +97,9 @@ public boolean execute() { kadProt.setNode(node); if (i == 0) { - dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolDasBuilderID))); + dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolDasBuilderID))); + builderAddress = node.getId(); } else if ((i > 0) && (i < (numEvilValidatorNodes + 1))) { dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolEvilDasID))); } else if (i >= (numEvilValidatorNodes + numEvilNonValidatorNodes + 1) @@ -119,7 +120,6 @@ public boolean execute() { dasProt.setKademliaProtocol(kadProt); kadProt.setEventsCallback(dasProt); - if (i == 0) builderAddress = dasProt.getKademliaProtocol().getKademliaNode().getId(); dasProt.setBuilderAddress(builderAddress); /*System.out.println( @@ -132,6 +132,7 @@ public boolean execute() { + " " + protocolKadID);*/ + if (dasProt instanceof DASProtocolBuilder) System.out.println("DASProtocol Builder " + i); generalNode.setProtocol(protocolKadID, kadProt); generalNode.setKademliaProtocol(kadProt); generalNode.setDASProtocol(dasProt); @@ -147,7 +148,8 @@ public boolean execute() { // for (DASProtocol validator : validators) { for (int i = 0; i < Network.size(); i++) { Node generalNode = Network.get(i); - if (i == 0) // generalNode.getDASProtocol().setNonValidators(nonValidatorsIds); + if (i == 0) // + generalNode.getDASProtocol().setNonValidators(nonValidatorsIds); generalNode.getDASProtocol().addKnownValidator(validatorsIds.toArray(new BigInteger[0])); } KademliaCommonConfigDas.networkSize = Network.size(); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index a73f38ba..ede80a04 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -133,6 +133,7 @@ public DASProtocol(String prefix) { searchTable = new SearchTable(); nonValidatorsIndexed = new TreeSet<>(); + isBuilder = false; } /** @@ -531,6 +532,7 @@ public void setNonValidators(List nonValidators) { for (BigInteger id : nonValidators) { nonValidatorsIndexed.add(id); } + searchTable.addNodes(nonValidators.toArray(new BigInteger[0])); } /** * Starts the random sampling operation diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index 8390dd8f..0df67141 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -79,7 +79,13 @@ protected void handleInitNewBlock(Message m, int myPid) { for (BigInteger id : idsValidators) { - logger.warning("Sending sample " + s.getIdByRow() + " " + s.getIdByColumn() + " to " + id); + logger.warning( + "Sending sample to validator " + + s.getIdByRow() + + " " + + s.getIdByColumn() + + " to " + + id); Node n = Util.nodeIdtoNode(id, kademliaId); DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); if (dasProt.isBuilder()) continue; @@ -99,6 +105,13 @@ protected void handleInitNewBlock(Message m, int myPid) { } for (BigInteger id : idsNonValidators) { + logger.warning( + "Sending sample to non-validator " + + s.getIdByRow() + + " " + + s.getIdByColumn() + + " to " + + id); Node n = Util.nodeIdtoNode(id, kademliaId); DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); if (dasProt.isBuilder()) continue; diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index 61a91b6c..fcc6a5e9 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -52,9 +52,7 @@ protected void handleInitGetSample(Message m, int myPid) { @Override protected void handleInitNewBlock(Message m, int myPid) { super.handleInitNewBlock(m, myPid); - logger.warning("Starting validator (rows and columns) sampling"); startRowsandColumnsSampling(); - logger.warning("Starting random sampling"); startRandomSampling(); } diff --git a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java index 8075db3a..64124827 100755 --- a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java @@ -135,9 +135,18 @@ public boolean execute() { Node n = Network.get(i); // b.initIterator(); // we add 1 ms delay to be sure the builder starts before validators. - if (n.getDASProtocol().isBuilder()) + if (n.getDASProtocol() instanceof DASProtocolBuilder + && n.getDASProtocol() + .getBuilderAddress() + .equals(n.getKademliaProtocol().getKademliaNode().getId())) { + System.out.println( + CommonState.getTime() + + " New block Builder " + + n.getKademliaProtocol().getKademliaNode().getId() + + " " + + i); EDSimulator.add(0, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); - else + } else if (!(n.getDASProtocol() instanceof DASProtocolBuilder)) EDSimulator.add(1, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); } ID_GENERATOR++; diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index 96dc8b16..549beaa9 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -45,7 +45,7 @@ public RandomSamplingOperation( for (Sample rs : randomSamples) { FetchingSample s = new FetchingSample(rs); samples.put(rs.getIdByRow(), s); - // samples.put(rs.getIdByColumn(), s); + samples.put(rs.getIdByColumn(), s); } createNodes(); } @@ -89,7 +89,7 @@ public void elaborateResponse(Sample[] sam, BigInteger node) { for (Sample s : sam) { - if (samples.containsKey(s.getId()) || samples.containsKey(s.getIdByColumn())) { + if (samples.containsKey(s.getId())) { FetchingSample fs = samples.get(s.getId()); if (!fs.isDownloaded()) { samplesCount++; @@ -97,6 +97,14 @@ public void elaborateResponse(Sample[] sam, BigInteger node) { fs.removeFetchingNode(nodes.get(node)); } } + /*if (samples.containsKey(s.getIdByColumn())) { + FetchingSample fs = samples.get(s.getIdByColumn()); + if (!fs.isDownloaded()) { + samplesCount++; + fs.setDownloaded(); + fs.removeFetchingNode(nodes.get(node)); + } + }*/ } nodes.remove(node); @@ -154,7 +162,9 @@ protected void createNodes() { found = true; } - if (!found && callback != null) callback.missing(sample, this); + if (!found && callback != null) { + callback.missing(sample, this); + } } } } From 181e5481ee23a26ab60f38a14c1e10ab76e4d63f Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Tue, 3 Oct 2023 16:07:07 +0200 Subject: [PATCH 05/98] fix sampling to node mapping --- simulator/config/dasprotocol.cfg | 4 ++-- .../kademlia/das/CustomDistributionDas.java | 6 +++-- .../kademlia/das/DASDHTProtocolValidator.java | 2 +- .../peersim/kademlia/das/DASProtocol.java | 7 +++++- .../kademlia/das/DASProtocolBuilder.java | 19 ++------------- .../kademlia/das/DASProtocolNonValidator.java | 1 - .../kademlia/das/DASProtocolValidator.java | 2 +- .../peersim/kademlia/das/EvilDASProtocol.java | 2 +- .../kademlia/das/TrafficGeneratorSample.java | 3 +-- .../operations/RandomSamplingOperation.java | 23 ++++++++----------- 10 files changed, 27 insertions(+), 42 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 2b4a37bb..4e2a66e5 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 50000 +SIZE 20000 # Random seed K 5 @@ -98,7 +98,7 @@ init.2statebuilder.transport 2unreltr control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 -control.0traffic.sample_copy_per_node 2 +control.0traffic.sample_copy_per_node 3 control.0traffic.block_dim_size 512 control.0traffic.kadprotocol 3kademlia diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index 6eb1404a..11cf1c30 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -144,11 +144,13 @@ public boolean execute() { generalNode.setProtocol(protocolDasNonValidatorID, null); } - // System.out.println("Validators " + validatorsIds.size()); + System.out.println("Validators " + validatorsIds.size()); + System.out.println("Non-Validators " + nonValidatorsIds.size()); + // for (DASProtocol validator : validators) { for (int i = 0; i < Network.size(); i++) { Node generalNode = Network.get(i); - if (i == 0) // + // if (i == 0) // generalNode.getDASProtocol().setNonValidators(nonValidatorsIds); generalNode.getDASProtocol().addKnownValidator(validatorsIds.toArray(new BigInteger[0])); } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolValidator.java index 441dea22..8cffb592 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolValidator.java @@ -23,7 +23,7 @@ public DASDHTProtocolValidator(String prefix) { @Override protected void handleSeedSample(Message m, int myPid) { - logger.warning("seed sample receveived"); + logger.warning("seed sample received"); if (m.body == null) return; } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index ede80a04..4b6f70bd 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -607,7 +607,12 @@ protected boolean doSampling(SamplingOperation sop) { if (sop instanceof ValidatorSamplingOperation) logger.warning("Sampling operation finished validator failed " + sop.getId()); - else logger.warning("Sampling operation finished random failed " + sop.getId()); + else { + logger.warning("Sampling operation finished random failed " + sop.getId()); + for (BigInteger id : sop.getSamples()) { + logger.warning("Missing sample " + id + " for op " + sop.getId()); + } + } samplingOp.remove(sop.getId()); KademliaObserver.reportOperation(sop); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index 0df67141..c2ff46dc 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -2,7 +2,6 @@ import java.math.BigInteger; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import peersim.core.Node; import peersim.edsim.EDSimulator; @@ -62,9 +61,9 @@ protected void handleInitNewBlock(Message m, int myPid) { // SearchTable.getNodesBySample(s.getIdByColumn()); List idsNonValidatorsRows = - getNonValidatorNodesbySample(s.getIdByRow(), radiusNonValidator); + searchTable.getNonValidatorNodesbySample(s.getIdByRow(), radiusNonValidator); List idsNonValidatorsColumns = - getNonValidatorNodesbySample(s.getIdByColumn(), radiusNonValidator); + searchTable.getNonValidatorNodesbySample(s.getIdByColumn(), radiusNonValidator); List idsValidators = new ArrayList<>(); idsValidators.addAll(idsValidatorsRows); @@ -166,18 +165,4 @@ public Object clone() { DASProtocolBuilder dolly = new DASProtocolBuilder(DASProtocolBuilder.prefix); return dolly; } - - private List getNonValidatorNodesbySample(BigInteger sampleId, BigInteger radius) { - - BigInteger bottom = sampleId.subtract(radius); - if (radius.compareTo(sampleId) == 1) bottom = BigInteger.ZERO; - - BigInteger top = sampleId.add(radius); - - Collection subSet = nonValidatorsIndexed.subSet(bottom, true, top, true); - return new ArrayList(subSet); - - // return sampleMap.get(sampleId); - - } } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java index 614e1336..731f826e 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java @@ -65,7 +65,6 @@ protected void handleInitGetSample(Message m, int myPid) { protected void handleInitNewBlock(Message m, int myPid) { logger.warning("Init block non-validator node - start sampling " + this); super.handleInitNewBlock(m, myPid); - logger.warning("Starting random sampling"); startRandomSampling(); } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index fcc6a5e9..1860ccb4 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -18,7 +18,7 @@ public DASProtocolValidator(String prefix) { @Override protected void handleSeedSample(Message m, int myPid) { - logger.warning("seed sample receveived"); + logger.warning("seed sample received"); if (m.body == null) return; Sample[] samples = (Sample[]) m.body; diff --git a/simulator/src/main/java/peersim/kademlia/das/EvilDASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/EvilDASProtocol.java index 978292bb..745f343a 100644 --- a/simulator/src/main/java/peersim/kademlia/das/EvilDASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/EvilDASProtocol.java @@ -13,7 +13,7 @@ public EvilDASProtocol(String prefix) { @Override protected void handleSeedSample(Message m, int myPid) { - logger.warning("seed sample receveived - do nothing " + this); + logger.warning("seed sample received - do nothing " + this); } @Override diff --git a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java index 64124827..5ca01105 100755 --- a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java @@ -116,8 +116,7 @@ public boolean execute() { if (start.isUp()) { for (int j = 0; j < 3; j++) { // send message - EDSimulator.add( - CommonState.r.nextInt(300000), generateFindNodeMessage(), start, kadpid); + EDSimulator.add(CommonState.r.nextInt(12000), generateFindNodeMessage(), start, kadpid); } EDSimulator.add( 0, diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index 549beaa9..e8468d16 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -45,7 +45,7 @@ public RandomSamplingOperation( for (Sample rs : randomSamples) { FetchingSample s = new FetchingSample(rs); samples.put(rs.getIdByRow(), s); - samples.put(rs.getIdByColumn(), s); + // samples.put(rs.getIdByColumn(), s); } createNodes(); } @@ -89,7 +89,7 @@ public void elaborateResponse(Sample[] sam, BigInteger node) { for (Sample s : sam) { - if (samples.containsKey(s.getId())) { + if (samples.containsKey(s.getId()) || samples.containsKey(s.getIdByColumn())) { FetchingSample fs = samples.get(s.getId()); if (!fs.isDownloaded()) { samplesCount++; @@ -115,18 +115,13 @@ protected void createNodes() { for (BigInteger sample : samples.keySet()) { if (!samples.get(sample).isDownloaded()) { - List validatorsBySampleRow = - // SearchTable.getNodesBySample(samples.get(sample).getId()); - searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusValidator); - List validatorsBySampleColumn = - // SearchTable.getNodesBySample(samples.get(sample).getIdByColumn()); - searchTable.getValidatorNodesbySample( - samples.get(sample).getIdByColumn(), radiusValidator); - List validatorsBySample = new ArrayList<>(); - validatorsBySample.addAll(validatorsBySampleRow); - validatorsBySample.addAll(validatorsBySampleColumn); + validatorsBySample.addAll( + searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusValidator)); + validatorsBySample.addAll( + searchTable.getValidatorNodesbySample( + samples.get(sample).getIdByColumn(), radiusValidator)); List nonValidatorsBySample = new ArrayList<>(); nonValidatorsBySample.addAll( @@ -138,8 +133,8 @@ protected void createNodes() { boolean found = false; - if (validatorsBySampleRow != null && validatorsBySampleRow.size() > 0) { - for (BigInteger id : validatorsBySampleRow) { + if (validatorsBySample != null && validatorsBySample.size() > 0) { + for (BigInteger id : validatorsBySample) { if (!nodes.containsKey(id)) { nodes.put(id, new Node(id)); nodes.get(id).addSample(samples.get(sample)); From 098e22d1ead08c10e6be43ecd0ec69746403f98b Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Tue, 3 Oct 2023 21:27:46 +0200 Subject: [PATCH 06/98] getting extra samples in case some fail for random sampling --- simulator/config/dasprotocol.cfg | 2 +- .../peersim/kademlia/das/KademliaCommonConfigDas.java | 4 +++- .../kademlia/das/operations/RandomSamplingOperation.java | 9 ++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 4e2a66e5..980f7770 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 20000 +SIZE 10000 # Random seed K 5 diff --git a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java index 92db762f..f33fc1a4 100644 --- a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java @@ -23,7 +23,9 @@ public class KademliaCommonConfigDas { public static int BLOCK_DIM_SIZE = 10; /** Number of samples retrieved for the random sampling */ - public static int N_SAMPLES = 75; + public static int N_SAMPLES = 105; + + public static int MAX_SAMPLING_FAILED = 3; public static int PARCEL_SIZE = 128; /** diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index e8468d16..f92fabb6 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -9,7 +9,6 @@ import peersim.kademlia.das.KademliaCommonConfigDas; import peersim.kademlia.das.MissingNode; import peersim.kademlia.das.Sample; -// import peersim.kademlia.das.SearchTable; import peersim.kademlia.das.SearchTable; /** @@ -53,10 +52,14 @@ public RandomSamplingOperation( public boolean completed() { boolean completed = true; + int failed = 0; for (FetchingSample s : samples.values()) { if (!s.isDownloaded()) { - completed = false; - break; + failed++; + if (failed > KademliaCommonConfigDas.MAX_SAMPLING_FAILED) { + completed = false; + break; + } } } return completed; From 8a8bb02a2687f420390cb1f1d3775455e93d974e Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Fri, 15 Sep 2023 10:46:40 +0200 Subject: [PATCH 07/98] xback to sample assignment based on id --- simulator/config/dasprotocol.cfg | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 980f7770..d556f89d 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -109,7 +109,11 @@ control.2turbolenceAdd.protocoldas 4dasprotocol control.2turbolenceAdd.protocolevildas 7evildasprotocol control.2turbolenceAdd.transport 2unreltr control.2turbolenceAdd.step TURBULENCE_STEP +<<<<<<< HEAD control.2turbolenceAdd.p_idle 0.9 +======= +control.2turbolenceAdd.p_idle 0.09 +>>>>>>> 62b294e (back to sample assignment based on id) control.2turbolenceAdd.p_rem 0.05 control.2turbolenceAdd.p_add 0.05 From ac2f6636b405432ed5f21a45e2068da7bee751c5 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Fri, 15 Sep 2023 15:44:16 +0200 Subject: [PATCH 08/98] add neighbour and search table refresh --- .../java/peersim/kademlia/StateBuilder.java | 10 ++-- .../peersim/kademlia/TrafficGenerator.java | 50 +++++++++++++++---- .../peersim/kademlia/das/DASProtocol.java | 4 ++ .../kademlia/das/KademliaCommonConfigDas.java | 4 +- .../java/peersim/kademlia/das/Neighbour.java | 28 +++++++++++ .../kademlia/das/RefreshSearchTable.java | 26 ++++++++++ .../peersim/kademlia/das/SearchTable.java | 4 ++ 7 files changed, 110 insertions(+), 16 deletions(-) create mode 100644 simulator/src/main/java/peersim/kademlia/das/Neighbour.java create mode 100644 simulator/src/main/java/peersim/kademlia/das/RefreshSearchTable.java diff --git a/simulator/src/main/java/peersim/kademlia/StateBuilder.java b/simulator/src/main/java/peersim/kademlia/StateBuilder.java index 8d764ae2..4e5eb755 100755 --- a/simulator/src/main/java/peersim/kademlia/StateBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/StateBuilder.java @@ -1,6 +1,5 @@ package peersim.kademlia; -import java.math.BigInteger; import java.util.Comparator; import peersim.config.Configuration; import peersim.core.CommonState; @@ -98,14 +97,15 @@ public int compare(Node o1, Node o2) { }); int sz = Network.size(); - // For every node, add 100 random nodes to its k-bucket - not sure why this was 50 previously... + // For every node, add 10 boostrap nodes for (int i = 0; i < sz; i++) { Node iNode = Network.get(i); KademliaProtocol iKad = (KademliaProtocol) (iNode.getProtocol(kademliaid)); - for (int k = 0; k < 100; k++) { + for (int k = 0; k < 25; k++) { KademliaProtocol jKad = (KademliaProtocol) (Network.get(CommonState.r.nextInt(sz)).getProtocol(kademliaid)); + // (KademliaProtocol) (Network.get(k).getProtocol(kademliaid)); if (jKad.getKademliaNode().isServer()) { iKad.getRoutingTable().addNeighbour(jKad.getKademliaNode().getId()); } @@ -113,7 +113,7 @@ public int compare(Node o1, Node o2) { } // Add 50 nearby nodes to each node's k-bucket - for (int i = 0; i < sz; i++) { + /*for (int i = 0; i < sz; i++) { Node iNode = Network.get(i); KademliaProtocol iKad = (KademliaProtocol) (iNode.getProtocol(kademliaid)); BigInteger iNodeId = iKad.getKademliaNode().getId(); @@ -133,7 +133,7 @@ public int compare(Node o1, Node o2) { } } } - } + }*/ return false; } // end execute() } diff --git a/simulator/src/main/java/peersim/kademlia/TrafficGenerator.java b/simulator/src/main/java/peersim/kademlia/TrafficGenerator.java index d6897e63..b36ac700 100755 --- a/simulator/src/main/java/peersim/kademlia/TrafficGenerator.java +++ b/simulator/src/main/java/peersim/kademlia/TrafficGenerator.java @@ -46,6 +46,20 @@ private Message generateFindNodeMessage() { } BigInteger dst = ((KademliaProtocol) (n.getProtocol(pid))).getKademliaNode().getId(); + System.out.println("Sending find node " + dst); + Message m = Message.makeInitFindNode(dst); + m.timestamp = CommonState.getTime(); + + return m; + } + + /** + * Generates a random find node message, by selecting randomly the destination. + * + * @return Message + */ + private Message generateFindNodeMessage(BigInteger dst) { + // Get an existing active destination node Message m = Message.makeInitFindNode(dst); m.timestamp = CommonState.getTime(); @@ -83,18 +97,34 @@ private Message generateRegionBasedFindNodeMessage() { */ public boolean execute() { - Node start; - do { - start = Network.get(CommonState.r.nextInt(Network.size())); - } while ((start == null) || (!start.isUp())); - - // send message - EDSimulator.add(0, generateFindNodeMessage(), start, pid); - // EDSimulator.add(0, generateRegionBasedFindNodeMessage(), start, pid); - + if (first) { + for (int i = 0; i < Network.size(); i++) { + Node start = Network.get(i); + if (start.isUp()) { + for (int j = 0; j < 3; j++) { + // send message + EDSimulator.add(0, generateFindNodeMessage(), start, pid); + } + EDSimulator.add( + 0, + generateFindNodeMessage(start.getKademliaProtocol().getKademliaNode().getId()), + start, + pid); + } + } + first = false; + } else { + Node start; + do { + start = Network.get(CommonState.r.nextInt(Network.size())); + } while ((start == null) || (!start.isUp())); + + // send message + EDSimulator.add(0, generateFindNodeMessage(), start, pid); + // EDSimulator.add(0, generateRegionBasedFindNodeMessage(), start, pid); + } return false; } - // ______________________________________________________________________________________________ } // End of class diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 4b6f70bd..5ea983b4 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -740,4 +740,8 @@ protected Message generateNewSampleMessage(BigInteger s) { return m; } + + public void refreshSearchTable() { + searchTable.refresh(); + } } diff --git a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java index f33fc1a4..8d9e6c94 100644 --- a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java @@ -1,5 +1,7 @@ package peersim.kademlia.das; +import peersim.kademlia.KademliaCommonConfig; + /** * Fixed Parameters for the DAS protocol. * @@ -40,7 +42,7 @@ public class KademliaCommonConfigDas { /** Number of samples returned by a single node */ public static int MAX_SAMPLES_RETURNED = 1000; - public static int MAX_NODES_RETURNED = 15; + public static int MAX_NODES_RETURNED = KademliaCommonConfig.K; /** Number of max hops during a sampling operation */ public static int MAX_HOPS = 5000; diff --git a/simulator/src/main/java/peersim/kademlia/das/Neighbour.java b/simulator/src/main/java/peersim/kademlia/das/Neighbour.java new file mode 100644 index 00000000..dba25ac8 --- /dev/null +++ b/simulator/src/main/java/peersim/kademlia/das/Neighbour.java @@ -0,0 +1,28 @@ +package peersim.kademlia.das; + +import java.math.BigInteger; + +public class Neighbour implements Comparable { + + BigInteger id; + int ttl; + + Neighbour(BigInteger id){ + this.id = id; + this.ttl=0; + } + + @Override + public int compareTo(Neighbour arg0) { + if(this.ttl getNodesbySample(Set samples, BigInteger rad return result; } + public void refresh() { + + } + /*public static void createSampleMap(Block currentBlock) { int validatorParcelSize = From 6e8716407f01274e98078a78f27d3193d87ec689 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Fri, 15 Sep 2023 18:44:22 +0200 Subject: [PATCH 09/98] ttl discovery done --- .../peersim/kademlia/das/DASProtocol.java | 33 +++++++--------- .../kademlia/das/DASProtocolBuilder.java | 5 --- .../kademlia/das/KademliaCommonConfigDas.java | 2 + .../java/peersim/kademlia/das/Neighbour.java | 39 +++++++++++-------- .../peersim/kademlia/das/SearchTable.java | 27 ++++++++++++- 5 files changed, 63 insertions(+), 43 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 5ea983b4..8abe9c24 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -294,18 +294,11 @@ protected void handleGetSample(Message m, int myPid) { // if (!isValidator()) // logger.warning("Non-validator received " + samples.size() + " from " + m.src.getId()); - List nodes = new ArrayList<>(); for (BigInteger id : samples) { Sample sample = (Sample) kv.get(id); if (sample != null) { s.add(sample); } - // node close to the sample ID - nodes.addAll( - Arrays.asList( - this.getKademliaProtocol() - .getRoutingTable() - .getNeighbours(Util.logDistance(id, this.getKademliaId())))); } // return a random subset of samples (if more than MAX_SAMPLES_RETURNED) Collections.shuffle(s); @@ -316,14 +309,6 @@ protected void handleGetSample(Message m, int myPid) { .toArray(new Sample[0]); else returnedSamples = s.toArray(new Sample[0]); - Collections.shuffle(nodes); - BigInteger[] returnedNodes; - if (nodes.size() > KademliaCommonConfigDas.MAX_NODES_RETURNED) - returnedNodes = - new HashSet(nodes.subList(0, KademliaCommonConfigDas.MAX_NODES_RETURNED)) - .toArray(new BigInteger[0]); - else returnedNodes = nodes.toArray(new BigInteger[0]); - logger.info("Get sample request responding with " + s.size() + " samples"); Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, returnedSamples); @@ -331,7 +316,7 @@ protected void handleGetSample(Message m, int myPid) { response.dst = m.src; response.src = this.kadProtocol.getKademliaNode(); response.ackId = m.id; // set ACK number - response.value = returnedNodes; + response.value = searchTable.getNeighbours(); sendMessage(response, m.src.getId(), myPid); } @@ -362,7 +347,10 @@ protected void handleGetSampleResponse(Message m, int myPid) { if (m.body == null) return; Sample[] samples = (Sample[]) m.body; - searchTable.addNodes((BigInteger[]) m.value); + // searchTable.addNodes((BigInteger[]) m.value); + for (Neighbour neigh : (Neighbour[]) m.value) { + searchTable.addNeighbour(neigh); + } for (Sample s : samples) { kv.add((BigInteger) s.getIdByRow(), s); @@ -528,7 +516,6 @@ public void addKnownValidator(BigInteger[] ids) { } public void setNonValidators(List nonValidators) { - // searchTable.addNodes(nonValidators.toArray(new BigInteger[0])); for (BigInteger id : nonValidators) { nonValidatorsIndexed.add(id); } @@ -641,7 +628,10 @@ public void operationComplete(Operation op) { FindOperation fop = (FindOperation) op; List list = fop.getNeighboursList(); list.remove(builderAddress); - searchTable.addNodes(list.toArray(new BigInteger[0])); + // searchTable.addNodes(list.toArray(new BigInteger[0])); + for (BigInteger id : list) { + searchTable.addNeighbour(new Neighbour(id)); + } logger.warning( "Search table operation complete" // + searchTable.samplesIndexed().size() @@ -680,7 +670,10 @@ public void nodesFound(Operation op, BigInteger[] neighbours) { logger.warning("No neighbours found"); return; } - searchTable.addNodes(list.toArray(new BigInteger[0])); + // searchTable.addNodes(list.toArray(new BigInteger[0])); + for (BigInteger id : list) { + searchTable.addNeighbour(new Neighbour(id)); + } logger.info( "Search table nodes found " // + searchTable.samplesIndexed().size() diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index c2ff46dc..e78aa4fe 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -150,11 +150,6 @@ protected void handleGetSampleResponse(Message m, int myPid) { logger.warning("Received sample builder node: do nothing"); } - public void setNonValidators(List nonValidators) { - for (BigInteger id : nonValidators) { - nonValidatorsIndexed.add(id); - } - } /** * Replicate this object by returning an identical copy.
* It is called by the initializer and do not fill any particular field. diff --git a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java index 8d9e6c94..da73b655 100644 --- a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java @@ -63,4 +63,6 @@ public class KademliaCommonConfigDas { public static int validatorsSize = 0; public static int networkSize = 0; + + public static int TTL = 10; } diff --git a/simulator/src/main/java/peersim/kademlia/das/Neighbour.java b/simulator/src/main/java/peersim/kademlia/das/Neighbour.java index dba25ac8..5d5e066a 100644 --- a/simulator/src/main/java/peersim/kademlia/das/Neighbour.java +++ b/simulator/src/main/java/peersim/kademlia/das/Neighbour.java @@ -4,25 +4,30 @@ public class Neighbour implements Comparable { - BigInteger id; - int ttl; + BigInteger id; + int last_seen; - Neighbour(BigInteger id){ - this.id = id; - this.ttl=0; - } + Neighbour(BigInteger id) { + this.id = id; + this.last_seen = 0; + } - @Override - public int compareTo(Neighbour arg0) { - if(this.ttl= KademliaCommonConfigDas.TTL) return true; + else return false; + } - + @Override + public int compareTo(Neighbour arg0) { + if (this.last_seen < arg0.last_seen) return 1; + else if (this.last_seen == arg0.last_seen) { + return 0; + } else { + return -1; + } + } } diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index 0c8b010c..09ac0f29 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -3,6 +3,7 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -15,6 +16,8 @@ public class SearchTable { // private Block currentBlock; + private List neighbours; + private TreeSet nodesIndexed; // , samplesIndexed; private static TreeSet validatorsIndexed = new TreeSet<>(); // , samplesIndexed; @@ -34,7 +37,7 @@ public SearchTable(/*Block currentblock , BigInteger id*/ ) { this.nonValidatorsIndexed = new TreeSet<>(); this.blackList = new HashSet<>(); - + this.neighbours = new ArrayList<>(); // routingTable = new RoutingTable(KademliaCommonConfig.K, KademliaCommonConfig.BITS, 0); // routingTable.setNodeId(id); } @@ -60,6 +63,10 @@ public SearchTable(/*Block currentblock , BigInteger id*/ ) { return result.toArray(new BigInteger[0]); }*/ + public void addNeighbour(Neighbour neigh) { + neighbours.add(neigh); + } + public void addNodes(BigInteger[] nodes) { for (BigInteger id : nodes) { @@ -167,8 +174,26 @@ public List getNodesbySample(Set samples, BigInteger rad return result; } + public Neighbour[] getNeighbours() { + + List result = new ArrayList<>(); + Collections.sort(neighbours); + + for (Neighbour neigh : neighbours) { + if (result.size() < KademliaCommonConfigDas.MAX_NODES_RETURNED) result.add(neigh); + else break; + } + return result.toArray(new Neighbour[0]); + } + public void refresh() { + List toRemove = new ArrayList<>(); + for (Neighbour neigh : neighbours) { + neigh.updateLastSeen(); + if (neigh.expired()) toRemove.add(neigh); + } + neighbours.removeAll(toRemove); } /*public static void createSampleMap(Block currentBlock) { From 6d9b8224f183210133d26e23d188bb5dcd32101a Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Fri, 29 Sep 2023 16:44:31 +0200 Subject: [PATCH 10/98] discoveries reporting --- simulator/config/dasprotocol.cfg | 6 +++- .../peersim/kademlia/KademliaObserver.java | 31 +++++++++++++++++++ .../peersim/kademlia/das/DASProtocol.java | 15 +++++++-- .../peersim/kademlia/das/EvilDASProtocol.java | 1 + .../java/peersim/kademlia/das/Neighbour.java | 28 ++++++++++++++++- .../peersim/kademlia/das/SearchTable.java | 24 ++++++++++++++ 6 files changed, 100 insertions(+), 5 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index d556f89d..f5119c3a 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -82,7 +82,7 @@ init.1uniqueNodeID.protocoldasbuilder 4dasprotocol init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvildas 7evildasprotocol -init.1uniqueNodeID.validator_rate 0.5 +init.1uniqueNodeID.validator_rate 1.0 init.1uniqueNodeID.evilNodeRatioValidator 0.0 init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 @@ -110,10 +110,14 @@ control.2turbolenceAdd.protocolevildas 7evildasprotocol control.2turbolenceAdd.transport 2unreltr control.2turbolenceAdd.step TURBULENCE_STEP <<<<<<< HEAD +<<<<<<< HEAD control.2turbolenceAdd.p_idle 0.9 ======= control.2turbolenceAdd.p_idle 0.09 >>>>>>> 62b294e (back to sample assignment based on id) +======= +control.2turbolenceAdd.p_idle 0.9 +>>>>>>> 54bd3fd (discoveries reporting) control.2turbolenceAdd.p_rem 0.05 control.2turbolenceAdd.p_add 0.05 diff --git a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java index 9ac6b326..6866a3c5 100755 --- a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java +++ b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java @@ -11,6 +11,8 @@ import peersim.core.CommonState; import peersim.core.Control; import peersim.core.Network; +import peersim.kademlia.das.Neighbour; +import peersim.kademlia.das.SearchTable; import peersim.kademlia.operations.Operation; import peersim.util.IncrementalStats; @@ -54,6 +56,10 @@ public class KademliaObserver implements Control { private static HashMap> operations = new HashMap>(); + /** Log of operations in the Kademlia network */ + private static HashMap> peerDiscoveries = + new HashMap>(); + /** Name of the folder where experiment logs are written */ private static String logFolderName; @@ -124,6 +130,9 @@ public static void writeOut() { if (!operations.isEmpty()) { writeLogs(operations, logFolderName + "/" + "operation.csv"); } + if (!peerDiscoveries.isEmpty()) { + writeLogs(peerDiscoveries, logFolderName + "/" + "peerDiscoveries.csv"); + } } /** @@ -193,4 +202,26 @@ public static void reportOperation(Operation op) { op.setStopTime(CommonState.getTime() - op.getTimestamp()); operations.put(op.getId(), op.toMap()); } + + public static void reportPeerDiscovery(Message m, SearchTable st) { + + if (m.src == null) return; + // Add the message to the message log, but first check if it hasn't already been added + assert (!messages.keySet().contains(m.id)); + Map result = new HashMap(); + Neighbour[] neighs = (Neighbour[])m.value; + + int notKnown=0; + for(Neighbour n : neighs){ + if(!st.isNeighbourKnown(n))notKnown++; + } + result.put("message_id", m.id); + result.put("dst_id",m.dst.getId()); + result.put("src_id",m.src.getId()); + result.put("total_peers", st.getAllNeighboursCount()); + result.put("peers_in_message", neighs.length); + result.put("peers_not_known", notKnown); + + messages.put(m.id, result); + } } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 8abe9c24..ce7ed60d 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -94,6 +94,8 @@ public abstract class DASProtocol implements Cloneable, EDProtocol, KademliaEven protected TreeSet nonValidatorsIndexed; // , samplesIndexed; + protected boolean isEvil; + /** * Replicate this object by returning an identical copy.
* It is called by the initializer and do not fill any particular field. @@ -111,6 +113,7 @@ public abstract class DASProtocol implements Cloneable, EDProtocol, KademliaEven public DASProtocol(String prefix) { DASProtocol.prefix = prefix; + isEvil = false; _init(); tid = Configuration.getPid(prefix + "." + PAR_TRANSPORT); // samplesRequested = 0; @@ -236,6 +239,10 @@ public boolean isValidator() { return this.isValidator; } + public boolean isEvil() { + return this.isEvil; + } + public void setBuilderAddress(BigInteger address) { this.builderAddress = address; searchTable.setBuilderAddress(address); @@ -422,7 +429,7 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { // interface // Timeout t = new Timeout(destId, m.id, m.operationId); Sample[] samples = (Sample[]) m.body; - BigInteger[] nghbrs = (BigInteger[]) m.value; + Neighbour[] nghbrs = (Neighbour[]) m.value; double samplesSize = 0.0; if (samples != null) samplesSize = samples.length * KademliaCommonConfigDas.SAMPLE_SIZE; double nghbrsSize = 0.0; @@ -630,7 +637,8 @@ public void operationComplete(Operation op) { list.remove(builderAddress); // searchTable.addNodes(list.toArray(new BigInteger[0])); for (BigInteger id : list) { - searchTable.addNeighbour(new Neighbour(id)); + Node n = Util.nodeIdtoNode(id, kademliaId); + searchTable.addNeighbour(new Neighbour(id, n, n.getDASProtocol().isEvil())); } logger.warning( "Search table operation complete" @@ -672,7 +680,8 @@ public void nodesFound(Operation op, BigInteger[] neighbours) { } // searchTable.addNodes(list.toArray(new BigInteger[0])); for (BigInteger id : list) { - searchTable.addNeighbour(new Neighbour(id)); + Node n = Util.nodeIdtoNode(id, kademliaId); + searchTable.addNeighbour(new Neighbour(id, n, n.getDASProtocol().isEvil())); } logger.info( "Search table nodes found " diff --git a/simulator/src/main/java/peersim/kademlia/das/EvilDASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/EvilDASProtocol.java index 745f343a..ce0ca9d1 100644 --- a/simulator/src/main/java/peersim/kademlia/das/EvilDASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/EvilDASProtocol.java @@ -9,6 +9,7 @@ public class EvilDASProtocol extends DASProtocol { public EvilDASProtocol(String prefix) { super(prefix); EvilDASProtocol.prefix = prefix; + isEvil = true; } @Override diff --git a/simulator/src/main/java/peersim/kademlia/das/Neighbour.java b/simulator/src/main/java/peersim/kademlia/das/Neighbour.java index 5d5e066a..2581e9e3 100644 --- a/simulator/src/main/java/peersim/kademlia/das/Neighbour.java +++ b/simulator/src/main/java/peersim/kademlia/das/Neighbour.java @@ -1,15 +1,20 @@ package peersim.kademlia.das; import java.math.BigInteger; +import peersim.core.Node; public class Neighbour implements Comparable { BigInteger id; int last_seen; + Node n; + boolean isEvil; - Neighbour(BigInteger id) { + Neighbour(BigInteger id, Node n, boolean isEvil) { this.id = id; this.last_seen = 0; + this.n = n; + this.isEvil = isEvil; } public void updateLastSeen() { @@ -21,6 +26,14 @@ public boolean expired() { else return false; } + public Node getNode() { + return n; + } + + public boolean isEvil() { + return isEvil; + } + @Override public int compareTo(Neighbour arg0) { if (this.last_seen < arg0.last_seen) return 1; @@ -30,4 +43,17 @@ else if (this.last_seen == arg0.last_seen) { return -1; } } + + @Override + public boolean equals(Object object) + { + boolean sameSame = false; + + if (object != null && object instanceof Neighbour) + { + sameSame = this.id.compareTo(((Neighbour) object).id)==0; + } + + return sameSame; + } } diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index 09ac0f29..be99372a 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -186,6 +186,30 @@ public Neighbour[] getNeighbours() { return result.toArray(new Neighbour[0]); } + public int getAllNeighboursCount() { + return neighbours.size(); + } + + public int getAllAliveNeighboursCount() { + int count = 0; + for (Neighbour neigh : neighbours) { + if (neigh.getNode().isUp()) count++; + } + return count; + } + + public int getMaliciousNeighboursCount() { + int count = 0; + for (Neighbour neigh : neighbours) { + if (neigh.isEvil()) count++; + } + return count; + } + + public boolean isNeighbourKnown(Neighbour neighbour){ + return neighbours.contains(neighbour); + } + public void refresh() { List toRemove = new ArrayList<>(); From 15ecb62d1e02d9057a2f8ad149d14e12655511bf Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sat, 30 Sep 2023 07:58:39 +0200 Subject: [PATCH 11/98] discovery reporting fix + ttl time based --- simulator/config/dasprotocol.cfg | 2 +- .../peersim/kademlia/KademliaObserver.java | 18 +++++++------ .../peersim/kademlia/das/DASProtocol.java | 4 ++- .../kademlia/das/KademliaCommonConfigDas.java | 2 +- .../java/peersim/kademlia/das/Neighbour.java | 25 +++++++++---------- .../peersim/kademlia/das/SearchTable.java | 10 +++++--- 6 files changed, 34 insertions(+), 27 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index f5119c3a..032b889c 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -82,7 +82,7 @@ init.1uniqueNodeID.protocoldasbuilder 4dasprotocol init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvildas 7evildasprotocol -init.1uniqueNodeID.validator_rate 1.0 +init.1uniqueNodeID.validator_rate 0.5 init.1uniqueNodeID.evilNodeRatioValidator 0.0 init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 diff --git a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java index 6866a3c5..4e7c9941 100755 --- a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java +++ b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java @@ -207,21 +207,23 @@ public static void reportPeerDiscovery(Message m, SearchTable st) { if (m.src == null) return; // Add the message to the message log, but first check if it hasn't already been added - assert (!messages.keySet().contains(m.id)); + assert (!peerDiscoveries.keySet().contains(m.id)); Map result = new HashMap(); - Neighbour[] neighs = (Neighbour[])m.value; + Neighbour[] neighs = (Neighbour[]) m.value; - int notKnown=0; - for(Neighbour n : neighs){ - if(!st.isNeighbourKnown(n))notKnown++; + int notKnown = 0; + for (Neighbour n : neighs) { + if (!st.isNeighbourKnown(n)) notKnown++; } + result.put("time", CommonState.getTime()); result.put("message_id", m.id); - result.put("dst_id",m.dst.getId()); - result.put("src_id",m.src.getId()); + result.put("dst_id", m.dst.getId()); + result.put("src_id", m.src.getId()); result.put("total_peers", st.getAllNeighboursCount()); + result.put("total_peers_alive", st.getAllAliveNeighboursCount()); result.put("peers_in_message", neighs.length); result.put("peers_not_known", notKnown); - messages.put(m.id, result); + peerDiscoveries.put(m.id, result); } } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index ce7ed60d..f83e0964 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -355,6 +355,8 @@ protected void handleGetSampleResponse(Message m, int myPid) { Sample[] samples = (Sample[]) m.body; // searchTable.addNodes((BigInteger[]) m.value); + + KademliaObserver.reportPeerDiscovery(m, searchTable); for (Neighbour neigh : (Neighbour[]) m.value) { searchTable.addNeighbour(neigh); } @@ -519,7 +521,7 @@ protected int columnWithHighestNumSamples() { public void addKnownValidator(BigInteger[] ids) { logger.info("Adding validator list " + ids.length); validatorsList = ids; - if (validatorsList != null) searchTable.addValidatorNodes(validatorsList); + if (validatorsList != null && isBuilder()) searchTable.addValidatorNodes(validatorsList); } public void setNonValidators(List nonValidators) { diff --git a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java index da73b655..17dcabe9 100644 --- a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java @@ -64,5 +64,5 @@ public class KademliaCommonConfigDas { public static int validatorsSize = 0; public static int networkSize = 0; - public static int TTL = 10; + public static long TTL = 100000; } diff --git a/simulator/src/main/java/peersim/kademlia/das/Neighbour.java b/simulator/src/main/java/peersim/kademlia/das/Neighbour.java index 2581e9e3..bc7a0d19 100644 --- a/simulator/src/main/java/peersim/kademlia/das/Neighbour.java +++ b/simulator/src/main/java/peersim/kademlia/das/Neighbour.java @@ -1,28 +1,29 @@ package peersim.kademlia.das; import java.math.BigInteger; +import peersim.core.CommonState; import peersim.core.Node; public class Neighbour implements Comparable { BigInteger id; - int last_seen; + long last_seen; Node n; boolean isEvil; Neighbour(BigInteger id, Node n, boolean isEvil) { this.id = id; - this.last_seen = 0; + this.last_seen = CommonState.getTime(); this.n = n; this.isEvil = isEvil; } - public void updateLastSeen() { - last_seen++; + public void updateLastSeen(long time) { + last_seen = time; } public boolean expired() { - if (last_seen >= KademliaCommonConfigDas.TTL) return true; + if (CommonState.getTime() - last_seen >= KademliaCommonConfigDas.TTL) return true; else return false; } @@ -45,15 +46,13 @@ else if (this.last_seen == arg0.last_seen) { } @Override - public boolean equals(Object object) - { - boolean sameSame = false; + public boolean equals(Object object) { + boolean sameSame = false; - if (object != null && object instanceof Neighbour) - { - sameSame = this.id.compareTo(((Neighbour) object).id)==0; - } + if (object != null && object instanceof Neighbour) { + sameSame = this.id.compareTo(((Neighbour) object).id) == 0; + } - return sameSame; + return sameSame; } } diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index be99372a..b8c940d9 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -64,7 +64,12 @@ public SearchTable(/*Block currentblock , BigInteger id*/ ) { }*/ public void addNeighbour(Neighbour neigh) { - neighbours.add(neigh); + if (!neighbours.contains(neigh)) neighbours.add(neigh); + else { + neighbours.remove(neigh); + // neigh.updateLastSeen(CommonState.getTime()); + neighbours.add(neigh); + } } public void addNodes(BigInteger[] nodes) { @@ -206,7 +211,7 @@ public int getMaliciousNeighboursCount() { return count; } - public boolean isNeighbourKnown(Neighbour neighbour){ + public boolean isNeighbourKnown(Neighbour neighbour) { return neighbours.contains(neighbour); } @@ -214,7 +219,6 @@ public void refresh() { List toRemove = new ArrayList<>(); for (Neighbour neigh : neighbours) { - neigh.updateLastSeen(); if (neigh.expired()) toRemove.add(neigh); } neighbours.removeAll(toRemove); From 661082ea088d218db1f13321abfb9e98de0ce670 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sat, 30 Sep 2023 09:41:46 +0200 Subject: [PATCH 12/98] discoveries report extended --- .../java/peersim/kademlia/KademliaObserver.java | 2 +- .../kademlia/das/CustomDistributionDas.java | 2 +- .../java/peersim/kademlia/das/SearchTable.java | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java index 4e7c9941..b03dc514 100755 --- a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java +++ b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java @@ -223,7 +223,7 @@ public static void reportPeerDiscovery(Message m, SearchTable st) { result.put("total_peers_alive", st.getAllAliveNeighboursCount()); result.put("peers_in_message", neighs.length); result.put("peers_not_known", notKnown); - + result.put("validators_discovered", st.getValidatorsNeighboursCount()); peerDiscoveries.put(m.id, result); } } diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index 11cf1c30..143db4dd 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -114,7 +114,7 @@ public boolean execute() { } else { dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolDasNonValidatorID))); nonValidatorsIds.add(kadProt.getKademliaNode().getId()); - node.setServer(false); + // node.setServer(false); } dasProt.setKademliaProtocol(kadProt); diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index b8c940d9..5b5a8923 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -195,6 +195,22 @@ public int getAllNeighboursCount() { return neighbours.size(); } + public int getValidatorsNeighboursCount() { + int count = 0; + for (Neighbour neigh : neighbours) { + if (neigh.getNode().getDASProtocol().isValidator()) count++; + } + return count; + } + + public int getNonValidatorsNeighboursCount() { + int count = 0; + for (Neighbour neigh : neighbours) { + if (!neigh.getNode().getDASProtocol().isValidator()) count++; + } + return count; + } + public int getAllAliveNeighboursCount() { int count = 0; for (Neighbour neigh : neighbours) { From 9edb090f2ea89392f7bbbd41865814039f51a990 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Tue, 3 Oct 2023 09:46:32 +0200 Subject: [PATCH 13/98] targeted discovery for missing samples --- simulator/config/dasprotocol.cfg | 4 +- .../peersim/kademlia/das/DASProtocol.java | 39 +++++++++++- .../java/peersim/kademlia/das/Neighbour.java | 12 ++-- .../peersim/kademlia/das/SearchTable.java | 60 +++++++++++++------ .../operations/RandomSamplingOperation.java | 8 ++- .../das/operations/SamplingOperation.java | 15 ++++- 6 files changed, 108 insertions(+), 30 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 032b889c..ecada28c 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -14,7 +14,7 @@ MINDELAY 100 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*1 +SIM_TIME 1000*60*10 CHURN_RATE_HOUR 5 @@ -137,4 +137,4 @@ control.3turbolenceAdd.p_add 0.25 control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logsDas +control.4.logfolder logsDas2 diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index f83e0964..d40249c7 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -96,6 +96,7 @@ public abstract class DASProtocol implements Cloneable, EDProtocol, KademliaEven protected boolean isEvil; + protected boolean missing; /** * Replicate this object by returning an identical copy.
* It is called by the initializer and do not fill any particular field. @@ -259,6 +260,7 @@ public BigInteger getBuilderAddress() { * @param myPid the sender Pid */ protected void handleInitNewBlock(Message m, int myPid) { + missing = false; time = CommonState.getTime(); currentBlock = (Block) m.body; kv.erase(); @@ -298,6 +300,7 @@ protected void handleGetSample(Message m, int myPid) { List samples = Arrays.asList((BigInteger[]) m.body); // samples to return List s = new ArrayList<>(); + // if (!isValidator()) // logger.warning("Non-validator received " + samples.size() + " from " + m.src.getId()); @@ -323,7 +326,27 @@ protected void handleGetSample(Message m, int myPid) { response.dst = m.src; response.src = this.kadProtocol.getKademliaNode(); response.ackId = m.id; // set ACK number - response.value = searchTable.getNeighbours(); + if (m.value instanceof BigInteger[]) { + BigInteger[] smpls = (BigInteger[]) m.value; + List neigh = new ArrayList<>(); + for (int i = 0; i < smpls.length; i++) { + Neighbour[] neighs = + searchTable.getNeighbours( + smpls[i], + currentBlock.computeRegionRadius( + KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, + KademliaCommonConfigDas.validatorsSize)); + for (Neighbour n : neighs) { + neigh.add(n); + if (neigh.size() >= KademliaCommonConfigDas.MAX_NODES_RETURNED) break; + } + if (neigh.size() >= KademliaCommonConfigDas.MAX_NODES_RETURNED) break; + } + response.value = neigh.toArray(new Neighbour[0]); + logger.warning("targeted sample request " + neigh.size()); + } else { + response.value = searchTable.getNeighbours(); + } sendMessage(response, m.src.getId(), myPid); } @@ -370,6 +393,16 @@ protected void handleGetSampleResponse(Message m, int myPid) { SamplingOperation op = (SamplingOperation) samplingOp.get(m.operationId); // We continue an existing operation + + logger.warning( + "Nodes discovered " + + ((Neighbour[]) m.value).length + + " " + + searchTable.getAllNeighboursCount() + + " " + + searchTable.getValidatorsNeighboursCount() + + " " + + op); if (op != null) { // keeping track of received samples op.elaborateResponse(samples, m.src.getId()); @@ -588,6 +621,7 @@ protected boolean doSampling(SamplingOperation sop) { Message msg = generateGetSampleMessage(reqSamples); msg.operationId = sop.getId(); msg.src = this.kadProtocol.getKademliaNode(); + if (missing) msg.value = reqSamples; success = true; msg.dst = Util.nodeIdtoNode(nextNode, kademliaId).getKademliaProtocol().getKademliaNode(); /*if (nextNode.compareTo(builderAddress) == 0) { @@ -600,7 +634,6 @@ protected boolean doSampling(SamplingOperation sop) { sop.getMessages(); } if (!success) { - if (sop instanceof ValidatorSamplingOperation) logger.warning("Sampling operation finished validator failed " + sop.getId()); else { @@ -705,7 +738,7 @@ public void nodesFound(Operation op, BigInteger[] neighbours) { public void missing(BigInteger sample, Operation op) { logger.warning("Missing nodes for sample " + sample + " " + kadOps.size()); - + missing = true; List ids = searchTable.getValidatorNodesbySample( sample, diff --git a/simulator/src/main/java/peersim/kademlia/das/Neighbour.java b/simulator/src/main/java/peersim/kademlia/das/Neighbour.java index bc7a0d19..54f3c476 100644 --- a/simulator/src/main/java/peersim/kademlia/das/Neighbour.java +++ b/simulator/src/main/java/peersim/kademlia/das/Neighbour.java @@ -6,10 +6,10 @@ public class Neighbour implements Comparable { - BigInteger id; - long last_seen; - Node n; - boolean isEvil; + protected BigInteger id; + protected long last_seen; + protected Node n; + protected boolean isEvil; Neighbour(BigInteger id, Node n, boolean isEvil) { this.id = id; @@ -18,6 +18,10 @@ public class Neighbour implements Comparable { this.isEvil = isEvil; } + public BigInteger getId() { + return id; + } + public void updateLastSeen(long time) { last_seen = time; } diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index 5b5a8923..ba32768e 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -16,7 +17,7 @@ public class SearchTable { // private Block currentBlock; - private List neighbours; + private HashMap neighbours; private TreeSet nodesIndexed; // , samplesIndexed; @@ -37,7 +38,7 @@ public SearchTable(/*Block currentblock , BigInteger id*/ ) { this.nonValidatorsIndexed = new TreeSet<>(); this.blackList = new HashSet<>(); - this.neighbours = new ArrayList<>(); + this.neighbours = new HashMap<>(); // routingTable = new RoutingTable(KademliaCommonConfig.K, KademliaCommonConfig.BITS, 0); // routingTable.setNodeId(id); } @@ -64,12 +65,9 @@ public SearchTable(/*Block currentblock , BigInteger id*/ ) { }*/ public void addNeighbour(Neighbour neigh) { - if (!neighbours.contains(neigh)) neighbours.add(neigh); - else { - neighbours.remove(neigh); - // neigh.updateLastSeen(CommonState.getTime()); - neighbours.add(neigh); - } + neighbours.remove(neigh.getId()); + neighbours.put(neigh.getId(), neigh); + nodesIndexed.add(neigh.id); } public void addNodes(BigInteger[] nodes) { @@ -113,7 +111,7 @@ public void removeNode(BigInteger node) { } public TreeSet nodesIndexed() { - return nonValidatorsIndexed; + return nodesIndexed; } public TreeSet getValidatorsIndexed() { @@ -182,9 +180,30 @@ public List getNodesbySample(Set samples, BigInteger rad public Neighbour[] getNeighbours() { List result = new ArrayList<>(); - Collections.sort(neighbours); + List neighs = new ArrayList<>(); + for (Neighbour n : neighbours.values()) { + neighs.add(n); + } + Collections.sort(neighs); - for (Neighbour neigh : neighbours) { + for (Neighbour neigh : neighs) { + if (result.size() < KademliaCommonConfigDas.MAX_NODES_RETURNED) result.add(neigh); + else break; + } + return result.toArray(new Neighbour[0]); + } + + public Neighbour[] getNeighbours(BigInteger id, BigInteger radius) { + + List nodes = getNodesbySample(id, radius); + List neighs = new ArrayList<>(); + List result = new ArrayList<>(); + for (BigInteger n : nodes) { + neighs.add(neighbours.get(n)); + } + Collections.sort(neighs); + + for (Neighbour neigh : neighs) { if (result.size() < KademliaCommonConfigDas.MAX_NODES_RETURNED) result.add(neigh); else break; } @@ -197,7 +216,7 @@ public int getAllNeighboursCount() { public int getValidatorsNeighboursCount() { int count = 0; - for (Neighbour neigh : neighbours) { + for (Neighbour neigh : neighbours.values()) { if (neigh.getNode().getDASProtocol().isValidator()) count++; } return count; @@ -205,7 +224,7 @@ public int getValidatorsNeighboursCount() { public int getNonValidatorsNeighboursCount() { int count = 0; - for (Neighbour neigh : neighbours) { + for (Neighbour neigh : neighbours.values()) { if (!neigh.getNode().getDASProtocol().isValidator()) count++; } return count; @@ -213,7 +232,7 @@ public int getNonValidatorsNeighboursCount() { public int getAllAliveNeighboursCount() { int count = 0; - for (Neighbour neigh : neighbours) { + for (Neighbour neigh : neighbours.values()) { if (neigh.getNode().isUp()) count++; } return count; @@ -221,23 +240,26 @@ public int getAllAliveNeighboursCount() { public int getMaliciousNeighboursCount() { int count = 0; - for (Neighbour neigh : neighbours) { + for (Neighbour neigh : neighbours.values()) { if (neigh.isEvil()) count++; } return count; } public boolean isNeighbourKnown(Neighbour neighbour) { - return neighbours.contains(neighbour); + return neighbours.containsKey(neighbour.getId()); } public void refresh() { List toRemove = new ArrayList<>(); - for (Neighbour neigh : neighbours) { - if (neigh.expired()) toRemove.add(neigh); + for (Neighbour neigh : neighbours.values()) { + if (neigh.expired()) { + toRemove.add(neigh); + nodesIndexed.remove(neigh.getId()); + } } - neighbours.removeAll(toRemove); + for (Neighbour n : toRemove) neighbours.remove(n.getId()); } /*public static void createSampleMap(Block currentBlock) { diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index f92fabb6..b3526e76 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -158,7 +158,13 @@ protected void createNodes() { } } found = true; - } + }*/ + List nodesBySampleRow = + // SearchTable.getNodesBySample(samples.get(sample).getId()); + searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator); + List nodesBySampleColumn = + // SearchTable.getNodesBySample(samples.get(sample).getIdByColumn()); + searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusValidator); if (!found && callback != null) { callback.missing(sample, this); diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index 531f3307..a67d536f 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -108,7 +108,7 @@ protected void createNodes() { if (!samples.get(sample).isDownloaded()) { // List validatorsBySample = SearchTable.getNodesBySample(sample); - List validatorsBySample = + /*List validatorsBySample = searchTable.getValidatorNodesbySample(sample, radiusValidator); List nonValidatorsBySample = searchTable.getNonValidatorNodesbySample(sample, radiusNonValidator); @@ -135,6 +135,19 @@ protected void createNodes() { } } found = true; + }*/ + List nodesBySample = searchTable.getNodesbySample(sample, radiusValidator); + boolean found = false; + if (nodesBySample != null && nodesBySample.size() > 0) { + for (BigInteger id : nodesBySample) { + if (!nodes.containsKey(id)) { + nodes.put(id, new Node(id)); + nodes.get(id).addSample(samples.get(sample)); + } else { + nodes.get(id).addSample(samples.get(sample)); + } + } + found = true; } if (!found && callback != null) callback.missing(sample, this); From ac7cba92c930231b6c363a854edc7b33f028033a Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Wed, 4 Oct 2023 12:30:20 +0200 Subject: [PATCH 14/98] updating neighbours seen time search table --- simulator/config/dasprotocol.cfg | 28 +++++++------------ .../peersim/kademlia/das/DASProtocol.java | 6 ++-- .../peersim/kademlia/das/SearchTable.java | 6 ++++ .../operations/RandomSamplingOperation.java | 8 +----- .../das/operations/SamplingOperation.java | 8 +++--- 5 files changed, 24 insertions(+), 32 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index ecada28c..07119a6c 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 10000 +SIZE 1000 # Random seed K 5 @@ -14,7 +14,7 @@ MINDELAY 100 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*10 +SIM_TIME 1000*60*1 CHURN_RATE_HOUR 5 @@ -23,7 +23,7 @@ TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP OBSERVER_STEP 10000 #Turbulence module is executed every TURBULENCE_STEP enabling churning -TURBULENCE_STEP 120000000 #100000000/SIZE +TURBULENCE_STEP TRAFFIC_STEP #100000000/SIZE # add network config parameters to simulation @@ -109,17 +109,9 @@ control.2turbolenceAdd.protocoldas 4dasprotocol control.2turbolenceAdd.protocolevildas 7evildasprotocol control.2turbolenceAdd.transport 2unreltr control.2turbolenceAdd.step TURBULENCE_STEP -<<<<<<< HEAD -<<<<<<< HEAD -control.2turbolenceAdd.p_idle 0.9 -======= -control.2turbolenceAdd.p_idle 0.09 ->>>>>>> 62b294e (back to sample assignment based on id) -======= -control.2turbolenceAdd.p_idle 0.9 ->>>>>>> 54bd3fd (discoveries reporting) -control.2turbolenceAdd.p_rem 0.05 -control.2turbolenceAdd.p_add 0.05 +control.2turbolenceAdd.p_idle 0.0 +control.2turbolenceAdd.p_rem 0.5 +control.2turbolenceAdd.p_add 0.5 # # turbulence validators control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator @@ -128,13 +120,13 @@ control.3turbolenceAdd.protocoldas 4dasprotocol control.3turbolenceAdd.protocolevildas 7evildasprotocol control.3turbolenceAdd.transport 2unreltr control.3turbolenceAdd.step TURBULENCE_STEP -control.3turbolenceAdd.p_idle 0.5 -control.3turbolenceAdd.p_rem 0.25 -control.3turbolenceAdd.p_add 0.25 +control.3turbolenceAdd.p_idle 0.9 +control.3turbolenceAdd.p_rem 0.05 +control.3turbolenceAdd.p_add 0.05 # ::::: OBSERVER ::::: #The observer is executed every OBSERVER_STEP and will generate data traces control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logsDas2 +control.4.logfolder logsDas diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index d40249c7..e5813370 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -166,6 +166,7 @@ public void processEvent(Node myNode, int myPid, Object event) { m = (Message) event; // m.dst = this.kadProtocol.getKademliaNode(); KademliaObserver.reportMsg(m, false); + searchTable.seenNeighbour(m.src.getId(), Util.nodeIdtoNode(m.src.getId(), myPid)); } switch (((SimpleEvent) event).getType()) { @@ -334,8 +335,7 @@ protected void handleGetSample(Message m, int myPid) { searchTable.getNeighbours( smpls[i], currentBlock.computeRegionRadius( - KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, - KademliaCommonConfigDas.validatorsSize)); + KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER)); for (Neighbour n : neighs) { neigh.add(n); if (neigh.size() >= KademliaCommonConfigDas.MAX_NODES_RETURNED) break; @@ -343,7 +343,7 @@ protected void handleGetSample(Message m, int myPid) { if (neigh.size() >= KademliaCommonConfigDas.MAX_NODES_RETURNED) break; } response.value = neigh.toArray(new Neighbour[0]); - logger.warning("targeted sample request " + neigh.size()); + // logger.warning("targeted sample request " + neigh.size()); } else { response.value = searchTable.getNeighbours(); } diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index ba32768e..ca5ac92e 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -10,6 +10,7 @@ import java.util.Set; import java.util.TreeSet; // import peersim.kademlia.KademliaCommonConfig; +import peersim.core.Node; public class SearchTable { @@ -81,6 +82,11 @@ public void addNodes(BigInteger[] nodes) { } } + public void seenNeighbour(BigInteger id, Node n) { + if (neighbours.get(id) != null) neighbours.remove(id); + neighbours.put(id, new Neighbour(id, n, n.getDASProtocol().isEvil())); + } + /*public void addNonValidatorNodes(BigInteger[] nodes) { for (BigInteger id : nodes) { diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index b3526e76..f92fabb6 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -158,13 +158,7 @@ protected void createNodes() { } } found = true; - }*/ - List nodesBySampleRow = - // SearchTable.getNodesBySample(samples.get(sample).getId()); - searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator); - List nodesBySampleColumn = - // SearchTable.getNodesBySample(samples.get(sample).getIdByColumn()); - searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusValidator); + } if (!found && callback != null) { callback.missing(sample, this); diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index a67d536f..0f8b6675 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -108,7 +108,7 @@ protected void createNodes() { if (!samples.get(sample).isDownloaded()) { // List validatorsBySample = SearchTable.getNodesBySample(sample); - /*List validatorsBySample = + List validatorsBySample = searchTable.getValidatorNodesbySample(sample, radiusValidator); List nonValidatorsBySample = searchTable.getNonValidatorNodesbySample(sample, radiusNonValidator); @@ -135,8 +135,8 @@ protected void createNodes() { } } found = true; - }*/ - List nodesBySample = searchTable.getNodesbySample(sample, radiusValidator); + } + /*List nodesBySample = searchTable.getNodesbySample(sample, radiusValidator); boolean found = false; if (nodesBySample != null && nodesBySample.size() > 0) { for (BigInteger id : nodesBySample) { @@ -148,7 +148,7 @@ protected void createNodes() { } } found = true; - } + }*/ if (!found && callback != null) callback.missing(sample, this); } From f1307d427805e241b3bdf508361712305ab7e7c4 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Wed, 4 Oct 2023 15:58:18 +0200 Subject: [PATCH 15/98] fixing turbulance --- simulator/config/dasprotocol.cfg | 20 +++--- .../peersim/kademlia/das/DASProtocol.java | 10 +-- .../kademlia/das/DASProtocolBuilder.java | 3 +- .../kademlia/das/DASProtocolNonValidator.java | 5 +- .../peersim/kademlia/das/SearchTable.java | 9 ++- .../peersim/kademlia/das/TurbulenceDas.java | 53 ++++++++------- .../kademlia/das/TurbulenceDasValidator.java | 66 ++++++++++--------- .../operations/RandomSamplingOperation.java | 28 ++++---- .../das/operations/SamplingOperation.java | 11 ++-- 9 files changed, 116 insertions(+), 89 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 07119a6c..42f5a225 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -104,20 +104,24 @@ control.0traffic.kadprotocol 3kademlia # turbulence non-validator control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas -control.2turbolenceAdd.protocol 3kademlia -control.2turbolenceAdd.protocoldas 4dasprotocol -control.2turbolenceAdd.protocolevildas 7evildasprotocol +control.2turbolenceAdd.protocolkad 3kademlia +control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +control.2turbolenceAdd.protocolEvildas 7evildasprotocol control.2turbolenceAdd.transport 2unreltr control.2turbolenceAdd.step TURBULENCE_STEP -control.2turbolenceAdd.p_idle 0.0 +control.2turbolenceAdd.p_idle 0.001 control.2turbolenceAdd.p_rem 0.5 control.2turbolenceAdd.p_add 0.5 # # turbulence validators control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator -control.3turbolenceAdd.protocol 3kademlia -control.3turbolenceAdd.protocoldas 4dasprotocol -control.3turbolenceAdd.protocolevildas 7evildasprotocol +control.3turbolenceAdd.protocolkad 3kademlia +control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +control.3turbolenceAdd.protocolEvildas 7evildasprotocol control.3turbolenceAdd.transport 2unreltr control.3turbolenceAdd.step TURBULENCE_STEP control.3turbolenceAdd.p_idle 0.9 @@ -129,4 +133,4 @@ control.3turbolenceAdd.p_add 0.05 control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logsDas +control.4.logfolder logsDas3 diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index e5813370..e3c77200 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -81,7 +81,7 @@ public abstract class DASProtocol implements Cloneable, EDProtocol, KademliaEven // protected int samplesRequested; - protected BigInteger[] validatorsList; + // protected BigInteger[] validatorsList; protected HashSet queried; @@ -166,7 +166,8 @@ public void processEvent(Node myNode, int myPid, Object event) { m = (Message) event; // m.dst = this.kadProtocol.getKademliaNode(); KademliaObserver.reportMsg(m, false); - searchTable.seenNeighbour(m.src.getId(), Util.nodeIdtoNode(m.src.getId(), myPid)); + if (m.src != null) + searchTable.seenNeighbour(m.src.getId(), Util.nodeIdtoNode(m.src.getId(), kademliaId)); } switch (((SimpleEvent) event).getType()) { @@ -553,8 +554,9 @@ protected int columnWithHighestNumSamples() { public void addKnownValidator(BigInteger[] ids) { logger.info("Adding validator list " + ids.length); - validatorsList = ids; - if (validatorsList != null && isBuilder()) searchTable.addValidatorNodes(validatorsList); + // validatorsList = ids; + // if (validatorsList != null && isBuilder()) searchTable.addValidatorNodes(validatorsList); + if (isBuilder()) searchTable.addValidatorNodes(ids); } public void setNonValidators(List nonValidators) { diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index e78aa4fe..125f4495 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -49,7 +49,8 @@ protected void handleInitNewBlock(Message m, int myPid) { boolean inRegion = false; BigInteger radiusValidator = currentBlock.computeRegionRadius( - KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, validatorsList.length); + KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, + searchTable.getValidatorsIndexed().size()); BigInteger radiusNonValidator = currentBlock.computeRegionRadius(KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java index 731f826e..2e04de18 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java @@ -45,10 +45,11 @@ protected void handleInitGetSample(Message m, int myPid) { BigInteger[] samples = {(BigInteger) m.body}; BigInteger radius = currentBlock.computeRegionRadius( - KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, validatorsList.length); + KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, + searchTable.getValidatorsIndexed().size()); for (BigInteger sample : samples) { if (!reqSamples.contains(sample)) { - for (BigInteger id : searchTable.getValidatorNodesbySample(sample, radius)) { + for (BigInteger id : searchTable.getNodesbySample(sample, radius)) { Message msg = generateGetSampleMessage(samples); msg.operationId = -1; msg.src = this.kadProtocol.getKademliaNode(); diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index ca5ac92e..e5a1720f 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -67,8 +67,9 @@ public SearchTable(/*Block currentblock , BigInteger id*/ ) { public void addNeighbour(Neighbour neigh) { neighbours.remove(neigh.getId()); + nodesIndexed.remove(neigh.getId()); neighbours.put(neigh.getId(), neigh); - nodesIndexed.add(neigh.id); + nodesIndexed.add(neigh.getId()); } public void addNodes(BigInteger[] nodes) { @@ -83,7 +84,11 @@ public void addNodes(BigInteger[] nodes) { } public void seenNeighbour(BigInteger id, Node n) { - if (neighbours.get(id) != null) neighbours.remove(id); + if (neighbours.get(id) != null) { + neighbours.remove(id); + nodesIndexed.remove(id); + } + nodesIndexed.add(id); neighbours.put(id, new Neighbour(id, n, n.getDASProtocol().isEvil())); } diff --git a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java index a7f6dd02..ca995436 100644 --- a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java @@ -34,9 +34,11 @@ */ public class TurbulenceDas implements Control { - private static final String PAR_PROT = "protocol"; - private static final String PAR_PROT_DAS = "protocoldas"; - private static final String PAR_PROT_EVIL_DAS = "protocolevildas"; + private static final String PAR_PROT = "protocolkad"; + private static final String PAR_PROT_DAS_BUILDER = "protocoldasbuilder"; + private static final String PAR_PROT_DAS_VAL = "protocoldasvalidator"; + private static final String PAR_PROT_DAS_NONVAL = "protocoldasnonvalidator"; + private static final String PAR_PROT_EVIL_DAS = "protocolEvildas"; private static final String PAR_TRANSPORT = "transport"; private static final String PAR_INIT = "init"; @@ -64,7 +66,9 @@ public class TurbulenceDas implements Control { private String prefix; private int kademliaid; - private int dasprotid; + private int dasprotbuildid; + private int dasprotvalid; + private int dasprotnonvalid; private int dasevilprotid; private int transportid; private int maxsize; @@ -77,7 +81,10 @@ public class TurbulenceDas implements Control { public TurbulenceDas(String prefix) { this.prefix = prefix; kademliaid = Configuration.getPid(this.prefix + "." + PAR_PROT); - dasprotid = Configuration.getPid(this.prefix + "." + PAR_PROT_DAS); + dasprotbuildid = Configuration.getPid(this.prefix + "." + PAR_PROT_DAS_BUILDER); + dasprotvalid = Configuration.getPid(this.prefix + "." + PAR_PROT_DAS_VAL); + dasprotnonvalid = Configuration.getPid(this.prefix + "." + PAR_PROT_DAS_NONVAL); + dasevilprotid = Configuration.getPid(this.prefix + "." + PAR_PROT_EVIL_DAS); transportid = Configuration.getPid(this.prefix + "." + PAR_TRANSPORT); @@ -127,11 +134,6 @@ public boolean add() { for (int j = 0; j < inits.length; ++j) inits[j].initialize(newNode); Network.add(newNode); - int count = 0; - for (int i = 0; i < Network.size(); ++i) if (Network.get(i).isUp()) count++; - - System.out.println("Adding non-validator node " + count); - // Get kademlia protocol of new node KademliaProtocol newKad = (KademliaProtocol) (newNode.getProtocol(kademliaid)); newNode.setKademliaProtocol(newKad); @@ -143,23 +145,30 @@ public boolean add() { KademliaNode node = new KademliaNode(urg.generate(), "127.0.0.1", 0); ((KademliaProtocol) (newNode.getProtocol(kademliaid))).setNode(node); - DASProtocol dasProt = ((DASProtocol) (newNode.getProtocol(dasprotid))); + DASProtocol dasProt = ((DASProtocol) (newNode.getProtocol(dasprotnonvalid))); - newNode.setProtocol(dasprotid, dasProt); + newNode.setProtocol(dasprotbuildid, dasProt); newKad.setNode(node); dasProt.setKademliaProtocol(newKad); - dasProt.setDASProtocolID(dasprotid); + dasProt.setDASProtocolID(dasprotbuildid); newKad.setEventsCallback(dasProt); newNode.setDASProtocol(dasProt); - newNode.setProtocol(dasprotid, dasProt); - newNode.setProtocol(dasevilprotid, dasProt); - - DASProtocol builder = ((DASProtocol) (Network.get(0).getProtocol(dasprotid))); - // dasProt.setBuilder(false); - BigInteger builderAddress = builder.getKademliaProtocol().getKademliaNode().getId(); - dasProt.setBuilderAddress(builderAddress); - // dasProt.setValidator(false); + newNode.setProtocol(dasprotvalid, null); + newNode.setProtocol(dasevilprotid, null); + newNode.setProtocol(dasprotnonvalid, null); + + int count = 0; + BigInteger builderAddress; + for (int i = 0; i < Network.size(); ++i) { + if (Network.get(i).isUp()) count++; + if (Network.get(i).getDASProtocol().isBuilder()) { + builderAddress = Network.get(i).getDASProtocol().getKademliaId(); + dasProt.setBuilderAddress(builderAddress); + } + } + System.out.println("Adding non-validator node " + count + " " + dasProt.getBuilderAddress()); + return false; } @@ -171,7 +180,7 @@ public boolean rem() { int i = Network.size(); do { remove = Network.get(CommonState.r.nextInt(Network.size())); - dasProt = ((DASProtocol) (remove).getProtocol(dasprotid)); + dasProt = ((DASProtocol) (remove).getProtocol(dasprotbuildid)); // } while ((remove == null) || dasProt.isBuilder() || dasProt.isValidator() || // (!remove.isUp())); i--; diff --git a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java index 2d6f0c80..9e51e3f6 100644 --- a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java @@ -1,8 +1,6 @@ package peersim.kademlia.das; import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; import peersim.config.Configuration; import peersim.core.CommonState; import peersim.core.Control; @@ -36,9 +34,11 @@ */ public class TurbulenceDasValidator implements Control { - private static final String PAR_PROT = "protocol"; - private static final String PAR_PROT_DAS = "protocoldas"; - private static final String PAR_PROT_EVIL_DAS = "protocolevildas"; + private static final String PAR_PROT = "protocolkad"; + private static final String PAR_PROT_DAS_BUILDER = "protocoldasbuilder"; + private static final String PAR_PROT_DAS_VAL = "protocoldasvalidator"; + private static final String PAR_PROT_DAS_NONVAL = "protocoldasnonvalidator"; + private static final String PAR_PROT_EVIL_DAS = "protocolEvildas"; private static final String PAR_TRANSPORT = "transport"; private static final String PAR_INIT = "init"; @@ -66,7 +66,9 @@ public class TurbulenceDasValidator implements Control { private String prefix; private int kademliaid; - private int dasprotid; + private int dasprotbuildid; + private int dasprotvalid; + private int dasprotnonvalid; private int dasevilprotid; private int transportid; private int maxsize; @@ -79,9 +81,11 @@ public class TurbulenceDasValidator implements Control { public TurbulenceDasValidator(String prefix) { this.prefix = prefix; kademliaid = Configuration.getPid(this.prefix + "." + PAR_PROT); - dasprotid = Configuration.getPid(this.prefix + "." + PAR_PROT_DAS); - dasevilprotid = Configuration.getPid(this.prefix + "." + PAR_PROT_EVIL_DAS); + dasprotbuildid = Configuration.getPid(this.prefix + "." + PAR_PROT_DAS_BUILDER); + dasprotvalid = Configuration.getPid(this.prefix + "." + PAR_PROT_DAS_VAL); + dasprotnonvalid = Configuration.getPid(this.prefix + "." + PAR_PROT_DAS_NONVAL); + dasevilprotid = Configuration.getPid(this.prefix + "." + PAR_PROT_EVIL_DAS); transportid = Configuration.getPid(this.prefix + "." + PAR_TRANSPORT); minsize = Configuration.getInt(this.prefix + "." + PAR_MINSIZE, 1); @@ -124,22 +128,11 @@ public TurbulenceDasValidator(String prefix) { // ______________________________________________________________________________________________ public boolean add() { - int count = 0; - List validatorList = new ArrayList<>(); - for (int i = 0; i < Network.size(); ++i) { - if (Network.get(i).isUp()) { - DASProtocol dasprot = Network.get(i).getDASProtocol(); - if (dasprot.isValidator()) validatorList.add(dasprot.getKademliaId()); - count++; - } - } // Add Node Node newNode = (Node) Network.prototype.clone(); for (int j = 0; j < inits.length; ++j) inits[j].initialize(newNode); Network.add(newNode); - System.out.println("Adding validator " + count); - // Get kademlia protocol of new node KademliaProtocol newKad = (KademliaProtocol) (newNode.getProtocol(kademliaid)); newNode.setKademliaProtocol(newKad); @@ -151,24 +144,33 @@ public boolean add() { KademliaNode node = new KademliaNode(urg.generate(), "127.0.0.1", 0); ((KademliaProtocol) (newNode.getProtocol(kademliaid))).setNode(node); - DASProtocol dasProt = ((DASProtocol) (newNode.getProtocol(dasprotid))); + DASProtocol dasProt = ((DASProtocol) (newNode.getProtocol(dasprotvalid))); - newNode.setProtocol(dasprotid, dasProt); + newNode.setProtocol(dasprotbuildid, dasProt); newKad.setNode(node); dasProt.setKademliaProtocol(newKad); - dasProt.setDASProtocolID(dasprotid); + dasProt.setDASProtocolID(dasprotbuildid); newKad.setEventsCallback(dasProt); newNode.setDASProtocol(dasProt); - newNode.setProtocol(dasprotid, dasProt); - newNode.setProtocol(dasevilprotid, dasProt); - - DASProtocol builder = ((DASProtocol) (Network.get(0).getProtocol(dasprotid))); - // dasProt.setBuilder(false); - BigInteger builderAddress = builder.getKademliaProtocol().getKademliaNode().getId(); - dasProt.setBuilderAddress(builderAddress); - // dasProt.setValidator(true); - dasProt.addKnownValidator(validatorList.toArray(new BigInteger[0])); + newNode.setProtocol(dasprotvalid, null); + newNode.setProtocol(dasevilprotid, null); + newNode.setProtocol(dasprotnonvalid, null); + + int count = 0; + BigInteger builderAddress; + for (int i = 0; i < Network.size(); ++i) { + if (Network.get(i).isUp()) count++; + if (Network.get(i).getDASProtocol().isBuilder()) { + builderAddress = Network.get(i).getDASProtocol().getKademliaId(); + dasProt.setBuilderAddress(builderAddress); + Network.get(i) + .getDASProtocol() + .addKnownValidator(new BigInteger[] {dasProt.getKademliaId()}); + } + } + System.out.println("Adding validator node " + count + " " + dasProt.getBuilderAddress()); + return false; } @@ -180,7 +182,7 @@ public boolean rem() { int i = Network.size(); do { remove = Network.get(CommonState.r.nextInt(Network.size())); - dasProt = ((DASProtocol) (remove).getProtocol(dasprotid)); + dasProt = ((DASProtocol) (remove).getProtocol(dasprotbuildid)); // } while ((remove == null) || dasProt.isBuilder() || dasProt.isValidator() || // (!remove.isUp())); i--; diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index f92fabb6..7bf11382 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -120,20 +120,22 @@ protected void createNodes() { List validatorsBySample = new ArrayList<>(); - validatorsBySample.addAll( + /*validatorsBySample.addAll( searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusValidator)); validatorsBySample.addAll( searchTable.getValidatorNodesbySample( - samples.get(sample).getIdByColumn(), radiusValidator)); - - List nonValidatorsBySample = new ArrayList<>(); - nonValidatorsBySample.addAll( - searchTable.getNonValidatorNodesbySample( - samples.get(sample).getId(), radiusNonValidator)); - nonValidatorsBySample.addAll( - searchTable.getNonValidatorNodesbySample( - samples.get(sample).getIdByColumn(), radiusNonValidator)); - + samples.get(sample).getIdByColumn(), radiusValidator));*/ + validatorsBySample.addAll( + searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator)); + + /* List nonValidatorsBySample = new ArrayList<>(); + nonValidatorsBySample.addAll( + searchTable.getNonValidatorNodesbySample( + samples.get(sample).getId(), radiusNonValidator)); + nonValidatorsBySample.addAll( + searchTable.getNonValidatorNodesbySample( + samples.get(sample).getIdByColumn(), radiusNonValidator)); + */ boolean found = false; if (validatorsBySample != null && validatorsBySample.size() > 0) { @@ -148,7 +150,7 @@ protected void createNodes() { found = true; } - if (nonValidatorsBySample != null && nonValidatorsBySample.size() > 0) { + /*if (nonValidatorsBySample != null && nonValidatorsBySample.size() > 0) { for (BigInteger id : nonValidatorsBySample) { if (!nodes.containsKey(id)) { nodes.put(id, new Node(id)); @@ -158,7 +160,7 @@ protected void createNodes() { } } found = true; - } + }*/ if (!found && callback != null) { callback.missing(sample, this); diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index 0f8b6675..97c2a2a4 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -108,11 +108,12 @@ protected void createNodes() { if (!samples.get(sample).isDownloaded()) { // List validatorsBySample = SearchTable.getNodesBySample(sample); - List validatorsBySample = + /*List validatorsBySample = searchTable.getValidatorNodesbySample(sample, radiusValidator); List nonValidatorsBySample = - searchTable.getNonValidatorNodesbySample(sample, radiusNonValidator); - + searchTable.getNonValidatorNodesbySample(sample, radiusNonValidator);*/ + List validatorsBySample = + searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator); boolean found = false; if (validatorsBySample != null && validatorsBySample.size() > 0) { for (BigInteger id : validatorsBySample) { @@ -125,7 +126,7 @@ protected void createNodes() { } found = true; } - if (nonValidatorsBySample != null && nonValidatorsBySample.size() > 0) { + /*if (nonValidatorsBySample != null && nonValidatorsBySample.size() > 0) { for (BigInteger id : nonValidatorsBySample) { if (!nodes.containsKey(id)) { nodes.put(id, new Node(id)); @@ -135,7 +136,7 @@ protected void createNodes() { } } found = true; - } + }*/ /*List nodesBySample = searchTable.getNodesbySample(sample, radiusValidator); boolean found = false; if (nodesBySample != null && nodesBySample.size() > 0) { From e758a7c065051472bb780af8c4876d5cd0f6bbea Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Wed, 4 Oct 2023 21:17:53 +0200 Subject: [PATCH 16/98] adding num random samples as parameter --- simulator/config/dasprotocol.cfg | 5 ++-- .../kademlia/das/TrafficGeneratorSample.java | 4 +++ .../operations/RandomSamplingOperation.java | 26 +++++++++---------- .../das/operations/SamplingOperation.java | 12 ++++----- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 42f5a225..deac31c3 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -98,8 +98,9 @@ init.2statebuilder.transport 2unreltr control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 -control.0traffic.sample_copy_per_node 3 -control.0traffic.block_dim_size 512 +control.0traffic.sample_copy_per_node 2 +control.0traffic.block_dim_size 100 +control.0traffic.num_samples 30 control.0traffic.kadprotocol 3kademlia # turbulence non-validator diff --git a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java index 5ca01105..522b0a4f 100755 --- a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java @@ -36,6 +36,8 @@ public class TrafficGeneratorSample implements Control { final String PAR_BLK_DIM_SIZE = "block_dim_size"; + final String PAR_NUM_SAMPLES = "num_samples"; + int mapfn; Block b; @@ -53,6 +55,8 @@ public TrafficGeneratorSample(String prefix) { KademliaCommonConfigDas.BLOCK_DIM_SIZE = Configuration.getInt( prefix + "." + PAR_BLK_DIM_SIZE, KademliaCommonConfigDas.BLOCK_DIM_SIZE); + KademliaCommonConfigDas.N_SAMPLES = + Configuration.getInt(prefix + "." + PAR_NUM_SAMPLES, KademliaCommonConfigDas.N_SAMPLES); } // ______________________________________________________________________________________________ diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index 7bf11382..f6bbd55d 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -120,22 +120,22 @@ protected void createNodes() { List validatorsBySample = new ArrayList<>(); - /*validatorsBySample.addAll( + validatorsBySample.addAll( searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusValidator)); validatorsBySample.addAll( searchTable.getValidatorNodesbySample( - samples.get(sample).getIdByColumn(), radiusValidator));*/ - validatorsBySample.addAll( - searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator)); - - /* List nonValidatorsBySample = new ArrayList<>(); - nonValidatorsBySample.addAll( - searchTable.getNonValidatorNodesbySample( - samples.get(sample).getId(), radiusNonValidator)); - nonValidatorsBySample.addAll( - searchTable.getNonValidatorNodesbySample( - samples.get(sample).getIdByColumn(), radiusNonValidator)); - */ + samples.get(sample).getIdByColumn(), radiusValidator)); + // validatorsBySample.addAll( + // searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator)); + + List nonValidatorsBySample = new ArrayList<>(); + nonValidatorsBySample.addAll( + searchTable.getNonValidatorNodesbySample( + samples.get(sample).getId(), radiusNonValidator)); + nonValidatorsBySample.addAll( + searchTable.getNonValidatorNodesbySample( + samples.get(sample).getIdByColumn(), radiusNonValidator)); + boolean found = false; if (validatorsBySample != null && validatorsBySample.size() > 0) { diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index 97c2a2a4..d9e56ad2 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -108,12 +108,12 @@ protected void createNodes() { if (!samples.get(sample).isDownloaded()) { // List validatorsBySample = SearchTable.getNodesBySample(sample); - /*List validatorsBySample = + List validatorsBySample = searchTable.getValidatorNodesbySample(sample, radiusValidator); List nonValidatorsBySample = - searchTable.getNonValidatorNodesbySample(sample, radiusNonValidator);*/ - List validatorsBySample = - searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator); + searchTable.getNonValidatorNodesbySample(sample, radiusNonValidator); + // List validatorsBySample = + // searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator); boolean found = false; if (validatorsBySample != null && validatorsBySample.size() > 0) { for (BigInteger id : validatorsBySample) { @@ -126,7 +126,7 @@ protected void createNodes() { } found = true; } - /*if (nonValidatorsBySample != null && nonValidatorsBySample.size() > 0) { + if (nonValidatorsBySample != null && nonValidatorsBySample.size() > 0) { for (BigInteger id : nonValidatorsBySample) { if (!nodes.containsKey(id)) { nodes.put(id, new Node(id)); @@ -136,7 +136,7 @@ protected void createNodes() { } } found = true; - }*/ + } /*List nodesBySample = searchTable.getNodesbySample(sample, radiusValidator); boolean found = false; if (nodesBySample != null && nodesBySample.size() > 0) { From 34343e8d6fbe9f8173116b541781157a18b4ebf2 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Thu, 5 Oct 2023 11:17:19 +0200 Subject: [PATCH 17/98] disable global node knowledge / enable node discovery --- simulator/config/dasprotocol.cfg | 10 +++++----- .../kademlia/das/DASProtocolNonValidator.java | 3 ++- .../das/operations/RandomSamplingOperation.java | 12 ++++++------ .../kademlia/das/operations/SamplingOperation.java | 12 ++++++------ 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index deac31c3..b2ddd4a3 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 1000 +SIZE 20000 # Random seed K 5 @@ -14,7 +14,7 @@ MINDELAY 100 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*1 +SIM_TIME 1000*60*10 CHURN_RATE_HOUR 5 @@ -98,9 +98,9 @@ init.2statebuilder.transport 2unreltr control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 -control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 100 -control.0traffic.num_samples 30 +control.0traffic.sample_copy_per_node 3 +control.0traffic.block_dim_size 512 +control.0traffic.num_samples 105 control.0traffic.kadprotocol 3kademlia # turbulence non-validator diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java index 2e04de18..c722f972 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java @@ -49,7 +49,8 @@ protected void handleInitGetSample(Message m, int myPid) { searchTable.getValidatorsIndexed().size()); for (BigInteger sample : samples) { if (!reqSamples.contains(sample)) { - for (BigInteger id : searchTable.getNodesbySample(sample, radius)) { + // for (BigInteger id : searchTable.getNodesbySample(sample, radius)) { + for (BigInteger id : searchTable.getValidatorNodesbySample(sample, radius)) { Message msg = generateGetSampleMessage(samples); msg.operationId = -1; msg.src = this.kadProtocol.getKademliaNode(); diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index f6bbd55d..4c9186a4 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -120,21 +120,21 @@ protected void createNodes() { List validatorsBySample = new ArrayList<>(); - validatorsBySample.addAll( + /*validatorsBySample.addAll( searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusValidator)); validatorsBySample.addAll( searchTable.getValidatorNodesbySample( - samples.get(sample).getIdByColumn(), radiusValidator)); - // validatorsBySample.addAll( - // searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator)); + samples.get(sample).getIdByColumn(), radiusValidator));*/ + validatorsBySample.addAll( + searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator)); - List nonValidatorsBySample = new ArrayList<>(); + /*List nonValidatorsBySample = new ArrayList<>(); nonValidatorsBySample.addAll( searchTable.getNonValidatorNodesbySample( samples.get(sample).getId(), radiusNonValidator)); nonValidatorsBySample.addAll( searchTable.getNonValidatorNodesbySample( - samples.get(sample).getIdByColumn(), radiusNonValidator)); + samples.get(sample).getIdByColumn(), radiusNonValidator));*/ boolean found = false; diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index d9e56ad2..97c2a2a4 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -108,12 +108,12 @@ protected void createNodes() { if (!samples.get(sample).isDownloaded()) { // List validatorsBySample = SearchTable.getNodesBySample(sample); - List validatorsBySample = + /*List validatorsBySample = searchTable.getValidatorNodesbySample(sample, radiusValidator); List nonValidatorsBySample = - searchTable.getNonValidatorNodesbySample(sample, radiusNonValidator); - // List validatorsBySample = - // searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator); + searchTable.getNonValidatorNodesbySample(sample, radiusNonValidator);*/ + List validatorsBySample = + searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator); boolean found = false; if (validatorsBySample != null && validatorsBySample.size() > 0) { for (BigInteger id : validatorsBySample) { @@ -126,7 +126,7 @@ protected void createNodes() { } found = true; } - if (nonValidatorsBySample != null && nonValidatorsBySample.size() > 0) { + /*if (nonValidatorsBySample != null && nonValidatorsBySample.size() > 0) { for (BigInteger id : nonValidatorsBySample) { if (!nodes.containsKey(id)) { nodes.put(id, new Node(id)); @@ -136,7 +136,7 @@ protected void createNodes() { } } found = true; - } + }*/ /*List nodesBySample = searchTable.getNodesbySample(sample, radiusValidator); boolean found = false; if (nodesBySample != null && nodesBySample.size() > 0) { From 6d742c9ff2b069ca69d2b724e306e424c251555c Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Fri, 6 Oct 2023 10:29:54 +0200 Subject: [PATCH 18/98] remove builder from discovery --- simulator/config/dasprotocol.cfg | 53 +++++++++---------- .../peersim/kademlia/das/DASProtocol.java | 7 +-- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index b2ddd4a3..df15229c 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 20000 +SIZE 10000 # Random seed K 5 @@ -14,16 +14,16 @@ MINDELAY 100 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*10 +SIM_TIME 1000*60*7 CHURN_RATE_HOUR 5 #Traffic generator is executed every TRAFFIC_STEP TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP -OBSERVER_STEP 10000 +OBSERVER_STEP 100000 #Turbulence module is executed every TURBULENCE_STEP enabling churning -TURBULENCE_STEP TRAFFIC_STEP #100000000/SIZE +TURBULENCE_STEP 100000000 # add network config parameters to simulation @@ -98,40 +98,35 @@ init.2statebuilder.transport 2unreltr control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 -control.0traffic.sample_copy_per_node 3 +control.0traffic.sample_copy_per_node 2 control.0traffic.block_dim_size 512 -control.0traffic.num_samples 105 control.0traffic.kadprotocol 3kademlia # turbulence non-validator -control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas -control.2turbolenceAdd.protocolkad 3kademlia -control.2turbolenceAdd.protocoldasbuilder 4dasprotocol -control.2turbolenceAdd.protocoldasvalidator 5dasprotocol -control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol -control.2turbolenceAdd.protocolEvildas 7evildasprotocol -control.2turbolenceAdd.transport 2unreltr -control.2turbolenceAdd.step TURBULENCE_STEP -control.2turbolenceAdd.p_idle 0.001 -control.2turbolenceAdd.p_rem 0.5 -control.2turbolenceAdd.p_add 0.5 +# control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +# control.2turbolenceAdd.protocol 3kademlia +# control.2turbolenceAdd.protocoldas 4dasprotocol +# control.2turbolenceAdd.protocolevildas 7evildasprotocol +# control.2turbolenceAdd.transport 2unreltr +# control.2turbolenceAdd.step TURBULENCE_STEP +# control.2turbolenceAdd.p_idle 0.5 +# control.2turbolenceAdd.p_rem 0.25 +# control.2turbolenceAdd.p_add 0.25 # # turbulence validators -control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator -control.3turbolenceAdd.protocolkad 3kademlia -control.3turbolenceAdd.protocoldasbuilder 4dasprotocol -control.3turbolenceAdd.protocoldasvalidator 5dasprotocol -control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol -control.3turbolenceAdd.protocolEvildas 7evildasprotocol -control.3turbolenceAdd.transport 2unreltr -control.3turbolenceAdd.step TURBULENCE_STEP -control.3turbolenceAdd.p_idle 0.9 -control.3turbolenceAdd.p_rem 0.05 -control.3turbolenceAdd.p_add 0.05 +# control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +# control.3turbolenceAdd.protocol 3kademlia +# control.3turbolenceAdd.protocoldas 4dasprotocol +# control.3turbolenceAdd.protocolevildas 7evildasprotocol +# control.3turbolenceAdd.transport 2unreltr +# control.3turbolenceAdd.step TURBULENCE_STEP +# control.3turbolenceAdd.p_idle 0.5 +# control.3turbolenceAdd.p_rem 0.25 +# control.3turbolenceAdd.p_add 0.25 # ::::: OBSERVER ::::: #The observer is executed every OBSERVER_STEP and will generate data traces control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logsDas3 +control.4.logfolder logsDas diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index e3c77200..b26c8399 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -382,7 +382,8 @@ protected void handleGetSampleResponse(Message m, int myPid) { KademliaObserver.reportPeerDiscovery(m, searchTable); for (Neighbour neigh : (Neighbour[]) m.value) { - searchTable.addNeighbour(neigh); + if(neigh.getId().compareTo(builderAddress)!=0) + searchTable.addNeighbour(neigh); } for (Sample s : samples) { @@ -741,7 +742,7 @@ public void missing(BigInteger sample, Operation op) { logger.warning("Missing nodes for sample " + sample + " " + kadOps.size()); missing = true; - List ids = + /*List ids = searchTable.getValidatorNodesbySample( sample, currentBlock.computeRegionRadius( @@ -749,7 +750,7 @@ public void missing(BigInteger sample, Operation op) { KademliaCommonConfigDas.validatorsSize)); for (BigInteger id : ids) { logger.warning("Found id " + id + " for sample " + sample); - } + }*/ } // ______________________________________________________________________________________________ From dd44dfe424d7d522b18aa86a9d30d03814168dee Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sun, 15 Oct 2023 20:51:05 +0200 Subject: [PATCH 19/98] increase radius to reasign when missing nodes for samples --- simulator/config/dasprotocol.cfg | 10 +- .../peersim/kademlia/das/DASProtocol.java | 3 +- .../kademlia/das/DASProtocolBuilder.java | 131 +++++++++++------- .../operations/RandomSamplingOperation.java | 48 +++---- .../das/operations/SamplingOperation.java | 57 +------- .../ValidatorSamplingOperation.java | 49 +++++++ 6 files changed, 155 insertions(+), 143 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index df15229c..9a272232 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 10000 +SIZE 1000 # Random seed K 5 @@ -14,14 +14,14 @@ MINDELAY 100 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*7 +SIM_TIME 1000*21 CHURN_RATE_HOUR 5 #Traffic generator is executed every TRAFFIC_STEP TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP -OBSERVER_STEP 100000 +OBSERVER_STEP 20000 #Turbulence module is executed every TURBULENCE_STEP enabling churning TURBULENCE_STEP 100000000 @@ -82,7 +82,7 @@ init.1uniqueNodeID.protocoldasbuilder 4dasprotocol init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvildas 7evildasprotocol -init.1uniqueNodeID.validator_rate 0.5 +init.1uniqueNodeID.validator_rate 1.0 init.1uniqueNodeID.evilNodeRatioValidator 0.0 init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 @@ -99,7 +99,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 512 +control.0traffic.block_dim_size 100 control.0traffic.kadprotocol 3kademlia # turbulence non-validator diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index b26c8399..b26cc048 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -382,8 +382,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { KademliaObserver.reportPeerDiscovery(m, searchTable); for (Neighbour neigh : (Neighbour[]) m.value) { - if(neigh.getId().compareTo(builderAddress)!=0) - searchTable.addNeighbour(neigh); + if (neigh.getId().compareTo(builderAddress) != 0) searchTable.addNeighbour(neigh); } for (Sample s : samples) { diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index 125f4495..503947e9 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -1,7 +1,6 @@ package peersim.kademlia.das; import java.math.BigInteger; -import java.util.ArrayList; import java.util.List; import peersim.core.Node; import peersim.edsim.EDSimulator; @@ -44,66 +43,96 @@ protected void handleInitNewBlock(Message m, int myPid) { int samplesValidators = 0; int samplesNonValidators = 0; + BigInteger radiusNonValidator = + currentBlock.computeRegionRadius(KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); + while (currentBlock.hasNext()) { - Sample s = currentBlock.next(); boolean inRegion = false; + Sample s = currentBlock.next(); + BigInteger radiusValidator = currentBlock.computeRegionRadius( KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, searchTable.getValidatorsIndexed().size()); - BigInteger radiusNonValidator = - currentBlock.computeRegionRadius(KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); - - // List idsValidatorsRows = SearchTable.getNodesBySample(s.getIdByRow()); - List idsValidatorsRows = - searchTable.getValidatorNodesbySample(s.getIdByRow(), radiusValidator); - List idsValidatorsColumns = - searchTable.getValidatorNodesbySample(s.getIdByColumn(), radiusValidator); - // SearchTable.getNodesBySample(s.getIdByColumn()); - - List idsNonValidatorsRows = - searchTable.getNonValidatorNodesbySample(s.getIdByRow(), radiusNonValidator); - List idsNonValidatorsColumns = - searchTable.getNonValidatorNodesbySample(s.getIdByColumn(), radiusNonValidator); - List idsValidators = new ArrayList<>(); - idsValidators.addAll(idsValidatorsRows); - idsValidators.addAll(idsValidatorsColumns); - - List idsNonValidators = new ArrayList<>(); - idsNonValidators.addAll(idsNonValidatorsRows); - idsNonValidators.addAll(idsNonValidatorsColumns); - - /* + " " - + +idsNonValidators.size());*/ - - for (BigInteger id : idsValidators) { + while (!inRegion) { + + List idsValidators = + searchTable.getValidatorNodesbySample(s.getIdByRow(), radiusValidator); + + for (BigInteger id : idsValidators) { + + logger.warning( + "Sending sample to validator " + + s.getIdByRow() + + " " + + s.getIdByColumn() + + " to " + + id); + Node n = Util.nodeIdtoNode(id, kademliaId); + DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); + if (dasProt.isBuilder()) continue; + if (n.isUp()) { + Sample[] samples = {s}; + Message msg = generateSeedSampleMessage(samples); + msg.operationId = -1; + msg.src = this.getKademliaProtocol().getKademliaNode(); + msg.dst = n.getKademliaProtocol().getKademliaNode(); + sendMessage(msg, id, dasProt.getDASProtocolID()); + samplesValidators++; + if (inRegion == false) { + samplesWithinRegion++; + inRegion = true; + } + } + } + if (!inRegion) radiusValidator = radiusValidator.multiply(BigInteger.valueOf(2)); + // System.out.println( + // "Sample id " + s.getIdByRow() + " " + s.getIdByColumn() + " " + radiusValidator); - logger.warning( - "Sending sample to validator " - + s.getIdByRow() - + " " - + s.getIdByColumn() - + " to " - + id); - Node n = Util.nodeIdtoNode(id, kademliaId); - DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); - if (dasProt.isBuilder()) continue; - if (n.isUp()) { - Sample[] samples = {s}; - Message msg = generateSeedSampleMessage(samples); - msg.operationId = -1; - msg.src = this.getKademliaProtocol().getKademliaNode(); - msg.dst = n.getKademliaProtocol().getKademliaNode(); - sendMessage(msg, id, dasProt.getDASProtocolID()); - samplesValidators++; - if (inRegion == false) { - samplesWithinRegion++; - inRegion = true; + } + inRegion = false; + while (!inRegion) { + + List idsValidators = + searchTable.getValidatorNodesbySample(s.getIdByColumn(), radiusValidator); + + /* + " " + + +idsNonValidators.size());*/ + + for (BigInteger id : idsValidators) { + + logger.warning( + "Sending sample to validator " + + s.getIdByRow() + + " " + + s.getIdByColumn() + + " to " + + id); + Node n = Util.nodeIdtoNode(id, kademliaId); + DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); + if (dasProt.isBuilder()) continue; + if (n.isUp()) { + Sample[] samples = {s}; + Message msg = generateSeedSampleMessage(samples); + msg.operationId = -1; + msg.src = this.getKademliaProtocol().getKademliaNode(); + msg.dst = n.getKademliaProtocol().getKademliaNode(); + sendMessage(msg, id, dasProt.getDASProtocolID()); + samplesValidators++; + if (inRegion == false) { + samplesWithinRegion++; + inRegion = true; + } } } + if (!inRegion) radiusValidator = radiusValidator.multiply(BigInteger.valueOf(2)); } + List idsNonValidators = + searchTable.getNonValidatorNodesbySample(s.getIdByRow(), radiusNonValidator); + idsNonValidators.addAll( + searchTable.getNonValidatorNodesbySample(s.getIdByColumn(), radiusNonValidator)); for (BigInteger id : idsNonValidators) { logger.warning( "Sending sample to non-validator " @@ -116,10 +145,6 @@ protected void handleInitNewBlock(Message m, int myPid) { DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); if (dasProt.isBuilder()) continue; if (n.isUp()) { - if (inRegion == false) { - samplesWithinRegion++; - inRegion = true; - } samplesNonValidators++; if (!dasProt.isValidator()) { diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index 4c9186a4..6ba16c61 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -118,28 +118,32 @@ protected void createNodes() { for (BigInteger sample : samples.keySet()) { if (!samples.get(sample).isDownloaded()) { - List validatorsBySample = new ArrayList<>(); - - /*validatorsBySample.addAll( - searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusValidator)); - validatorsBySample.addAll( - searchTable.getValidatorNodesbySample( - samples.get(sample).getIdByColumn(), radiusValidator));*/ - validatorsBySample.addAll( - searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator)); - - /*List nonValidatorsBySample = new ArrayList<>(); - nonValidatorsBySample.addAll( + List nodesBySample = new ArrayList<>(); + + // nodesBySample.addAll( + // searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator)); + + BigInteger radiusUsed = radiusValidator; + + while (nodesBySample.isEmpty()) { + nodesBySample.addAll( + searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusUsed)); + nodesBySample.addAll( + searchTable.getValidatorNodesbySample( + samples.get(sample).getIdByColumn(), radiusUsed)); + radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); + } + nodesBySample.addAll( searchTable.getNonValidatorNodesbySample( samples.get(sample).getId(), radiusNonValidator)); - nonValidatorsBySample.addAll( + nodesBySample.addAll( searchTable.getNonValidatorNodesbySample( - samples.get(sample).getIdByColumn(), radiusNonValidator));*/ + samples.get(sample).getIdByColumn(), radiusNonValidator)); boolean found = false; - if (validatorsBySample != null && validatorsBySample.size() > 0) { - for (BigInteger id : validatorsBySample) { + if (nodesBySample != null && nodesBySample.size() > 0) { + for (BigInteger id : nodesBySample) { if (!nodes.containsKey(id)) { nodes.put(id, new Node(id)); nodes.get(id).addSample(samples.get(sample)); @@ -150,18 +154,6 @@ protected void createNodes() { found = true; } - /*if (nonValidatorsBySample != null && nonValidatorsBySample.size() > 0) { - for (BigInteger id : nonValidatorsBySample) { - if (!nodes.containsKey(id)) { - nodes.put(id, new Node(id)); - nodes.get(id).addSample(samples.get(sample)); - } else { - nodes.get(id).addSample(samples.get(sample)); - } - } - found = true; - }*/ - if (!found && callback != null) { callback.missing(sample, this); } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index 97c2a2a4..27bd7bcb 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -42,9 +42,7 @@ public SamplingOperation( completed = false; this.isValidator = isValidator; currentBlock = block; - radiusValidator = - currentBlock.computeRegionRadius( - KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, numValidators); + radiusNonValidator = currentBlock.computeRegionRadius(KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); samples = new HashMap<>(); @@ -103,58 +101,7 @@ public BigInteger getRadiusNonValidator() { return radiusNonValidator; } - protected void createNodes() { - for (BigInteger sample : samples.keySet()) { - if (!samples.get(sample).isDownloaded()) { - - // List validatorsBySample = SearchTable.getNodesBySample(sample); - /*List validatorsBySample = - searchTable.getValidatorNodesbySample(sample, radiusValidator); - List nonValidatorsBySample = - searchTable.getNonValidatorNodesbySample(sample, radiusNonValidator);*/ - List validatorsBySample = - searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator); - boolean found = false; - if (validatorsBySample != null && validatorsBySample.size() > 0) { - for (BigInteger id : validatorsBySample) { - if (!nodes.containsKey(id)) { - nodes.put(id, new Node(id)); - nodes.get(id).addSample(samples.get(sample)); - } else { - nodes.get(id).addSample(samples.get(sample)); - } - } - found = true; - } - /*if (nonValidatorsBySample != null && nonValidatorsBySample.size() > 0) { - for (BigInteger id : nonValidatorsBySample) { - if (!nodes.containsKey(id)) { - nodes.put(id, new Node(id)); - nodes.get(id).addSample(samples.get(sample)); - } else { - nodes.get(id).addSample(samples.get(sample)); - } - } - found = true; - }*/ - /*List nodesBySample = searchTable.getNodesbySample(sample, radiusValidator); - boolean found = false; - if (nodesBySample != null && nodesBySample.size() > 0) { - for (BigInteger id : nodesBySample) { - if (!nodes.containsKey(id)) { - nodes.put(id, new Node(id)); - nodes.get(id).addSample(samples.get(sample)); - } else { - nodes.get(id).addSample(samples.get(sample)); - } - } - found = true; - }*/ - - if (!found && callback != null) callback.missing(sample, this); - } - } - } + protected abstract void createNodes(); public BigInteger[] doSampling() { diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index b69eb083..1b0ba173 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -1,7 +1,9 @@ package peersim.kademlia.das.operations; import java.math.BigInteger; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import peersim.kademlia.das.Block; import peersim.kademlia.das.MissingNode; @@ -131,6 +133,53 @@ public int getColumn() { return column; } + @Override + protected void createNodes() { + for (BigInteger sample : samples.keySet()) { + if (!samples.get(sample).isDownloaded()) { + + List nodesBySample = new ArrayList<>(); + // searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator); + if (row > 0) { + BigInteger radiusUsed = radiusValidator; + while (nodesBySample.isEmpty()) { + nodesBySample.addAll( + searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusUsed)); + radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); + } + nodesBySample.addAll( + searchTable.getNonValidatorNodesbySample( + samples.get(sample).getId(), radiusNonValidator)); + } else { + BigInteger radiusUsed = radiusValidator; + while (nodesBySample.isEmpty()) { + nodesBySample.addAll( + searchTable.getValidatorNodesbySample( + samples.get(sample).getIdByColumn(), radiusUsed)); + radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); + } + nodesBySample.addAll( + searchTable.getNonValidatorNodesbySample( + samples.get(sample).getIdByColumn(), radiusNonValidator)); + } + boolean found = false; + if (nodesBySample != null && nodesBySample.size() > 0) { + for (BigInteger id : nodesBySample) { + if (!nodes.containsKey(id)) { + nodes.put(id, new Node(id)); + nodes.get(id).addSample(samples.get(sample)); + } else { + nodes.get(id).addSample(samples.get(sample)); + } + } + found = true; + } + + if (!found && callback != null) callback.missing(sample, this); + } + } + } + public Map toMap() { // System.out.println("Mapping"); Map result = new HashMap(); From 6e07a1b3a6f969b3e4da4ef5f7ef6f38332af603 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Mon, 16 Oct 2023 11:58:11 +0200 Subject: [PATCH 20/98] switch to learned nodes + bug fix --- simulator/config/dasprotocol.cfg | 8 +++---- .../peersim/kademlia/das/DASProtocol.java | 19 +++++++-------- .../kademlia/das/TrafficGeneratorSample.java | 11 +++++++-- .../operations/RandomSamplingOperation.java | 20 ++++++++-------- .../ValidatorSamplingOperation.java | 23 +++++++++++-------- 5 files changed, 46 insertions(+), 35 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 9a272232..8d3cc3c6 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 1000 +SIZE 10000 # Random seed K 5 @@ -14,7 +14,7 @@ MINDELAY 100 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*21 +SIM_TIME 1000*60*7 CHURN_RATE_HOUR 5 @@ -82,7 +82,7 @@ init.1uniqueNodeID.protocoldasbuilder 4dasprotocol init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvildas 7evildasprotocol -init.1uniqueNodeID.validator_rate 1.0 +init.1uniqueNodeID.validator_rate 0.5 init.1uniqueNodeID.evilNodeRatioValidator 0.0 init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 @@ -99,7 +99,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 100 +control.0traffic.block_dim_size 512 control.0traffic.kadprotocol 3kademlia # turbulence non-validator diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index b26cc048..fb2ecf10 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -417,17 +417,14 @@ protected void handleGetSampleResponse(Message m, int myPid) { + " " + ((SamplingOperation) op).samplesCount()); - if (!op.completed() && op.getHops() < KademliaCommonConfigDas.MAX_HOPS) { - if (op instanceof ValidatorSamplingOperation - && (CommonState.getTime() - op.getTimestamp()) - > KademliaCommonConfigDas.VALIDATOR_DEADLINE - || op instanceof RandomSamplingOperation - && (CommonState.getTime() - op.getTimestamp()) - > KademliaCommonConfigDas.RANDOM_SAMPLING_DEADLINE) { - samplingOp.remove(m.operationId); - logger.warning("Sampling operation finished"); - KademliaObserver.reportOperation(op); - } + if (!op.completed() + && op.getHops() < KademliaCommonConfigDas.MAX_HOPS + && (op instanceof ValidatorSamplingOperation + && (CommonState.getTime() - op.getTimestamp()) + <= KademliaCommonConfigDas.VALIDATOR_DEADLINE + || op instanceof RandomSamplingOperation + && (CommonState.getTime() - op.getTimestamp()) + <= KademliaCommonConfigDas.RANDOM_SAMPLING_DEADLINE)) { doSampling(op); } else { logger.warning("Operation completed"); diff --git a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java index 522b0a4f..232aafd1 100755 --- a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java @@ -42,7 +42,7 @@ public class TrafficGeneratorSample implements Control { Block b; private long ID_GENERATOR = 0; - + long lastTime = 0; private boolean first = true, second = false; // ______________________________________________________________________________________________ @@ -138,6 +138,13 @@ public boolean execute() { Node n = Network.get(i); // b.initIterator(); // we add 1 ms delay to be sure the builder starts before validators. + if (n.isUp()) + EDSimulator.add( + CommonState.r.nextLong(CommonState.getTime() - lastTime), + generateFindNodeMessage(), + n, + kadpid); + if (n.getDASProtocol() instanceof DASProtocolBuilder && n.getDASProtocol() .getBuilderAddress() @@ -155,7 +162,7 @@ public boolean execute() { ID_GENERATOR++; second = false; } - + lastTime = CommonState.getTime(); return false; } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index 6ba16c61..19d82d0b 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -127,18 +127,20 @@ protected void createNodes() { while (nodesBySample.isEmpty()) { nodesBySample.addAll( - searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusUsed)); + searchTable.getNodesbySample(samples.get(sample).getId(), radiusUsed)); + // searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusUsed)); nodesBySample.addAll( - searchTable.getValidatorNodesbySample( - samples.get(sample).getIdByColumn(), radiusUsed)); + searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusUsed)); + // searchTable.getValidatorNodesbySample( + // samples.get(sample).getIdByColumn(), radiusUsed)); radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); } - nodesBySample.addAll( - searchTable.getNonValidatorNodesbySample( - samples.get(sample).getId(), radiusNonValidator)); - nodesBySample.addAll( - searchTable.getNonValidatorNodesbySample( - samples.get(sample).getIdByColumn(), radiusNonValidator)); + // nodesBySample.addAll( + // searchTable.getNonValidatorNodesbySample( + // samples.get(sample).getId(), radiusNonValidator)); + // nodesBySample.addAll( + // searchTable.getNonValidatorNodesbySample( + // samples.get(sample).getIdByColumn(), radiusNonValidator)); boolean found = false; diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index 1b0ba173..0c2272b9 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -144,23 +144,28 @@ protected void createNodes() { BigInteger radiusUsed = radiusValidator; while (nodesBySample.isEmpty()) { nodesBySample.addAll( - searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusUsed)); + searchTable.getNodesbySample(samples.get(sample).getId(), radiusUsed)); + // searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusUsed)); radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); } - nodesBySample.addAll( - searchTable.getNonValidatorNodesbySample( - samples.get(sample).getId(), radiusNonValidator)); + // nodesBySample.addAll(searchTable.getNodesbySample(samples.get(sample).getId(), + // radiusNonValidator)); + // searchTable.getNonValidatorNodesbySample(samples.get(sample).getId(), + // radiusNonValidator)); } else { BigInteger radiusUsed = radiusValidator; while (nodesBySample.isEmpty()) { nodesBySample.addAll( - searchTable.getValidatorNodesbySample( - samples.get(sample).getIdByColumn(), radiusUsed)); + searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusUsed)); + // searchTable.getValidatorNodesbySample(samples.get(sample).getIdByColumn(), + // radiusUsed)); radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); } - nodesBySample.addAll( - searchTable.getNonValidatorNodesbySample( - samples.get(sample).getIdByColumn(), radiusNonValidator)); + // nodesBySample.addAll(searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), + // radiusNonValidator)); + + // searchTable.getNonValidatorNodesbySample(samples.get(sample).getIdByColumn(), + // radiusNonValidator)); } boolean found = false; if (nodesBySample != null && nodesBySample.size() > 0) { From b5d583fb9188f29bc54b4e65f8cb34f7ac69f56b Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Mon, 16 Oct 2023 12:24:06 +0200 Subject: [PATCH 21/98] filtering builder address from searchtable --- .../peersim/kademlia/das/SearchTable.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index e5a1720f..0809eff3 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -75,21 +75,25 @@ public void addNeighbour(Neighbour neigh) { public void addNodes(BigInteger[] nodes) { for (BigInteger id : nodes) { - if (!blackList.contains(id) - && !validatorsIndexed.contains(id) - && !builderAddress.equals(id)) { - nonValidatorsIndexed.add(id); + if (id.compareTo(builderAddress) != 0) { + if (!blackList.contains(id) + && !validatorsIndexed.contains(id) + && !builderAddress.equals(id)) { + nonValidatorsIndexed.add(id); + } } } } public void seenNeighbour(BigInteger id, Node n) { - if (neighbours.get(id) != null) { - neighbours.remove(id); - nodesIndexed.remove(id); + if (id.compareTo(builderAddress) != 0) { + if (neighbours.get(id) != null) { + neighbours.remove(id); + nodesIndexed.remove(id); + } + nodesIndexed.add(id); + neighbours.put(id, new Neighbour(id, n, n.getDASProtocol().isEvil())); } - nodesIndexed.add(id); - neighbours.put(id, new Neighbour(id, n, n.getDASProtocol().isEvil())); } /*public void addNonValidatorNodes(BigInteger[] nodes) { From bf61d5338a080da5dfda8b707546dbd2d7062223 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Tue, 17 Oct 2023 15:27:39 +0200 Subject: [PATCH 22/98] load builder searchtable with validators --- simulator/config/dasprotocol.cfg | 6 +++--- .../src/main/java/peersim/kademlia/StateBuilder.java | 2 +- .../java/peersim/kademlia/das/CustomDistributionDas.java | 9 +++++++++ .../src/main/java/peersim/kademlia/das/DASProtocol.java | 4 ++++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 8d3cc3c6..273da10e 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 10000 +SIZE 5000 # Random seed K 5 @@ -14,7 +14,7 @@ MINDELAY 100 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*7 +SIM_TIME 1000*60*2 CHURN_RATE_HOUR 5 @@ -129,4 +129,4 @@ control.0traffic.kadprotocol 3kademlia control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logsDas +control.4.logfolder logsDas2 diff --git a/simulator/src/main/java/peersim/kademlia/StateBuilder.java b/simulator/src/main/java/peersim/kademlia/StateBuilder.java index 4e5eb755..1160665a 100755 --- a/simulator/src/main/java/peersim/kademlia/StateBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/StateBuilder.java @@ -98,10 +98,10 @@ public int compare(Node o1, Node o2) { int sz = Network.size(); // For every node, add 10 boostrap nodes + for (int i = 0; i < sz; i++) { Node iNode = Network.get(i); KademliaProtocol iKad = (KademliaProtocol) (iNode.getProtocol(kademliaid)); - for (int k = 0; k < 25; k++) { KademliaProtocol jKad = (KademliaProtocol) (Network.get(CommonState.r.nextInt(sz)).getProtocol(kademliaid)); diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index 143db4dd..c6b6361c 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -81,6 +81,7 @@ public boolean execute() { "Number of malicious nodes: " + numEvilValidatorNodes + " " + numEvilNonValidatorNodes); List validatorsIds = new ArrayList<>(); List nonValidatorsIds = new ArrayList<>(); + List validators = new ArrayList<>(); for (int i = 0; i < Network.size(); ++i) { Node generalNode = Network.get(i); @@ -100,6 +101,7 @@ public boolean execute() { dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolDasBuilderID))); builderAddress = node.getId(); + validators.add(generalNode); } else if ((i > 0) && (i < (numEvilValidatorNodes + 1))) { dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolEvilDasID))); } else if (i >= (numEvilValidatorNodes + numEvilNonValidatorNodes + 1) @@ -153,6 +155,13 @@ public boolean execute() { // if (i == 0) // generalNode.getDASProtocol().setNonValidators(nonValidatorsIds); generalNode.getDASProtocol().addKnownValidator(validatorsIds.toArray(new BigInteger[0])); + if (generalNode.getDASProtocol().isBuilder()) { + for (Node n : validators) + generalNode + .getDASProtocol() + .getSearchTable() + .addNeighbour(new Neighbour(n.getDASProtocol().getKademliaId(), n, false)); + } } KademliaCommonConfigDas.networkSize = Network.size(); KademliaCommonConfigDas.validatorsSize = numValidators; diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index fb2ecf10..2cb49f4b 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -562,6 +562,10 @@ public void setNonValidators(List nonValidators) { } searchTable.addNodes(nonValidators.toArray(new BigInteger[0])); } + + public SearchTable getSearchTable() { + return searchTable; + } /** * Starts the random sampling operation * From 9b17b4000ddefb88bd5a63279f2437bbb0dd5e53 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Wed, 18 Oct 2023 11:31:41 +0200 Subject: [PATCH 23/98] pull from builder in seeding phase --- simulator/config/dasprotocol.cfg | 2 +- .../peersim/kademlia/das/DASProtocol.java | 18 ++--- .../kademlia/das/DASProtocolBuilder.java | 77 +++++++++++++------ .../kademlia/das/DASProtocolNonValidator.java | 38 +++------ .../kademlia/das/DASProtocolValidator.java | 41 +++------- .../peersim/kademlia/das/SearchTable.java | 2 +- .../kademlia/das/TrafficGeneratorSample.java | 18 ----- 7 files changed, 83 insertions(+), 113 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 273da10e..dba931cc 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -99,7 +99,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 512 +control.0traffic.block_dim_size 100 control.0traffic.kadprotocol 3kademlia # turbulence non-validator diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 2cb49f4b..29beaa61 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -297,7 +297,7 @@ protected void handleSeedSample(Message m, int myPid) { protected void handleGetSample(Message m, int myPid) { // kv is for storing the sample you have - logger.info("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); + logger.warning("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); // sample IDs that are requested in the message List samples = Arrays.asList((BigInteger[]) m.body); // samples to return @@ -321,7 +321,7 @@ protected void handleGetSample(Message m, int myPid) { .toArray(new Sample[0]); else returnedSamples = s.toArray(new Sample[0]); - logger.info("Get sample request responding with " + s.size() + " samples"); + logger.warning("Get sample request responding with " + s.size() + " samples"); Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, returnedSamples); response.operationId = m.operationId; @@ -379,6 +379,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { Sample[] samples = (Sample[]) m.body; // searchTable.addNodes((BigInteger[]) m.value); + logger.warning("Get sample response with " + samples.length + " samples from " + m.src.getId()); KademliaObserver.reportPeerDiscovery(m, searchTable); for (Neighbour neigh : (Neighbour[]) m.value) { @@ -502,7 +503,7 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { if (m.getType() == Message.MSG_GET_SAMPLE) { // is a request Timeout t = new Timeout(destId, m.id, m.operationId); long latency = transport.getLatency(src, dest); - logger.warning("Send message added " + m.id + " " + latency); + logger.warning("Send message added " + m.id + " " + latency + " " + destId); // add to sent msg this.sentMsg.put(m.id, m.timestamp); @@ -742,15 +743,6 @@ public void missing(BigInteger sample, Operation op) { logger.warning("Missing nodes for sample " + sample + " " + kadOps.size()); missing = true; - /*List ids = - searchTable.getValidatorNodesbySample( - sample, - currentBlock.computeRegionRadius( - KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, - KademliaCommonConfigDas.validatorsSize)); - for (BigInteger id : ids) { - logger.warning("Found id " + id + " for sample " + sample); - }*/ } // ______________________________________________________________________________________________ @@ -773,7 +765,7 @@ protected Message generateSeedSampleMessage(Sample[] s) { * * @return Message */ - protected Message generateNewSampleMessage(BigInteger s) { + protected Message generateNewSampleMessage(BigInteger[] s) { Message m = Message.makeInitGetSample(s); m.timestamp = CommonState.getTime(); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index 503947e9..69a3446a 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -1,7 +1,10 @@ package peersim.kademlia.das; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import peersim.core.Network; import peersim.core.Node; import peersim.edsim.EDSimulator; import peersim.kademlia.Message; @@ -10,24 +13,20 @@ public class DASProtocolBuilder extends DASProtocol { protected static String prefix = null; + protected HashMap> samplesToRequest; public DASProtocolBuilder(String prefix) { super(prefix); DASProtocolBuilder.prefix = prefix; isBuilder = true; isValidator = false; + samplesToRequest = new HashMap<>(); } @Override - protected void handleGetSample(Message m, int myPid) { - /** Ignore sample request * */ - logger.warning("Builder handle get sample - return nothing " + this); - } - - @Override - protected void handleSeedSample(Message m, int myPid) { - System.err.println("Builder should not receive seed sample"); - System.exit(-1); + protected void handleInitGetSample(Message m, int myPid) { + logger.warning("Init block builder node - getting samples " + this); + System.err.println("Wrong eventInit block builder node - getting samples "); } @Override @@ -49,7 +48,8 @@ protected void handleInitNewBlock(Message m, int myPid) { while (currentBlock.hasNext()) { boolean inRegion = false; Sample s = currentBlock.next(); - + kv.add(s.getId(), s); + kv.add(s.getIdByColumn(), s); BigInteger radiusValidator = currentBlock.computeRegionRadius( KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, @@ -62,7 +62,7 @@ protected void handleInitNewBlock(Message m, int myPid) { for (BigInteger id : idsValidators) { - logger.warning( + logger.info( "Sending sample to validator " + s.getIdByRow() + " " @@ -73,12 +73,19 @@ protected void handleInitNewBlock(Message m, int myPid) { DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); if (dasProt.isBuilder()) continue; if (n.isUp()) { - Sample[] samples = {s}; + /*Sample[] samples = {s}; Message msg = generateSeedSampleMessage(samples); msg.operationId = -1; msg.src = this.getKademliaProtocol().getKademliaNode(); msg.dst = n.getKademliaProtocol().getKademliaNode(); - sendMessage(msg, id, dasProt.getDASProtocolID()); + sendMessage(msg, id, dasProt.getDASProtocolID());*/ + if (!samplesToRequest.containsKey(id)) { + List samples = new ArrayList<>(); + samples.add(s.getId()); + samplesToRequest.put(id, samples); + } else { + samplesToRequest.get(id).add(s.getId()); + } samplesValidators++; if (inRegion == false) { samplesWithinRegion++; @@ -102,7 +109,7 @@ protected void handleInitNewBlock(Message m, int myPid) { for (BigInteger id : idsValidators) { - logger.warning( + logger.info( "Sending sample to validator " + s.getIdByRow() + " " @@ -113,12 +120,19 @@ protected void handleInitNewBlock(Message m, int myPid) { DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); if (dasProt.isBuilder()) continue; if (n.isUp()) { - Sample[] samples = {s}; + /*Sample[] samples = {s}; Message msg = generateSeedSampleMessage(samples); msg.operationId = -1; msg.src = this.getKademliaProtocol().getKademliaNode(); msg.dst = n.getKademliaProtocol().getKademliaNode(); - sendMessage(msg, id, dasProt.getDASProtocolID()); + sendMessage(msg, id, dasProt.getDASProtocolID());*/ + if (!samplesToRequest.containsKey(id)) { + List samples = new ArrayList<>(); + samples.add(s.getId()); + samplesToRequest.put(id, samples); + } else { + samplesToRequest.get(id).add(s.getId()); + } samplesValidators++; if (inRegion == false) { samplesWithinRegion++; @@ -134,7 +148,7 @@ protected void handleInitNewBlock(Message m, int myPid) { idsNonValidators.addAll( searchTable.getNonValidatorNodesbySample(s.getIdByColumn(), radiusNonValidator)); for (BigInteger id : idsNonValidators) { - logger.warning( + logger.info( "Sending sample to non-validator " + s.getIdByRow() + " " @@ -148,12 +162,33 @@ protected void handleInitNewBlock(Message m, int myPid) { samplesNonValidators++; if (!dasProt.isValidator()) { - EDSimulator.add(2, generateNewSampleMessage(s.getId()), n, dasProt.getDASProtocolID()); + // EDSimulator.add(0, generateNewSampleMessage(s.getId()), n, + // dasProt.getDASProtocolID()); + if (!samplesToRequest.containsKey(id)) { + List samples = new ArrayList<>(); + samples.add(s.getId()); + samplesToRequest.put(id, samples); + } else { + samplesToRequest.get(id).add(s.getId()); + } } } } } + for (int i = 0; i < Network.size(); i++) { + Node n = Network.get(i); + DASProtocol dasProt = n.getDASProtocol(); + BigInteger id = dasProt.getKademliaId(); + if (!dasProt.isBuilder && samplesToRequest.containsKey(id)) { + EDSimulator.add( + 1, + generateNewSampleMessage(samplesToRequest.get(id).toArray(new BigInteger[0])), + n, + dasProt.getDASProtocolID()); + } + } + logger.warning( samplesWithinRegion + " samples out of " @@ -165,12 +200,6 @@ protected void handleInitNewBlock(Message m, int myPid) { + samplesNonValidators); } - @Override - protected void handleInitGetSample(Message m, int myPid) { - logger.warning("Error. Init block builder node - getting samples. do nothing " + this); - // super.handleInitGetSample(m, myPid); - } - @Override protected void handleGetSampleResponse(Message m, int myPid) { logger.warning("Received sample builder node: do nothing"); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java index c722f972..800dabd1 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java @@ -1,7 +1,8 @@ package peersim.kademlia.das; import java.math.BigInteger; -import java.util.HashSet; +import java.util.ArrayList; +import java.util.List; import peersim.core.Node; import peersim.kademlia.Message; import peersim.kademlia.Util; @@ -9,55 +10,37 @@ public class DASProtocolNonValidator extends DASProtocol { protected static String prefix = null; - - protected HashSet reqSamples; + protected List validatorsContacted; public DASProtocolNonValidator(String prefix) { super(prefix); DASProtocolNonValidator.prefix = prefix; isValidator = false; isBuilder = false; - reqSamples = new HashSet<>(); - } - - @Override - protected void handleSeedSample(Message m, int myPid) { - logger.warning("Non-validator should not receive seed sample"); - System.exit(-1); - /*if (m.body == null) return; - - Sample[] samples = (Sample[]) m.body; - for (Sample s : samples) { - logger.warning("Received sample:" + kv.occupancy() + " " + s.getRow() + " " + s.getColumn()); - - kv.add((BigInteger) s.getIdByRow(), s); - kv.add((BigInteger) s.getIdByColumn(), s); - // count # of samples for each row and column - column[s.getColumn() - 1]++; - row[s.getRow() - 1]++; - }*/ + validatorsContacted = new ArrayList<>(); } @Override protected void handleInitGetSample(Message m, int myPid) { logger.warning("Init block non-validator node - getting samples " + this); // super.handleInitGetSample(m, myPid); - BigInteger[] samples = {(BigInteger) m.body}; + if (currentBlock == null) System.err.println("Error block not init yet"); + BigInteger[] samples = (BigInteger[]) m.body; BigInteger radius = currentBlock.computeRegionRadius( KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, searchTable.getValidatorsIndexed().size()); for (BigInteger sample : samples) { - if (!reqSamples.contains(sample)) { - // for (BigInteger id : searchTable.getNodesbySample(sample, radius)) { - for (BigInteger id : searchTable.getValidatorNodesbySample(sample, radius)) { + // for (BigInteger id : searchTable.getNodesbySample(sample, radius)) { + for (BigInteger id : searchTable.getValidatorNodesbySample(sample, radius)) { + if (!validatorsContacted.contains(id)) { Message msg = generateGetSampleMessage(samples); msg.operationId = -1; msg.src = this.kadProtocol.getKademliaNode(); Node n = Util.nodeIdtoNode(id, kademliaId); msg.dst = n.getKademliaProtocol().getKademliaNode(); sendMessage(msg, id, myPid); - reqSamples.add(sample); + validatorsContacted.add(id); } } } @@ -67,6 +50,7 @@ protected void handleInitGetSample(Message m, int myPid) { protected void handleInitNewBlock(Message m, int myPid) { logger.warning("Init block non-validator node - start sampling " + this); super.handleInitNewBlock(m, myPid); + validatorsContacted.clear(); startRandomSampling(); } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index 1860ccb4..ceb1ec96 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -2,7 +2,9 @@ import java.math.BigInteger; import peersim.core.CommonState; +import peersim.core.Node; import peersim.kademlia.Message; +import peersim.kademlia.Util; import peersim.kademlia.das.operations.ValidatorSamplingOperation; public class DASProtocolValidator extends DASProtocol { @@ -16,37 +18,18 @@ public DASProtocolValidator(String prefix) { isBuilder = false; } - @Override - protected void handleSeedSample(Message m, int myPid) { - logger.warning("seed sample received"); - if (m.body == null) return; - - Sample[] samples = (Sample[]) m.body; - for (Sample s : samples) { - logger.warning( - "Received sample:" - + kv.occupancy() - + " " - + s.getRow() - + " " - + s.getColumn() - + " " - + s.getIdByRow() - + " " - + s.getIdByColumn()); - - kv.add((BigInteger) s.getIdByRow(), s); - kv.add((BigInteger) s.getIdByColumn(), s); - // count # of samples for each row and column - column[s.getColumn() - 1]++; - row[s.getRow() - 1]++; - } - } - @Override protected void handleInitGetSample(Message m, int myPid) { - logger.warning("Error. Init block validator node - getting samples. do nothing " + this); - // super.handleInitGetSample(m, myPid); + logger.warning("Init block non-validator node - getting samples " + this); + if (currentBlock == null) System.err.println("Error block not init yet"); + BigInteger[] samples = (BigInteger[]) m.body; + + Message msg = generateGetSampleMessage(samples); + msg.operationId = -1; + msg.src = this.kadProtocol.getKademliaNode(); + Node n = Util.nodeIdtoNode(builderAddress, kademliaId); + msg.dst = n.getKademliaProtocol().getKademliaNode(); + sendMessage(msg, builderAddress, myPid); } @Override diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index 0809eff3..97bddd58 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -107,7 +107,7 @@ public void seenNeighbour(BigInteger id, Node n) { public void addValidatorNodes(BigInteger[] nodes) { for (BigInteger id : nodes) { - if (!blackList.contains(id)) { + if (!blackList.contains(id) && id.compareTo(builderAddress) != 0) { validatorsIndexed.add(id); } // routingTable.addNeighbour(id); diff --git a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java index 232aafd1..9b7e1ec0 100755 --- a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java @@ -139,25 +139,7 @@ public boolean execute() { // b.initIterator(); // we add 1 ms delay to be sure the builder starts before validators. if (n.isUp()) - EDSimulator.add( - CommonState.r.nextLong(CommonState.getTime() - lastTime), - generateFindNodeMessage(), - n, - kadpid); - - if (n.getDASProtocol() instanceof DASProtocolBuilder - && n.getDASProtocol() - .getBuilderAddress() - .equals(n.getKademliaProtocol().getKademliaNode().getId())) { - System.out.println( - CommonState.getTime() - + " New block Builder " - + n.getKademliaProtocol().getKademliaNode().getId() - + " " - + i); EDSimulator.add(0, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); - } else if (!(n.getDASProtocol() instanceof DASProtocolBuilder)) - EDSimulator.add(1, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); } ID_GENERATOR++; second = false; From 788c1ebf7443655998dad1154876222fa01c3f62 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Wed, 18 Oct 2023 12:42:23 +0200 Subject: [PATCH 24/98] caching samples requests to reply later on when samples received --- simulator/config/dasprotocol.cfg | 16 +++--- .../peersim/kademlia/das/DASProtocol.java | 54 +++++++++++++++++-- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index dba931cc..8de84d1c 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -5,12 +5,12 @@ # ::::: GLOBAL :::::: # Network size -SIZE 5000 +SIZE 1000 # Random seed K 5 -MINDELAY 100 +MINDELAY 5 MAXDELAY 100 #Simulation time in ms @@ -39,14 +39,16 @@ network.size SIZE protocol.0link peersim.core.IdleProtocol #A protocol that stores links. It does nothing apart from that. Use by default -protocol.1uniftr peersim.transport.UniformRandomTransport -protocol.1uniftr.mindelay MINDELAY -protocol.1uniftr.maxdelay MAXDELAY +protocol.1pairwiselattr peersim.transport.PairwiseFixedLatencyTransport +protocol.1pairwiselattr.mindelay MINDELAY +protocol.1pairwiselattr.maxdelay MAXDELAY +protocol.1pairwiselattr.size SIZE + #transport layer that reliably delivers messages with a random delay, emulating TCP protocol.2unreltr peersim.transport.UnreliableTransport protocol.2unreltr.drop 0 -protocol.2unreltr.transport 1uniftr +protocol.2unreltr.transport 1pairwiselattr #Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. #Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P @@ -82,7 +84,7 @@ init.1uniqueNodeID.protocoldasbuilder 4dasprotocol init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvildas 7evildasprotocol -init.1uniqueNodeID.validator_rate 0.5 +init.1uniqueNodeID.validator_rate 1.0 init.1uniqueNodeID.evilNodeRatioValidator 0.0 init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 29beaa61..4214aec9 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -97,6 +98,9 @@ public abstract class DASProtocol implements Cloneable, EDProtocol, KademliaEven protected boolean isEvil; protected boolean missing; + + protected HashMap> missingSamples; + /** * Replicate this object by returning an identical copy.
* It is called by the initializer and do not fill any particular field. @@ -138,6 +142,7 @@ public DASProtocol(String prefix) { searchTable = new SearchTable(); nonValidatorsIndexed = new TreeSet<>(); isBuilder = false; + missingSamples = new HashMap<>(); } /** @@ -310,20 +315,39 @@ protected void handleGetSample(Message m, int myPid) { Sample sample = (Sample) kv.get(id); if (sample != null) { s.add(sample); + } else { + if (missingSamples.containsKey(id)) missingSamples.get(id).add(m); + else { + List nodeIds = new ArrayList<>(); + nodeIds.add(m); + missingSamples.put(id, nodeIds); + } + // logger.warning("Sample request missing"); } } // return a random subset of samples (if more than MAX_SAMPLES_RETURNED) Collections.shuffle(s); Sample[] returnedSamples; - if (s.size() > KademliaCommonConfigDas.MAX_SAMPLES_RETURNED) + /*if (s.size() > KademliaCommonConfigDas.MAX_SAMPLES_RETURNED) returnedSamples = new HashSet(s.subList(0, KademliaCommonConfigDas.MAX_SAMPLES_RETURNED)) .toArray(new Sample[0]); - else returnedSamples = s.toArray(new Sample[0]); + else */ + returnedSamples = s.toArray(new Sample[0]); logger.warning("Get sample request responding with " + s.size() + " samples"); - Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, returnedSamples); + if (returnedSamples.length > 0) { + Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, returnedSamples); + response.operationId = m.operationId; + response.dst = m.src; + response.src = this.kadProtocol.getKademliaNode(); + response.ackId = m.id; // set ACK number + response.value = searchTable.getNeighbours(); + + sendMessage(response, m.src.getId(), myPid); + } + /*Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, returnedSamples); response.operationId = m.operationId; response.dst = m.src; response.src = this.kadProtocol.getKademliaNode(); @@ -348,7 +372,7 @@ protected void handleGetSample(Message m, int myPid) { } else { response.value = searchTable.getNeighbours(); } - sendMessage(response, m.src.getId(), myPid); + sendMessage(response, m.src.getId(), myPid);*/ } private void reconstruct(Sample s) { @@ -391,6 +415,26 @@ protected void handleGetSampleResponse(Message m, int myPid) { kv.add((BigInteger) s.getIdByColumn(), s); // count # of samples for each row and column and reconstruct if more than half received reconstruct(s); + + if (missingSamples.containsKey(s.getId()) || missingSamples.containsKey(s.getIdByColumn())) { + logger.info("Sample received missing " + s.getId() + " " + s.getIdByColumn()); + List messages = new ArrayList<>(); + if (missingSamples.containsKey(s.getId())) messages.addAll(missingSamples.get(s.getId())); + if (missingSamples.containsKey(s.getIdByColumn())) + messages.addAll(missingSamples.get(s.getIdByColumn())); + for (Message msg : messages) { + Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, new Sample[] {s}); + response.operationId = msg.operationId; + response.dst = msg.src; + response.src = this.kadProtocol.getKademliaNode(); + response.ackId = msg.id; // set ACK number + response.value = searchTable.getNeighbours(); + logger.warning("Sending sample to " + msg.src.getId()); + sendMessage(response, msg.src.getId(), myPid); + } + missingSamples.remove(s.getId()); + missingSamples.remove(s.getIdByColumn()); + } } SamplingOperation op = (SamplingOperation) samplingOp.get(m.operationId); @@ -507,7 +551,7 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { // add to sent msg this.sentMsg.put(m.id, m.timestamp); - EDSimulator.add(4 * latency, t, src, myPid); // set delay = 2*RTT + EDSimulator.add(10000, t, src, myPid); // set delay = 2*RTT } } From 228b301a1e832dd95d2f10120a31910a206f0b17 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Thu, 19 Oct 2023 10:13:52 +0200 Subject: [PATCH 25/98] adapt sampling to caching requests + activate turbulence --- simulator/config/dasprotocol.cfg | 49 ++++++++------- .../kademlia/das/CustomDistributionDas.java | 4 +- .../peersim/kademlia/das/DASProtocol.java | 59 +++++++++++-------- .../kademlia/das/DASProtocolValidator.java | 2 +- .../kademlia/das/KademliaCommonConfigDas.java | 4 +- .../peersim/kademlia/das/SearchTable.java | 2 +- .../kademlia/das/TrafficGeneratorSample.java | 47 ++++----------- .../peersim/kademlia/das/TurbulenceDas.java | 11 ++++ .../kademlia/das/TurbulenceDasValidator.java | 12 ++++ .../operations/RandomSamplingOperation.java | 40 +++++++------ .../ValidatorSamplingOperation.java | 37 ++++++------ 11 files changed, 142 insertions(+), 125 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 8de84d1c..7e80d187 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -23,7 +23,7 @@ TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP OBSERVER_STEP 20000 #Turbulence module is executed every TURBULENCE_STEP enabling churning -TURBULENCE_STEP 100000000 +TURBULENCE_STEP 1000 # add network config parameters to simulation @@ -84,7 +84,7 @@ init.1uniqueNodeID.protocoldasbuilder 4dasprotocol init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvildas 7evildasprotocol -init.1uniqueNodeID.validator_rate 1.0 +init.1uniqueNodeID.validator_rate 0.5 init.1uniqueNodeID.evilNodeRatioValidator 0.0 init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 @@ -101,34 +101,39 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 100 +control.0traffic.block_dim_size 512 +control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia # turbulence non-validator -# control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas -# control.2turbolenceAdd.protocol 3kademlia -# control.2turbolenceAdd.protocoldas 4dasprotocol -# control.2turbolenceAdd.protocolevildas 7evildasprotocol -# control.2turbolenceAdd.transport 2unreltr -# control.2turbolenceAdd.step TURBULENCE_STEP -# control.2turbolenceAdd.p_idle 0.5 -# control.2turbolenceAdd.p_rem 0.25 -# control.2turbolenceAdd.p_add 0.25 +control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +control.2turbolenceAdd.protocolkad 3kademlia +control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +control.2turbolenceAdd.protocolEvildas 7evildasprotocol +control.2turbolenceAdd.transport 2unreltr +control.2turbolenceAdd.step TURBULENCE_STEP +control.2turbolenceAdd.p_idle 0.1 +control.2turbolenceAdd.p_rem 0.45 +control.2turbolenceAdd.p_add 0.45 # # turbulence validators -# control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator -# control.3turbolenceAdd.protocol 3kademlia -# control.3turbolenceAdd.protocoldas 4dasprotocol -# control.3turbolenceAdd.protocolevildas 7evildasprotocol -# control.3turbolenceAdd.transport 2unreltr -# control.3turbolenceAdd.step TURBULENCE_STEP -# control.3turbolenceAdd.p_idle 0.5 -# control.3turbolenceAdd.p_rem 0.25 -# control.3turbolenceAdd.p_add 0.25 +control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +control.3turbolenceAdd.protocolkad 3kademlia +control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +control.3turbolenceAdd.protocolEvildas 7evildasprotocol +control.3turbolenceAdd.transport 2unreltr +control.3turbolenceAdd.step TURBULENCE_STEP +control.3turbolenceAdd.p_idle 0.9 +control.3turbolenceAdd.p_rem 0.05 +control.3turbolenceAdd.p_add 0.05 # ::::: OBSERVER ::::: #The observer is executed every OBSERVER_STEP and will generate data traces control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logsDas2 +control.4.logfolder logsDas diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index c6b6361c..191b51ef 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -155,13 +155,13 @@ public boolean execute() { // if (i == 0) // generalNode.getDASProtocol().setNonValidators(nonValidatorsIds); generalNode.getDASProtocol().addKnownValidator(validatorsIds.toArray(new BigInteger[0])); - if (generalNode.getDASProtocol().isBuilder()) { + /*if (generalNode.getDASProtocol().isBuilder()) { for (Node n : validators) generalNode .getDASProtocol() .getSearchTable() .addNeighbour(new Neighbour(n.getDASProtocol().getKademliaId(), n, false)); - } + }*/ } KademliaCommonConfigDas.networkSize = Network.size(); KademliaCommonConfigDas.validatorsSize = numValidators; diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 4214aec9..0f8c8eb1 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -10,7 +10,6 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -201,20 +200,22 @@ public void processEvent(Node myNode, int myPid, Object event) { case Timeout.TIMEOUT: // timeout Timeout t = (Timeout) event; + SamplingOperation sop = samplingOp.get(t.opID); if (sentMsg.containsKey(t.msgID)) { // the response msg isn't arrived // remove form sentMsg logger.warning("Timeouuuuut! " + t.msgID); sentMsg.remove(t.msgID); // this.searchTable.removeNode(t.node); - SamplingOperation sop = samplingOp.get(t.opID); if (sop != null) { if (!sop.completed()) { logger.warning("Samping operation found"); - - doSampling(sop); + sop.elaborateResponse(null, null); } } } + if (sop != null) { + doSampling(sop); + } break; } } @@ -302,19 +303,29 @@ protected void handleSeedSample(Message m, int myPid) { protected void handleGetSample(Message m, int myPid) { // kv is for storing the sample you have - logger.warning("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); + logger.info("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); // sample IDs that are requested in the message List samples = Arrays.asList((BigInteger[]) m.body); // samples to return - List s = new ArrayList<>(); + // List s = new ArrayList<>(); // if (!isValidator()) // logger.warning("Non-validator received " + samples.size() + " from " + m.src.getId()); for (BigInteger id : samples) { + logger.info("Requesting sample " + id + " from " + m.src.getId()); Sample sample = (Sample) kv.get(id); if (sample != null) { - s.add(sample); + // s.add(sample); + + Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, new Sample[] {sample}); + response.operationId = m.operationId; + response.dst = m.src; + response.src = this.kadProtocol.getKademliaNode(); + response.ackId = m.id; // set ACK number + response.value = searchTable.getNeighbours(); + + sendMessage(response, m.src.getId(), myPid); } else { if (missingSamples.containsKey(id)) missingSamples.get(id).add(m); else { @@ -326,27 +337,20 @@ protected void handleGetSample(Message m, int myPid) { } } // return a random subset of samples (if more than MAX_SAMPLES_RETURNED) - Collections.shuffle(s); - Sample[] returnedSamples; + // Collections.shuffle(s); + // Sample[] returnedSamples; /*if (s.size() > KademliaCommonConfigDas.MAX_SAMPLES_RETURNED) returnedSamples = new HashSet(s.subList(0, KademliaCommonConfigDas.MAX_SAMPLES_RETURNED)) .toArray(new Sample[0]); else */ - returnedSamples = s.toArray(new Sample[0]); + // returnedSamples = s.toArray(new Sample[0]); - logger.warning("Get sample request responding with " + s.size() + " samples"); + // logger.warning("Get sample request responding with " + sample.getId() + " samples"); - if (returnedSamples.length > 0) { - Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, returnedSamples); - response.operationId = m.operationId; - response.dst = m.src; - response.src = this.kadProtocol.getKademliaNode(); - response.ackId = m.id; // set ACK number - response.value = searchTable.getNeighbours(); + /*if (returnedSamples.length > 0) { - sendMessage(response, m.src.getId(), myPid); - } + }*/ /*Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, returnedSamples); response.operationId = m.operationId; response.dst = m.src; @@ -403,7 +407,13 @@ protected void handleGetSampleResponse(Message m, int myPid) { Sample[] samples = (Sample[]) m.body; // searchTable.addNodes((BigInteger[]) m.value); - logger.warning("Get sample response with " + samples.length + " samples from " + m.src.getId()); + logger.info( + "Get sample response " + + samples[0].getId() + + " " + + samples[0].getIdByColumn() + + " samples from " + + m.src.getId()); KademliaObserver.reportPeerDiscovery(m, searchTable); for (Neighbour neigh : (Neighbour[]) m.value) { @@ -462,7 +472,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { + " " + ((SamplingOperation) op).samplesCount()); - if (!op.completed() + /*if (!op.completed() && op.getHops() < KademliaCommonConfigDas.MAX_HOPS && (op instanceof ValidatorSamplingOperation && (CommonState.getTime() - op.getTimestamp()) @@ -471,7 +481,8 @@ protected void handleGetSampleResponse(Message m, int myPid) { && (CommonState.getTime() - op.getTimestamp()) <= KademliaCommonConfigDas.RANDOM_SAMPLING_DEADLINE)) { doSampling(op); - } else { + } else {*/ + if (op.completed()) { logger.warning("Operation completed"); samplingOp.remove(m.operationId); if (op instanceof ValidatorSamplingOperation) @@ -551,7 +562,7 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { // add to sent msg this.sentMsg.put(m.id, m.timestamp); - EDSimulator.add(10000, t, src, myPid); // set delay = 2*RTT + EDSimulator.add(4 * 100, t, src, myPid); // set delay = 2*RTT } } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index ceb1ec96..1e3a5955 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -20,7 +20,7 @@ public DASProtocolValidator(String prefix) { @Override protected void handleInitGetSample(Message m, int myPid) { - logger.warning("Init block non-validator node - getting samples " + this); + logger.warning("Init block validator node - getting samples " + this); if (currentBlock == null) System.err.println("Error block not init yet"); BigInteger[] samples = (BigInteger[]) m.body; diff --git a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java index 17dcabe9..ecb3fa2e 100644 --- a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java @@ -25,9 +25,9 @@ public class KademliaCommonConfigDas { public static int BLOCK_DIM_SIZE = 10; /** Number of samples retrieved for the random sampling */ - public static int N_SAMPLES = 105; + public static int N_SAMPLES = 75; - public static int MAX_SAMPLING_FAILED = 3; + public static int MAX_SAMPLING_FAILED = 0; public static int PARCEL_SIZE = 128; /** diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index 97bddd58..0b0199d5 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -199,7 +199,7 @@ public Neighbour[] getNeighbours() { for (Neighbour n : neighbours.values()) { neighs.add(n); } - Collections.sort(neighs); + Collections.shuffle(neighs); for (Neighbour neigh : neighs) { if (result.size() < KademliaCommonConfigDas.MAX_NODES_RETURNED) result.add(neigh); diff --git a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java index 9b7e1ec0..8649539c 100755 --- a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java @@ -1,15 +1,13 @@ package peersim.kademlia.das; -import java.math.BigInteger; import peersim.config.Configuration; import peersim.core.CommonState; import peersim.core.Control; import peersim.core.Network; import peersim.core.Node; import peersim.edsim.EDSimulator; -import peersim.kademlia.KademliaCommonConfig; import peersim.kademlia.Message; -import peersim.kademlia.UniformRandomGenerator; +import peersim.kademlia.Util; /** * This control generates samples every 5 min that are stored in a single node (builder) and starts @@ -73,38 +71,6 @@ private Message generateNewBlockMessage(Block b) { return m; } - // ______________________________________________________________________________________________ - /** - * generates a random find node message, by selecting randomly the destination. - * - * @return Message - */ - private Message generateFindNodeMessage() { - - UniformRandomGenerator urg = - new UniformRandomGenerator(KademliaCommonConfig.BITS, CommonState.r); - BigInteger id = urg.generate(); - - Message m = Message.makeInitFindNode(id); - m.timestamp = CommonState.getTime(); - - return m; - } - - // ______________________________________________________________________________________________ - /** - * generates a random find node message, by selecting randomly the destination. - * - * @return Message - */ - private Message generateFindNodeMessage(BigInteger id) { - - Message m = Message.makeInitFindNode(id); - m.timestamp = CommonState.getTime(); - - return m; - } - // ______________________________________________________________________________________________ /** * every call of this control generates and send a random find node message @@ -120,11 +86,12 @@ public boolean execute() { if (start.isUp()) { for (int j = 0; j < 3; j++) { // send message - EDSimulator.add(CommonState.r.nextInt(12000), generateFindNodeMessage(), start, kadpid); + EDSimulator.add( + CommonState.r.nextInt(12000), Util.generateFindNodeMessage(), start, kadpid); } EDSimulator.add( 0, - generateFindNodeMessage(start.getKademliaProtocol().getKademliaNode().getId()), + Util.generateFindNodeMessage(start.getKademliaProtocol().getKademliaNode().getId()), start, kadpid); } @@ -138,6 +105,12 @@ public boolean execute() { Node n = Network.get(i); // b.initIterator(); // we add 1 ms delay to be sure the builder starts before validators. + EDSimulator.add( + CommonState.r.nextLong(CommonState.getTime() - lastTime), + Util.generateFindNodeMessage(), + n, + kadpid); + if (n.isUp()) EDSimulator.add(0, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); } diff --git a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java index ca995436..9f60fb18 100644 --- a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java @@ -7,10 +7,12 @@ import peersim.core.Network; import peersim.core.Node; import peersim.dynamics.NodeInitializer; +import peersim.edsim.EDSimulator; import peersim.kademlia.KademliaCommonConfig; import peersim.kademlia.KademliaNode; import peersim.kademlia.KademliaProtocol; import peersim.kademlia.UniformRandomGenerator; +import peersim.kademlia.Util; /** * Turbulcen class is only for test/statistical purpose. This Control execute a node add or remove @@ -167,6 +169,15 @@ public boolean add() { dasProt.setBuilderAddress(builderAddress); } } + for (int j = 0; j < 3; j++) { + // send message + EDSimulator.add(0, Util.generateFindNodeMessage(), newNode, kademliaid); + } + EDSimulator.add( + 0, + Util.generateFindNodeMessage(newNode.getKademliaProtocol().getKademliaNode().getId()), + newNode, + kademliaid); System.out.println("Adding non-validator node " + count + " " + dasProt.getBuilderAddress()); return false; diff --git a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java index 9e51e3f6..34949e82 100644 --- a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java @@ -7,10 +7,12 @@ import peersim.core.Network; import peersim.core.Node; import peersim.dynamics.NodeInitializer; +import peersim.edsim.EDSimulator; import peersim.kademlia.KademliaCommonConfig; import peersim.kademlia.KademliaNode; import peersim.kademlia.KademliaProtocol; import peersim.kademlia.UniformRandomGenerator; +import peersim.kademlia.Util; /** * Turbulcen class is only for test/statistical purpose. This Control execute a node add or remove @@ -169,6 +171,16 @@ public boolean add() { .addKnownValidator(new BigInteger[] {dasProt.getKademliaId()}); } } + for (int j = 0; j < 3; j++) { + // send message + EDSimulator.add( + CommonState.r.nextInt(0), Util.generateFindNodeMessage(), newNode, kademliaid); + } + EDSimulator.add( + 0, + Util.generateFindNodeMessage(newNode.getKademliaProtocol().getKademliaNode().getId()), + newNode, + kademliaid); System.out.println("Adding validator node " + count + " " + dasProt.getBuilderAddress()); return false; diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index 19d82d0b..7be2be1e 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -90,28 +90,30 @@ public void elaborateResponse(Sample[] sam, BigInteger node) { } } - for (Sample s : sam) { - - if (samples.containsKey(s.getId()) || samples.containsKey(s.getIdByColumn())) { - FetchingSample fs = samples.get(s.getId()); - if (!fs.isDownloaded()) { - samplesCount++; - fs.setDownloaded(); - fs.removeFetchingNode(nodes.get(node)); + if (sam != null) { + for (Sample s : sam) { + if (samples.containsKey(s.getId()) || samples.containsKey(s.getIdByColumn())) { + FetchingSample fs = samples.get(s.getId()); + if (!fs.isDownloaded()) { + samplesCount++; + fs.setDownloaded(); + fs.removeFetchingNode(nodes.get(node)); + } } + /*if (samples.containsKey(s.getIdByColumn())) { + FetchingSample fs = samples.get(s.getIdByColumn()); + if (!fs.isDownloaded()) { + samplesCount++; + fs.setDownloaded(); + fs.removeFetchingNode(nodes.get(node)); + } + }*/ } - /*if (samples.containsKey(s.getIdByColumn())) { - FetchingSample fs = samples.get(s.getIdByColumn()); - if (!fs.isDownloaded()) { - samplesCount++; - fs.setDownloaded(); - fs.removeFetchingNode(nodes.get(node)); - } - }*/ } - - nodes.remove(node); - askNodes.add(node); + if (node != null) { + nodes.remove(node); + askNodes.add(node); + } } protected void createNodes() { diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index 0c2272b9..02ea7ea3 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -94,30 +94,33 @@ public void elaborateResponse(Sample[] sam, BigInteger n) { s.removeFetchingNode(node); } } - for (Sample s : sam) { - if (row > 0) { - if (samples.containsKey(s.getId())) { - FetchingSample fs = samples.get(s.getId()); - if (!fs.isDownloaded()) { - fs.setDownloaded(); - samplesCount++; + if (sam != null) { + for (Sample s : sam) { + if (row > 0) { + if (samples.containsKey(s.getId())) { + FetchingSample fs = samples.get(s.getId()); + if (!fs.isDownloaded()) { + fs.setDownloaded(); + samplesCount++; + } } - } - } else { - if (samples.containsKey(s.getIdByColumn())) { - FetchingSample fs = samples.get(s.getIdByColumn()); - if (!fs.isDownloaded()) { - fs.setDownloaded(); - samplesCount++; + } else { + if (samples.containsKey(s.getIdByColumn())) { + FetchingSample fs = samples.get(s.getIdByColumn()); + if (!fs.isDownloaded()) { + fs.setDownloaded(); + samplesCount++; + } } } } } // System.out.println("Row " + samplesCount + " " + samples.size()); if (samplesCount >= samples.size() / 2) completed = true; - askNodes.add(n); - - nodes.remove(n); + if (node != null) { + askNodes.add(n); + nodes.remove(n); + } } public boolean completed() { From 64ec51008a0226236248c42139ea37fa6a41e5d7 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Thu, 19 Oct 2023 12:02:05 +0200 Subject: [PATCH 26/98] removed non-responding nodes from search table --- simulator/config/dasprotocol.cfg | 28 ++++++------ .../peersim/kademlia/das/DASProtocol.java | 1 + .../kademlia/das/KademliaCommonConfigDas.java | 2 +- .../peersim/kademlia/das/SearchTable.java | 2 + .../kademlia/das/TrafficGeneratorSample.java | 10 ++--- .../peersim/kademlia/das/TurbulenceDas.java | 39 +++++++++++------ .../kademlia/das/TurbulenceDasValidator.java | 43 +++++++++++-------- 7 files changed, 74 insertions(+), 51 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 7e80d187..ca17d686 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -16,7 +16,6 @@ MAXDELAY 100 #Simulation time in ms SIM_TIME 1000*60*2 -CHURN_RATE_HOUR 5 #Traffic generator is executed every TRAFFIC_STEP TRAFFIC_STEP 12000 #10000000/SIZE @@ -24,6 +23,7 @@ TRAFFIC_STEP 12000 #10000000/SIZE OBSERVER_STEP 20000 #Turbulence module is executed every TURBULENCE_STEP enabling churning TURBULENCE_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 # add network config parameters to simulation @@ -84,7 +84,7 @@ init.1uniqueNodeID.protocoldasbuilder 4dasprotocol init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvildas 7evildasprotocol -init.1uniqueNodeID.validator_rate 0.5 +init.1uniqueNodeID.validator_rate 1.0 init.1uniqueNodeID.evilNodeRatioValidator 0.0 init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 @@ -101,22 +101,22 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 512 +control.0traffic.block_dim_size 100 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia # turbulence non-validator -control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas -control.2turbolenceAdd.protocolkad 3kademlia -control.2turbolenceAdd.protocoldasbuilder 4dasprotocol -control.2turbolenceAdd.protocoldasvalidator 5dasprotocol -control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol -control.2turbolenceAdd.protocolEvildas 7evildasprotocol -control.2turbolenceAdd.transport 2unreltr -control.2turbolenceAdd.step TURBULENCE_STEP -control.2turbolenceAdd.p_idle 0.1 -control.2turbolenceAdd.p_rem 0.45 -control.2turbolenceAdd.p_add 0.45 +#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +#control.2turbolenceAdd.protocolkad 3kademlia +#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.2turbolenceAdd.protocolEvildas 7evildasprotocol +#control.2turbolenceAdd.transport 2unreltr +#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +#control.2turbolenceAdd.p_idle 0.1 +#control.2turbolenceAdd.p_rem 0.45 +#control.2turbolenceAdd.p_add 0.45 # # turbulence validators control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 0f8c8eb1..679b7f3f 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -212,6 +212,7 @@ public void processEvent(Node myNode, int myPid, Object event) { sop.elaborateResponse(null, null); } } + searchTable.removeNode(t.node); } if (sop != null) { doSampling(sop); diff --git a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java index ecb3fa2e..85d322cc 100644 --- a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java @@ -64,5 +64,5 @@ public class KademliaCommonConfigDas { public static int validatorsSize = 0; public static int networkSize = 0; - public static long TTL = 100000; + public static long TTL = 60000; } diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index 0b0199d5..b2f15dfb 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -123,6 +123,8 @@ public void removeNode(BigInteger node) { this.nodesIndexed.remove(node); // this.validatorsIndexed.remove(node); this.nonValidatorsIndexed.remove(node); + this.neighbours.remove(node); + validatorsIndexed.remove(node); } public TreeSet nodesIndexed() { diff --git a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java index 8649539c..f90a4aa8 100755 --- a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java @@ -105,11 +105,11 @@ public boolean execute() { Node n = Network.get(i); // b.initIterator(); // we add 1 ms delay to be sure the builder starts before validators. - EDSimulator.add( - CommonState.r.nextLong(CommonState.getTime() - lastTime), - Util.generateFindNodeMessage(), - n, - kadpid); + /*EDSimulator.add( + CommonState.r.nextLong(CommonState.getTime() - lastTime), + Util.generateFindNodeMessage(), + n, + kadpid);*/ if (n.isUp()) EDSimulator.add(0, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); diff --git a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java index 9f60fb18..28d52e8b 100644 --- a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java @@ -78,7 +78,7 @@ public class TurbulenceDas implements Control { private double p_idle; private double p_add; private double p_rem; - + private UniformRandomGenerator urg; // ______________________________________________________________________________________________ public TurbulenceDas(String prefix) { this.prefix = prefix; @@ -97,7 +97,7 @@ public TurbulenceDas(String prefix) { Object[] tmp = Configuration.getInstanceArray(prefix + "." + PAR_INIT); inits = new NodeInitializer[tmp.length]; for (int i = 0; i < tmp.length; ++i) inits[i] = (NodeInitializer) tmp[i]; - + urg = new UniformRandomGenerator(KademliaCommonConfig.BITS, CommonState.r); // Load probability from configuration file p_idle = Configuration.getDouble(this.prefix + "." + PAR_IDLE, 0); // idle default 0 p_add = Configuration.getDouble(this.prefix + "." + PAR_ADD, 0.5); // add default 0.5 @@ -138,23 +138,23 @@ public boolean add() { // Get kademlia protocol of new node KademliaProtocol newKad = (KademliaProtocol) (newNode.getProtocol(kademliaid)); - newNode.setKademliaProtocol(newKad); - newKad.setProtocolID(kademliaid); // newNode.setProtocol(kademliaid, newKad); // Set node ID - UniformRandomGenerator urg = - new UniformRandomGenerator(KademliaCommonConfig.BITS, CommonState.r); + KademliaNode node = new KademliaNode(urg.generate(), "127.0.0.1", 0); - ((KademliaProtocol) (newNode.getProtocol(kademliaid))).setNode(node); DASProtocol dasProt = ((DASProtocol) (newNode.getProtocol(dasprotnonvalid))); - newNode.setProtocol(dasprotbuildid, dasProt); newKad.setNode(node); + newKad.setProtocolID(kademliaid); + newKad.setEventsCallback(dasProt); dasProt.setKademliaProtocol(newKad); dasProt.setDASProtocolID(dasprotbuildid); - newKad.setEventsCallback(dasProt); + + newNode.setKademliaProtocol(newKad); + newNode.setProtocol(dasprotbuildid, dasProt); + newNode.setDASProtocol(dasProt); newNode.setProtocol(dasprotvalid, null); newNode.setProtocol(dasevilprotid, null); @@ -169,16 +169,27 @@ public boolean add() { dasProt.setBuilderAddress(builderAddress); } } + + for (int k = 0; k < 25; k++) { + KademliaProtocol jKad = (KademliaProtocol) (Network.get(k).getProtocol(kademliaid)); + if (jKad.getKademliaNode().isServer()) { + newKad.getRoutingTable().addNeighbour(jKad.getKademliaNode().getId()); + } + } for (int j = 0; j < 3; j++) { // send message EDSimulator.add(0, Util.generateFindNodeMessage(), newNode, kademliaid); } EDSimulator.add( - 0, - Util.generateFindNodeMessage(newNode.getKademliaProtocol().getKademliaNode().getId()), - newNode, - kademliaid); - System.out.println("Adding non-validator node " + count + " " + dasProt.getBuilderAddress()); + 0, Util.generateFindNodeMessage(newKad.getKademliaNode().getId()), newNode, kademliaid); + System.out.println( + CommonState.getTime() + + " Adding non-validator node " + + count + + " " + + newKad.getKademliaNode().getId() + + " " + + dasProt.getBuilderAddress()); return false; } diff --git a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java index 34949e82..3b816816 100644 --- a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java @@ -78,6 +78,7 @@ public class TurbulenceDasValidator implements Control { private double p_idle; private double p_add; private double p_rem; + private UniformRandomGenerator urg; // ______________________________________________________________________________________________ public TurbulenceDasValidator(String prefix) { @@ -96,6 +97,7 @@ public TurbulenceDasValidator(String prefix) { Object[] tmp = Configuration.getInstanceArray(prefix + "." + PAR_INIT); inits = new NodeInitializer[tmp.length]; for (int i = 0; i < tmp.length; ++i) inits[i] = (NodeInitializer) tmp[i]; + urg = new UniformRandomGenerator(KademliaCommonConfig.BITS, CommonState.r); // Load probability from configuration file p_idle = Configuration.getDouble(this.prefix + "." + PAR_IDLE, 0); // idle default 0 @@ -137,23 +139,23 @@ public boolean add() { // Get kademlia protocol of new node KademliaProtocol newKad = (KademliaProtocol) (newNode.getProtocol(kademliaid)); - newNode.setKademliaProtocol(newKad); - newKad.setProtocolID(kademliaid); // newNode.setProtocol(kademliaid, newKad); // Set node ID - UniformRandomGenerator urg = - new UniformRandomGenerator(KademliaCommonConfig.BITS, CommonState.r); + KademliaNode node = new KademliaNode(urg.generate(), "127.0.0.1", 0); - ((KademliaProtocol) (newNode.getProtocol(kademliaid))).setNode(node); DASProtocol dasProt = ((DASProtocol) (newNode.getProtocol(dasprotvalid))); - newNode.setProtocol(dasprotbuildid, dasProt); newKad.setNode(node); + newKad.setProtocolID(kademliaid); + newKad.setEventsCallback(dasProt); dasProt.setKademliaProtocol(newKad); dasProt.setDASProtocolID(dasprotbuildid); - newKad.setEventsCallback(dasProt); + + newNode.setKademliaProtocol(newKad); + newNode.setProtocol(dasprotbuildid, dasProt); + newNode.setDASProtocol(dasProt); newNode.setProtocol(dasprotvalid, null); newNode.setProtocol(dasevilprotid, null); @@ -166,22 +168,29 @@ public boolean add() { if (Network.get(i).getDASProtocol().isBuilder()) { builderAddress = Network.get(i).getDASProtocol().getKademliaId(); dasProt.setBuilderAddress(builderAddress); - Network.get(i) - .getDASProtocol() - .addKnownValidator(new BigInteger[] {dasProt.getKademliaId()}); + } + } + + for (int k = 0; k < 25; k++) { + KademliaProtocol jKad = (KademliaProtocol) (Network.get(k).getProtocol(kademliaid)); + if (jKad.getKademliaNode().isServer()) { + newKad.getRoutingTable().addNeighbour(jKad.getKademliaNode().getId()); } } for (int j = 0; j < 3; j++) { // send message - EDSimulator.add( - CommonState.r.nextInt(0), Util.generateFindNodeMessage(), newNode, kademliaid); + EDSimulator.add(0, Util.generateFindNodeMessage(), newNode, kademliaid); } EDSimulator.add( - 0, - Util.generateFindNodeMessage(newNode.getKademliaProtocol().getKademliaNode().getId()), - newNode, - kademliaid); - System.out.println("Adding validator node " + count + " " + dasProt.getBuilderAddress()); + 0, Util.generateFindNodeMessage(newKad.getKademliaNode().getId()), newNode, kademliaid); + System.out.println( + CommonState.getTime() + + " Adding validator node " + + count + + " " + + newKad.getKademliaNode().getId() + + " " + + dasProt.getBuilderAddress()); return false; } From bd33de32122dd1d0a240bbe0da53e7047c94cbc6 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Thu, 19 Oct 2023 12:27:40 +0200 Subject: [PATCH 27/98] turbulence fix filling routing table --- simulator/config/dasprotocol.cfg | 4 ++-- .../java/peersim/kademlia/das/TurbulenceDas.java | 12 ++++++++---- .../peersim/kademlia/das/TurbulenceDasValidator.java | 12 ++++++++---- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index ca17d686..f327a3b3 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -22,7 +22,7 @@ TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP OBSERVER_STEP 20000 #Turbulence module is executed every TURBULENCE_STEP enabling churning -TURBULENCE_STEP 1000 +TURBULENCE_STEP 100 TURBULENCE_STEP_NONVAL 1000 @@ -102,7 +102,7 @@ control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 control.0traffic.block_dim_size 100 -control.0traffic.num_samples 75 +control.0traffic.num_samples 25 control.0traffic.kadprotocol 3kademlia # turbulence non-validator diff --git a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java index 28d52e8b..4320adac 100644 --- a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java @@ -170,10 +170,14 @@ public boolean add() { } } - for (int k = 0; k < 25; k++) { - KademliaProtocol jKad = (KademliaProtocol) (Network.get(k).getProtocol(kademliaid)); - if (jKad.getKademliaNode().isServer()) { - newKad.getRoutingTable().addNeighbour(jKad.getKademliaNode().getId()); + int k = 0; + while(k<25) { + if(Network.get(k).isUp()){ + KademliaProtocol jKad = (KademliaProtocol) (Network.get(k).getProtocol(kademliaid)); + if (jKad.getKademliaNode().isServer()) { + newKad.getRoutingTable().addNeighbour(jKad.getKademliaNode().getId()); + } + k++; } } for (int j = 0; j < 3; j++) { diff --git a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java index 3b816816..fc8c38cb 100644 --- a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java @@ -171,10 +171,14 @@ public boolean add() { } } - for (int k = 0; k < 25; k++) { - KademliaProtocol jKad = (KademliaProtocol) (Network.get(k).getProtocol(kademliaid)); - if (jKad.getKademliaNode().isServer()) { - newKad.getRoutingTable().addNeighbour(jKad.getKademliaNode().getId()); + int k = 0; + while(k<25) { + if(Network.get(k).isUp()){ + KademliaProtocol jKad = (KademliaProtocol) (Network.get(k).getProtocol(kademliaid)); + if (jKad.getKademliaNode().isServer()) { + newKad.getRoutingTable().addNeighbour(jKad.getKademliaNode().getId()); + } + k++; } } for (int j = 0; j < 3; j++) { From 9d6d15679c8e17ae6d7cebec886dccfb116e391a Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Thu, 19 Oct 2023 15:33:42 +0200 Subject: [PATCH 28/98] update last seen only when direct contact neighbour --- simulator/config/dasprotocol.cfg | 26 +++++++++---------- .../peersim/kademlia/das/DASProtocol.java | 2 +- .../peersim/kademlia/das/SearchTable.java | 18 +++++++------ .../peersim/kademlia/das/TurbulenceDas.java | 4 +-- .../kademlia/das/TurbulenceDasValidator.java | 4 +-- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index f327a3b3..96495d33 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -22,7 +22,7 @@ TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP OBSERVER_STEP 20000 #Turbulence module is executed every TURBULENCE_STEP enabling churning -TURBULENCE_STEP 100 +TURBULENCE_STEP 100000000 TURBULENCE_STEP_NONVAL 1000 @@ -102,7 +102,7 @@ control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 control.0traffic.block_dim_size 100 -control.0traffic.num_samples 25 +control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia # turbulence non-validator @@ -119,17 +119,17 @@ control.0traffic.kadprotocol 3kademlia #control.2turbolenceAdd.p_add 0.45 # # turbulence validators -control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator -control.3turbolenceAdd.protocolkad 3kademlia -control.3turbolenceAdd.protocoldasbuilder 4dasprotocol -control.3turbolenceAdd.protocoldasvalidator 5dasprotocol -control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol -control.3turbolenceAdd.protocolEvildas 7evildasprotocol -control.3turbolenceAdd.transport 2unreltr -control.3turbolenceAdd.step TURBULENCE_STEP -control.3turbolenceAdd.p_idle 0.9 -control.3turbolenceAdd.p_rem 0.05 -control.3turbolenceAdd.p_add 0.05 +#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +#control.3turbolenceAdd.protocolkad 3kademlia +#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.3turbolenceAdd.protocolEvildas 7evildasprotocol +#control.3turbolenceAdd.transport 2unreltr +#control.3turbolenceAdd.step TURBULENCE_STEP +#control.3turbolenceAdd.p_idle 0.9 +#control.3turbolenceAdd.p_rem 0.05 +#control.3turbolenceAdd.p_add 0.05 # ::::: OBSERVER ::::: #The observer is executed every OBSERVER_STEP and will generate data traces diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 679b7f3f..c1b4dd8c 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -212,7 +212,7 @@ public void processEvent(Node myNode, int myPid, Object event) { sop.elaborateResponse(null, null); } } - searchTable.removeNode(t.node); + // searchTable.removeNode(t.node); } if (sop != null) { doSampling(sop); diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index b2f15dfb..a51650d3 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -9,6 +9,8 @@ import java.util.List; import java.util.Set; import java.util.TreeSet; + +import peersim.core.CommonState; // import peersim.kademlia.KademliaCommonConfig; import peersim.core.Node; @@ -66,10 +68,10 @@ public SearchTable(/*Block currentblock , BigInteger id*/ ) { }*/ public void addNeighbour(Neighbour neigh) { - neighbours.remove(neigh.getId()); - nodesIndexed.remove(neigh.getId()); - neighbours.put(neigh.getId(), neigh); - nodesIndexed.add(neigh.getId()); + if (neighbours.get(neigh.getId()) == null) { + neighbours.put(neigh.getId(), neigh); + nodesIndexed.add(neigh.getId()); + } } public void addNodes(BigInteger[] nodes) { @@ -88,11 +90,11 @@ public void addNodes(BigInteger[] nodes) { public void seenNeighbour(BigInteger id, Node n) { if (id.compareTo(builderAddress) != 0) { if (neighbours.get(id) != null) { - neighbours.remove(id); - nodesIndexed.remove(id); + neighbours.get(id).updateLastSeen(CommonState.getTime()); + } else { + nodesIndexed.add(id); + neighbours.put(id, new Neighbour(id, n, n.getDASProtocol().isEvil())); } - nodesIndexed.add(id); - neighbours.put(id, new Neighbour(id, n, n.getDASProtocol().isEvil())); } } diff --git a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java index 4320adac..32b5f199 100644 --- a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java @@ -171,8 +171,8 @@ public boolean add() { } int k = 0; - while(k<25) { - if(Network.get(k).isUp()){ + while (k < 25) { + if (Network.get(k).isUp()) { KademliaProtocol jKad = (KademliaProtocol) (Network.get(k).getProtocol(kademliaid)); if (jKad.getKademliaNode().isServer()) { newKad.getRoutingTable().addNeighbour(jKad.getKademliaNode().getId()); diff --git a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java index fc8c38cb..7e74cd38 100644 --- a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java @@ -172,8 +172,8 @@ public boolean add() { } int k = 0; - while(k<25) { - if(Network.get(k).isUp()){ + while (k < 25) { + if (Network.get(k).isUp()) { KademliaProtocol jKad = (KademliaProtocol) (Network.get(k).getProtocol(kademliaid)); if (jKad.getKademliaNode().isServer()) { newKad.getRoutingTable().addNeighbour(jKad.getKademliaNode().getId()); From 58d9214342d9e0215163fbafb9cffb9550e19e8f Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Thu, 19 Oct 2023 16:03:27 +0200 Subject: [PATCH 29/98] refresh search table in config --- simulator/config/dasprotocol.cfg | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 96495d33..4409bbff 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -24,7 +24,7 @@ OBSERVER_STEP 20000 #Turbulence module is executed every TURBULENCE_STEP enabling churning TURBULENCE_STEP 100000000 TURBULENCE_STEP_NONVAL 1000 - +REFRESH_STEP 1000 # add network config parameters to simulation random.seed 24680 @@ -105,6 +105,10 @@ control.0traffic.block_dim_size 100 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia +#TrafficGenerator class sends and initial +control.1refresh peersim.kademlia.das.RefreshSearchTable +control.1refresh.step REFRESH_STEP + # turbulence non-validator #control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas #control.2turbolenceAdd.protocolkad 3kademlia From 47fe624f1420913bd550209a4b7783692136b09b Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Thu, 19 Oct 2023 16:04:59 +0200 Subject: [PATCH 30/98] refresh search table in config --- .../src/main/java/peersim/kademlia/das/RefreshSearchTable.java | 3 ++- simulator/src/main/java/peersim/kademlia/das/SearchTable.java | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/RefreshSearchTable.java b/simulator/src/main/java/peersim/kademlia/das/RefreshSearchTable.java index 13cab7f3..c2ca0923 100644 --- a/simulator/src/main/java/peersim/kademlia/das/RefreshSearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/RefreshSearchTable.java @@ -1,9 +1,10 @@ package peersim.kademlia.das; +import peersim.core.Control; import peersim.core.Network; import peersim.core.Node; -public class RefreshSearchTable { +public class RefreshSearchTable implements Control { private String prefix; // ______________________________________________________________________________________________ diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index a51650d3..7b42222d 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -9,7 +9,6 @@ import java.util.List; import java.util.Set; import java.util.TreeSet; - import peersim.core.CommonState; // import peersim.kademlia.KademliaCommonConfig; import peersim.core.Node; From 6e1506b74527b10464fb1aa81b7d6f91d4211401 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Thu, 19 Oct 2023 19:22:49 +0200 Subject: [PATCH 31/98] fix bug when no nodes found for a sample --- simulator/config/dasprotocol.cfg | 26 +++++++++---------- .../peersim/kademlia/das/DASProtocol.java | 21 +++++++++------ .../operations/RandomSamplingOperation.java | 2 +- .../ValidatorSamplingOperation.java | 4 +-- 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 4409bbff..2e0690c9 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -22,7 +22,7 @@ TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP OBSERVER_STEP 20000 #Turbulence module is executed every TURBULENCE_STEP enabling churning -TURBULENCE_STEP 100000000 +TURBULENCE_STEP 1000 TURBULENCE_STEP_NONVAL 1000 REFRESH_STEP 1000 @@ -122,18 +122,18 @@ control.1refresh.step REFRESH_STEP #control.2turbolenceAdd.p_rem 0.45 #control.2turbolenceAdd.p_add 0.45 -# # turbulence validators -#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator -#control.3turbolenceAdd.protocolkad 3kademlia -#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol -#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol -#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol -#control.3turbolenceAdd.protocolEvildas 7evildasprotocol -#control.3turbolenceAdd.transport 2unreltr -#control.3turbolenceAdd.step TURBULENCE_STEP -#control.3turbolenceAdd.p_idle 0.9 -#control.3turbolenceAdd.p_rem 0.05 -#control.3turbolenceAdd.p_add 0.05 +# turbulence validators +control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +control.3turbolenceAdd.protocolkad 3kademlia +control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +control.3turbolenceAdd.protocolEvildas 7evildasprotocol +control.3turbolenceAdd.transport 2unreltr +control.3turbolenceAdd.step TURBULENCE_STEP +control.3turbolenceAdd.p_idle 0.9 +control.3turbolenceAdd.p_rem 0.05 +control.3turbolenceAdd.p_add 0.05 # ::::: OBSERVER ::::: #The observer is executed every OBSERVER_STEP and will generate data traces diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index c1b4dd8c..14ef12de 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -313,6 +313,7 @@ protected void handleGetSample(Message m, int myPid) { // if (!isValidator()) // logger.warning("Non-validator received " + samples.size() + " from " + m.src.getId()); + boolean sampleFound = false; for (BigInteger id : samples) { logger.info("Requesting sample " + id + " from " + m.src.getId()); Sample sample = (Sample) kv.get(id); @@ -327,6 +328,7 @@ protected void handleGetSample(Message m, int myPid) { response.value = searchTable.getNeighbours(); sendMessage(response, m.src.getId(), myPid); + sampleFound = true; } else { if (missingSamples.containsKey(id)) missingSamples.get(id).add(m); else { @@ -337,6 +339,16 @@ protected void handleGetSample(Message m, int myPid) { // logger.warning("Sample request missing"); } } + if (!sampleFound) { + Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, new Sample[] {}); + response.operationId = m.operationId; + response.dst = m.src; + response.src = this.kadProtocol.getKademliaNode(); + response.ackId = m.id; // set ACK number + response.value = searchTable.getNeighbours(); + + sendMessage(response, m.src.getId(), myPid); + } // return a random subset of samples (if more than MAX_SAMPLES_RETURNED) // Collections.shuffle(s); // Sample[] returnedSamples; @@ -408,13 +420,6 @@ protected void handleGetSampleResponse(Message m, int myPid) { Sample[] samples = (Sample[]) m.body; // searchTable.addNodes((BigInteger[]) m.value); - logger.info( - "Get sample response " - + samples[0].getId() - + " " - + samples[0].getIdByColumn() - + " samples from " - + m.src.getId()); KademliaObserver.reportPeerDiscovery(m, searchTable); for (Neighbour neigh : (Neighbour[]) m.value) { @@ -460,7 +465,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { + searchTable.getValidatorsNeighboursCount() + " " + op); - if (op != null) { + if (op != null && samples.length > 0) { // keeping track of received samples op.elaborateResponse(samples, m.src.getId()); logger.warning( diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index 7be2be1e..2a5ded98 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -127,7 +127,7 @@ protected void createNodes() { BigInteger radiusUsed = radiusValidator; - while (nodesBySample.isEmpty()) { + while (nodesBySample.isEmpty() && radiusUsed.compareTo(Block.MAX_KEY) == -1) { nodesBySample.addAll( searchTable.getNodesbySample(samples.get(sample).getId(), radiusUsed)); // searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusUsed)); diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index 02ea7ea3..4b893b47 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -145,7 +145,7 @@ protected void createNodes() { // searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator); if (row > 0) { BigInteger radiusUsed = radiusValidator; - while (nodesBySample.isEmpty()) { + while (nodesBySample.isEmpty() && radiusUsed.compareTo(Block.MAX_KEY) == -1) { nodesBySample.addAll( searchTable.getNodesbySample(samples.get(sample).getId(), radiusUsed)); // searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusUsed)); @@ -157,7 +157,7 @@ protected void createNodes() { // radiusNonValidator)); } else { BigInteger radiusUsed = radiusValidator; - while (nodesBySample.isEmpty()) { + while (nodesBySample.isEmpty() && radiusUsed.compareTo(Block.MAX_KEY) == -1) { nodesBySample.addAll( searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusUsed)); // searchTable.getValidatorNodesbySample(samples.get(sample).getIdByColumn(), From f8b54f3ffaa3a160b90df781b35f69f65c525636 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Fri, 20 Oct 2023 14:31:07 +0200 Subject: [PATCH 32/98] fix bug do sampling --- simulator/config/dasprotocol.cfg | 44 +++++++++---------- .../peersim/kademlia/das/DASProtocol.java | 36 +++++++++------ .../peersim/kademlia/das/TurbulenceDas.java | 2 +- .../das/operations/SamplingOperation.java | 5 +++ 4 files changed, 51 insertions(+), 36 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 2e0690c9..5b3065ba 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -110,30 +110,30 @@ control.1refresh peersim.kademlia.das.RefreshSearchTable control.1refresh.step REFRESH_STEP # turbulence non-validator -#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas -#control.2turbolenceAdd.protocolkad 3kademlia -#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol -#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol -#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol -#control.2turbolenceAdd.protocolEvildas 7evildasprotocol -#control.2turbolenceAdd.transport 2unreltr -#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL -#control.2turbolenceAdd.p_idle 0.1 -#control.2turbolenceAdd.p_rem 0.45 -#control.2turbolenceAdd.p_add 0.45 +control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +control.2turbolenceAdd.protocolkad 3kademlia +control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +control.2turbolenceAdd.protocolEvildas 7evildasprotocol +control.2turbolenceAdd.transport 2unreltr +control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +control.2turbolenceAdd.p_idle 0.1 +control.2turbolenceAdd.p_rem 0.45 +control.2turbolenceAdd.p_add 0.45 # turbulence validators -control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator -control.3turbolenceAdd.protocolkad 3kademlia -control.3turbolenceAdd.protocoldasbuilder 4dasprotocol -control.3turbolenceAdd.protocoldasvalidator 5dasprotocol -control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol -control.3turbolenceAdd.protocolEvildas 7evildasprotocol -control.3turbolenceAdd.transport 2unreltr -control.3turbolenceAdd.step TURBULENCE_STEP -control.3turbolenceAdd.p_idle 0.9 -control.3turbolenceAdd.p_rem 0.05 -control.3turbolenceAdd.p_add 0.05 +#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +#control.3turbolenceAdd.protocolkad 3kademlia +#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.3turbolenceAdd.protocolEvildas 7evildasprotocol +#control.3turbolenceAdd.transport 2unreltr +#control.3turbolenceAdd.step TURBULENCE_STEP +#control.3turbolenceAdd.p_idle 0.9 +#control.3turbolenceAdd.p_rem 0.05 +#control.3turbolenceAdd.p_add 0.05 # ::::: OBSERVER ::::: #The observer is executed every OBSERVER_STEP and will generate data traces diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 14ef12de..9acfbfe4 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -281,8 +281,17 @@ protected void handleInitNewBlock(Message m, int myPid) { for (SamplingOperation sop : samplingOp.values()) { KademliaObserver.reportOperation(sop); if (sop instanceof ValidatorSamplingOperation) - logger.warning("Sampling operation finished validator " + sop.getId()); - else logger.warning("Sampling operation finished random " + sop.getId()); + logger.warning("Sampling operation finished validator failed" + sop.getId()); + else { + logger.warning("Sampling operation finished random failed" + sop.getId()); + for (BigInteger id : sop.getSamples()) { + logger.warning("Missing sample when failed " + id); + } + for (peersim.kademlia.das.operations.Node n : sop.getNodes()) { + + logger.warning("Missing sample failed pending node " + n.getId()); + } + } } samplingOp.clear(); kadOps.clear(); @@ -304,7 +313,7 @@ protected void handleSeedSample(Message m, int myPid) { protected void handleGetSample(Message m, int myPid) { // kv is for storing the sample you have - logger.info("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); + // logger.warning("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); // sample IDs that are requested in the message List samples = Arrays.asList((BigInteger[]) m.body); // samples to return @@ -315,7 +324,7 @@ protected void handleGetSample(Message m, int myPid) { boolean sampleFound = false; for (BigInteger id : samples) { - logger.info("Requesting sample " + id + " from " + m.src.getId()); + logger.warning("Requesting sample " + id + " from " + m.src.getId()); Sample sample = (Sample) kv.get(id); if (sample != null) { // s.add(sample); @@ -431,6 +440,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { kv.add((BigInteger) s.getIdByColumn(), s); // count # of samples for each row and column and reconstruct if more than half received reconstruct(s); + logger.warning("Sample received " + s.getId() + " " + s.getIdByColumn()); if (missingSamples.containsKey(s.getId()) || missingSamples.containsKey(s.getIdByColumn())) { logger.info("Sample received missing " + s.getId() + " " + s.getIdByColumn()); @@ -465,7 +475,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { + searchTable.getValidatorsNeighboursCount() + " " + op); - if (op != null && samples.length > 0) { + if (op != null) { // keeping track of received samples op.elaborateResponse(samples, m.src.getId()); logger.warning( @@ -478,7 +488,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { + " " + ((SamplingOperation) op).samplesCount()); - /*if (!op.completed() + if (!op.completed() && op.getHops() < KademliaCommonConfigDas.MAX_HOPS && (op instanceof ValidatorSamplingOperation && (CommonState.getTime() - op.getTimestamp()) @@ -487,7 +497,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { && (CommonState.getTime() - op.getTimestamp()) <= KademliaCommonConfigDas.RANDOM_SAMPLING_DEADLINE)) { doSampling(op); - } else {*/ + } // else { if (op.completed()) { logger.warning("Operation completed"); samplingOp.remove(m.operationId); @@ -698,7 +708,7 @@ protected boolean doSampling(SamplingOperation sop) { sendMessage(msg, nextNode, dasID); sop.getMessages(); } - if (!success) { + /*if (!success) { if (sop instanceof ValidatorSamplingOperation) logger.warning("Sampling operation finished validator failed " + sop.getId()); else { @@ -710,7 +720,7 @@ protected boolean doSampling(SamplingOperation sop) { samplingOp.remove(sop.getId()); KademliaObserver.reportOperation(sop); - } + }*/ } return success; } @@ -740,7 +750,7 @@ public void operationComplete(Operation op) { Node n = Util.nodeIdtoNode(id, kademliaId); searchTable.addNeighbour(new Neighbour(id, n, n.getDASProtocol().isEvil())); } - logger.warning( + /*logger.warning( "Search table operation complete" // + searchTable.samplesIndexed().size() // + " " @@ -761,7 +771,7 @@ public void operationComplete(Operation op) { + kadOps.size() + " " + kadOps.get(op).getAvailableRequests()); - kadOps.remove(op); + kadOps.remove(op);*/ } } @@ -783,7 +793,7 @@ public void nodesFound(Operation op, BigInteger[] neighbours) { Node n = Util.nodeIdtoNode(id, kademliaId); searchTable.addNeighbour(new Neighbour(id, n, n.getDASProtocol().isEvil())); } - logger.info( + /*logger.info( "Search table nodes found " // + searchTable.samplesIndexed().size() // + " " @@ -796,7 +806,7 @@ public void nodesFound(Operation op, BigInteger[] neighbours) { logger.info("Sampling operation found"); doSampling(kadOps.get(op)); } - } + }*/ } @Override diff --git a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java index 32b5f199..a287e7d3 100644 --- a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java @@ -214,7 +214,7 @@ public boolean rem() { && i > 0); // Remove node (set its state to DOWN) remove.setFailState(Node.DOWN); - System.out.println("Removing validator " + dasProt.getKademliaId()); + System.out.println("Removing non-validator " + dasProt.getKademliaId()); return false; } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index 27bd7bcb..70d77746 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -2,6 +2,7 @@ import java.math.BigInteger; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; @@ -128,6 +129,10 @@ public BigInteger[] doSampling() { return result.toArray(new BigInteger[0]); } + public Collection getNodes() { + return nodes.values(); + } + public abstract void elaborateResponse(Sample[] sam, BigInteger node); public abstract void elaborateResponse(Sample[] sam); From 1a5e3e7ee3d8ab1da88017de81ed9e537d7f0e9e Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Mon, 23 Oct 2023 13:31:56 +0200 Subject: [PATCH 33/98] fix bug das turbulence --- simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java | 2 +- .../main/java/peersim/kademlia/das/TurbulenceDasValidator.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java index a287e7d3..2b7d57a6 100644 --- a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java @@ -177,8 +177,8 @@ public boolean add() { if (jKad.getKademliaNode().isServer()) { newKad.getRoutingTable().addNeighbour(jKad.getKademliaNode().getId()); } - k++; } + k++; } for (int j = 0; j < 3; j++) { // send message diff --git a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java index 7e74cd38..462bc93f 100644 --- a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java @@ -178,8 +178,8 @@ public boolean add() { if (jKad.getKademliaNode().isServer()) { newKad.getRoutingTable().addNeighbour(jKad.getKademliaNode().getId()); } - k++; } + k++; } for (int j = 0; j < 3; j++) { // send message From a21af027fc034c95d507fbeff058cea61711b909 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Mon, 23 Oct 2023 14:42:51 +0200 Subject: [PATCH 34/98] enable periodic lookup --- simulator/config/dasprotocol.cfg | 46 +++++++++---------- .../kademlia/das/TrafficGeneratorSample.java | 10 ++-- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 5b3065ba..1b54d819 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -14,7 +14,7 @@ MINDELAY 5 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*2 +SIM_TIME 1000*60*10 #Traffic generator is executed every TRAFFIC_STEP @@ -110,30 +110,30 @@ control.1refresh peersim.kademlia.das.RefreshSearchTable control.1refresh.step REFRESH_STEP # turbulence non-validator -control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas -control.2turbolenceAdd.protocolkad 3kademlia -control.2turbolenceAdd.protocoldasbuilder 4dasprotocol -control.2turbolenceAdd.protocoldasvalidator 5dasprotocol -control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol -control.2turbolenceAdd.protocolEvildas 7evildasprotocol -control.2turbolenceAdd.transport 2unreltr -control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL -control.2turbolenceAdd.p_idle 0.1 -control.2turbolenceAdd.p_rem 0.45 -control.2turbolenceAdd.p_add 0.45 +#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +#control.2turbolenceAdd.protocolkad 3kademlia +#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.2turbolenceAdd.protocolEvildas 7evildasprotocol +#control.2turbolenceAdd.transport 2unreltr +#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +#control.2turbolenceAdd.p_idle 0.1 +#control.2turbolenceAdd.p_rem 0.45 +#control.2turbolenceAdd.p_add 0.45 # turbulence validators -#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator -#control.3turbolenceAdd.protocolkad 3kademlia -#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol -#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol -#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol -#control.3turbolenceAdd.protocolEvildas 7evildasprotocol -#control.3turbolenceAdd.transport 2unreltr -#control.3turbolenceAdd.step TURBULENCE_STEP -#control.3turbolenceAdd.p_idle 0.9 -#control.3turbolenceAdd.p_rem 0.05 -#control.3turbolenceAdd.p_add 0.05 +control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +control.3turbolenceAdd.protocolkad 3kademlia +control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +control.3turbolenceAdd.protocolEvildas 7evildasprotocol +control.3turbolenceAdd.transport 2unreltr +control.3turbolenceAdd.step TURBULENCE_STEP +control.3turbolenceAdd.p_idle 0.1 +control.3turbolenceAdd.p_rem 0.45 +control.3turbolenceAdd.p_add 0.45 # ::::: OBSERVER ::::: #The observer is executed every OBSERVER_STEP and will generate data traces diff --git a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java index f90a4aa8..8649539c 100755 --- a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java @@ -105,11 +105,11 @@ public boolean execute() { Node n = Network.get(i); // b.initIterator(); // we add 1 ms delay to be sure the builder starts before validators. - /*EDSimulator.add( - CommonState.r.nextLong(CommonState.getTime() - lastTime), - Util.generateFindNodeMessage(), - n, - kadpid);*/ + EDSimulator.add( + CommonState.r.nextLong(CommonState.getTime() - lastTime), + Util.generateFindNodeMessage(), + n, + kadpid); if (n.isUp()) EDSimulator.add(0, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); From a3bc0dd0f6414409b1f887a719ac8ed84f778b53 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Mon, 23 Oct 2023 15:13:46 +0200 Subject: [PATCH 35/98] removing logs --- .../src/main/java/peersim/kademlia/das/DASProtocol.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 9acfbfe4..11db3036 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -313,7 +313,7 @@ protected void handleSeedSample(Message m, int myPid) { protected void handleGetSample(Message m, int myPid) { // kv is for storing the sample you have - // logger.warning("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); + logger.info("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); // sample IDs that are requested in the message List samples = Arrays.asList((BigInteger[]) m.body); // samples to return @@ -324,7 +324,7 @@ protected void handleGetSample(Message m, int myPid) { boolean sampleFound = false; for (BigInteger id : samples) { - logger.warning("Requesting sample " + id + " from " + m.src.getId()); + logger.info("Requesting sample " + id + " from " + m.src.getId()); Sample sample = (Sample) kv.get(id); if (sample != null) { // s.add(sample); @@ -440,7 +440,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { kv.add((BigInteger) s.getIdByColumn(), s); // count # of samples for each row and column and reconstruct if more than half received reconstruct(s); - logger.warning("Sample received " + s.getId() + " " + s.getIdByColumn()); + logger.info("Sample received " + s.getId() + " " + s.getIdByColumn()); if (missingSamples.containsKey(s.getId()) || missingSamples.containsKey(s.getIdByColumn())) { logger.info("Sample received missing " + s.getId() + " " + s.getIdByColumn()); @@ -455,7 +455,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { response.src = this.kadProtocol.getKademliaNode(); response.ackId = msg.id; // set ACK number response.value = searchTable.getNeighbours(); - logger.warning("Sending sample to " + msg.src.getId()); + // logger.warning("Sending sample to " + msg.src.getId()); sendMessage(response, msg.src.getId(), myPid); } missingSamples.remove(s.getId()); From 6e6784598ab1000da9b66a3d8592ee8aa4beb7d7 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Tue, 24 Oct 2023 09:31:00 +0200 Subject: [PATCH 36/98] disable periodic kad lookups --- .../peersim/kademlia/das/TrafficGeneratorSample.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java index 8649539c..f90a4aa8 100755 --- a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java @@ -105,11 +105,11 @@ public boolean execute() { Node n = Network.get(i); // b.initIterator(); // we add 1 ms delay to be sure the builder starts before validators. - EDSimulator.add( - CommonState.r.nextLong(CommonState.getTime() - lastTime), - Util.generateFindNodeMessage(), - n, - kadpid); + /*EDSimulator.add( + CommonState.r.nextLong(CommonState.getTime() - lastTime), + Util.generateFindNodeMessage(), + n, + kadpid);*/ if (n.isUp()) EDSimulator.add(0, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); From 9839c88c225ae267f304a148202324f23267f1e8 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Wed, 25 Oct 2023 14:30:04 +0200 Subject: [PATCH 37/98] update in search table, avoid dead nodes discovery --- simulator/config/dasprotocol.cfg | 4 ++-- .../peersim/kademlia/das/DASProtocol.java | 18 +++++++++------- .../kademlia/das/DASProtocolNonValidator.java | 1 + .../kademlia/das/DASProtocolValidator.java | 1 + .../kademlia/das/KademliaCommonConfigDas.java | 2 +- .../java/peersim/kademlia/das/Neighbour.java | 4 ++++ .../peersim/kademlia/das/SearchTable.java | 9 ++++---- .../kademlia/das/TrafficGeneratorSample.java | 2 +- .../peersim/kademlia/das/TurbulenceDas.java | 21 ++++++++++++------- .../kademlia/das/TurbulenceDasValidator.java | 20 +++++++++++------- 10 files changed, 51 insertions(+), 31 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 1b54d819..e3a77564 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -14,7 +14,7 @@ MINDELAY 5 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*10 +SIM_TIME 1000*60*5 #Traffic generator is executed every TRAFFIC_STEP @@ -22,7 +22,7 @@ TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP OBSERVER_STEP 20000 #Turbulence module is executed every TURBULENCE_STEP enabling churning -TURBULENCE_STEP 1000 +TURBULENCE_STEP 100 TURBULENCE_STEP_NONVAL 1000 REFRESH_STEP 1000 diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 11db3036..239e090b 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -96,7 +96,7 @@ public abstract class DASProtocol implements Cloneable, EDProtocol, KademliaEven protected boolean isEvil; - protected boolean missing; + protected boolean init; protected HashMap> missingSamples; @@ -142,6 +142,7 @@ public DASProtocol(String prefix) { nonValidatorsIndexed = new TreeSet<>(); isBuilder = false; missingSamples = new HashMap<>(); + init = false; } /** @@ -170,8 +171,10 @@ public void processEvent(Node myNode, int myPid, Object event) { m = (Message) event; // m.dst = this.kadProtocol.getKademliaNode(); KademliaObserver.reportMsg(m, false); - if (m.src != null) - searchTable.seenNeighbour(m.src.getId(), Util.nodeIdtoNode(m.src.getId(), kademliaId)); + if (m.src != null) { + Node n = Util.nodeIdtoNode(m.src.getId(), kademliaId); + searchTable.addNeighbour(new Neighbour(m.src.getId(), n, n.getDASProtocol().isEvil())); + } } switch (((SimpleEvent) event).getType()) { @@ -269,7 +272,7 @@ public BigInteger getBuilderAddress() { * @param myPid the sender Pid */ protected void handleInitNewBlock(Message m, int myPid) { - missing = false; + init = true; time = CommonState.getTime(); currentBlock = (Block) m.body; kv.erase(); @@ -430,6 +433,8 @@ protected void handleGetSampleResponse(Message m, int myPid) { Sample[] samples = (Sample[]) m.body; // searchTable.addNodes((BigInteger[]) m.value); + logger.warning("Samples received " + samples.length); + KademliaObserver.reportPeerDiscovery(m, searchTable); for (Neighbour neigh : (Neighbour[]) m.value) { if (neigh.getId().compareTo(builderAddress) != 0) searchTable.addNeighbour(neigh); @@ -440,7 +445,6 @@ protected void handleGetSampleResponse(Message m, int myPid) { kv.add((BigInteger) s.getIdByColumn(), s); // count # of samples for each row and column and reconstruct if more than half received reconstruct(s); - logger.info("Sample received " + s.getId() + " " + s.getIdByColumn()); if (missingSamples.containsKey(s.getId()) || missingSamples.containsKey(s.getIdByColumn())) { logger.info("Sample received missing " + s.getId() + " " + s.getIdByColumn()); @@ -696,7 +700,7 @@ protected boolean doSampling(SamplingOperation sop) { Message msg = generateGetSampleMessage(reqSamples); msg.operationId = sop.getId(); msg.src = this.kadProtocol.getKademliaNode(); - if (missing) msg.value = reqSamples; + // if (missing) msg.value = reqSamples; success = true; msg.dst = Util.nodeIdtoNode(nextNode, kademliaId).getKademliaProtocol().getKademliaNode(); /*if (nextNode.compareTo(builderAddress) == 0) { @@ -813,7 +817,7 @@ public void nodesFound(Operation op, BigInteger[] neighbours) { public void missing(BigInteger sample, Operation op) { logger.warning("Missing nodes for sample " + sample + " " + kadOps.size()); - missing = true; + // missing = true; } // ______________________________________________________________________________________________ diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java index 800dabd1..788a5a54 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java @@ -22,6 +22,7 @@ public DASProtocolNonValidator(String prefix) { @Override protected void handleInitGetSample(Message m, int myPid) { + if (!init) return; logger.warning("Init block non-validator node - getting samples " + this); // super.handleInitGetSample(m, myPid); if (currentBlock == null) System.err.println("Error block not init yet"); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index 1e3a5955..3a657abf 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -20,6 +20,7 @@ public DASProtocolValidator(String prefix) { @Override protected void handleInitGetSample(Message m, int myPid) { + if (!init) return; logger.warning("Init block validator node - getting samples " + this); if (currentBlock == null) System.err.println("Error block not init yet"); BigInteger[] samples = (BigInteger[]) m.body; diff --git a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java index 85d322cc..8a5b8ebe 100644 --- a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java @@ -64,5 +64,5 @@ public class KademliaCommonConfigDas { public static int validatorsSize = 0; public static int networkSize = 0; - public static long TTL = 60000; + public static long TTL = 30000; } diff --git a/simulator/src/main/java/peersim/kademlia/das/Neighbour.java b/simulator/src/main/java/peersim/kademlia/das/Neighbour.java index 54f3c476..c531215e 100644 --- a/simulator/src/main/java/peersim/kademlia/das/Neighbour.java +++ b/simulator/src/main/java/peersim/kademlia/das/Neighbour.java @@ -22,6 +22,10 @@ public BigInteger getId() { return id; } + public long getLastSeen() { + return last_seen; + } + public void updateLastSeen(long time) { last_seen = time; } diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index 7b42222d..32884a1c 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -9,9 +9,7 @@ import java.util.List; import java.util.Set; import java.util.TreeSet; -import peersim.core.CommonState; // import peersim.kademlia.KademliaCommonConfig; -import peersim.core.Node; public class SearchTable { @@ -70,6 +68,9 @@ public void addNeighbour(Neighbour neigh) { if (neighbours.get(neigh.getId()) == null) { neighbours.put(neigh.getId(), neigh); nodesIndexed.add(neigh.getId()); + } else { + if (neighbours.get(neigh.getId()).getLastSeen() < neigh.getLastSeen()) + neighbours.get(neigh.getId()).updateLastSeen(neigh.getLastSeen()); } } @@ -86,7 +87,7 @@ public void addNodes(BigInteger[] nodes) { } } - public void seenNeighbour(BigInteger id, Node n) { + /*public void seenNeighbour(BigInteger id, Node n) { if (id.compareTo(builderAddress) != 0) { if (neighbours.get(id) != null) { neighbours.get(id).updateLastSeen(CommonState.getTime()); @@ -95,7 +96,7 @@ public void seenNeighbour(BigInteger id, Node n) { neighbours.put(id, new Neighbour(id, n, n.getDASProtocol().isEvil())); } } - } + }*/ /*public void addNonValidatorNodes(BigInteger[] nodes) { diff --git a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java index f90a4aa8..7e986629 100755 --- a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java @@ -79,7 +79,7 @@ private Message generateNewBlockMessage(Block b) { */ public boolean execute() { Block b = new Block(KademliaCommonConfigDas.BLOCK_DIM_SIZE, ID_GENERATOR); - + System.out.println(CommonState.getTime() + " next"); if (first) { for (int i = 0; i < Network.size(); i++) { Node start = Network.get(i); diff --git a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java index 2b7d57a6..1cb1c788 100644 --- a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDas.java @@ -7,12 +7,10 @@ import peersim.core.Network; import peersim.core.Node; import peersim.dynamics.NodeInitializer; -import peersim.edsim.EDSimulator; import peersim.kademlia.KademliaCommonConfig; import peersim.kademlia.KademliaNode; import peersim.kademlia.KademliaProtocol; import peersim.kademlia.UniformRandomGenerator; -import peersim.kademlia.Util; /** * Turbulcen class is only for test/statistical purpose. This Control execute a node add or remove @@ -161,7 +159,7 @@ public boolean add() { newNode.setProtocol(dasprotnonvalid, null); int count = 0; - BigInteger builderAddress; + BigInteger builderAddress = BigInteger.valueOf(0); for (int i = 0; i < Network.size(); ++i) { if (Network.get(i).isUp()) count++; if (Network.get(i).getDASProtocol().isBuilder()) { @@ -170,22 +168,29 @@ public boolean add() { } } + /*Node builder = Util.nodeIdtoNode(builderAddress, dasprotbuildid); + DASProtocol builderDAS = builder.getDASProtocol(); + builderDAS.getSearchTable().addValidatorNodes(new BigInteger[] {dasProt.getKademliaId()});*/ int k = 0; - while (k < 25) { - if (Network.get(k).isUp()) { - KademliaProtocol jKad = (KademliaProtocol) (Network.get(k).getProtocol(kademliaid)); + while (k < 100) { + Node n = Network.get(CommonState.r.nextInt(Network.size())); + if (n.isUp()) { + KademliaProtocol jKad = (KademliaProtocol) n.getProtocol(kademliaid); if (jKad.getKademliaNode().isServer()) { newKad.getRoutingTable().addNeighbour(jKad.getKademliaNode().getId()); + dasProt.searchTable.addNeighbour( + new Neighbour(jKad.getKademliaNode().getId(), n, n.getDASProtocol().isEvil())); } } k++; } - for (int j = 0; j < 3; j++) { + /*for (int j = 0; j < 3; j++) { // send message EDSimulator.add(0, Util.generateFindNodeMessage(), newNode, kademliaid); } EDSimulator.add( - 0, Util.generateFindNodeMessage(newKad.getKademliaNode().getId()), newNode, kademliaid); + 0, Util.generateFindNodeMessage(newKad.getKademliaNode().getId()), newNode, kademliaid);*/ + System.out.println( CommonState.getTime() + " Adding non-validator node " diff --git a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java index 462bc93f..331fb536 100644 --- a/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/TurbulenceDasValidator.java @@ -7,7 +7,6 @@ import peersim.core.Network; import peersim.core.Node; import peersim.dynamics.NodeInitializer; -import peersim.edsim.EDSimulator; import peersim.kademlia.KademliaCommonConfig; import peersim.kademlia.KademliaNode; import peersim.kademlia.KademliaProtocol; @@ -162,7 +161,7 @@ public boolean add() { newNode.setProtocol(dasprotnonvalid, null); int count = 0; - BigInteger builderAddress; + BigInteger builderAddress = BigInteger.valueOf(0); for (int i = 0; i < Network.size(); ++i) { if (Network.get(i).isUp()) count++; if (Network.get(i).getDASProtocol().isBuilder()) { @@ -171,22 +170,28 @@ public boolean add() { } } + Node builder = Util.nodeIdtoNode(builderAddress, kademliaid); + DASProtocol builderDAS = builder.getDASProtocol(); + builderDAS.getSearchTable().addValidatorNodes(new BigInteger[] {dasProt.getKademliaId()}); int k = 0; - while (k < 25) { - if (Network.get(k).isUp()) { - KademliaProtocol jKad = (KademliaProtocol) (Network.get(k).getProtocol(kademliaid)); + while (k < 100) { + Node n = Network.get(CommonState.r.nextInt(Network.size())); + if (n.isUp()) { + KademliaProtocol jKad = (KademliaProtocol) n.getProtocol(kademliaid); if (jKad.getKademliaNode().isServer()) { newKad.getRoutingTable().addNeighbour(jKad.getKademliaNode().getId()); + dasProt.searchTable.addNeighbour( + new Neighbour(jKad.getKademliaNode().getId(), n, n.getDASProtocol().isEvil())); } } k++; } - for (int j = 0; j < 3; j++) { + /*for (int j = 0; j < 3; j++) { // send message EDSimulator.add(0, Util.generateFindNodeMessage(), newNode, kademliaid); } EDSimulator.add( - 0, Util.generateFindNodeMessage(newKad.getKademliaNode().getId()), newNode, kademliaid); + 0, Util.generateFindNodeMessage(newKad.getKademliaNode().getId()), newNode, kademliaid);*/ System.out.println( CommonState.getTime() + " Adding validator node " @@ -195,7 +200,6 @@ public boolean add() { + newKad.getKademliaNode().getId() + " " + dasProt.getBuilderAddress()); - return false; } From e79327b89d2d027c5e876f8fb70cce24bd844c2f Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Thu, 26 Oct 2023 10:16:00 +0200 Subject: [PATCH 38/98] add report discovery in the configuration --- simulator/config/dasprotocol.cfg | 36 ++++++++++--------- .../peersim/kademlia/das/DASProtocol.java | 8 ++++- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index e3a77564..1ad9d0be 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -14,7 +14,7 @@ MINDELAY 5 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*5 +SIM_TIME 1000*60*1 #Traffic generator is executed every TRAFFIC_STEP @@ -22,8 +22,8 @@ TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP OBSERVER_STEP 20000 #Turbulence module is executed every TURBULENCE_STEP enabling churning -TURBULENCE_STEP 100 -TURBULENCE_STEP_NONVAL 1000 +TURBULENCE_STEP 10000 +TURBULENCE_STEP_NONVAL 100 REFRESH_STEP 1000 # add network config parameters to simulation @@ -63,18 +63,22 @@ protocol.3kademlia.FINDMODE 1 protocol.4dasprotocol peersim.kademlia.das.DASProtocolBuilder protocol.4dasprotocol.transport 2unreltr protocol.4dasprotocol.kademlia 3kademlia +protocol.4dasprotocol.reportDiscovery false protocol.5dasprotocol peersim.kademlia.das.DASProtocolValidator protocol.5dasprotocol.transport 2unreltr protocol.5dasprotocol.kademlia 3kademlia +protocol.5dasprotocol.reportDiscovery false protocol.6dasprotocol peersim.kademlia.das.DASProtocolNonValidator protocol.6dasprotocol.transport 2unreltr protocol.6dasprotocol.kademlia 3kademlia +protocol.6dasprotocol.reportDiscovery false protocol.7evildasprotocol peersim.kademlia.das.EvilDASProtocol protocol.7evildasprotocol.transport 2unreltr protocol.7evildasprotocol.kademlia 3kademlia +protocol.7evildasprotocol.reportDiscovery false # ::::: INITIALIZERS ::::: #Class that initializes nodes with kademlia protocol and generates uniform ids @@ -84,7 +88,7 @@ init.1uniqueNodeID.protocoldasbuilder 4dasprotocol init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvildas 7evildasprotocol -init.1uniqueNodeID.validator_rate 1.0 +init.1uniqueNodeID.validator_rate 0.5 init.1uniqueNodeID.evilNodeRatioValidator 0.0 init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 @@ -110,17 +114,17 @@ control.1refresh peersim.kademlia.das.RefreshSearchTable control.1refresh.step REFRESH_STEP # turbulence non-validator -#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas -#control.2turbolenceAdd.protocolkad 3kademlia -#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol -#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol -#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol -#control.2turbolenceAdd.protocolEvildas 7evildasprotocol -#control.2turbolenceAdd.transport 2unreltr -#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL -#control.2turbolenceAdd.p_idle 0.1 -#control.2turbolenceAdd.p_rem 0.45 -#control.2turbolenceAdd.p_add 0.45 +control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +control.2turbolenceAdd.protocolkad 3kademlia +control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +control.2turbolenceAdd.protocolEvildas 7evildasprotocol +control.2turbolenceAdd.transport 2unreltr +control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +control.2turbolenceAdd.p_idle 0.1 +control.2turbolenceAdd.p_rem 0.45 +control.2turbolenceAdd.p_add 0.45 # turbulence validators control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator @@ -140,4 +144,4 @@ control.3turbolenceAdd.p_add 0.45 control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logsDas +control.4.logfolder logsDas2 diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 239e090b..8e9c0884 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -45,6 +45,9 @@ public abstract class DASProtocol implements Cloneable, EDProtocol, KademliaEven protected static final String PAR_KADEMLIA = "kademlia"; protected static final String PAR_ALPHA = "alpha"; protected static final String PAR_PARCEL = "parcelSize"; + protected static final String PAR_DISC = "reportDiscovery"; + + private boolean reportDiscovery; private static String prefix = null; private UnreliableTransport transport; /** Store the time until which this node's uplink is busy sending data */ @@ -128,6 +131,9 @@ public DASProtocol(String prefix) { KademliaCommonConfigDas.PARCEL_SIZE = Configuration.getInt(prefix + "." + PAR_PARCEL, KademliaCommonConfigDas.PARCEL_SIZE); + + reportDiscovery = Configuration.getBoolean(prefix + "." + PAR_DISC, false); + kv = new KeyValueStore(); samplingOp = new LinkedHashMap(); kadOps = new LinkedHashMap(); @@ -435,7 +441,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { logger.warning("Samples received " + samples.length); - KademliaObserver.reportPeerDiscovery(m, searchTable); + if (reportDiscovery) KademliaObserver.reportPeerDiscovery(m, searchTable); for (Neighbour neigh : (Neighbour[]) m.value) { if (neigh.getId().compareTo(builderAddress) != 0) searchTable.addNeighbour(neigh); } From da8e55130ec1a4f8372aacfb3795a0689a540c30 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Thu, 26 Oct 2023 15:31:21 +0200 Subject: [PATCH 39/98] fix bug removing fetching samples from queried nodes --- simulator/config/dasprotocol.cfg | 50 ++++---- .../kademlia/das/CustomDistributionDas.java | 14 +++ .../peersim/kademlia/das/DASProtocol.java | 111 ++---------------- .../kademlia/das/TrafficGeneratorSample.java | 39 +++--- .../peersim/kademlia/das/operations/Node.java | 4 + .../operations/RandomSamplingOperation.java | 35 ++---- .../das/operations/SamplingOperation.java | 59 ++++++++-- .../ValidatorSamplingOperation.java | 27 ++--- 8 files changed, 133 insertions(+), 206 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 1ad9d0be..07b6e6cb 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -14,7 +14,7 @@ MINDELAY 5 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*1 +SIM_TIME 1000*60*5 #Traffic generator is executed every TRAFFIC_STEP @@ -22,8 +22,8 @@ TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP OBSERVER_STEP 20000 #Turbulence module is executed every TURBULENCE_STEP enabling churning -TURBULENCE_STEP 10000 -TURBULENCE_STEP_NONVAL 100 +TURBULENCE_STEP 1000000 +TURBULENCE_STEP_NONVAL 1000000 REFRESH_STEP 1000 # add network config parameters to simulation @@ -114,30 +114,30 @@ control.1refresh peersim.kademlia.das.RefreshSearchTable control.1refresh.step REFRESH_STEP # turbulence non-validator -control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas -control.2turbolenceAdd.protocolkad 3kademlia -control.2turbolenceAdd.protocoldasbuilder 4dasprotocol -control.2turbolenceAdd.protocoldasvalidator 5dasprotocol -control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol -control.2turbolenceAdd.protocolEvildas 7evildasprotocol -control.2turbolenceAdd.transport 2unreltr -control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL -control.2turbolenceAdd.p_idle 0.1 -control.2turbolenceAdd.p_rem 0.45 -control.2turbolenceAdd.p_add 0.45 +#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +#control.2turbolenceAdd.protocolkad 3kademlia +#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.2turbolenceAdd.protocolEvildas 7evildasprotocol +#control.2turbolenceAdd.transport 2unreltr +#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +#control.2turbolenceAdd.p_idle 0.1 +#control.2turbolenceAdd.p_rem 0.45 +#control.2turbolenceAdd.p_add 0.45 # turbulence validators -control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator -control.3turbolenceAdd.protocolkad 3kademlia -control.3turbolenceAdd.protocoldasbuilder 4dasprotocol -control.3turbolenceAdd.protocoldasvalidator 5dasprotocol -control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol -control.3turbolenceAdd.protocolEvildas 7evildasprotocol -control.3turbolenceAdd.transport 2unreltr -control.3turbolenceAdd.step TURBULENCE_STEP -control.3turbolenceAdd.p_idle 0.1 -control.3turbolenceAdd.p_rem 0.45 -control.3turbolenceAdd.p_add 0.45 +#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +#control.3turbolenceAdd.protocolkad 3kademlia +#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.3turbolenceAdd.protocolEvildas 7evildasprotocol +#control.3turbolenceAdd.transport 2unreltr +#control.3turbolenceAdd.step TURBULENCE_STEP +#control.3turbolenceAdd.p_idle 0.1 +#control.3turbolenceAdd.p_rem 0.45 +#control.3turbolenceAdd.p_add 0.45 # ::::: OBSERVER ::::: #The observer is executed every OBSERVER_STEP and will generate data traces diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index 191b51ef..619a56e5 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -162,7 +162,21 @@ public boolean execute() { .getSearchTable() .addNeighbour(new Neighbour(n.getDASProtocol().getKademliaId(), n, false)); }*/ + int k = 0; + while (k < 100) { + Node n = Network.get(CommonState.r.nextInt(Network.size())); + if (n.isUp()) { + KademliaProtocol jKad = (KademliaProtocol) n.getProtocol(protocolKadID); + generalNode + .getDASProtocol() + .searchTable + .addNeighbour( + new Neighbour(jKad.getKademliaNode().getId(), n, n.getDASProtocol().isEvil())); + } + k++; + } } + KademliaCommonConfigDas.networkSize = Network.size(); KademliaCommonConfigDas.validatorsSize = numValidators; return false; diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 8e9c0884..8cf4c093 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -217,8 +217,8 @@ public void processEvent(Node myNode, int myPid, Object event) { // this.searchTable.removeNode(t.node); if (sop != null) { if (!sop.completed()) { - logger.warning("Samping operation found"); - sop.elaborateResponse(null, null); + logger.warning("Sampling operation found " + sop.getId()); + sop.elaborateResponse(null, t.node); } } // searchTable.removeNode(t.node); @@ -325,11 +325,6 @@ protected void handleGetSample(Message m, int myPid) { logger.info("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); // sample IDs that are requested in the message List samples = Arrays.asList((BigInteger[]) m.body); - // samples to return - // List s = new ArrayList<>(); - - // if (!isValidator()) - // logger.warning("Non-validator received " + samples.size() + " from " + m.src.getId()); boolean sampleFound = false; for (BigInteger id : samples) { @@ -367,47 +362,6 @@ protected void handleGetSample(Message m, int myPid) { sendMessage(response, m.src.getId(), myPid); } - // return a random subset of samples (if more than MAX_SAMPLES_RETURNED) - // Collections.shuffle(s); - // Sample[] returnedSamples; - /*if (s.size() > KademliaCommonConfigDas.MAX_SAMPLES_RETURNED) - returnedSamples = - new HashSet(s.subList(0, KademliaCommonConfigDas.MAX_SAMPLES_RETURNED)) - .toArray(new Sample[0]); - else */ - // returnedSamples = s.toArray(new Sample[0]); - - // logger.warning("Get sample request responding with " + sample.getId() + " samples"); - - /*if (returnedSamples.length > 0) { - - }*/ - /*Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, returnedSamples); - response.operationId = m.operationId; - response.dst = m.src; - response.src = this.kadProtocol.getKademliaNode(); - response.ackId = m.id; // set ACK number - if (m.value instanceof BigInteger[]) { - BigInteger[] smpls = (BigInteger[]) m.value; - List neigh = new ArrayList<>(); - for (int i = 0; i < smpls.length; i++) { - Neighbour[] neighs = - searchTable.getNeighbours( - smpls[i], - currentBlock.computeRegionRadius( - KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER)); - for (Neighbour n : neighs) { - neigh.add(n); - if (neigh.size() >= KademliaCommonConfigDas.MAX_NODES_RETURNED) break; - } - if (neigh.size() >= KademliaCommonConfigDas.MAX_NODES_RETURNED) break; - } - response.value = neigh.toArray(new Neighbour[0]); - // logger.warning("targeted sample request " + neigh.size()); - } else { - response.value = searchTable.getNeighbours(); - } - sendMessage(response, m.src.getId(), myPid);*/ } private void reconstruct(Sample s) { @@ -439,7 +393,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { Sample[] samples = (Sample[]) m.body; // searchTable.addNodes((BigInteger[]) m.value); - logger.warning("Samples received " + samples.length); + logger.warning("Samples received " + samples.length + " from " + m.src.getId()); if (reportDiscovery) KademliaObserver.reportPeerDiscovery(m, searchTable); for (Neighbour neigh : (Neighbour[]) m.value) { @@ -678,6 +632,7 @@ protected void startRandomSampling() { protected boolean doSampling(SamplingOperation sop) { + logger.warning("Doingsampling " + sop.getId() + " " + sop.getPending()); if (sop.completed()) { samplingOp.remove(sop.getId()); KademliaObserver.reportOperation(sop); @@ -688,7 +643,7 @@ protected boolean doSampling(SamplingOperation sop) { return true; } else { boolean success = false; - if (sop.getAvailableRequests() == 0) { + if (sop.getPending() == 0) { logger.warning("Doing sampling again " + sop.getId()); BigInteger[] nextNodes = sop.doSampling(); for (BigInteger nextNode : nextNodes) { @@ -699,7 +654,7 @@ protected boolean doSampling(SamplingOperation sop) { + " " + reqSamples.length + " " - + sop.getAvailableRequests() + + sop.getPending() + " " + sop.getId()); @@ -709,28 +664,12 @@ protected boolean doSampling(SamplingOperation sop) { // if (missing) msg.value = reqSamples; success = true; msg.dst = Util.nodeIdtoNode(nextNode, kademliaId).getKademliaProtocol().getKademliaNode(); - /*if (nextNode.compareTo(builderAddress) == 0) { - logger.warning("Error sending to builder or 0 samples assigned"); - continue; - }*/ + sop.addMessage(msg.id); // logger.warning("Send message " + dasID + " " + this); sendMessage(msg, nextNode, dasID); sop.getMessages(); } - /*if (!success) { - if (sop instanceof ValidatorSamplingOperation) - logger.warning("Sampling operation finished validator failed " + sop.getId()); - else { - logger.warning("Sampling operation finished random failed " + sop.getId()); - for (BigInteger id : sop.getSamples()) { - logger.warning("Missing sample " + id + " for op " + sop.getId()); - } - } - - samplingOp.remove(sop.getId()); - KademliaObserver.reportOperation(sop); - }*/ } return success; } @@ -760,28 +699,6 @@ public void operationComplete(Operation op) { Node n = Util.nodeIdtoNode(id, kademliaId); searchTable.addNeighbour(new Neighbour(id, n, n.getDASProtocol().isEvil())); } - /*logger.warning( - "Search table operation complete" - // + searchTable.samplesIndexed().size() - // + " " - + searchTable.nodesIndexed().size() - + " " - // + kadOps.get(op).nrHops - // + " " - + list.size()); - - if (kadOps.get(op) == null) return; - - if (!kadOps.get(op).completed()) { - doSampling(kadOps.get(op)); - } - - logger.warning( - "Sampling operation found " - + kadOps.size() - + " " - + kadOps.get(op).getAvailableRequests()); - kadOps.remove(op);*/ } } @@ -803,20 +720,6 @@ public void nodesFound(Operation op, BigInteger[] neighbours) { Node n = Util.nodeIdtoNode(id, kademliaId); searchTable.addNeighbour(new Neighbour(id, n, n.getDASProtocol().isEvil())); } - /*logger.info( - "Search table nodes found " - // + searchTable.samplesIndexed().size() - // + " " - + searchTable.nodesIndexed().size() - + " " - + neighbours.length); - - if (kadOps.get(op) != null) { - if (!kadOps.get(op).completed()) { - logger.info("Sampling operation found"); - doSampling(kadOps.get(op)); - } - }*/ } @Override diff --git a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java index 7e986629..d8e73bb7 100755 --- a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java @@ -7,7 +7,6 @@ import peersim.core.Node; import peersim.edsim.EDSimulator; import peersim.kademlia.Message; -import peersim.kademlia.Util; /** * This control generates samples every 5 min that are stored in a single node (builder) and starts @@ -80,7 +79,7 @@ private Message generateNewBlockMessage(Block b) { public boolean execute() { Block b = new Block(KademliaCommonConfigDas.BLOCK_DIM_SIZE, ID_GENERATOR); System.out.println(CommonState.getTime() + " next"); - if (first) { + /*if (first) { for (int i = 0; i < Network.size(); i++) { Node start = Network.get(i); if (start.isUp()) { @@ -98,25 +97,25 @@ public boolean execute() { } first = false; second = true; - } else /*if (second)*/ { - - // SearchTable.createSampleMap(b); - for (int i = 0; i < Network.size(); i++) { - Node n = Network.get(i); - // b.initIterator(); - // we add 1 ms delay to be sure the builder starts before validators. - /*EDSimulator.add( - CommonState.r.nextLong(CommonState.getTime() - lastTime), - Util.generateFindNodeMessage(), - n, - kadpid);*/ - - if (n.isUp()) - EDSimulator.add(0, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); - } - ID_GENERATOR++; - second = false; + } else if (second) {*/ + + // SearchTable.createSampleMap(b); + for (int i = 0; i < Network.size(); i++) { + Node n = Network.get(i); + // b.initIterator(); + // we add 1 ms delay to be sure the builder starts before validators. + /*EDSimulator.add( + CommonState.r.nextLong(CommonState.getTime() - lastTime), + Util.generateFindNodeMessage(), + n, + kadpid);*/ + + if (n.isUp()) + EDSimulator.add(0, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); } + ID_GENERATOR++; + second = false; + // } lastTime = CommonState.getTime(); return false; } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/Node.java b/simulator/src/main/java/peersim/kademlia/das/operations/Node.java index fb4432f8..8d39898d 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/Node.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/Node.java @@ -30,6 +30,10 @@ public List getSamples() { return samples; } + public void removeFetchingSample(FetchingSample s) { + samples.remove(s); + } + public void setBeingAsked(boolean value) { this.beingAsked = value; } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index 2a5ded98..b5859c6d 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -46,7 +46,7 @@ public RandomSamplingOperation( samples.put(rs.getIdByRow(), s); // samples.put(rs.getIdByColumn(), s); } - createNodes(); + // createNodes(); } public boolean completed() { @@ -80,13 +80,14 @@ public void elaborateResponse(Sample[] sam) { } public void elaborateResponse(Sample[] sam, BigInteger node) { - this.available_requests--; + // this.available_requests--; // if (this.available_requests == 0) nodes.clear(); - + pendingNodes.remove(node); Node n = nodes.get(node); if (n != null) { for (FetchingSample s : n.getSamples()) { s.removeFetchingNode(n); + s.setDownloaded(); } } @@ -100,20 +101,10 @@ public void elaborateResponse(Sample[] sam, BigInteger node) { fs.removeFetchingNode(nodes.get(node)); } } - /*if (samples.containsKey(s.getIdByColumn())) { - FetchingSample fs = samples.get(s.getIdByColumn()); - if (!fs.isDownloaded()) { - samplesCount++; - fs.setDownloaded(); - fs.removeFetchingNode(nodes.get(node)); - } - }*/ } } - if (node != null) { - nodes.remove(node); - askNodes.add(node); - } + nodes.remove(node); + askedNodes.add(node); } protected void createNodes() { @@ -122,29 +113,19 @@ protected void createNodes() { List nodesBySample = new ArrayList<>(); - // nodesBySample.addAll( - // searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator)); - BigInteger radiusUsed = radiusValidator; while (nodesBySample.isEmpty() && radiusUsed.compareTo(Block.MAX_KEY) == -1) { nodesBySample.addAll( searchTable.getNodesbySample(samples.get(sample).getId(), radiusUsed)); - // searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusUsed)); nodesBySample.addAll( searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusUsed)); - // searchTable.getValidatorNodesbySample( - // samples.get(sample).getIdByColumn(), radiusUsed)); + radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); } - // nodesBySample.addAll( - // searchTable.getNonValidatorNodesbySample( - // samples.get(sample).getId(), radiusNonValidator)); - // nodesBySample.addAll( - // searchTable.getNonValidatorNodesbySample( - // samples.get(sample).getIdByColumn(), radiusNonValidator)); boolean found = false; + nodesBySample.removeAll(askedNodes); if (nodesBySample != null && nodesBySample.size() > 0) { for (BigInteger id : nodesBySample) { diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index 70d77746..2618945f 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -30,7 +30,8 @@ public abstract class SamplingOperation extends FindOperation { protected LinkedHashMap nodes; protected HashMap samples; - protected List askNodes; + protected List askedNodes; + protected List pendingNodes; public SamplingOperation( BigInteger srcNode, @@ -48,9 +49,10 @@ public SamplingOperation( currentBlock.computeRegionRadius(KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); samples = new HashMap<>(); nodes = new LinkedHashMap<>(); - this.available_requests = 0; + // this.available_requests = 0; aggressiveness = 0; - askNodes = new ArrayList<>(); + askedNodes = new ArrayList<>(); + pendingNodes = new ArrayList<>(); timesIncreased = 0; } @@ -69,15 +71,16 @@ public SamplingOperation( this.isValidator = isValidator; this.callback = callback; currentBlock = block; - this.available_requests = 0; + // this.available_requests = 0; aggressiveness = 0; radiusValidator = currentBlock.computeRegionRadius( KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, numValidators); radiusNonValidator = currentBlock.computeRegionRadius(KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); - askNodes = new ArrayList<>(); + askedNodes = new ArrayList<>(); timesIncreased = 0; + pendingNodes = new ArrayList<>(); // queried = new HashSet<>(); // TODO Auto-generated constructor stub } @@ -107,18 +110,48 @@ public BigInteger getRadiusNonValidator() { public BigInteger[] doSampling() { aggressiveness += KademliaCommonConfigDas.aggressiveness_step; + //System.out.println("[" + srcNode + "] nodes " + nodes.size()); + List toRemove = new ArrayList<>(); + for (BigInteger n : nodes.keySet()) { + List sToRemove = new ArrayList<>(); + for (FetchingSample s : nodes.get(n).getSamples()) { + /*System.out.println( + "[" + + srcNode + + "] nodes " + + n + + " " + + nodes.get(n).isBeingAsked() + + " " + + nodes.get(n).getScore() + + " " + + aggressiveness + + " " + + s.isDownloaded() + + " " + + +s.beingFetchedFrom.size());*/ + if (s.isDownloaded()) sToRemove.add(s); + } + for (FetchingSample s : sToRemove) { + nodes.get(n).removeFetchingSample(s); + } + if (nodes.get(n).getSamples().size() == 0) toRemove.add(n); + } + for (BigInteger id : toRemove) nodes.remove(id); + + if (nodes.isEmpty()) { + + createNodes(); + // System.out.println("[" + srcNode + "] Repopulating nodes " + nodes.size()); + } for (Node n : nodes.values()) n.setAgressiveness(aggressiveness); List result = new ArrayList<>(); for (Node n : nodes.values()) { - /*System.out.println( - this.srcNode + "] Querying node " + n.getId() + " " + +n.getScore() + " " + this.getId()); - for (FetchingSample fs : n.getSamples()) - System.out.println( - this.srcNode + "] Sample " + fs.beingFetchedFrom.size() + " " + fs.isDownloaded());*/ if (!n.isBeingAsked() && n.getScore() > 0) { // break; n.setBeingAsked(true); - this.available_requests++; + // this.available_requests++; + pendingNodes.add(n.getId()); for (FetchingSample s : n.getSamples()) { s.addFetchingNode(n); } @@ -140,4 +173,8 @@ public Collection getNodes() { public int samplesCount() { return samplesCount; } + + public int getPending() { + return pendingNodes.size(); + } } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index 4b893b47..dff871d3 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -55,7 +55,7 @@ public ValidatorSamplingOperation( } } this.searchTable = searchTable; - createNodes(); + // createNodes(); } public void elaborateResponse(Sample[] sam) { @@ -85,9 +85,10 @@ public void elaborateResponse(Sample[] sam) { public void elaborateResponse(Sample[] sam, BigInteger n) { - this.available_requests--; + // this.available_requests--; // if (this.available_requests == 0) nodes.clear(); + pendingNodes.remove(n); Node node = nodes.get(n); if (node != null) { for (FetchingSample s : node.getSamples()) { @@ -117,10 +118,9 @@ public void elaborateResponse(Sample[] sam, BigInteger n) { } // System.out.println("Row " + samplesCount + " " + samples.size()); if (samplesCount >= samples.size() / 2) completed = true; - if (node != null) { - askNodes.add(n); - nodes.remove(n); - } + + askedNodes.add(n); + nodes.remove(n); } public boolean completed() { @@ -142,35 +142,24 @@ protected void createNodes() { if (!samples.get(sample).isDownloaded()) { List nodesBySample = new ArrayList<>(); - // searchTable.getNodesbySample(samples.get(sample).getId(), radiusValidator); if (row > 0) { BigInteger radiusUsed = radiusValidator; while (nodesBySample.isEmpty() && radiusUsed.compareTo(Block.MAX_KEY) == -1) { nodesBySample.addAll( searchTable.getNodesbySample(samples.get(sample).getId(), radiusUsed)); - // searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusUsed)); radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); } - // nodesBySample.addAll(searchTable.getNodesbySample(samples.get(sample).getId(), - // radiusNonValidator)); - // searchTable.getNonValidatorNodesbySample(samples.get(sample).getId(), - // radiusNonValidator)); } else { BigInteger radiusUsed = radiusValidator; while (nodesBySample.isEmpty() && radiusUsed.compareTo(Block.MAX_KEY) == -1) { nodesBySample.addAll( searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusUsed)); - // searchTable.getValidatorNodesbySample(samples.get(sample).getIdByColumn(), - // radiusUsed)); + radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); } - // nodesBySample.addAll(searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), - // radiusNonValidator)); - - // searchTable.getNonValidatorNodesbySample(samples.get(sample).getIdByColumn(), - // radiusNonValidator)); } boolean found = false; + nodesBySample.removeAll(askedNodes); if (nodesBySample != null && nodesBySample.size() > 0) { for (BigInteger id : nodesBySample) { if (!nodes.containsKey(id)) { From 682f4d143bc893b1f78a23def6d938804100addf Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Thu, 26 Oct 2023 15:47:59 +0200 Subject: [PATCH 40/98] avoid adding builder search table --- .../peersim/kademlia/das/SearchTable.java | 14 ++++---- .../das/operations/SamplingOperation.java | 32 +++++++++---------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index 32884a1c..f8a63033 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -65,12 +65,14 @@ public SearchTable(/*Block currentblock , BigInteger id*/ ) { }*/ public void addNeighbour(Neighbour neigh) { - if (neighbours.get(neigh.getId()) == null) { - neighbours.put(neigh.getId(), neigh); - nodesIndexed.add(neigh.getId()); - } else { - if (neighbours.get(neigh.getId()).getLastSeen() < neigh.getLastSeen()) - neighbours.get(neigh.getId()).updateLastSeen(neigh.getLastSeen()); + if (neigh.getId().compareTo(builderAddress) != 0) { + if (neighbours.get(neigh.getId()) == null) { + neighbours.put(neigh.getId(), neigh); + nodesIndexed.add(neigh.getId()); + } else { + if (neighbours.get(neigh.getId()).getLastSeen() < neigh.getLastSeen()) + neighbours.get(neigh.getId()).updateLastSeen(neigh.getLastSeen()); + } } } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index 2618945f..38450e5c 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -110,26 +110,26 @@ public BigInteger getRadiusNonValidator() { public BigInteger[] doSampling() { aggressiveness += KademliaCommonConfigDas.aggressiveness_step; - //System.out.println("[" + srcNode + "] nodes " + nodes.size()); + // System.out.println("[" + srcNode + "] nodes " + nodes.size()); List toRemove = new ArrayList<>(); for (BigInteger n : nodes.keySet()) { List sToRemove = new ArrayList<>(); for (FetchingSample s : nodes.get(n).getSamples()) { /*System.out.println( - "[" - + srcNode - + "] nodes " - + n - + " " - + nodes.get(n).isBeingAsked() - + " " - + nodes.get(n).getScore() - + " " - + aggressiveness - + " " - + s.isDownloaded() - + " " - + +s.beingFetchedFrom.size());*/ + "[" + + srcNode + + "] nodes " + + n + + " " + + nodes.get(n).isBeingAsked() + + " " + + nodes.get(n).getScore() + + " " + + aggressiveness + + " " + + s.isDownloaded() + + " " + + +s.beingFetchedFrom.size());*/ if (s.isDownloaded()) sToRemove.add(s); } for (FetchingSample s : sToRemove) { @@ -142,7 +142,7 @@ public BigInteger[] doSampling() { if (nodes.isEmpty()) { createNodes(); - // System.out.println("[" + srcNode + "] Repopulating nodes " + nodes.size()); + // System.out.println("[" + srcNode + "] Repopulating nodes " + nodes.size()); } for (Node n : nodes.values()) n.setAgressiveness(aggressiveness); List result = new ArrayList<>(); From a4ae8fe03c0aede2ddb113a3907d6d06783b953b Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Thu, 26 Oct 2023 15:54:20 +0200 Subject: [PATCH 41/98] removing logs --- .../main/java/peersim/kademlia/das/DASProtocol.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 8cf4c093..15628600 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -393,7 +393,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { Sample[] samples = (Sample[]) m.body; // searchTable.addNodes((BigInteger[]) m.value); - logger.warning("Samples received " + samples.length + " from " + m.src.getId()); + logger.info("Samples received " + samples.length + " from " + m.src.getId()); if (reportDiscovery) KademliaObserver.reportPeerDiscovery(m, searchTable); for (Neighbour neigh : (Neighbour[]) m.value) { @@ -430,7 +430,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { SamplingOperation op = (SamplingOperation) samplingOp.get(m.operationId); // We continue an existing operation - logger.warning( + logger.info( "Nodes discovered " + ((Neighbour[]) m.value).length + " " @@ -442,7 +442,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { if (op != null) { // keeping track of received samples op.elaborateResponse(samples, m.src.getId()); - logger.warning( + logger.info( "Continue operation " + op.getId() + " " @@ -538,7 +538,7 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { if (m.getType() == Message.MSG_GET_SAMPLE) { // is a request Timeout t = new Timeout(destId, m.id, m.operationId); long latency = transport.getLatency(src, dest); - logger.warning("Send message added " + m.id + " " + latency + " " + destId); + logger.info("Send message added " + m.id + " " + latency + " " + destId); // add to sent msg this.sentMsg.put(m.id, m.timestamp); @@ -632,7 +632,7 @@ protected void startRandomSampling() { protected boolean doSampling(SamplingOperation sop) { - logger.warning("Doingsampling " + sop.getId() + " " + sop.getPending()); + logger.info("Doingsampling " + sop.getId() + " " + sop.getPending()); if (sop.completed()) { samplingOp.remove(sop.getId()); KademliaObserver.reportOperation(sop); From 44732b9e2a9037a4650c322472c16d4fe784f00e Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Fri, 27 Oct 2023 10:39:30 +0200 Subject: [PATCH 42/98] reducing memory usage --- simulator/config/dasprotocol.cfg | 52 +++++++++---------- .../kademlia/das/CustomDistributionDas.java | 9 +--- .../peersim/kademlia/das/DASProtocol.java | 14 ++--- .../kademlia/das/DASProtocolBuilder.java | 26 ++-------- .../kademlia/das/DASProtocolNonValidator.java | 2 - .../java/peersim/kademlia/das/Sample.java | 38 ++++---------- 6 files changed, 44 insertions(+), 97 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 07b6e6cb..5b263c45 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -14,7 +14,7 @@ MINDELAY 5 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*5 +SIM_TIME 1000*60*1 #Traffic generator is executed every TRAFFIC_STEP @@ -22,8 +22,8 @@ TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP OBSERVER_STEP 20000 #Turbulence module is executed every TURBULENCE_STEP enabling churning -TURBULENCE_STEP 1000000 -TURBULENCE_STEP_NONVAL 1000000 +TURBULENCE_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 REFRESH_STEP 1000 # add network config parameters to simulation @@ -105,7 +105,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 100 +control.0traffic.block_dim_size 512 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia @@ -114,30 +114,30 @@ control.1refresh peersim.kademlia.das.RefreshSearchTable control.1refresh.step REFRESH_STEP # turbulence non-validator -#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas -#control.2turbolenceAdd.protocolkad 3kademlia -#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol -#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol -#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol -#control.2turbolenceAdd.protocolEvildas 7evildasprotocol -#control.2turbolenceAdd.transport 2unreltr -#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL -#control.2turbolenceAdd.p_idle 0.1 -#control.2turbolenceAdd.p_rem 0.45 -#control.2turbolenceAdd.p_add 0.45 +control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +control.2turbolenceAdd.protocolkad 3kademlia +control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +control.2turbolenceAdd.protocolEvildas 7evildasprotocol +control.2turbolenceAdd.transport 2unreltr +control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +control.2turbolenceAdd.p_idle 0.1 +control.2turbolenceAdd.p_rem 0.45 +control.2turbolenceAdd.p_add 0.45 # turbulence validators -#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator -#control.3turbolenceAdd.protocolkad 3kademlia -#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol -#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol -#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol -#control.3turbolenceAdd.protocolEvildas 7evildasprotocol -#control.3turbolenceAdd.transport 2unreltr -#control.3turbolenceAdd.step TURBULENCE_STEP -#control.3turbolenceAdd.p_idle 0.1 -#control.3turbolenceAdd.p_rem 0.45 -#control.3turbolenceAdd.p_add 0.45 +control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +control.3turbolenceAdd.protocolkad 3kademlia +control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +control.3turbolenceAdd.protocolEvildas 7evildasprotocol +control.3turbolenceAdd.transport 2unreltr +control.3turbolenceAdd.step TURBULENCE_STEP +control.3turbolenceAdd.p_idle 0.9 +control.3turbolenceAdd.p_rem 0.05 +control.3turbolenceAdd.p_add 0.05 # ::::: OBSERVER ::::: #The observer is executed every OBSERVER_STEP and will generate data traces diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index 619a56e5..ea158974 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -152,16 +152,9 @@ public boolean execute() { // for (DASProtocol validator : validators) { for (int i = 0; i < Network.size(); i++) { Node generalNode = Network.get(i); - // if (i == 0) // generalNode.getDASProtocol().setNonValidators(nonValidatorsIds); generalNode.getDASProtocol().addKnownValidator(validatorsIds.toArray(new BigInteger[0])); - /*if (generalNode.getDASProtocol().isBuilder()) { - for (Node n : validators) - generalNode - .getDASProtocol() - .getSearchTable() - .addNeighbour(new Neighbour(n.getDASProtocol().getKademliaId(), n, false)); - }*/ + int k = 0; while (k < 100) { Node n = Network.get(CommonState.r.nextInt(Network.size())); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 15628600..478d9771 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -15,7 +15,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.TreeMap; -import java.util.TreeSet; import java.util.logging.Logger; import peersim.config.Configuration; import peersim.core.CommonState; @@ -95,8 +94,6 @@ public abstract class DASProtocol implements Cloneable, EDProtocol, KademliaEven protected long time; - protected TreeSet nonValidatorsIndexed; // , samplesIndexed; - protected boolean isEvil; protected boolean init; @@ -145,7 +142,6 @@ public DASProtocol(String prefix) { sentMsg = new TreeMap(); searchTable = new SearchTable(); - nonValidatorsIndexed = new TreeSet<>(); isBuilder = false; missingSamples = new HashMap<>(); init = false; @@ -430,7 +426,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { SamplingOperation op = (SamplingOperation) samplingOp.get(m.operationId); // We continue an existing operation - logger.info( + logger.warning( "Nodes discovered " + ((Neighbour[]) m.value).length + " " @@ -593,10 +589,8 @@ public void addKnownValidator(BigInteger[] ids) { } public void setNonValidators(List nonValidators) { - for (BigInteger id : nonValidators) { - nonValidatorsIndexed.add(id); - } - searchTable.addNodes(nonValidators.toArray(new BigInteger[0])); + + if (isBuilder()) searchTable.addNodes(nonValidators.toArray(new BigInteger[0])); } public SearchTable getSearchTable() { @@ -725,7 +719,7 @@ public void nodesFound(Operation op, BigInteger[] neighbours) { @Override public void missing(BigInteger sample, Operation op) { - logger.warning("Missing nodes for sample " + sample + " " + kadOps.size()); + logger.info("Missing nodes for sample " + sample + " " + kadOps.size()); // missing = true; } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index 69a3446a..f4646f48 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -33,15 +33,11 @@ protected void handleInitGetSample(Message m, int myPid) { protected void handleInitNewBlock(Message m, int myPid) { super.handleInitNewBlock(m, myPid); logger.warning("Builder new block:" + currentBlock.getBlockId()); - /*+ " " - + validatorsList.length - + " " - + nonValidatorsIndexed.size());*/ int samplesWithinRegion = 0; // samples that are within at least one node's region int samplesValidators = 0; int samplesNonValidators = 0; - + samplesToRequest.clear(); BigInteger radiusNonValidator = currentBlock.computeRegionRadius(KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); @@ -73,12 +69,7 @@ protected void handleInitNewBlock(Message m, int myPid) { DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); if (dasProt.isBuilder()) continue; if (n.isUp()) { - /*Sample[] samples = {s}; - Message msg = generateSeedSampleMessage(samples); - msg.operationId = -1; - msg.src = this.getKademliaProtocol().getKademliaNode(); - msg.dst = n.getKademliaProtocol().getKademliaNode(); - sendMessage(msg, id, dasProt.getDASProtocolID());*/ + if (!samplesToRequest.containsKey(id)) { List samples = new ArrayList<>(); samples.add(s.getId()); @@ -94,9 +85,6 @@ protected void handleInitNewBlock(Message m, int myPid) { } } if (!inRegion) radiusValidator = radiusValidator.multiply(BigInteger.valueOf(2)); - // System.out.println( - // "Sample id " + s.getIdByRow() + " " + s.getIdByColumn() + " " + radiusValidator); - } inRegion = false; while (!inRegion) { @@ -120,12 +108,7 @@ protected void handleInitNewBlock(Message m, int myPid) { DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); if (dasProt.isBuilder()) continue; if (n.isUp()) { - /*Sample[] samples = {s}; - Message msg = generateSeedSampleMessage(samples); - msg.operationId = -1; - msg.src = this.getKademliaProtocol().getKademliaNode(); - msg.dst = n.getKademliaProtocol().getKademliaNode(); - sendMessage(msg, id, dasProt.getDASProtocolID());*/ + if (!samplesToRequest.containsKey(id)) { List samples = new ArrayList<>(); samples.add(s.getId()); @@ -162,8 +145,7 @@ protected void handleInitNewBlock(Message m, int myPid) { samplesNonValidators++; if (!dasProt.isValidator()) { - // EDSimulator.add(0, generateNewSampleMessage(s.getId()), n, - // dasProt.getDASProtocolID()); + if (!samplesToRequest.containsKey(id)) { List samples = new ArrayList<>(); samples.add(s.getId()); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java index 788a5a54..0b5166dc 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java @@ -24,7 +24,6 @@ public DASProtocolNonValidator(String prefix) { protected void handleInitGetSample(Message m, int myPid) { if (!init) return; logger.warning("Init block non-validator node - getting samples " + this); - // super.handleInitGetSample(m, myPid); if (currentBlock == null) System.err.println("Error block not init yet"); BigInteger[] samples = (BigInteger[]) m.body; BigInteger radius = @@ -32,7 +31,6 @@ protected void handleInitGetSample(Message m, int myPid) { KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, searchTable.getValidatorsIndexed().size()); for (BigInteger sample : samples) { - // for (BigInteger id : searchTable.getNodesbySample(sample, radius)) { for (BigInteger id : searchTable.getValidatorNodesbySample(sample, radius)) { if (!validatorsContacted.contains(id)) { Message msg = generateGetSampleMessage(samples); diff --git a/simulator/src/main/java/peersim/kademlia/das/Sample.java b/simulator/src/main/java/peersim/kademlia/das/Sample.java index a4ff4baf..432adc06 100644 --- a/simulator/src/main/java/peersim/kademlia/das/Sample.java +++ b/simulator/src/main/java/peersim/kademlia/das/Sample.java @@ -9,45 +9,38 @@ public class Sample { /** Row and column numbers of a sample within a block */ private int row, column; - /** The unique ID of the block that this sample belongs to */ - private long blockId; - /** The key of a sample in the DHT keyspace using rows number as reference */ private BigInteger idByRow; /** The key of a sample in the DHT keyspace using column number as reference */ private BigInteger idByColumn; - /** Block that this sample is part of */ - private Block block; /** Initialise a sample instance and map it to the keyspace */ public Sample(long blockId, int row, int column, Block b) { this.idByColumn = this.idByRow = null; - this.block = b; this.row = row; this.column = column; - this.blockId = blockId; - computeID(); + computeID(blockId, b); } /** * Sample numbering to map each sample to an integer in the range 1 to SIZE*SIZE Samples are * ordered by row */ - public int sampleNumberByRow() { - return (this.row - 1) * this.block.getSize() + (this.column - 1); + public int sampleNumberByRow(Block b) { + return (this.row - 1) * b.getSize() + (this.column - 1); } /** * Sample numbering to map each sample to an integer in the range 1 to SIZE*SIZE Samples are * ordered by column */ - public int sampleNumberByColumn() { - return (this.column - 1) * this.block.getSize() + (this.row - 1); + public int sampleNumberByColumn(Block b) { + return (this.column - 1) * b.getSize() + (this.row - 1); } /** Map this sample to the DHT keyspace */ - public void computeID() { + public void computeID(long blockId, Block b) { if (KademliaCommonConfigDas.MAPPING_FN == KademliaCommonConfigDas.SAMPLE_MAPPING_RANDOM) { try { String idName = @@ -62,22 +55,14 @@ public void computeID() { } } else if (KademliaCommonConfigDas.MAPPING_FN == KademliaCommonConfigDas.SAMPLE_MAPPING_REGION_BASED) { - /*System.out.println( - "ComputeId " - + this.row - + " " - + this.column - + " " - + this.sampleNumberByRow() - + " " - + this.sampleNumberByColumn());*/ + this.idByRow = Block.INTER_SAMPLE_GAP - .multiply(BigInteger.valueOf(this.sampleNumberByRow())) + .multiply(BigInteger.valueOf(this.sampleNumberByRow(b))) .add(BigInteger.valueOf(blockId)); this.idByColumn = Block.INTER_SAMPLE_GAP - .multiply(BigInteger.valueOf(this.sampleNumberByColumn())) + .multiply(BigInteger.valueOf(this.sampleNumberByColumn(b))) .add(BigInteger.valueOf(blockId)) .add(BigInteger.valueOf(1)); @@ -125,11 +110,6 @@ public int getColumn() { return this.column; } - /** Block id which the sample is part of */ - public long getBlockId() { - return blockId; - } - /** Computed identifier of the sample, depending of the mapping mode */ public BigInteger getId() { return idByRow; From 19308ece6fed6d7fbcd538b6c1cb13b87cc142d0 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Fri, 27 Oct 2023 11:49:11 +0200 Subject: [PATCH 43/98] validator evil class --- simulator/config/dasprotocol.cfg | 2 +- .../kademlia/das/CustomDistributionDas.java | 13 ----- .../peersim/kademlia/das/DASProtocol.java | 10 +--- .../peersim/kademlia/das/EvilDASProtocol.java | 55 ------------------- 4 files changed, 2 insertions(+), 78 deletions(-) delete mode 100644 simulator/src/main/java/peersim/kademlia/das/EvilDASProtocol.java diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 5b263c45..0bec94f8 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -144,4 +144,4 @@ control.3turbolenceAdd.p_add 0.05 control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logsDas2 +control.4.logfolder logsDas diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index ea158974..5eb3e5ad 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -25,7 +25,6 @@ public class CustomDistributionDas implements peersim.core.Control { private static final String PAR_PROT_DAS_BUILDER = "protocoldasbuilder"; private static final String PAR_PROT_DAS_VALIDATOR = "protocoldasvalidator"; private static final String PAR_PROT_DAS_NON_VALIDATOR = "protocoldasnonvalidator"; - private static final String PAR_PROT_EVIL_KAD = "protocolEvilkad"; private static final String PAR_PROT_EVIL_DAS = "protocolEvildas"; private static final String PAR_EVIL_RATIO_VAL = "evilNodeRatioValidator"; private static final String PAR_EVIL_RATIO_NONVAL = "evilNodeRatioNonValidator"; @@ -35,7 +34,6 @@ public class CustomDistributionDas implements peersim.core.Control { /** Protocol identifiers for Kademlia, DAS, etc. * */ private int protocolKadID; - private int protocolEvilKadID; private int protocolDasBuilderID; private int protocolDasValidatorID; private int protocolDasNonValidatorID; @@ -52,7 +50,6 @@ public class CustomDistributionDas implements peersim.core.Control { public CustomDistributionDas(String prefix) { protocolKadID = Configuration.getPid(prefix + "." + PAR_PROT_KAD); - protocolEvilKadID = Configuration.getPid(prefix + "." + PAR_PROT_EVIL_KAD, protocolKadID); protocolDasBuilderID = Configuration.getPid(prefix + "." + PAR_PROT_DAS_BUILDER); protocolDasValidatorID = Configuration.getPid(prefix + "." + PAR_PROT_DAS_VALIDATOR); protocolDasNonValidatorID = Configuration.getPid(prefix + "." + PAR_PROT_DAS_NON_VALIDATOR); @@ -124,16 +121,6 @@ public boolean execute() { dasProt.setBuilderAddress(builderAddress); - /*System.out.println( - "Dasprot id " - + protocolDasBuilderID - + " " - + protocolDasValidatorID - + " " - + protocolDasNonValidatorID - + " " - + protocolKadID);*/ - if (dasProt instanceof DASProtocolBuilder) System.out.println("DASProtocol Builder " + i); generalNode.setProtocol(protocolKadID, kadProt); generalNode.setKademliaProtocol(kadProt); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 478d9771..767dee7b 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -11,7 +11,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.TreeMap; @@ -81,12 +80,6 @@ public abstract class DASProtocol implements Cloneable, EDProtocol, KademliaEven protected int[] row, column; - // protected int samplesRequested; - - // protected BigInteger[] validatorsList; - - protected HashSet queried; - protected int dasID; /** trace message sent for timeout purpose */ @@ -136,7 +129,6 @@ public DASProtocol(String prefix) { kadOps = new LinkedHashMap(); samplingStarted = false; - queried = new HashSet(); uploadInterfaceBusyUntil = 0; sentMsg = new TreeMap(); @@ -278,6 +270,7 @@ protected void handleInitNewBlock(Message m, int myPid) { time = CommonState.getTime(); currentBlock = (Block) m.body; kv.erase(); + missingSamples.clear(); // samplesRequested = 0; row = new int[currentBlock.getSize()]; column = new int[currentBlock.getSize()]; @@ -300,7 +293,6 @@ protected void handleInitNewBlock(Message m, int myPid) { } samplingOp.clear(); kadOps.clear(); - queried.clear(); } protected void handleSeedSample(Message m, int myPid) { diff --git a/simulator/src/main/java/peersim/kademlia/das/EvilDASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/EvilDASProtocol.java deleted file mode 100644 index ce0ca9d1..00000000 --- a/simulator/src/main/java/peersim/kademlia/das/EvilDASProtocol.java +++ /dev/null @@ -1,55 +0,0 @@ -package peersim.kademlia.das; - -import peersim.kademlia.Message; - -public class EvilDASProtocol extends DASProtocol { - - protected static String prefix = null; - - public EvilDASProtocol(String prefix) { - super(prefix); - EvilDASProtocol.prefix = prefix; - isEvil = true; - } - - @Override - protected void handleSeedSample(Message m, int myPid) { - logger.warning("seed sample received - do nothing " + this); - } - - @Override - protected void handleGetSample(Message m, int myPid) { - /** Ignore sample request * */ - logger.warning("Handle get sample - return nothing " + this); - } - - @Override - protected void handleInitNewBlock(Message m, int myPid) { - logger.warning("Init block evil node - do nothing"); - } - - @Override - protected void handleInitGetSample(Message m, int myPid) { - logger.warning("Init block evil node - getting samples " + this); - // super.handleInitGetSample(m, myPid); - } - - @Override - protected void handleGetSampleResponse(Message m, int myPid) { - logger.warning("Received sample evil node: do nothing"); - } - - /*public void processEvent(Node myNode, int myPid, Object event) { - logger.warning("Process event " + myPid + " " + this); - }*/ - /** - * Replicate this object by returning an identical copy.
- * It is called by the initializer and do not fill any particular field. - * - * @return Object - */ - public Object clone() { - EvilDASProtocol dolly = new EvilDASProtocol(EvilDASProtocol.prefix); - return dolly; - } -} From 4228a5c2b1cced9e9e464871fd7269e67d29fb9a Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Fri, 27 Oct 2023 12:37:25 +0200 Subject: [PATCH 44/98] init evil nodes --- simulator/config/dasprotocol.cfg | 16 +++++++++---- .../kademlia/das/CustomDistributionDas.java | 24 ++++++++++++------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 0bec94f8..088780a5 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -75,11 +75,16 @@ protocol.6dasprotocol.transport 2unreltr protocol.6dasprotocol.kademlia 3kademlia protocol.6dasprotocol.reportDiscovery false -protocol.7evildasprotocol peersim.kademlia.das.EvilDASProtocol +protocol.7evildasprotocol peersim.kademlia.das.DASProtocolEvilValidator protocol.7evildasprotocol.transport 2unreltr protocol.7evildasprotocol.kademlia 3kademlia protocol.7evildasprotocol.reportDiscovery false +protocol.8evildasprotocol peersim.kademlia.das.DASProtocolEvilNonValidator +protocol.8evildasprotocol.transport 2unreltr +protocol.8evildasprotocol.kademlia 3kademlia +protocol.8evildasprotocol.reportDiscovery false + # ::::: INITIALIZERS ::::: #Class that initializes nodes with kademlia protocol and generates uniform ids init.1uniqueNodeID peersim.kademlia.das.CustomDistributionDas @@ -87,10 +92,11 @@ init.1uniqueNodeID.protocolkad 3kademlia init.1uniqueNodeID.protocoldasbuilder 4dasprotocol init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol -init.1uniqueNodeID.protocolEvildas 7evildasprotocol +init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol +init.1uniqueNodeID.protocolEvildas 8evildasprotocol init.1uniqueNodeID.validator_rate 0.5 -init.1uniqueNodeID.evilNodeRatioValidator 0.0 -init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 +init.1uniqueNodeID.evilNodeRatioValidator 0.5 +init.1uniqueNodeID.evilNodeRatioNonValidator 0.5 #Adds initial state to the routing tables @@ -105,7 +111,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 512 +control.0traffic.block_dim_size 100 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index 5eb3e5ad..3ce8a799 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -26,6 +26,7 @@ public class CustomDistributionDas implements peersim.core.Control { private static final String PAR_PROT_DAS_VALIDATOR = "protocoldasvalidator"; private static final String PAR_PROT_DAS_NON_VALIDATOR = "protocoldasnonvalidator"; private static final String PAR_PROT_EVIL_DAS = "protocolEvildas"; + private static final String PAR_PROT_EVIL_VAL_DAS = "protocolEvilValDas"; private static final String PAR_EVIL_RATIO_VAL = "evilNodeRatioValidator"; private static final String PAR_EVIL_RATIO_NONVAL = "evilNodeRatioNonValidator"; @@ -39,6 +40,8 @@ public class CustomDistributionDas implements peersim.core.Control { private int protocolDasNonValidatorID; private int protocolEvilDasID; + private int protocolEvilValDasID; + /** Ratio of evil nodes to total number of nodes * */ private double evilRatioValidator; @@ -54,6 +57,8 @@ public CustomDistributionDas(String prefix) { protocolDasValidatorID = Configuration.getPid(prefix + "." + PAR_PROT_DAS_VALIDATOR); protocolDasNonValidatorID = Configuration.getPid(prefix + "." + PAR_PROT_DAS_NON_VALIDATOR); protocolEvilDasID = Configuration.getPid(prefix + "." + PAR_PROT_EVIL_DAS, 0); + protocolEvilValDasID = Configuration.getPid(prefix + "." + PAR_PROT_EVIL_VAL_DAS, 0); + evilRatioValidator = Configuration.getDouble(prefix + "." + PAR_EVIL_RATIO_VAL, 0.0); evilRatioNonValidator = Configuration.getDouble(prefix + "." + PAR_EVIL_RATIO_NONVAL, 0.0); urg = new UniformRandomGenerator(KademliaCommonConfig.BITS, CommonState.r); @@ -70,7 +75,8 @@ public boolean execute() { int numValidators = (int) (Network.size() * validatorRate); - System.out.println("Validators " + numValidators); + System.out.println( + "Validators " + numValidators + " " + evilRatioValidator + " " + evilRatioNonValidator); int numEvilValidatorNodes = (int) (numValidators * evilRatioValidator); int numEvilNonValidatorNodes = (int) ((Network.size() - numValidators) * evilRatioNonValidator); @@ -79,7 +85,7 @@ public boolean execute() { List validatorsIds = new ArrayList<>(); List nonValidatorsIds = new ArrayList<>(); List validators = new ArrayList<>(); - + numValidators = numValidators - numEvilValidatorNodes; for (int i = 0; i < Network.size(); ++i) { Node generalNode = Network.get(i); BigInteger id; @@ -100,16 +106,16 @@ public boolean execute() { builderAddress = node.getId(); validators.add(generalNode); } else if ((i > 0) && (i < (numEvilValidatorNodes + 1))) { + dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolEvilValDasID))); + validatorsIds.add(kadProt.getKademliaNode().getId()); + } else if ((i > numEvilValidatorNodes) + && (i < (numEvilValidatorNodes + numEvilNonValidatorNodes + 1))) { dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolEvilDasID))); - } else if (i >= (numEvilValidatorNodes + numEvilNonValidatorNodes + 1) - && i - < (numEvilValidatorNodes - + numEvilNonValidatorNodes - + (numValidators - numEvilValidatorNodes) - + 1)) { + nonValidatorsIds.add(kadProt.getKademliaNode().getId()); + } else if (i > (numEvilValidatorNodes + numEvilNonValidatorNodes) + && i < (numEvilValidatorNodes + numEvilNonValidatorNodes + (numValidators) + 1)) { dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolDasValidatorID))); validatorsIds.add(kadProt.getKademliaNode().getId()); - } else { dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolDasNonValidatorID))); nonValidatorsIds.add(kadProt.getKademliaNode().getId()); From 9887a5ef62bc734b9e19375de28b221f2f309140 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Fri, 27 Oct 2023 13:06:54 +0200 Subject: [PATCH 45/98] return other evil nodes discovery by malicious --- simulator/config/dasprotocol.cfg | 4 +- .../kademlia/das/CustomDistributionDas.java | 8 ++ .../peersim/kademlia/das/SearchTable.java | 88 ++++--------------- 3 files changed, 29 insertions(+), 71 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 088780a5..e5ba37d4 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -95,8 +95,8 @@ init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol init.1uniqueNodeID.protocolEvildas 8evildasprotocol init.1uniqueNodeID.validator_rate 0.5 -init.1uniqueNodeID.evilNodeRatioValidator 0.5 -init.1uniqueNodeID.evilNodeRatioNonValidator 0.5 +init.1uniqueNodeID.evilNodeRatioValidator 0 +init.1uniqueNodeID.evilNodeRatioNonValidator 0 #Adds initial state to the routing tables diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index 3ce8a799..5e542863 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -84,6 +84,7 @@ public boolean execute() { "Number of malicious nodes: " + numEvilValidatorNodes + " " + numEvilNonValidatorNodes); List validatorsIds = new ArrayList<>(); List nonValidatorsIds = new ArrayList<>(); + List evilNodes = new ArrayList<>(); List validators = new ArrayList<>(); numValidators = numValidators - numEvilValidatorNodes; for (int i = 0; i < Network.size(); ++i) { @@ -108,10 +109,12 @@ public boolean execute() { } else if ((i > 0) && (i < (numEvilValidatorNodes + 1))) { dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolEvilValDasID))); validatorsIds.add(kadProt.getKademliaNode().getId()); + evilNodes.add(generalNode); } else if ((i > numEvilValidatorNodes) && (i < (numEvilValidatorNodes + numEvilNonValidatorNodes + 1))) { dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolEvilDasID))); nonValidatorsIds.add(kadProt.getKademliaNode().getId()); + evilNodes.add(generalNode); } else if (i > (numEvilValidatorNodes + numEvilNonValidatorNodes) && i < (numEvilValidatorNodes + numEvilNonValidatorNodes + (numValidators) + 1)) { dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolDasValidatorID))); @@ -135,6 +138,7 @@ public boolean execute() { generalNode.setProtocol(protocolDasBuilderID, dasProt); generalNode.setProtocol(protocolEvilDasID, null); + generalNode.setProtocol(protocolEvilValDasID, null); generalNode.setProtocol(protocolDasValidatorID, null); generalNode.setProtocol(protocolDasNonValidatorID, null); } @@ -148,6 +152,10 @@ public boolean execute() { generalNode.getDASProtocol().setNonValidators(nonValidatorsIds); generalNode.getDASProtocol().addKnownValidator(validatorsIds.toArray(new BigInteger[0])); + if (generalNode.getDASProtocol().isEvil()) { + DASProtocolEvilValidator dasEvil = (DASProtocolEvilValidator) generalNode.getDASProtocol(); + dasEvil.setEvilIds(evilNodes); + } int k = 0; while (k < 100) { Node n = Network.get(CommonState.r.nextInt(Network.size())); diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index f8a63033..a58be836 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -9,14 +9,10 @@ import java.util.List; import java.util.Set; import java.util.TreeSet; -// import peersim.kademlia.KademliaCommonConfig; +import peersim.core.Node; public class SearchTable { - // private HashMap> sampleMap; - - // private Block currentBlock; - private HashMap neighbours; private TreeSet nodesIndexed; // , samplesIndexed; @@ -27,43 +23,19 @@ public class SearchTable { private HashSet blackList; // , samplesIndexed; - // private static HashMap> sampleMap = new HashMap<>(); private BigInteger builderAddress; - public SearchTable(/*Block currentblock , BigInteger id*/ ) { + private List evilIds; + + public SearchTable() { - // this.currentBlock = currentblock; - // this.sampleMap = new HashMap<>(); this.nodesIndexed = new TreeSet<>(); this.nonValidatorsIndexed = new TreeSet<>(); this.blackList = new HashSet<>(); this.neighbours = new HashMap<>(); - // routingTable = new RoutingTable(KademliaCommonConfig.K, KademliaCommonConfig.BITS, 0); - // routingTable.setNodeId(id); } - /*public void setBlock(Block currentBlock) { - this.currentBlock = currentBlock; - }*/ - - /*public BigInteger[] getSamples(BigInteger peerId) { - - List result = new ArrayList<>(); - Collections.addAll( - result, - currentBlock.getSamplesByRadiusByColumn( - peerId, - currentBlock.computeRegionRadius(KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER))); - Collections.addAll( - result, - currentBlock.getSamplesByRadiusByRow( - peerId, - currentBlock.computeRegionRadius(KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER))); - - return result.toArray(new BigInteger[0]); - }*/ - public void addNeighbour(Neighbour neigh) { if (neigh.getId().compareTo(builderAddress) != 0) { if (neighbours.get(neigh.getId()) == null) { @@ -89,32 +61,11 @@ public void addNodes(BigInteger[] nodes) { } } - /*public void seenNeighbour(BigInteger id, Node n) { - if (id.compareTo(builderAddress) != 0) { - if (neighbours.get(id) != null) { - neighbours.get(id).updateLastSeen(CommonState.getTime()); - } else { - nodesIndexed.add(id); - neighbours.put(id, new Neighbour(id, n, n.getDASProtocol().isEvil())); - } - } - }*/ - - /*public void addNonValidatorNodes(BigInteger[] nodes) { - - for (BigInteger id : nodes) { - if (!blackList.contains(id) && !validatorsIndexed.contains(id)) { - nodesIndexed.add(id); - } - } - }*/ - public void addValidatorNodes(BigInteger[] nodes) { for (BigInteger id : nodes) { if (!blackList.contains(id) && id.compareTo(builderAddress) != 0) { validatorsIndexed.add(id); } - // routingTable.addNeighbour(id); } } @@ -123,9 +74,7 @@ public void setBuilderAddress(BigInteger builderAddress) { } public void removeNode(BigInteger node) { - // this.blackList.add(node); this.nodesIndexed.remove(node); - // this.validatorsIndexed.remove(node); this.nonValidatorsIndexed.remove(node); this.neighbours.remove(node); validatorsIndexed.remove(node); @@ -139,10 +88,6 @@ public TreeSet getValidatorsIndexed() { return validatorsIndexed; } - /*public HashSet samplesIndexed() { - return samplesIndexed; - }*/ - public List getNodesbySample(BigInteger sampleId, BigInteger radius) { BigInteger bottom = sampleId.subtract(radius); @@ -153,9 +98,6 @@ public List getNodesbySample(BigInteger sampleId, BigInteger radius) Collection subSet = nodesIndexed.subSet(bottom, true, top, true); return new ArrayList(subSet); - - // return sampleMap.get(sampleId); - } public List getValidatorNodesbySample(BigInteger sampleId, BigInteger radius) { @@ -167,9 +109,6 @@ public List getValidatorNodesbySample(BigInteger sampleId, BigIntege if (top.compareTo(Block.MAX_KEY) == 1) top = Block.MAX_KEY; Collection subSet = validatorsIndexed.subSet(bottom, true, top, true); return new ArrayList(subSet); - - // return sampleMap.get(sampleId); - } public List getNonValidatorNodesbySample(BigInteger sampleId, BigInteger radius) { @@ -182,9 +121,6 @@ public List getNonValidatorNodesbySample(BigInteger sampleId, BigInt Collection subSet = nonValidatorsIndexed.subSet(bottom, true, top, true); return new ArrayList(subSet); - - // return sampleMap.get(sampleId); - } public List getNodesbySample(Set samples, BigInteger radius) { @@ -192,7 +128,6 @@ public List getNodesbySample(Set samples, BigInteger rad List result = new ArrayList<>(); for (BigInteger sample : samples) { - // if (sampleMap.get(sample) != null) result.addAll(sampleMap.get(sample)); result.addAll(getNodesbySample(sample, radius)); } return result; @@ -214,6 +149,21 @@ public Neighbour[] getNeighbours() { return result.toArray(new Neighbour[0]); } + public void setEvilIds(List ids) { + this.evilIds = ids; + } + + public Neighbour[] getEvilNeighbours() { + + List result = new ArrayList<>(); + if (evilIds != null) { + for (Node n : evilIds) { + result.add(new Neighbour(n.getDASProtocol().getKademliaId(), n, true)); + } + } + return result.toArray(new Neighbour[0]); + } + public Neighbour[] getNeighbours(BigInteger id, BigInteger radius) { List nodes = getNodesbySample(id, radius); From efc95450cbe0a6ce95c08d246843489429c19455 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Fri, 27 Oct 2023 18:09:27 +0200 Subject: [PATCH 46/98] clean code --- simulator/config/dasprotocol.cfg | 50 ++++---- .../peersim/kademlia/das/DASProtocol.java | 10 +- .../peersim/kademlia/das/SearchTable.java | 112 ------------------ 3 files changed, 30 insertions(+), 142 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index e5ba37d4..7d751292 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 1000 +SIZE 100 # Random seed K 5 @@ -14,7 +14,7 @@ MINDELAY 5 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*1 +SIM_TIME 1000*60*30 #Traffic generator is executed every TRAFFIC_STEP @@ -111,7 +111,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 100 +control.0traffic.block_dim_size 10 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia @@ -120,30 +120,30 @@ control.1refresh peersim.kademlia.das.RefreshSearchTable control.1refresh.step REFRESH_STEP # turbulence non-validator -control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas -control.2turbolenceAdd.protocolkad 3kademlia -control.2turbolenceAdd.protocoldasbuilder 4dasprotocol -control.2turbolenceAdd.protocoldasvalidator 5dasprotocol -control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol -control.2turbolenceAdd.protocolEvildas 7evildasprotocol -control.2turbolenceAdd.transport 2unreltr -control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL -control.2turbolenceAdd.p_idle 0.1 -control.2turbolenceAdd.p_rem 0.45 -control.2turbolenceAdd.p_add 0.45 +#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +#control.2turbolenceAdd.protocolkad 3kademlia +#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.2turbolenceAdd.protocolEvildas 7evildasprotocol +#control.2turbolenceAdd.transport 2unreltr +#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +#control.2turbolenceAdd.p_idle 0.1 +#control.2turbolenceAdd.p_rem 0.45 +#control.2turbolenceAdd.p_add 0.45 # turbulence validators -control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator -control.3turbolenceAdd.protocolkad 3kademlia -control.3turbolenceAdd.protocoldasbuilder 4dasprotocol -control.3turbolenceAdd.protocoldasvalidator 5dasprotocol -control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol -control.3turbolenceAdd.protocolEvildas 7evildasprotocol -control.3turbolenceAdd.transport 2unreltr -control.3turbolenceAdd.step TURBULENCE_STEP -control.3turbolenceAdd.p_idle 0.9 -control.3turbolenceAdd.p_rem 0.05 -control.3turbolenceAdd.p_add 0.05 +#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +#control.3turbolenceAdd.protocolkad 3kademlia +#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.3turbolenceAdd.protocolEvildas 7evildasprotocol +#control.3turbolenceAdd.transport 2unreltr +#control.3turbolenceAdd.step TURBULENCE_STEP +#control.3turbolenceAdd.p_idle 0.9 +#control.3turbolenceAdd.p_rem 0.05 +#control.3turbolenceAdd.p_add 0.05 # ::::: OBSERVER ::::: #The observer is executed every OBSERVER_STEP and will generate data traces diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 767dee7b..9470c0a8 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -274,7 +274,7 @@ protected void handleInitNewBlock(Message m, int myPid) { // samplesRequested = 0; row = new int[currentBlock.getSize()]; column = new int[currentBlock.getSize()]; - + sentMsg.clear(); // clearing any pending operation from previous block for (SamplingOperation sop : samplingOp.values()) { KademliaObserver.reportOperation(sop); @@ -310,7 +310,7 @@ protected void handleSeedSample(Message m, int myPid) { protected void handleGetSample(Message m, int myPid) { // kv is for storing the sample you have - logger.info("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); + logger.warning("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); // sample IDs that are requested in the message List samples = Arrays.asList((BigInteger[]) m.body); @@ -526,7 +526,7 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { if (m.getType() == Message.MSG_GET_SAMPLE) { // is a request Timeout t = new Timeout(destId, m.id, m.operationId); long latency = transport.getLatency(src, dest); - logger.info("Send message added " + m.id + " " + latency + " " + destId); + logger.warning("Send message added " + m.id + " " + latency + " " + destId); // add to sent msg this.sentMsg.put(m.id, m.timestamp); @@ -624,8 +624,8 @@ protected boolean doSampling(SamplingOperation sop) { KademliaObserver.reportOperation(sop); // logger.warning("Sampling operation finished " + sop.getId()); if (sop instanceof ValidatorSamplingOperation) - logger.warning("Sampling operation finished validator dosampling " + sop.getId()); - else logger.warning("Sampling operation finished random dosampling " + sop.getId()); + logger.warning("Sampling operation completed validator dosampling " + sop.getId()); + else logger.warning("Sampling operation completed random dosampling " + sop.getId()); return true; } else { boolean success = false; diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index a58be836..ecebe2b0 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -233,116 +233,4 @@ public void refresh() { for (Neighbour n : toRemove) neighbours.remove(n.getId()); } - /*public static void createSampleMap(Block currentBlock) { - - int validatorParcelSize = - (currentBlock.getSize() - * currentBlock.getSize() - * KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER) - / KademliaCommonConfigDas.validatorsSize; - - if (validatorParcelSize == 0) validatorParcelSize = 1; - Random r = new Random(); - List list = new ArrayList(validatorsIndexed); - - List sampleList = new ArrayList<>(); - - // Assigning samples to node by row - for (int h = 0; h < KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER; h++) { - for (int i = 0; i < currentBlock.getSize(); i++) { - for (int j = 0; j < currentBlock.getSize(); j++) { - sampleList.add(currentBlock.getSample(i, j).getIdByRow()); - if (sampleList.size() == validatorParcelSize) { - BigInteger node = list.get(r.nextInt(list.size())); - // samples.put(node, sampleList); - for (BigInteger sample : sampleList) { - if (sampleMap.containsKey(sample)) { - - sampleMap.get(sample).add(node); - } else { - List nList = new ArrayList<>(); - nList.add(node); - sampleMap.put(sample, nList); - } - } - sampleList.clear(); - } - } - } - } - if (sampleList.size() != 0) { - BigInteger node = list.get(r.nextInt(list.size())); - // samples.put(node, sampleList); - for (BigInteger sample : sampleList) { - if (sampleMap.containsKey(sample)) sampleMap.get(sample).add(node); - else { - List nList = new ArrayList<>(); - nList.add(node); - sampleMap.put(sample, nList); - } - } - sampleList.clear(); - } - - // Assigning samples to node by column - for (int h = 0; h < KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER; h++) { - for (int i = 0; i < currentBlock.getSize(); i++) { - for (int j = 0; j < currentBlock.getSize(); j++) { - sampleList.add(currentBlock.getSample(j, i).getIdByColumn()); - if (sampleList.size() == validatorParcelSize) { - BigInteger node = list.get(r.nextInt(list.size())); - // samples.put(node, sampleList); - for (BigInteger sample : sampleList) { - // System.out.println("assign samples to node " + node + " " + nodeMap.size()); - if (sampleMap.containsKey(sample)) { - - sampleMap.get(sample).add(node); - } else { - List nList = new ArrayList<>(); - nList.add(node); - sampleMap.put(sample, nList); - } - } - sampleList.clear(); - } - } - } - } - if (sampleList.size() != 0) { - BigInteger node = list.get(r.nextInt(list.size())); - // samples.put(node, sampleList); - for (BigInteger sample : sampleList) { - if (sampleMap.containsKey(sample)) sampleMap.get(sample).add(node); - else { - List nList = new ArrayList<>(); - nList.add(node); - sampleMap.put(sample, nList); - } - } - sampleList.clear(); - } - - System.out.println( - "samples " - + validatorParcelSize - + " " - + sampleMap.size() - + " " - + sampleList.size() - + " " - + currentBlock.getSize()); - - //for (List l : sampleMap.values()) { - // System.out.println("samples " + l.size()); - //} - }*/ - - /*public static List getNodesBySample(BigInteger s) { - return sampleMap.get(s); - } - - public BigInteger[] findKClosestValidators(BigInteger sampleId) { - - return routingTable.getNeighbours(sampleId, sampleId); - }*/ } From b7f8c54ab46ecb9401766fad09777ae9a86e119a Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Fri, 27 Oct 2023 18:16:15 +0200 Subject: [PATCH 47/98] make report msg optional --- .../src/main/java/peersim/kademlia/das/DASProtocol.java | 6 ++++-- .../src/main/java/peersim/kademlia/das/SearchTable.java | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 9470c0a8..255b5db5 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -44,8 +44,9 @@ public abstract class DASProtocol implements Cloneable, EDProtocol, KademliaEven protected static final String PAR_ALPHA = "alpha"; protected static final String PAR_PARCEL = "parcelSize"; protected static final String PAR_DISC = "reportDiscovery"; + protected static final String PAR_MSG = "reportMsg"; - private boolean reportDiscovery; + private boolean reportDiscovery, msgReport; private static String prefix = null; private UnreliableTransport transport; /** Store the time until which this node's uplink is busy sending data */ @@ -123,6 +124,7 @@ public DASProtocol(String prefix) { Configuration.getInt(prefix + "." + PAR_PARCEL, KademliaCommonConfigDas.PARCEL_SIZE); reportDiscovery = Configuration.getBoolean(prefix + "." + PAR_DISC, false); + msgReport = Configuration.getBoolean(prefix + "." + PAR_MSG, false); kv = new KeyValueStore(); samplingOp = new LinkedHashMap(); @@ -164,7 +166,7 @@ public void processEvent(Node myNode, int myPid, Object event) { if (s instanceof Message) { m = (Message) event; // m.dst = this.kadProtocol.getKademliaNode(); - KademliaObserver.reportMsg(m, false); + if (msgReport) KademliaObserver.reportMsg(m, false); if (m.src != null) { Node n = Util.nodeIdtoNode(m.src.getId(), kademliaId); searchTable.addNeighbour(new Neighbour(m.src.getId(), n, n.getDASProtocol().isEvil())); diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index ecebe2b0..4c74547e 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -232,5 +232,4 @@ public void refresh() { } for (Neighbour n : toRemove) neighbours.remove(n.getId()); } - } From d0f881da4e4d4c5e2e53c4effb34db3812bf890f Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Mon, 30 Oct 2023 12:05:28 +0100 Subject: [PATCH 48/98] evil das protocol + config --- simulator/config/dasprotocol.cfg | 50 ++++---- .../config/malicious/dasprotocolevil.cfg | 111 ++++++++++++------ .../das/DASProtocolEvilNonValidator.java | 48 ++++++++ .../das/DASProtocolEvilValidator.java | 54 +++++++++ 4 files changed, 205 insertions(+), 58 deletions(-) create mode 100644 simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilNonValidator.java create mode 100644 simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilValidator.java diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 7d751292..89efff51 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 100 +SIZE 5000 # Random seed K 5 @@ -14,7 +14,7 @@ MINDELAY 5 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*30 +SIM_TIME 1000*60*10 #Traffic generator is executed every TRAFFIC_STEP @@ -111,7 +111,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 10 +control.0traffic.block_dim_size 512 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia @@ -120,30 +120,30 @@ control.1refresh peersim.kademlia.das.RefreshSearchTable control.1refresh.step REFRESH_STEP # turbulence non-validator -#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas -#control.2turbolenceAdd.protocolkad 3kademlia -#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol -#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol -#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol -#control.2turbolenceAdd.protocolEvildas 7evildasprotocol -#control.2turbolenceAdd.transport 2unreltr -#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL -#control.2turbolenceAdd.p_idle 0.1 -#control.2turbolenceAdd.p_rem 0.45 -#control.2turbolenceAdd.p_add 0.45 +control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +control.2turbolenceAdd.protocolkad 3kademlia +control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +control.2turbolenceAdd.protocolEvildas 7evildasprotocol +control.2turbolenceAdd.transport 2unreltr +control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +control.2turbolenceAdd.p_idle 0.1 +control.2turbolenceAdd.p_rem 0.45 +control.2turbolenceAdd.p_add 0.45 # turbulence validators -#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator -#control.3turbolenceAdd.protocolkad 3kademlia -#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol -#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol -#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol -#control.3turbolenceAdd.protocolEvildas 7evildasprotocol -#control.3turbolenceAdd.transport 2unreltr -#control.3turbolenceAdd.step TURBULENCE_STEP -#control.3turbolenceAdd.p_idle 0.9 -#control.3turbolenceAdd.p_rem 0.05 -#control.3turbolenceAdd.p_add 0.05 +control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +control.3turbolenceAdd.protocolkad 3kademlia +control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +control.3turbolenceAdd.protocolEvildas 7evildasprotocol +control.3turbolenceAdd.transport 2unreltr +control.3turbolenceAdd.step TURBULENCE_STEP +control.3turbolenceAdd.p_idle 0.9 +control.3turbolenceAdd.p_rem 0.05 +control.3turbolenceAdd.p_add 0.05 # ::::: OBSERVER ::::: #The observer is executed every OBSERVER_STEP and will generate data traces diff --git a/simulator/config/malicious/dasprotocolevil.cfg b/simulator/config/malicious/dasprotocolevil.cfg index 311b216d..03ff121c 100644 --- a/simulator/config/malicious/dasprotocolevil.cfg +++ b/simulator/config/malicious/dasprotocolevil.cfg @@ -5,24 +5,26 @@ # ::::: GLOBAL :::::: # Network size -SIZE 5000 +SIZE 1000 # Random seed K 5 -MINDELAY 100 +MINDELAY 5 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*12 +SIM_TIME 1000*60*10 + #Traffic generator is executed every TRAFFIC_STEP -TRAFFIC_STEP 300000 #10000000/SIZE +TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP -OBSERVER_STEP 100000 +OBSERVER_STEP 20000 #Turbulence module is executed every TURBULENCE_STEP enabling churning -TURBULENCE_STEP (SIM_TIME*20)/SIZE #100000000/SIZE - +TURBULENCE_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 +REFRESH_STEP 1000 # add network config parameters to simulation random.seed 24680 @@ -37,14 +39,16 @@ network.size SIZE protocol.0link peersim.core.IdleProtocol #A protocol that stores links. It does nothing apart from that. Use by default -protocol.1uniftr peersim.transport.UniformRandomTransport -protocol.1uniftr.mindelay MINDELAY -protocol.1uniftr.maxdelay MAXDELAY +protocol.1pairwiselattr peersim.transport.PairwiseFixedLatencyTransport +protocol.1pairwiselattr.mindelay MINDELAY +protocol.1pairwiselattr.maxdelay MAXDELAY +protocol.1pairwiselattr.size SIZE + #transport layer that reliably delivers messages with a random delay, emulating TCP protocol.2unreltr peersim.transport.UnreliableTransport protocol.2unreltr.drop 0 -protocol.2unreltr.transport 1uniftr +protocol.2unreltr.transport 1pairwiselattr #Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. #Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P @@ -56,23 +60,43 @@ protocol.3kademlia.FINDMODE 1 #Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. #Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P -protocol.4dasprotocol peersim.kademlia.das.DASProtocol +protocol.4dasprotocol peersim.kademlia.das.DASProtocolBuilder protocol.4dasprotocol.transport 2unreltr protocol.4dasprotocol.kademlia 3kademlia +protocol.4dasprotocol.reportDiscovery false + +protocol.5dasprotocol peersim.kademlia.das.DASProtocolValidator +protocol.5dasprotocol.transport 2unreltr +protocol.5dasprotocol.kademlia 3kademlia +protocol.5dasprotocol.reportDiscovery false + +protocol.6dasprotocol peersim.kademlia.das.DASProtocolNonValidator +protocol.6dasprotocol.transport 2unreltr +protocol.6dasprotocol.kademlia 3kademlia +protocol.6dasprotocol.reportDiscovery false -protocol.5evildasprotocol peersim.kademlia.das.EvilDASProtocol -protocol.5evildasprotocol.transport 2unreltr -protocol.5evildasprotocol.kademlia 3kademlia -#init.1uniqueNodeID.protocolEvildas 5evildasprotocol +protocol.7evildasprotocol peersim.kademlia.das.DASProtocolEvilValidator +protocol.7evildasprotocol.transport 2unreltr +protocol.7evildasprotocol.kademlia 3kademlia +protocol.7evildasprotocol.reportDiscovery false + +protocol.8evildasprotocol peersim.kademlia.das.DASProtocolEvilNonValidator +protocol.8evildasprotocol.transport 2unreltr +protocol.8evildasprotocol.kademlia 3kademlia +protocol.8evildasprotocol.reportDiscovery false # ::::: INITIALIZERS ::::: #Class that initializes nodes with kademlia protocol and generates uniform ids init.1uniqueNodeID peersim.kademlia.das.CustomDistributionDas init.1uniqueNodeID.protocolkad 3kademlia -init.1uniqueNodeID.protocoldas 4dasprotocol -init.1uniqueNodeID.protocolEvildas 5evildasprotocol +init.1uniqueNodeID.protocoldasbuilder 4dasprotocol +init.1uniqueNodeID.protocoldasvalidator 5dasprotocol +init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol +init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol +init.1uniqueNodeID.protocolEvildas 8evildasprotocol init.1uniqueNodeID.validator_rate 1.0 -init.1uniqueNodeID.evilNodeRatio 0.5 +init.1uniqueNodeID.evilNodeRatioValidator 0.5 +init.1uniqueNodeID.evilNodeRatioNonValidator 0 #Adds initial state to the routing tables @@ -84,25 +108,46 @@ init.2statebuilder.transport 2unreltr #TrafficGenerator class sends and initial control.0traffic peersim.kademlia.das.TrafficGeneratorSample -control.0traffic.kadprotocol 3kademlia -control.0traffic.dasprotocol 4dasprotocol control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 512 +control.0traffic.block_dim_size 100 +control.0traffic.num_samples 75 +control.0traffic.kadprotocol 3kademlia -# turbulence -#control.2turbolenceAdd peersim.kademlia.Turbulence -#control.2turbolenceAdd.protocol 3kademlia +#TrafficGenerator class sends and initial +control.1refresh peersim.kademlia.das.RefreshSearchTable +control.1refresh.step REFRESH_STEP + +# turbulence non-validator +#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +#control.2turbolenceAdd.protocolkad 3kademlia +#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.2turbolenceAdd.protocolEvildas 7evildasprotocol #control.2turbolenceAdd.transport 2unreltr -#control.2turbolenceAdd.step TURBULENCE_STEP -#control.2turbolenceAdd.p_idle 0.5 -#control.2turbolenceAdd.p_rem 0.25 -#control.2turbolenceAdd.p_add 0.25 +#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +#control.2turbolenceAdd.p_idle 0.1 +#control.2turbolenceAdd.p_rem 0.45 +#control.2turbolenceAdd.p_add 0.45 + +# turbulence validators +#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +#control.3turbolenceAdd.protocolkad 3kademlia +#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.3turbolenceAdd.protocolEvildas 7evildasprotocol +#control.3turbolenceAdd.transport 2unreltr +#control.3turbolenceAdd.step TURBULENCE_STEP +#control.3turbolenceAdd.p_idle 0.9 +#control.3turbolenceAdd.p_rem 0.05 +#control.3turbolenceAdd.p_add 0.05 # ::::: OBSERVER ::::: #The observer is executed every OBSERVER_STEP and will generate data traces -control.3 peersim.kademlia.KademliaObserver -control.3.protocol 3kademlia -control.3.step OBSERVER_STEP -control.3.logfolder logsTest0.5 \ No newline at end of file +control.4 peersim.kademlia.KademliaObserver +control.4.protocol 3kademlia +control.4.step OBSERVER_STEP +control.4.logfolder logsDasEvil diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilNonValidator.java new file mode 100644 index 00000000..e84c35b2 --- /dev/null +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilNonValidator.java @@ -0,0 +1,48 @@ +package peersim.kademlia.das; + +import peersim.kademlia.Message; + +public class DASProtocolEvilNonValidator extends DASProtocolNonValidator { + + protected static String prefix = null; + + public DASProtocolEvilNonValidator(String prefix) { + super(prefix); + DASProtocolEvilNonValidator.prefix = prefix; + isEvil = true; + isValidator = false; + isBuilder = false; + } + + @Override + protected void handleInitGetSample(Message m, int myPid) { + logger.warning("Init block evil node validator - getting samples " + this); + // super.handleInitGetSample(m, myPid); + } + + protected void handleGetSample(Message m, int myPid) { + // kv is for storing the sample you have + logger.info("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); + // sample IDs that are requested in the message + + Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, new Sample[] {}); + response.operationId = m.operationId; + response.dst = m.src; + response.src = this.kadProtocol.getKademliaNode(); + response.ackId = m.id; // set ACK number + response.value = searchTable.getEvilNeighbours(); + + sendMessage(response, m.src.getId(), myPid); + } + /** + * Replicate this object by returning an identical copy.
+ * It is called by the initializer and do not fill any particular field. + * + * @return Object + */ + public Object clone() { + DASProtocolEvilNonValidator dolly = + new DASProtocolEvilNonValidator(DASProtocolEvilNonValidator.prefix); + return dolly; + } +} diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilValidator.java new file mode 100644 index 00000000..a600459a --- /dev/null +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilValidator.java @@ -0,0 +1,54 @@ +package peersim.kademlia.das; + +import java.util.List; +import peersim.core.Node; +import peersim.kademlia.Message; + +public class DASProtocolEvilValidator extends DASProtocolValidator { + + protected static String prefix = null; + + public DASProtocolEvilValidator(String prefix) { + super(prefix); + DASProtocolEvilValidator.prefix = prefix; + isEvil = true; + isValidator = true; + isBuilder = false; + } + + @Override + protected void handleInitGetSample(Message m, int myPid) { + logger.warning("Init block evil node validator - getting samples " + this); + // super.handleInitGetSample(m, myPid); + } + + protected void handleGetSample(Message m, int myPid) { + // kv is for storing the sample you have + logger.info("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); + // sample IDs that are requested in the message + + Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, new Sample[] {}); + response.operationId = m.operationId; + response.dst = m.src; + response.src = this.kadProtocol.getKademliaNode(); + response.ackId = m.id; // set ACK number + response.value = searchTable.getEvilNeighbours(); + + sendMessage(response, m.src.getId(), myPid); + } + + public void setEvilIds(List evilIds) { + searchTable.setEvilIds(evilIds); + } + + /** + * Replicate this object by returning an identical copy.
+ * It is called by the initializer and do not fill any particular field. + * + * @return Object + */ + public Object clone() { + DASProtocolEvilValidator dolly = new DASProtocolEvilValidator(DASProtocolEvilValidator.prefix); + return dolly; + } +} From 0f6768c41d5e011d580d87ec73d0bae7804cd18d Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Mon, 30 Oct 2023 12:10:18 +0100 Subject: [PATCH 49/98] disable discovery table reporting for evil nodes --- simulator/config/malicious/dasprotocolevil.cfg | 10 +++++----- .../main/java/peersim/kademlia/das/DASProtocol.java | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil.cfg b/simulator/config/malicious/dasprotocolevil.cfg index 03ff121c..924a1208 100644 --- a/simulator/config/malicious/dasprotocolevil.cfg +++ b/simulator/config/malicious/dasprotocolevil.cfg @@ -63,27 +63,27 @@ protocol.3kademlia.FINDMODE 1 protocol.4dasprotocol peersim.kademlia.das.DASProtocolBuilder protocol.4dasprotocol.transport 2unreltr protocol.4dasprotocol.kademlia 3kademlia -protocol.4dasprotocol.reportDiscovery false +protocol.4dasprotocol.reportDiscovery true protocol.5dasprotocol peersim.kademlia.das.DASProtocolValidator protocol.5dasprotocol.transport 2unreltr protocol.5dasprotocol.kademlia 3kademlia -protocol.5dasprotocol.reportDiscovery false +protocol.5dasprotocol.reportDiscovery true protocol.6dasprotocol peersim.kademlia.das.DASProtocolNonValidator protocol.6dasprotocol.transport 2unreltr protocol.6dasprotocol.kademlia 3kademlia -protocol.6dasprotocol.reportDiscovery false +protocol.6dasprotocol.reportDiscovery true protocol.7evildasprotocol peersim.kademlia.das.DASProtocolEvilValidator protocol.7evildasprotocol.transport 2unreltr protocol.7evildasprotocol.kademlia 3kademlia -protocol.7evildasprotocol.reportDiscovery false +protocol.7evildasprotocol.reportDiscovery true protocol.8evildasprotocol peersim.kademlia.das.DASProtocolEvilNonValidator protocol.8evildasprotocol.transport 2unreltr protocol.8evildasprotocol.kademlia 3kademlia -protocol.8evildasprotocol.reportDiscovery false +protocol.8evildasprotocol.reportDiscovery true # ::::: INITIALIZERS ::::: #Class that initializes nodes with kademlia protocol and generates uniform ids diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 255b5db5..6de908b1 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -385,7 +385,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { logger.info("Samples received " + samples.length + " from " + m.src.getId()); - if (reportDiscovery) KademliaObserver.reportPeerDiscovery(m, searchTable); + if (reportDiscovery && !isEvil()) KademliaObserver.reportPeerDiscovery(m, searchTable); for (Neighbour neigh : (Neighbour[]) m.value) { if (neigh.getId().compareTo(builderAddress) != 0) searchTable.addNeighbour(neigh); } From a558284626b3629a0861b86663aa177bf8e27028 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Mon, 30 Oct 2023 12:12:36 +0100 Subject: [PATCH 50/98] return random nodes search table --- simulator/src/main/java/peersim/kademlia/das/SearchTable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index 4c74547e..660055e3 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -172,7 +172,7 @@ public Neighbour[] getNeighbours(BigInteger id, BigInteger radius) { for (BigInteger n : nodes) { neighs.add(neighbours.get(n)); } - Collections.sort(neighs); + Collections.shuffle(neighs); for (Neighbour neigh : neighs) { if (result.size() < KademliaCommonConfigDas.MAX_NODES_RETURNED) result.add(neigh); From 2c01ddbe9f2e37116231e3dad0584aebc4a08d7c Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Mon, 30 Oct 2023 13:08:41 +0100 Subject: [PATCH 51/98] limit number of evil nodes returned search table --- simulator/config/malicious/dasprotocolevil.cfg | 4 ++-- .../src/main/java/peersim/kademlia/KademliaObserver.java | 1 + .../src/main/java/peersim/kademlia/das/SearchTable.java | 5 ++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil.cfg b/simulator/config/malicious/dasprotocolevil.cfg index 924a1208..ef070f08 100644 --- a/simulator/config/malicious/dasprotocolevil.cfg +++ b/simulator/config/malicious/dasprotocolevil.cfg @@ -14,7 +14,7 @@ MINDELAY 5 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*10 +SIM_TIME 1000*60*1 #Traffic generator is executed every TRAFFIC_STEP @@ -111,7 +111,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 100 +control.0traffic.block_dim_size 512 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia diff --git a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java index b03dc514..69bdf130 100755 --- a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java +++ b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java @@ -223,6 +223,7 @@ public static void reportPeerDiscovery(Message m, SearchTable st) { result.put("total_peers_alive", st.getAllAliveNeighboursCount()); result.put("peers_in_message", neighs.length); result.put("peers_not_known", notKnown); + result.put("malicious_peers", st.getMaliciousNeighboursCount()); result.put("validators_discovered", st.getValidatorsNeighboursCount()); peerDiscoveries.put(m.id, result); } diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index 660055e3..eec823e1 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -157,8 +157,11 @@ public Neighbour[] getEvilNeighbours() { List result = new ArrayList<>(); if (evilIds != null) { + Collections.shuffle(evilIds); for (Node n : evilIds) { - result.add(new Neighbour(n.getDASProtocol().getKademliaId(), n, true)); + if (result.size() < KademliaCommonConfigDas.MAX_NODES_RETURNED) + result.add(new Neighbour(n.getDASProtocol().getKademliaId(), n, true)); + else break; } } return result.toArray(new Neighbour[0]); From ad439a0cd842771b2f74dc3480f025079925823f Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Mon, 30 Oct 2023 16:33:25 +0100 Subject: [PATCH 52/98] adding extra nodes in the same row/column for sampling to overcome malicious --- .../config/malicious/dasprotocolevil.cfg | 2 +- .../das/operations/FetchingSample.java | 4 +++ .../operations/RandomSamplingOperation.java | 3 ++ .../das/operations/SamplingOperation.java | 6 +++- .../ValidatorSamplingOperation.java | 32 +++++++++++++++++++ 5 files changed, 45 insertions(+), 2 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil.cfg b/simulator/config/malicious/dasprotocolevil.cfg index ef070f08..9967a064 100644 --- a/simulator/config/malicious/dasprotocolevil.cfg +++ b/simulator/config/malicious/dasprotocolevil.cfg @@ -95,7 +95,7 @@ init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol init.1uniqueNodeID.protocolEvildas 8evildasprotocol init.1uniqueNodeID.validator_rate 1.0 -init.1uniqueNodeID.evilNodeRatioValidator 0.5 +init.1uniqueNodeID.evilNodeRatioValidator 0.25 init.1uniqueNodeID.evilNodeRatioNonValidator 0 diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/FetchingSample.java b/simulator/src/main/java/peersim/kademlia/das/operations/FetchingSample.java index a22e10ce..69f00359 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/FetchingSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/FetchingSample.java @@ -25,6 +25,10 @@ public BigInteger getId() { return s.getId(); } + public Sample getSample(){ + return s; + } + public BigInteger getIdByColumn() { return s.getIdByColumn(); } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index b5859c6d..2e604d28 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -146,6 +146,9 @@ protected void createNodes() { } } + protected void addExtraNodes() { + + } public Map toMap() { // System.out.println("Mapping"); Map result = new HashMap(); diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index 38450e5c..3a3664cc 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -107,6 +107,8 @@ public BigInteger getRadiusNonValidator() { protected abstract void createNodes(); + protected abstract void addExtraNodes(); + public BigInteger[] doSampling() { aggressiveness += KademliaCommonConfigDas.aggressiveness_step; @@ -140,10 +142,12 @@ public BigInteger[] doSampling() { for (BigInteger id : toRemove) nodes.remove(id); if (nodes.isEmpty()) { - createNodes(); // System.out.println("[" + srcNode + "] Repopulating nodes " + nodes.size()); } + if(nodes.isEmpty()){ + addExtraNodes(); + } for (Node n : nodes.values()) n.setAgressiveness(aggressiveness); List result = new ArrayList<>(); for (Node n : nodes.values()) { diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index dff871d3..afe2e4b9 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -177,6 +177,38 @@ protected void createNodes() { } } + protected void addExtraNodes() { + for (BigInteger sample : samples.keySet()) { + if (!samples.get(sample).isDownloaded()) { + List nodesBySample = new ArrayList<>(); + BigInteger radiusUsed = radiusValidator; + if(row>0){ + Sample[] sRow = currentBlock.getSamplesByRow(samples.get(sample).getSample().getRow()); + for(Sample s : sRow){ + nodesBySample.addAll(searchTable.getNodesbySample(s.getId(), radiusUsed)); + } + } else { + Sample[] sColumn = currentBlock.getSamplesByColumn(samples.get(sample).getSample().getColumn()); + for(Sample s : sColumn){ + nodesBySample.addAll(searchTable.getNodesbySample(s.getIdByColumn(), radiusUsed)); + } + } + + nodesBySample.removeAll(askedNodes); + if (nodesBySample != null && nodesBySample.size() > 0) { + for (BigInteger id : nodesBySample) { + if (!nodes.containsKey(id)) { + nodes.put(id, new Node(id)); + nodes.get(id).addSample(samples.get(sample)); + } else { + nodes.get(id).addSample(samples.get(sample)); + } + } + } + } + } + } + public Map toMap() { // System.out.println("Mapping"); Map result = new HashMap(); From 92425554f45589dff979cf1ac22c6b7b3700e58d Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Wed, 1 Nov 2023 11:21:36 +0100 Subject: [PATCH 53/98] back to multiple samples per message --- simulator/config/dasprotocol.cfg | 4 +- .../config/malicious/dasprotocolevil.cfg | 8 +- .../src/main/java/peersim/kademlia/Util.java | 17 ++++ .../main/java/peersim/kademlia/das/Block.java | 49 ++++++++++-- .../peersim/kademlia/das/DASProtocol.java | 77 +++++++++++++++---- .../das/DASProtocolEvilNonValidator.java | 3 +- .../das/DASProtocolEvilValidator.java | 3 +- .../kademlia/das/DASProtocolValidator.java | 16 +++- .../peersim/kademlia/das/SearchTable.java | 16 ++-- .../das/operations/FetchingSample.java | 2 +- .../operations/RandomSamplingOperation.java | 3 +- .../das/operations/SamplingOperation.java | 14 +++- .../ValidatorSamplingOperation.java | 18 +++-- 13 files changed, 180 insertions(+), 50 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 89efff51..4bbc4927 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -14,7 +14,7 @@ MINDELAY 5 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*10 +SIM_TIME 1000*60*1 #Traffic generator is executed every TRAFFIC_STEP @@ -111,7 +111,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 512 +control.0traffic.block_dim_size 100 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia diff --git a/simulator/config/malicious/dasprotocolevil.cfg b/simulator/config/malicious/dasprotocolevil.cfg index 9967a064..144b133c 100644 --- a/simulator/config/malicious/dasprotocolevil.cfg +++ b/simulator/config/malicious/dasprotocolevil.cfg @@ -20,7 +20,7 @@ SIM_TIME 1000*60*1 #Traffic generator is executed every TRAFFIC_STEP TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP -OBSERVER_STEP 20000 +OBSERVER_STEP 10000 #Turbulence module is executed every TURBULENCE_STEP enabling churning TURBULENCE_STEP 1000 TURBULENCE_STEP_NONVAL 1000 @@ -95,7 +95,7 @@ init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol init.1uniqueNodeID.protocolEvildas 8evildasprotocol init.1uniqueNodeID.validator_rate 1.0 -init.1uniqueNodeID.evilNodeRatioValidator 0.25 +init.1uniqueNodeID.evilNodeRatioValidator 0.5 init.1uniqueNodeID.evilNodeRatioNonValidator 0 @@ -111,7 +111,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 512 +control.0traffic.block_dim_size 100 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia @@ -150,4 +150,4 @@ control.1refresh.step REFRESH_STEP control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logsDasEvil +control.4.logfolder logsDasEvil2 diff --git a/simulator/src/main/java/peersim/kademlia/Util.java b/simulator/src/main/java/peersim/kademlia/Util.java index 569e78fe..bf30c84b 100755 --- a/simulator/src/main/java/peersim/kademlia/Util.java +++ b/simulator/src/main/java/peersim/kademlia/Util.java @@ -1,7 +1,13 @@ package peersim.kademlia; +import com.google.common.base.Functions; import java.math.BigInteger; +import java.util.Collection; +import java.util.Comparator; +import java.util.Map.Entry; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; import peersim.core.CommonState; import peersim.core.Network; import peersim.core.Node; @@ -200,4 +206,15 @@ public static Node nodeIdtoNode(BigInteger searchNodeId, int kademliaid) { // If no node with the desired ID was found, return null return null; } + + public static V mostCommon(final Collection items) { + return items.stream() + .filter(Objects::nonNull) + .collect(Collectors.groupingBy(Functions.identity(), Collectors.counting())) + .entrySet() + .stream() + .max(Comparator.comparing(Entry::getValue)) + .map(Entry::getKey) + .orElse(null); + } } diff --git a/simulator/src/main/java/peersim/kademlia/das/Block.java b/simulator/src/main/java/peersim/kademlia/das/Block.java index f07af034..a87ad93a 100644 --- a/simulator/src/main/java/peersim/kademlia/das/Block.java +++ b/simulator/src/main/java/peersim/kademlia/das/Block.java @@ -11,6 +11,7 @@ import peersim.core.CommonState; import peersim.core.Network; import peersim.kademlia.KademliaCommonConfig; +import peersim.kademlia.Util; public class Block implements Iterator, Cloneable { @@ -45,6 +46,8 @@ public class Block implements Iterator, Cloneable { private HashMap> parcelByRow; private HashMap> parcelByColumn; + private HashMap sampleMap; + // Constructor with block id public Block(long id) { @@ -59,7 +62,7 @@ public Block(long id) { this.blockId = id; blockSamples = new Sample[SIZE][SIZE]; row = column = 0; - + sampleMap = new HashMap<>(); parcelMap = new HashMap<>(); parcelByRow = new HashMap<>(); parcelByColumn = new HashMap<>(); @@ -68,7 +71,8 @@ public Block(long id) { blockSamples[i][j] = new Sample(blockId, i + 1, j + 1, this); samplesByRow.add(blockSamples[i][j].getIdByRow()); samplesByColumn.add(blockSamples[i][j].getIdByColumn()); - // sampleMap.put(blockSamples[i][j].getIdByColumn(), blockSamples[i][j].getIdByRow()); + sampleMap.put(blockSamples[i][j].getIdByRow(), blockSamples[i][j]); + sampleMap.put(blockSamples[i][j].getIdByColumn(), blockSamples[i][j]); } } } @@ -86,7 +90,7 @@ public Block(int size, long id) { this.blockId = id; blockSamples = new Sample[SIZE][SIZE]; row = column = 0; - + sampleMap = new HashMap<>(); parcelMap = new HashMap<>(); parcelByRow = new HashMap<>(); parcelByColumn = new HashMap<>(); @@ -96,7 +100,8 @@ public Block(int size, long id) { blockSamples[i][j] = new Sample(blockId, i + 1, j + 1, this); samplesByRow.add(blockSamples[i][j].getIdByRow()); samplesByColumn.add(blockSamples[i][j].getIdByColumn()); - // sampleMap.put(blockSamples[i][j].getIdByColumn(), blockSamples[i][j].getIdByRow()); + sampleMap.put(blockSamples[i][j].getIdByRow(), blockSamples[i][j]); + sampleMap.put(blockSamples[i][j].getIdByColumn(), blockSamples[i][j]); } } } @@ -112,13 +117,15 @@ public Block(Sample[][] blockSamples, int size, long id) { // samples = new TreeSet<>(); samplesByRow = new TreeSet<>(); samplesByColumn = new TreeSet<>(); + sampleMap = new HashMap<>(); for (int i = 0; i < blockSamples.length; i++) { for (int j = 0; j < blockSamples[0].length; j++) { blockSamples[i][j] = new Sample(blockId, i + 1, j + 1, this); samplesByRow.add(blockSamples[i][j].getIdByRow()); samplesByColumn.add(blockSamples[i][j].getIdByColumn()); - // sampleMap.put(blockSamples[i][j].getIdByColumn(), blockSamples[i][j].getIdByRow()); + sampleMap.put(blockSamples[i][j].getIdByRow(), blockSamples[i][j]); + sampleMap.put(blockSamples[i][j].getIdByColumn(), blockSamples[i][j]); } } } @@ -264,6 +271,38 @@ public BigInteger[] getNRandomSamplesIds(int n) { return samples; } + public int findClosestRow(BigInteger nodeid, BigInteger radius) { + BigInteger bottom = nodeid.subtract(radius); + if (radius.compareTo(nodeid) == 1) bottom = BigInteger.ZERO; + + BigInteger top = nodeid.add(radius); + if (top.compareTo(Block.MAX_KEY) == 1) top = Block.MAX_KEY; + + Collection subSet = samplesByRow.subSet(bottom, true, top, true); + List rows = new ArrayList<>(); + for (BigInteger id : subSet) { + rows.add(sampleMap.get(id).getRow()); + } + System.out.println(rows.size() + " " + KademliaCommonConfigDas.validatorsSize + " " + radius); + return Util.mostCommon(rows); + } + + public int findClosestColumn(BigInteger nodeid, BigInteger radius) { + + BigInteger bottom = nodeid.subtract(radius); + if (radius.compareTo(nodeid) == 1) bottom = BigInteger.ZERO; + + BigInteger top = nodeid.add(radius); + if (top.compareTo(Block.MAX_KEY) == 1) top = Block.MAX_KEY; + + Collection subSet = samplesByColumn.subSet(bottom, true, top, true); + List column = new ArrayList<>(); + for (BigInteger id : subSet) { + column.add(sampleMap.get(id).getColumn()); + } + return Util.mostCommon(column); + } + /* Returns n random selected samples */ public Sample[] getNRandomSamples(int n) { diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 6de908b1..e74d386c 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -213,9 +213,10 @@ public void processEvent(Node myNode, int myPid, Object event) { } // searchTable.removeNode(t.node); } - if (sop != null) { + /*if (sop != null) { + logger.warning("Doing sampling timeout"); doSampling(sop); - } + }*/ break; } } @@ -316,14 +317,17 @@ protected void handleGetSample(Message m, int myPid) { // sample IDs that are requested in the message List samples = Arrays.asList((BigInteger[]) m.body); - boolean sampleFound = false; + // boolean sampleFound = false; + + List samplesToSend = new ArrayList<>(); + for (BigInteger id : samples) { logger.info("Requesting sample " + id + " from " + m.src.getId()); Sample sample = (Sample) kv.get(id); if (sample != null) { // s.add(sample); - Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, new Sample[] {sample}); + /*Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, new Sample[] {sample}); response.operationId = m.operationId; response.dst = m.src; response.src = this.kadProtocol.getKademliaNode(); @@ -331,7 +335,8 @@ protected void handleGetSample(Message m, int myPid) { response.value = searchTable.getNeighbours(); sendMessage(response, m.src.getId(), myPid); - sampleFound = true; + sampleFound = true;*/ + samplesToSend.add(sample); } else { if (missingSamples.containsKey(id)) missingSamples.get(id).add(m); else { @@ -342,15 +347,26 @@ protected void handleGetSample(Message m, int myPid) { // logger.warning("Sample request missing"); } } - if (!sampleFound) { + if (samplesToSend.isEmpty()) { Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, new Sample[] {}); response.operationId = m.operationId; response.dst = m.src; response.src = this.kadProtocol.getKademliaNode(); response.ackId = m.id; // set ACK number - response.value = searchTable.getNeighbours(); + response.value = searchTable.getNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED); sendMessage(response, m.src.getId(), myPid); + } else { + Message response = + new Message(Message.MSG_GET_SAMPLE_RESPONSE, samplesToSend.toArray(new Sample[0])); + response.operationId = m.operationId; + response.dst = m.src; + response.src = this.kadProtocol.getKademliaNode(); + response.ackId = m.id; // set ACK number + response.value = + searchTable.getNeighbours( + KademliaCommonConfigDas.MAX_NODES_RETURNED * samplesToSend.size()); + sendMessage(response, m.src.getId(), myPid); } } @@ -383,12 +399,20 @@ protected void handleGetSampleResponse(Message m, int myPid) { Sample[] samples = (Sample[]) m.body; // searchTable.addNodes((BigInteger[]) m.value); - logger.info("Samples received " + samples.length + " from " + m.src.getId()); - + if (samplingOp.get(m.operationId) != null) + logger.warning( + "Samples received " + + samples.length + + " from " + + m.src.getId() + + " " + + samplingOp.get(m.operationId).getPending()); + else logger.warning("Samples received " + samples.length + " from " + m.src.getId()); if (reportDiscovery && !isEvil()) KademliaObserver.reportPeerDiscovery(m, searchTable); for (Neighbour neigh : (Neighbour[]) m.value) { if (neigh.getId().compareTo(builderAddress) != 0) searchTable.addNeighbour(neigh); } + HashMap> toSend = new HashMap<>(); for (Sample s : samples) { kv.add((BigInteger) s.getIdByRow(), s); @@ -403,24 +427,45 @@ protected void handleGetSampleResponse(Message m, int myPid) { if (missingSamples.containsKey(s.getIdByColumn())) messages.addAll(missingSamples.get(s.getIdByColumn())); for (Message msg : messages) { - Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, new Sample[] {s}); + /*Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, new Sample[] {s}); response.operationId = msg.operationId; response.dst = msg.src; response.src = this.kadProtocol.getKademliaNode(); response.ackId = msg.id; // set ACK number response.value = searchTable.getNeighbours(); // logger.warning("Sending sample to " + msg.src.getId()); - sendMessage(response, msg.src.getId(), myPid); + sendMessage(response, msg.src.getId(), myPid);*/ + if (toSend.get(msg) != null) { + toSend.get(msg).add(s); + } else { + List sToSend = new ArrayList<>(); + sToSend.add(s); + toSend.put(msg, sToSend); + } } missingSamples.remove(s.getId()); missingSamples.remove(s.getIdByColumn()); } } + for (Message msg : toSend.keySet()) { + Message response = + new Message(Message.MSG_GET_SAMPLE_RESPONSE, toSend.get(msg).toArray(new Sample[0])); + response.operationId = msg.operationId; + response.dst = msg.src; + response.src = this.kadProtocol.getKademliaNode(); + response.ackId = msg.id; // set ACK number + response.value = + searchTable.getNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED * toSend.size()); + // logger.warning("Sending sample to " + msg.src.getId()); + sendMessage(response, msg.src.getId(), myPid); + } + toSend.clear(); + SamplingOperation op = (SamplingOperation) samplingOp.get(m.operationId); // We continue an existing operation - logger.warning( + logger.info( "Nodes discovered " + ((Neighbour[]) m.value).length + " " @@ -432,7 +477,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { if (op != null) { // keeping track of received samples op.elaborateResponse(samples, m.src.getId()); - logger.info( + logger.warning( "Continue operation " + op.getId() + " " @@ -440,7 +485,9 @@ protected void handleGetSampleResponse(Message m, int myPid) { + " " + searchTable.nodesIndexed().size() + " " - + ((SamplingOperation) op).samplesCount()); + + ((SamplingOperation) op).samplesCount() + + " " + + ((SamplingOperation) op).getPending()); if (!op.completed() && op.getHops() < KademliaCommonConfigDas.MAX_HOPS @@ -453,7 +500,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { doSampling(op); } // else { if (op.completed()) { - logger.warning("Operation completed"); + // logger.warning("Operation completed"); samplingOp.remove(m.operationId); if (op instanceof ValidatorSamplingOperation) logger.warning("Sampling operation finished validator completed " + op.getId()); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilNonValidator.java index e84c35b2..45d25ea3 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilNonValidator.java @@ -30,8 +30,7 @@ protected void handleGetSample(Message m, int myPid) { response.dst = m.src; response.src = this.kadProtocol.getKademliaNode(); response.ackId = m.id; // set ACK number - response.value = searchTable.getEvilNeighbours(); - + response.value = searchTable.getEvilNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED); sendMessage(response, m.src.getId(), myPid); } /** diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilValidator.java index a600459a..7930e7d5 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilValidator.java @@ -32,8 +32,7 @@ protected void handleGetSample(Message m, int myPid) { response.dst = m.src; response.src = this.kadProtocol.getKademliaNode(); response.ackId = m.id; // set ACK number - response.value = searchTable.getEvilNeighbours(); - + response.value = searchTable.getEvilNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED); sendMessage(response, m.src.getId(), myPid); } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index 3a657abf..a84c1c4e 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -60,9 +60,21 @@ protected void startRowsandColumnsSampling() { // start 2 row 2 column Validator operation (1 row/column with the highest number of samples // already downloaded and another random) createValidatorSamplingOperation( - CommonState.r.nextInt(KademliaCommonConfigDas.BLOCK_DIM_SIZE) + 1, 0, time); + currentBlock.findClosestRow( + this.getKademliaId(), + currentBlock.computeRegionRadius( + KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, + KademliaCommonConfigDas.validatorsSize)), + 0, + time); createValidatorSamplingOperation( - 0, CommonState.r.nextInt(KademliaCommonConfigDas.BLOCK_DIM_SIZE) + 1, time); + 0, + currentBlock.findClosestColumn( + this.getKademliaId(), + currentBlock.computeRegionRadius( + KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, + KademliaCommonConfigDas.validatorsSize)), + time); createValidatorSamplingOperation( CommonState.r.nextInt(KademliaCommonConfigDas.BLOCK_DIM_SIZE) + 1, 0, time); createValidatorSamplingOperation( diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index eec823e1..2c272053 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -133,17 +133,17 @@ public List getNodesbySample(Set samples, BigInteger rad return result; } - public Neighbour[] getNeighbours() { + public Neighbour[] getNeighbours(int n) { List result = new ArrayList<>(); List neighs = new ArrayList<>(); - for (Neighbour n : neighbours.values()) { - neighs.add(n); + for (Neighbour neigh : neighbours.values()) { + neighs.add(neigh); } Collections.shuffle(neighs); for (Neighbour neigh : neighs) { - if (result.size() < KademliaCommonConfigDas.MAX_NODES_RETURNED) result.add(neigh); + if (result.size() < n) result.add(neigh); else break; } return result.toArray(new Neighbour[0]); @@ -153,14 +153,14 @@ public void setEvilIds(List ids) { this.evilIds = ids; } - public Neighbour[] getEvilNeighbours() { + public Neighbour[] getEvilNeighbours(int n) { List result = new ArrayList<>(); if (evilIds != null) { Collections.shuffle(evilIds); - for (Node n : evilIds) { - if (result.size() < KademliaCommonConfigDas.MAX_NODES_RETURNED) - result.add(new Neighbour(n.getDASProtocol().getKademliaId(), n, true)); + for (Node neigh : evilIds) { + if (result.size() < n) + result.add(new Neighbour(neigh.getDASProtocol().getKademliaId(), neigh, true)); else break; } } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/FetchingSample.java b/simulator/src/main/java/peersim/kademlia/das/operations/FetchingSample.java index 69f00359..5e23f30a 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/FetchingSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/FetchingSample.java @@ -25,7 +25,7 @@ public BigInteger getId() { return s.getId(); } - public Sample getSample(){ + public Sample getSample() { return s; } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index 2e604d28..c7901b5b 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -146,9 +146,8 @@ protected void createNodes() { } } - protected void addExtraNodes() { + protected void addExtraNodes() {} - } public Map toMap() { // System.out.println("Mapping"); Map result = new HashMap(); diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index 3a3664cc..7cd99dc0 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -6,6 +6,7 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; +import peersim.core.CommonState; import peersim.kademlia.das.Block; import peersim.kademlia.das.KademliaCommonConfigDas; import peersim.kademlia.das.MissingNode; @@ -145,8 +146,19 @@ public BigInteger[] doSampling() { createNodes(); // System.out.println("[" + srcNode + "] Repopulating nodes " + nodes.size()); } - if(nodes.isEmpty()){ + if (nodes.isEmpty()) { addExtraNodes(); + System.out.println( + "[" + + CommonState.getTime() + + "][" + + srcNode + + "] Adding extra nodes " + + nodes.size() + + " " + + aggressiveness + + " " + + askedNodes.size()); } for (Node n : nodes.values()) n.setAgressiveness(aggressiveness); List result = new ArrayList<>(); diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index afe2e4b9..78283d55 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -3,6 +3,7 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import peersim.kademlia.das.Block; @@ -182,16 +183,21 @@ protected void addExtraNodes() { if (!samples.get(sample).isDownloaded()) { List nodesBySample = new ArrayList<>(); BigInteger radiusUsed = radiusValidator; - if(row>0){ + if (row > 0) { Sample[] sRow = currentBlock.getSamplesByRow(samples.get(sample).getSample().getRow()); - for(Sample s : sRow){ - nodesBySample.addAll(searchTable.getNodesbySample(s.getId(), radiusUsed)); + List nodes = new ArrayList<>(); + for (Sample s : sRow) { + nodes.addAll(searchTable.getNodesbySample(s.getId(), radiusUsed)); } + nodesBySample.addAll(new ArrayList<>(new LinkedHashSet<>(nodes))); } else { - Sample[] sColumn = currentBlock.getSamplesByColumn(samples.get(sample).getSample().getColumn()); - for(Sample s : sColumn){ - nodesBySample.addAll(searchTable.getNodesbySample(s.getIdByColumn(), radiusUsed)); + Sample[] sColumn = + currentBlock.getSamplesByColumn(samples.get(sample).getSample().getColumn()); + List nodes = new ArrayList<>(); + for (Sample s : sColumn) { + nodes.addAll(searchTable.getNodesbySample(s.getIdByColumn(), radiusUsed)); } + nodesBySample.addAll(new ArrayList<>(new LinkedHashSet<>(nodes))); } nodesBySample.removeAll(askedNodes); From 791870c4053c6499d39650438ebb98da5f04fc4e Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Wed, 1 Nov 2023 13:01:28 +0100 Subject: [PATCH 54/98] solved bug in random sampling process sample counting --- simulator/config/malicious/dasprotocolevil.cfg | 2 +- .../kademlia/das/operations/RandomSamplingOperation.java | 2 +- .../kademlia/das/operations/ValidatorSamplingOperation.java | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil.cfg b/simulator/config/malicious/dasprotocolevil.cfg index 144b133c..be3c35ae 100644 --- a/simulator/config/malicious/dasprotocolevil.cfg +++ b/simulator/config/malicious/dasprotocolevil.cfg @@ -95,7 +95,7 @@ init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol init.1uniqueNodeID.protocolEvildas 8evildasprotocol init.1uniqueNodeID.validator_rate 1.0 -init.1uniqueNodeID.evilNodeRatioValidator 0.5 +init.1uniqueNodeID.evilNodeRatioValidator 0.7 init.1uniqueNodeID.evilNodeRatioNonValidator 0 diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index c7901b5b..e546fcdb 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -87,7 +87,7 @@ public void elaborateResponse(Sample[] sam, BigInteger node) { if (n != null) { for (FetchingSample s : n.getSamples()) { s.removeFetchingNode(n); - s.setDownloaded(); + // s.setDownloaded(); } } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index 78283d55..09469a04 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -189,6 +189,8 @@ protected void addExtraNodes() { for (Sample s : sRow) { nodes.addAll(searchTable.getNodesbySample(s.getId(), radiusUsed)); } + nodes.addAll( + searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusUsed)); nodesBySample.addAll(new ArrayList<>(new LinkedHashSet<>(nodes))); } else { Sample[] sColumn = @@ -197,6 +199,7 @@ protected void addExtraNodes() { for (Sample s : sColumn) { nodes.addAll(searchTable.getNodesbySample(s.getIdByColumn(), radiusUsed)); } + nodes.addAll(searchTable.getNodesbySample(samples.get(sample).getId(), radiusUsed)); nodesBySample.addAll(new ArrayList<>(new LinkedHashSet<>(nodes))); } From 42acbe694ce5d210a6192c6d4771aa6c1ab45c29 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Wed, 1 Nov 2023 13:32:52 +0100 Subject: [PATCH 55/98] adding extra nodes for random sampling --- .../config/malicious/dasprotocolevil.cfg | 14 ++++---- .../operations/RandomSamplingOperation.java | 35 +++++++++++++++++-- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil.cfg b/simulator/config/malicious/dasprotocolevil.cfg index be3c35ae..b9c6b2c0 100644 --- a/simulator/config/malicious/dasprotocolevil.cfg +++ b/simulator/config/malicious/dasprotocolevil.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 1000 +SIZE 5000 # Random seed K 5 @@ -63,27 +63,27 @@ protocol.3kademlia.FINDMODE 1 protocol.4dasprotocol peersim.kademlia.das.DASProtocolBuilder protocol.4dasprotocol.transport 2unreltr protocol.4dasprotocol.kademlia 3kademlia -protocol.4dasprotocol.reportDiscovery true +protocol.4dasprotocol.reportDiscovery false protocol.5dasprotocol peersim.kademlia.das.DASProtocolValidator protocol.5dasprotocol.transport 2unreltr protocol.5dasprotocol.kademlia 3kademlia -protocol.5dasprotocol.reportDiscovery true +protocol.5dasprotocol.reportDiscovery false protocol.6dasprotocol peersim.kademlia.das.DASProtocolNonValidator protocol.6dasprotocol.transport 2unreltr protocol.6dasprotocol.kademlia 3kademlia -protocol.6dasprotocol.reportDiscovery true +protocol.6dasprotocol.reportDiscovery false protocol.7evildasprotocol peersim.kademlia.das.DASProtocolEvilValidator protocol.7evildasprotocol.transport 2unreltr protocol.7evildasprotocol.kademlia 3kademlia -protocol.7evildasprotocol.reportDiscovery true +protocol.7evildasprotocol.reportDiscovery false protocol.8evildasprotocol peersim.kademlia.das.DASProtocolEvilNonValidator protocol.8evildasprotocol.transport 2unreltr protocol.8evildasprotocol.kademlia 3kademlia -protocol.8evildasprotocol.reportDiscovery true +protocol.8evildasprotocol.reportDiscovery false # ::::: INITIALIZERS ::::: #Class that initializes nodes with kademlia protocol and generates uniform ids @@ -111,7 +111,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 100 +control.0traffic.block_dim_size 512 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index e546fcdb..26104f0f 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -3,6 +3,7 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import peersim.kademlia.das.Block; @@ -87,7 +88,7 @@ public void elaborateResponse(Sample[] sam, BigInteger node) { if (n != null) { for (FetchingSample s : n.getSamples()) { s.removeFetchingNode(n); - // s.setDownloaded(); + // s.setDownloaded(); } } @@ -146,7 +147,37 @@ protected void createNodes() { } } - protected void addExtraNodes() {} + protected void addExtraNodes() { + for (BigInteger sample : samples.keySet()) { + if (!samples.get(sample).isDownloaded()) { + List nodesBySample = new ArrayList<>(); + BigInteger radiusUsed = radiusValidator; + Sample[] sRow = currentBlock.getSamplesByRow(samples.get(sample).getSample().getRow()); + List nodesToAdd = new ArrayList<>(); + for (Sample s : sRow) { + nodesToAdd.addAll(searchTable.getNodesbySample(s.getId(), radiusUsed)); + } + Sample[] sColumn = + currentBlock.getSamplesByColumn(samples.get(sample).getSample().getColumn()); + for (Sample s : sColumn) { + nodesToAdd.addAll(searchTable.getNodesbySample(s.getIdByColumn(), radiusUsed)); + } + nodesBySample.addAll(new ArrayList<>(new LinkedHashSet<>(nodesToAdd))); + + nodesBySample.removeAll(askedNodes); + if (nodesBySample != null && nodesBySample.size() > 0) { + for (BigInteger id : nodesBySample) { + if (!nodes.containsKey(id)) { + nodes.put(id, new Node(id)); + nodes.get(id).addSample(samples.get(sample)); + } else { + nodes.get(id).addSample(samples.get(sample)); + } + } + } + } + } + } public Map toMap() { // System.out.println("Mapping"); From 0e603187bf93dca968fa271cf5a04571e26a6e14 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sun, 5 Nov 2023 17:31:28 +0100 Subject: [PATCH 56/98] bug fixed when timeouts to continue sampling --- .../src/main/java/peersim/kademlia/das/DASProtocol.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index e74d386c..68ef9d81 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -207,8 +207,9 @@ public void processEvent(Node myNode, int myPid, Object event) { // this.searchTable.removeNode(t.node); if (sop != null) { if (!sop.completed()) { - logger.warning("Sampling operation found " + sop.getId()); sop.elaborateResponse(null, t.node); + logger.warning("Sampling operation found " + sop.getId() + " " + sop.getPending()); + doSampling(sop); } } // searchTable.removeNode(t.node); @@ -414,6 +415,8 @@ protected void handleGetSampleResponse(Message m, int myPid) { } HashMap> toSend = new HashMap<>(); for (Sample s : samples) { + logger.warning( + "Sample received " + s.getId() + " " + s.getIdByColumn() + " from " + m.src.getId()); kv.add((BigInteger) s.getIdByRow(), s); kv.add((BigInteger) s.getIdByColumn(), s); From 3027f7f29e2a4e8ebc106ae98dd84c1f8bf1b33a Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sat, 11 Nov 2023 17:04:41 +0100 Subject: [PATCH 57/98] send samples after reconstruction --- simulator/config/dasprotocol.cfg | 4 +- .../config/malicious/dasprotocolevil.cfg | 58 +++++++++---------- .../kademlia/das/CustomDistributionDas.java | 11 +++- .../peersim/kademlia/das/DASProtocol.java | 58 ++++++++++--------- .../kademlia/das/DASProtocolNonValidator.java | 5 +- .../kademlia/das/DASProtocolValidator.java | 6 +- .../operations/RandomSamplingOperation.java | 11 +++- .../das/operations/SamplingOperation.java | 1 + .../ValidatorSamplingOperation.java | 4 +- 9 files changed, 91 insertions(+), 67 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 4bbc4927..83d9254e 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -111,7 +111,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 100 +control.0traffic.block_dim_size 512 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia @@ -150,4 +150,4 @@ control.3turbolenceAdd.p_add 0.05 control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logsDas +control.4.logfolder logsDas2 diff --git a/simulator/config/malicious/dasprotocolevil.cfg b/simulator/config/malicious/dasprotocolevil.cfg index b9c6b2c0..30be707d 100644 --- a/simulator/config/malicious/dasprotocolevil.cfg +++ b/simulator/config/malicious/dasprotocolevil.cfg @@ -1,11 +1,11 @@ -# :::::::::::::::::::::::::::::::::::::::::::::::::::::: +# :::::::::::::::::::::::::::::::::`::::::::::::::::::::: # :: Kademlia Default Configuration # :::::::::::::::::::::::::::::::::::::::::::::::::::::: # ::::: GLOBAL :::::: # Network size -SIZE 5000 +SIZE 1000 # Random seed K 5 @@ -14,7 +14,7 @@ MINDELAY 5 MAXDELAY 100 #Simulation time in ms -SIM_TIME 1000*60*1 +SIM_TIME 24001 #Traffic generator is executed every TRAFFIC_STEP @@ -22,8 +22,8 @@ TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP OBSERVER_STEP 10000 #Turbulence module is executed every TURBULENCE_STEP enabling churning -TURBULENCE_STEP 1000 -TURBULENCE_STEP_NONVAL 1000 +TURBULENCE_STEP 10000000 +TURBULENCE_STEP_NONVAL 10000000 REFRESH_STEP 1000 # add network config parameters to simulation @@ -96,7 +96,7 @@ init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol init.1uniqueNodeID.protocolEvildas 8evildasprotocol init.1uniqueNodeID.validator_rate 1.0 init.1uniqueNodeID.evilNodeRatioValidator 0.7 -init.1uniqueNodeID.evilNodeRatioNonValidator 0 +init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 #Adds initial state to the routing tables @@ -120,34 +120,34 @@ control.1refresh peersim.kademlia.das.RefreshSearchTable control.1refresh.step REFRESH_STEP # turbulence non-validator -#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas -#control.2turbolenceAdd.protocolkad 3kademlia -#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol -#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol -#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol -#control.2turbolenceAdd.protocolEvildas 7evildasprotocol -#control.2turbolenceAdd.transport 2unreltr -#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL -#control.2turbolenceAdd.p_idle 0.1 -#control.2turbolenceAdd.p_rem 0.45 -#control.2turbolenceAdd.p_add 0.45 +control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +control.2turbolenceAdd.protocolkad 3kademlia +control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +control.2turbolenceAdd.protocolEvildas 7evildasprotocol +control.2turbolenceAdd.transport 2unreltr +control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +control.2turbolenceAdd.p_idle 0.1 +control.2turbolenceAdd.p_rem 0.45 +control.2turbolenceAdd.p_add 0.45 # turbulence validators -#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator -#control.3turbolenceAdd.protocolkad 3kademlia -#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol -#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol -#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol -#control.3turbolenceAdd.protocolEvildas 7evildasprotocol -#control.3turbolenceAdd.transport 2unreltr -#control.3turbolenceAdd.step TURBULENCE_STEP -#control.3turbolenceAdd.p_idle 0.9 -#control.3turbolenceAdd.p_rem 0.05 -#control.3turbolenceAdd.p_add 0.05 +control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +control.3turbolenceAdd.protocolkad 3kademlia +control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +control.3turbolenceAdd.protocolEvildas 7evildasprotocol +control.3turbolenceAdd.transport 2unreltr +control.3turbolenceAdd.step TURBULENCE_STEP +control.3turbolenceAdd.p_idle 0.9 +control.3turbolenceAdd.p_rem 0.05 +control.3turbolenceAdd.p_add 0.05 # ::::: OBSERVER ::::: #The observer is executed every OBSERVER_STEP and will generate data traces control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logsDasEvil2 +control.4.logfolder logsDasEvil0.7 diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index 5e542863..bc7850b0 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -153,8 +153,15 @@ public boolean execute() { generalNode.getDASProtocol().addKnownValidator(validatorsIds.toArray(new BigInteger[0])); if (generalNode.getDASProtocol().isEvil()) { - DASProtocolEvilValidator dasEvil = (DASProtocolEvilValidator) generalNode.getDASProtocol(); - dasEvil.setEvilIds(evilNodes); + if (generalNode.getDASProtocol() instanceof DASProtocolEvilValidator) { + DASProtocolEvilValidator dasEvil = + (DASProtocolEvilValidator) generalNode.getDASProtocol(); + dasEvil.setEvilIds(evilNodes); + } else { + DASProtocolEvilNonValidator dasEvil = + (DASProtocolEvilNonValidator) generalNode.getDASProtocol(); + dasEvil.setEvilIds(evilNodes); + } } int k = 0; while (k < 100) { diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 68ef9d81..d6476f04 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -413,7 +413,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { for (Neighbour neigh : (Neighbour[]) m.value) { if (neigh.getId().compareTo(builderAddress) != 0) searchTable.addNeighbour(neigh); } - HashMap> toSend = new HashMap<>(); + for (Sample s : samples) { logger.warning( "Sample received " + s.getId() + " " + s.getIdByColumn() + " from " + m.src.getId()); @@ -422,34 +422,8 @@ protected void handleGetSampleResponse(Message m, int myPid) { kv.add((BigInteger) s.getIdByColumn(), s); // count # of samples for each row and column and reconstruct if more than half received reconstruct(s); - - if (missingSamples.containsKey(s.getId()) || missingSamples.containsKey(s.getIdByColumn())) { - logger.info("Sample received missing " + s.getId() + " " + s.getIdByColumn()); - List messages = new ArrayList<>(); - if (missingSamples.containsKey(s.getId())) messages.addAll(missingSamples.get(s.getId())); - if (missingSamples.containsKey(s.getIdByColumn())) - messages.addAll(missingSamples.get(s.getIdByColumn())); - for (Message msg : messages) { - /*Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, new Sample[] {s}); - response.operationId = msg.operationId; - response.dst = msg.src; - response.src = this.kadProtocol.getKademliaNode(); - response.ackId = msg.id; // set ACK number - response.value = searchTable.getNeighbours(); - // logger.warning("Sending sample to " + msg.src.getId()); - sendMessage(response, msg.src.getId(), myPid);*/ - if (toSend.get(msg) != null) { - toSend.get(msg).add(s); - } else { - List sToSend = new ArrayList<>(); - sToSend.add(s); - toSend.put(msg, sToSend); - } - } - missingSamples.remove(s.getId()); - missingSamples.remove(s.getIdByColumn()); - } } + HashMap> toSend = findMissingSamples(samples); for (Message msg : toSend.keySet()) { Message response = @@ -480,6 +454,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { if (op != null) { // keeping track of received samples op.elaborateResponse(samples, m.src.getId()); + op.elaborateResponse(kv.getAll().toArray(new Sample[0])); logger.warning( "Continue operation " + op.getId() @@ -513,6 +488,33 @@ protected void handleGetSampleResponse(Message m, int myPid) { } } + private HashMap> findMissingSamples(Sample[] samples) { + HashMap> toSend = new HashMap<>(); + List toRemove = new ArrayList<>(); + for (BigInteger id : missingSamples.keySet()) { + if (kv.get(id) != null) { + Sample s = (Sample) kv.get(id); + for (Message msg : missingSamples.get(id)) { + + if (toSend.get(msg) != null) { + toSend.get(msg).add(s); + } else { + List sToSend = new ArrayList<>(); + sToSend.add(s); + toSend.put(msg, sToSend); + } + } + toRemove.add(s.getId()); + toRemove.add(s.getIdByColumn()); + } + } + for (BigInteger id : toRemove) { + missingSamples.remove(id); + } + + return toSend; + } + /** * send a message with current transport layer and starting the timeout timer (wich is an event) * if the message is a request diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java index 0b5166dc..3f8049ab 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java @@ -50,9 +50,12 @@ protected void handleInitNewBlock(Message m, int myPid) { logger.warning("Init block non-validator node - start sampling " + this); super.handleInitNewBlock(m, myPid); validatorsContacted.clear(); - startRandomSampling(); + if (!isEvil) startRandomSampling(); } + public void setEvilIds(List evilIds) { + searchTable.setEvilIds(evilIds); + } /** * Replicate this object by returning an identical copy.
* It is called by the initializer and do not fill any particular field. diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index a84c1c4e..97997ac2 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -36,8 +36,10 @@ protected void handleInitGetSample(Message m, int myPid) { @Override protected void handleInitNewBlock(Message m, int myPid) { super.handleInitNewBlock(m, myPid); - startRowsandColumnsSampling(); - startRandomSampling(); + if (!isEvil) { + startRowsandColumnsSampling(); + startRandomSampling(); + } } /** diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index 26104f0f..a7cf033f 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -105,7 +105,7 @@ public void elaborateResponse(Sample[] sam, BigInteger node) { } } nodes.remove(node); - askedNodes.add(node); + // askedNodes.add(node); } protected void createNodes() { @@ -177,6 +177,15 @@ protected void addExtraNodes() { } } } + + /*if (nodes.size() == 0 && getSamples().length > 0) { + Sample[] randomSamples = currentBlock.getNRandomSamples(getSamples().length * 10); + for (Sample rs : randomSamples) { + FetchingSample s = new FetchingSample(rs); + samples.put(rs.getIdByRow(), s); + } + createNodes(); + }*/ } public Map toMap() { diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index 7cd99dc0..cc4be4ad 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -175,6 +175,7 @@ public BigInteger[] doSampling() { } } + askedNodes.addAll(result); return result.toArray(new BigInteger[0]); } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index 09469a04..260489b8 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -120,7 +120,7 @@ public void elaborateResponse(Sample[] sam, BigInteger n) { // System.out.println("Row " + samplesCount + " " + samples.size()); if (samplesCount >= samples.size() / 2) completed = true; - askedNodes.add(n); + // askedNodes.add(n); nodes.remove(n); } @@ -183,7 +183,7 @@ protected void addExtraNodes() { if (!samples.get(sample).isDownloaded()) { List nodesBySample = new ArrayList<>(); BigInteger radiusUsed = radiusValidator; - if (row > 0) { + if (column > 0) { Sample[] sRow = currentBlock.getSamplesByRow(samples.get(sample).getSample().getRow()); List nodes = new ArrayList<>(); for (Sample s : sRow) { From 1903c725236075d3337d0946b52d1fb21f9a8552 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Wed, 29 Nov 2023 09:09:10 +0100 Subject: [PATCH 58/98] alternative fetching when malicious --- .../config/malicious/dasprotocolevil.cfg | 18 +-- simulator/python/analysis_vs_evil.ipynb | 138 +++++++++--------- .../peersim/kademlia/das/DASProtocol.java | 11 +- .../kademlia/das/DASProtocolNonValidator.java | 12 +- .../kademlia/das/DASProtocolValidator.java | 11 +- .../kademlia/das/KademliaCommonConfigDas.java | 4 +- .../peersim/kademlia/das/SearchTable.java | 6 + .../kademlia/das/TrafficGeneratorSample.java | 4 +- .../operations/RandomSamplingOperation.java | 55 +++++-- .../das/operations/SamplingOperation.java | 25 +++- .../ValidatorSamplingOperation.java | 15 +- 11 files changed, 191 insertions(+), 108 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil.cfg b/simulator/config/malicious/dasprotocolevil.cfg index 30be707d..9bb3ca17 100644 --- a/simulator/config/malicious/dasprotocolevil.cfg +++ b/simulator/config/malicious/dasprotocolevil.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 1000 +SIZE 10000 # Random seed K 5 @@ -14,16 +14,16 @@ MINDELAY 5 MAXDELAY 100 #Simulation time in ms -SIM_TIME 24001 +SIM_TIME 60001 #Traffic generator is executed every TRAFFIC_STEP TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP -OBSERVER_STEP 10000 +OBSERVER_STEP 1000 #Turbulence module is executed every TURBULENCE_STEP enabling churning -TURBULENCE_STEP 10000000 -TURBULENCE_STEP_NONVAL 10000000 +TURBULENCE_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 REFRESH_STEP 1000 # add network config parameters to simulation @@ -94,9 +94,9 @@ init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol init.1uniqueNodeID.protocolEvildas 8evildasprotocol -init.1uniqueNodeID.validator_rate 1.0 -init.1uniqueNodeID.evilNodeRatioValidator 0.7 -init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 +init.1uniqueNodeID.validator_rate 0.5 +init.1uniqueNodeID.evilNodeRatioValidator 0 +init.1uniqueNodeID.evilNodeRatioNonValidator 0 #Adds initial state to the routing tables @@ -150,4 +150,4 @@ control.3turbolenceAdd.p_add 0.05 control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logsDasEvil0.7 +control.4.logfolder logsDasEvil0WithNon diff --git a/simulator/python/analysis_vs_evil.ipynb b/simulator/python/analysis_vs_evil.ipynb index 6d9410dd..bc67e0f7 100644 --- a/simulator/python/analysis_vs_evil.ipynb +++ b/simulator/python/analysis_vs_evil.ipynb @@ -1,7 +1,6 @@ { "cells": [ { - "attachments": {}, "cell_type": "markdown", "id": "f2905ced", "metadata": {}, @@ -49,19 +48,17 @@ "## Simulation parameters\n", "\n", "* Number of nodes: 5000\n", - "* Number of attackers: Range from 0% to 50%\n", + "* Number of attackers: Range from 0% to 75%\n", "* Number of validators: All nodes are validators\n", - "* Overhead parameter: 2\n", - "* Latency between nodes: 100ms\n", + "* Redundancy parameter: 2\n", + "* Latency between nodes: 5ms - 100ms\n", "* Number of samples per block : 512x512\n", "* Sample size: 512 bytes\n", - "* Blocks: Single block simulation.\n", - "* Number of random samples fetch: 75. \n", - "* Alpha: 3" + "* Blocks: 5 blocks simulation.\n", + "* Number of random samples fetch: 75. \n" ] }, { - "attachments": {}, "cell_type": "markdown", "id": "edd080e7", "metadata": {}, @@ -71,7 +68,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 2, "id": "2983fa0b", "metadata": { "vscode": { @@ -84,20 +81,18 @@ "import numpy as np\n", "import pandas as pd\n", "\n", - "ops_path = {'DAS': '../logsTest/operation.csv', \n", - " 'Evil-0.1': '../logsEvil0.1/operation.csv',\n", - " 'Evil-0.2': '../logsEvil0.2/operation.csv',\n", - " 'Evil-0.3': '../logsEvil0.3/operation.csv',\n", - " 'Evil-0.4': '../logsEvil0.4/operation.csv',\n", - " 'Evil-0.5': '../logsEvil0.5/operation.csv'\n", - " }\n", - "msgs_path = {'DAS': '../logsTest/messages.csv', \n", - " 'Evil-0.1': '../logsEvil0.1/messages.csv',\n", - " 'Evil-0.2': '../logsEvil0.2/messages.csv',\n", - " 'Evil-0.3': '../logsEvil0.3/messages.csv',\n", - " 'Evil-0.4': '../logsEvil0.4/messages.csv',\n", - " 'Evil-0.5': '../logsEvil0.5/messages.csv'\n", + "ops_path = {'DAS': '../logsDasEvil0WithNon/operation.csv', \n", + " 'Evil-0.25': '../logsDasEvil0.25WithNon/operation.csv',\n", + " 'Evil-0.5': '../logsDasEvil0.5WithNon/operation.csv',\n", + " 'Evil-0.75': '../logsDasEvil0.75WithNon/operation.csv'\n", " }\n", + "#msgs_path = {'DAS': '../logsTest/messages.csv', \n", + "# 'Evil-0.1': '../logsEvil0.1/messages.csv',\n", + "# 'Evil-0.2': '../logsEvil0.2/messages.csv',\n", + "# 'Evil-0.3': '../logsEvil0.3/messages.csv',\n", + "# 'Evil-0.4': '../logsEvil0.4/messages.csv',\n", + "# 'Evil-0.5': '../logsEvil0.5/messages.csv'\n", + "# }\n", "\n", "\n", "builder_address = '83814183170291850251680823880522715558189094423550585243365458794131648333116'\n", @@ -106,22 +101,20 @@ "msg_df={}\n", "for key in ops_path:\n", " op_df[key] = pd.read_csv(ops_path[key],index_col=False,low_memory=False)\n", - "for key in msgs_path:\n", - " msg_df[key] = pd.read_csv(msgs_path[key],index_col=False,low_memory=False)\n" + "#for key in msgs_path:\n", + "# msg_df[key] = pd.read_csv(msgs_path[key],index_col=False,low_memory=False)\n" ] }, { - "attachments": {}, "cell_type": "markdown", "id": "fd77860f", "metadata": {}, "source": [ - "In this graph we observe the CDF of the time required to complete the validator sampling of the DAS protocol, with and without attackers in the simulation, from 0\\% to 50\\% of attackers in the simulation.\n", - "We observe in all cases the validator sampling is completed on time, with small differences on the time required." + "In this graph we observe the CDF of the time required by validators to fetch 2 rows and 2 columnns using the DAS protocol, with and without attackers in the simulation, from 0\\% to 75\\% of malicious in the simulation.\n", + "We observe in all cases the validator sampling is completed on time, although when the number of malicious nodes in the network is 75\\% the time required to fetch the rows and columns is increased substantially and is close to the time limit of 4 seconds for some nodes." ] }, { - "attachments": {}, "cell_type": "markdown", "id": "c6cc3d58", "metadata": {}, @@ -129,7 +122,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 3, "id": "0c418d95", "metadata": { "vscode": { @@ -143,13 +136,13 @@ "Text(0.5, 0, 'Operation complete time (ms)')" ] }, - "execution_count": 8, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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eHhg69atGDt2LJo1awZ3d3eMHj0a7777btmNohrINm2Ke2Y1AQB5hU/8KhO2NczLtwEiIqIqqERXFI6IiCj0cFN8fLxema+vL/bt21eSphRDu2dGrTmAXpERKLhAsATpQf6TpIIrBksS5KsM48FzuUz6t65emUrCD1M3IOVSMsyseZsEIiJ6+vDeTxVMJTJRw718bj0pqXglYSIienqV+5RuIiIioorAPTVVhHgwJVtop2o/+FPgQbl2uYA8HVwITUE5AKHRQJOXV7mDICIiqkQMNRUkNz8V99O+xH2Rjc8G9oT2+jOC15chIiIqEww1FSQ3Pw0Q9wEAmvxy2qMiSbBxdIJL3WfKZ/tERERVGENNBVOb1kTovNkPzX4qOK1J/lOSIEmqh2Y+FUyJkv+E9OCE4II/JTy0nIiI6CnGUFPBJMkI1jUcK7sbREREisPZT0RERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCAw1REREpAgMNURERKQIDDVERESkCCUKNQsXLoSXlxfMzMzg4+ODAwcOFGm9NWvWQJIk9OzZsyTNEhERERWq2KEmJiYG48aNQ2RkJI4cOYLmzZsjICAAKSkpj13v0qVLGD9+PNq1a1fizhIREREVptihZu7cuQgPD8fgwYPRuHFjREdHw8LCAsuWLSt0nfz8fAQHB2PatGmoW7duqTpMREREZEixQk1OTg4OHz4Mf3//fzegUsHf3x8JCQmFrjd9+nQ4OTlhyJAhRWonOzsbGRkZOg8iIiKixylWqLl58yby8/Ph7OysU+7s7IykpCSD6+zZswdLly7FV199VeR2oqKiYGtrKz88PDyK000iIiJ6CpXr7Kc7d+4gJCQEX331FRwdHYu83qRJk5Ceni4/rl69Wo69JCIiIiUwLk5lR0dHGBkZITk5Wac8OTkZLi4uevXPnz+PS5cuoXv37nKZRqMpaNjYGImJiahXr57eemq1Gmq1ujhdIyIioqdcsfbUmJqawtvbG9u3b5fLNBoNtm/fDl9fX736DRs2xJ9//oljx47Jj9deew2dOnXCsWPHeFiJiIiIykyx9tQAwLhx4xAaGoqWLVuiVatWmDdvHu7evYvBgwcDAAYNGgR3d3dERUXBzMwMTZo00Vnfzs4OAPTKiYiIiEqj2KEmKCgIN27cwJQpU5CUlIQWLVogNjZWPnn4ypUrUKl4oWIiIiKqWJIQQlR2J54kIyMDtra2SE9Ph42NTWV3p0QWDByCnPxkmKldMGLl15XdHSIionJX0b/f3KVCREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKwFBDREREisBQQ0RERIrAUENERESKUKJQs3DhQnh5ecHMzAw+Pj44cOBAoXW/+uortGvXDvb29rC3t4e/v/9j6xMRERGVRLFDTUxMDMaNG4fIyEgcOXIEzZs3R0BAAFJSUgzWj4+Px4ABA7Bz504kJCTAw8MDXbp0wbVr10rdeSIiIiKtYoeauXPnIjw8HIMHD0bjxo0RHR0NCwsLLFu2zGD9VatW4e2330aLFi3QsGFDfP3119BoNNi+fXupO09ERESkVaxQk5OTg8OHD8Pf3//fDahU8Pf3R0JCQpG2kZWVhdzcXDg4OBRaJzs7GxkZGToPIiIioscpVqi5efMm8vPz4ezsrFPu7OyMpKSkIm3j3XffhZubm04welRUVBRsbW3lh4eHR3G6SURERE+hCp39NHPmTKxZswbr16+HmZlZofUmTZqE9PR0+XH16tUK7CURERFVR8bFqezo6AgjIyMkJyfrlCcnJ8PFxeWx686ZMwczZ87Etm3b0KxZs8fWVavVUKvVxekaERERPeWKtafG1NQU3t7eOif5ak/69fX1LXS9WbNmYcaMGYiNjUXLli1L3lsiIiKiQhRrTw0AjBs3DqGhoWjZsiVatWqFefPm4e7duxg8eDAAYNCgQXB3d0dUVBQA4L///S+mTJmC1atXw8vLSz73xsrKClZWVmU4FCIiInqaFTvUBAUF4caNG5gyZQqSkpLQokULxMbGyicPX7lyBSrVvzuAFi1ahJycHPTp00dnO5GRkZg6dWrpek9ERET0QLFDDQBEREQgIiLC4LL4+Hid15cuXSpJE0RERETFwns/ERERkSIw1BAREZEiMNQQERGRIjDUEBERkSIw1BAREZEiMNQQERGRIjDUEBERkSIw1BAREZEiMNQQERGRIjDUEBERkSIw1BAREZEiMNQQERGRIjDUEBERkSIw1BAREZEiMNQQERGRIjDUEBERkSIw1BAREZEiMNQQERGRIjDUEBERkSIw1BAREZEiMNQQERGRIjDUEBERkSIw1BAREZEiMNQQERGRIjDUEBERkSIw1BAREZEiMNQQERGRIjDUEBERkSIw1BAREZEiMNQQERGRIjDUEBERkSIw1BAREZEiMNQQERGRIjDUEBERkSIw1BAREZEiMNQQERGRIjDUEBERkSIw1BAREZEiMNQQERGRIjDUEBERkSIw1BAREZEiMNQQERGRIjDUEBERkSIw1BAREZEiMNQQERGRIjDUEBERkSIw1BAREZEiMNQQERGRIjDUEBERkSIw1BAREZEiMNQQERGRIjDUEBERkSIw1BAR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", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjUAAAHHCAYAAABHp6kXAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAACPuElEQVR4nOzdd5hU1f348ff07b3DsoXeq3QEBQVULFFEJYhEIRaMisaWKJaf4tdEbCESjYgaERXFEhBFimJEkN6XtnS2s71NOb8/7szAsG0Wtu/n9Tzz3DvnnnvvuTPL7odTdUophRBCCCFEM6dv7AIIIYQQQtQFCWqEEEII0SJIUCOEEEKIFkGCGiGEEEK0CBLUCCGEEKJFkKBGCCGEEC2CBDVCCCGEaBEkqBFCCCFEiyBBjRBCCCFaBAlqhBAAHDlyBJ1Ox8KFCxu7KBeksLCQu+66i5iYGHQ6HQ8++GCD3XvhwoXodDo2bdpUY95Ro0YxatSo+i9ULbjKf+TIkcYuihAXRYIa0WQdOnSIP/7xjyQnJ+Pj40NQUBDDhg3j9ddfp6SkxJ0vMTERnU6HTqdDr9cTEhJCz549mTFjBhs2bKj02q78579iYmIa6vEu2MMPP0y3bt0auxhNzosvvsjChQu55557+PDDD5kyZUqtz//yyy/rp3BNRGt4RtG6GRu7AEJUZtmyZUycOBGLxcLtt99Ojx49KC8v5+eff+bPf/4zu3fv5u2333bn79OnDw8//DAABQUF7N27l88++4x33nmHhx56iLlz51a4xxVXXMHtt9/ukebr61u/D1YHli1bxoQJExq7GE3O6tWrGTx4MLNnz76g81988UVuuukmrr/++rot2Hm+//77er1+dap6xilTpnDLLbdgsVgap2BC1BEJakSTk5qayi233EJCQgKrV68mNjbWfey+++7j4MGDLFu2zOOcNm3a8Pvf/94j7f/+7/+47bbbePXVV+nYsSP33HOPx/FOnTpVOOdCFBUV4e/vf9HX8cbhw4dJSUlh/vz5DXK/5iQjI6NZ1GCZzebGLkIFBoMBg8HQ2MUQ4qJJ85Nocl5++WUKCwt59913PQIalw4dOvDAAw/UeB1fX18+/PBDwsLCeOGFF6iLBeldfQ9+/PFH7r33XqKiomjbtq37+D//+U+6d++OxWIhLi6O++67j9zcXPfxN954A4PB4JH2yiuvoNPpmDVrljvNbrcTGBjIY4895nH/ZcuWERwczPDhw91pJ0+e5M477yQuLg6LxUJSUhL33HMP5eXl7jyHDx9m4sSJhIWF4efnx+DBgysEhpWpqv/HHXfcQWJiovu9qz/O3//+d+bNm0dycjJ+fn5ceeWVHD9+HKUUzz//PG3btsXX15frrruOnJwcj2smJiZyzTXX8PPPPzNw4EB8fHxITk7mgw8+qLaMa9euRafTkZqayrJly9xNia7+IWVlZcyePZsOHTpgsViIj4/n0UcfpayszH0NnU5HUVER77//vvv8O+64o1afsetes2bNIjIyEn9/f2644QYyMzOr/Uxd5f/000954YUXaNu2LT4+PowePZqDBw9WeF7X5+vr68vAgQNZt26dV/10qnvGyvrUuL6PtWvXMmDAAHx9fenZsydr164F4IsvvqBnz574+PjQv39/tm7dWuGe+/bt46abbiIsLAwfHx8GDBjA119/XW05hbgYUlMjmpxvvvmG5ORkhg4detHXCggI4IYbbuDdd99lz549dO/e3X2stLSUrKwsj/yBgYFeVcHfe++9REZG8vTTT1NUVATAM888w7PPPsuYMWO45557SElJ4a233uK3337jf//7HyaTiREjRuBwOPj555+55pprAFi3bh16vZ5169a5r79161YKCwu59NJLPe67fPlyrrjiCoxG7Z/uqVOnGDhwILm5ucyYMYMuXbpw8uRJlixZQnFxMWazmfT0dIYOHUpxcTF/+tOfCA8P5/333+faa69lyZIl3HDDDRf24Vbio48+ory8nPvvv5+cnBxefvllbr75Zi6//HLWrl3LY489xsGDB3nzzTd55JFHWLBggcf5Bw8e5KabbuLOO+9k6tSpLFiwgDvuuIP+/ft7fHfn6tq1Kx9++CEPPfQQbdu2dTdDRkZG4nA4uPbaa/n555+ZMWMGXbt2ZefOnbz66qvs37/f3b/kww8/5K677mLgwIHMmDEDgPbt23v9Gbvcf//9hIaGMnv2bI4cOcJrr73GzJkz+eSTT2r87F566SX0ej2PPPIIeXl5vPzyy0yePNmjX9hbb73FzJkzGTFiBA899BBHjhzh+uuvJzQ01CO4rkx1z1iVgwcPctttt/HHP/6R3//+9/z9739nwoQJzJ8/nyeffJJ7770XgDlz5nDzzTeTkpKCXq/9X3n3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", "text/plain": [ "
" ] @@ -177,24 +170,22 @@ "ax3.legend()\n", "ax3.set_ylim([0,1])\n", "\n", - "ax3.set_title(\"CDF Row/Column validator sampling time\")\n", + "ax3.set_title(\"CDF row/column fetching time\")\n", "ax3.set_xlabel(\"Operation complete time (ms)\")" ] }, { - "attachments": {}, "cell_type": "markdown", "id": "3debb1ed", "metadata": {}, "source": [ - "In this graph we observe the CDF of the hops (nodes contacted) required to complete the validator sampling of the DAS protocol, with and without attackers in the simulation, from 0\\% to 50\\% of attackers in the simulation.\n", - "We observe in all cases the validator sampling is completed on time, with small differences on the nodes contacted.\n", - "We cans ee the maximum number of hops required is 5, even with 50% malicious nodes." + "In this graph we observe the CDF of the number of requests required to complete the row and column fetching using the DAS protocol, with and without attackers in the simulation, from 0\\% to 75\\% of attackers in the simulation.\n", + "As we can see in the required time, we see a substantially increase when the number of malicious nodes in the network is very high (75\\%)" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 4, "id": "707322b0", "metadata": { "vscode": { @@ -205,16 +196,16 @@ { "data": { "text/plain": [ - "Text(0.5, 0, '# hops')" + "Text(0.5, 0, '# Messages')" ] }, - "execution_count": 10, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -230,41 +221,37 @@ "\n", " vsdf = op_df[key].loc[(op_df[key]['type'] == 'ValidatorSamplingOperation')]\n", "\n", - " x = np.sort(vsdf['hops'])\n", - " N = vsdf['hops'].count()\n", + " x = np.sort(vsdf['num_messages'])\n", + " N = vsdf['num_messages'].count()\n", " # get the cdf values of y\n", " y = np.arange(N) / float(N)\n", "\n", " ax8.plot(x, y,label=key)\n", "\n", "ax8.legend()\n", - "ax8.set_xlim([0,10])\n", + "#ax8.set_xlim([0,10])\n", "ax8.set_ylim([0,1])\n", "\n", - "ax8.set_title(\"CDF Row/Column sampling hops\")\n", - "ax8.set_xlabel(\"# hops\")" + "ax8.set_title(\"CDF number of requests per row/column fetching process\")\n", + "ax8.set_xlabel(\"# Messages\")" ] }, { - "attachments": {}, "cell_type": "markdown", "id": "1f80f0a7", "metadata": {}, "source": [ - "In this graph we observe the CDF of the time required to complete the random sampling of the DAS protocol, with and without attackers in the simulation, from 0\\% to 50\\% of attackers in the simulation.\n", - "In this case we do observe some performance degradation with scenarios with more than 30\\% of malicious nodes.\n", - "When 40\\% of nodes are attackers, the samples obtained is close to 95\\%, and with 50\\% is below 70\\%.\n", - "Note that we have not evaluated DAS protocol with any complementary method to get samples when sampling fails. These methods could be:\n", - " - Getting missing samples directly from the builder.\n", + "In this graph we observe the CDF of the time required to complete the random sampling (fetching 75 random samples) of the DAS protocol, with and without attackers in the simulation, from 0\\% to 75\\% of attackers in the simulation.\n", + "In this case we do observe some performance degradation with scenarios with more than 50\\% of malicious nodes.\n", + "However all nodes manage to finish the random sampling within the deadline of 12 seconds.\n", + "The performance degradation is related to the necessity to add complementary method to get samples when sampling fails. These methods are be:\n", " - Getting missing samples from validators they downloaded the row or column for that sample.\n", - " - Trying to obtain 10 additional samples for each missing sample.\n", - "\n", - "In next reports we will include an evaluation of different methods could be applied to improve random sampling in the presence of attackers." + " - Trying to obtain 10 additional samples for each missing sample.\n" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 5, "id": "a511ead6", "metadata": { "vscode": { @@ -278,13 +265,13 @@ "Text(0.5, 0, 'Operation complete time (ms)')" ] }, - "execution_count": 11, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjUAAAHHCAYAAABHp6kXAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAACP/UlEQVR4nOzdd3hUZdrH8e+0THpCSA8p9F4DhFAEpIOgrouFiICK6664ImtZ3FVQ18W2LuqrsjbQBQR1QRQhiBSVKlU6ofckQEidlCnP+8eQgSEJJCHJJJP7c11zzcxpz30yIfPjnOecR6OUUgghhBBC1HFaVxcghBBCCFEVJNQIIYQQwi1IqBFCCCGEW5BQI4QQQgi3IKFGCCGEEG5BQo0QQggh3IKEGiGEEEK4BQk1QgghhHALEmqEEEII4RYk1AhRj0yfPh2NRuPqMuq88ePHExcX5zRNo9Ewffp0l9RTltLqFMKdSagRdd6RI0f4wx/+QJMmTfD09MTf359evXrx9ttvk5+f71guLi4OjUaDRqNBq9USGBhI+/bteeSRR9i8eXOp2y5e/tpHeHj4dWtau3at0/I6nY7Q0FB+//vfs3///irdf1G/nT17lunTp7Nz505XlyKEy+ldXYAQN+P7779n9OjRGI1GHnjgAdq1a0dRURHr1q3j6aefZu/evXz44YeO5Tt16sRf/vIXAHJycti/fz9fffUVH330EU8++SRvvfVWiTYGDRrEAw884DTNy8urXPX9+c9/plu3bpjNZnbt2sWsWbNYu3Yte/bsuWEwEnVLfn4+en3N/0k9e/YsL774InFxcXTq1Mlp3kcffYTNZqvxmoRwFQk1os46duwY9957L7GxsaxevZqIiAjHvMcee4zDhw/z/fffO60TFRXF/fff7zTttddeY8yYMfz73/+mefPm/PGPf3Sa36JFixLrlFefPn34/e9/73jfsmVL/vjHP/L555/zzDPPVGqbonby9PR0dQklGAwGV5cgRI2S00+iznr99dfJzc3lk08+cQo0xZo1a8YTTzxxw+14eXnx3//+l6CgIF555RWqc+D6Pn36APZTZld788036dmzJw0bNsTLy4v4+Hi+/vrrEutrNBomTZrEN998Q7t27TAajbRt25bk5OQSy65bt45u3brh6elJ06ZN+c9//lNqTRaLhZdffpmmTZtiNBqJi4vj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", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjkAAAHHCAYAAABdm0mZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAACXBklEQVR4nOzdd3xT9frA8U9W03TvQSmUJUOWgiCIExSuE3+KCMhS8aKiIq6LCjiu4kQUEUQFREFQL7hQFBGciMoGkV3K6t4z6/z+OE1o6KAtTdKmz/v16uukJ2c8SUr78B3PV6MoioIQQgghhI/RejsAIYQQQgh3kCRHCCGEED5JkhwhhBBC+CRJcoQQQgjhkyTJEUIIIYRPkiRHCCGEED5JkhwhhBBC+CRJcoQQQgjhkyTJEUIIIYRPkiRHiGbkqaeeQqPReDuMJm/cuHEkJSW57NNoNDz11FNeiac6VcUpRHMiSY5o8g4ePMi///1v2rZti7+/PyEhIVx00UW8/vrrlJSUOI9LSkpCo9Gg0WjQarWEhYXRrVs37rrrLjZt2lTltR3Hn/4VFxdXY0wbNmxwOV6n0xETE8PNN9/Mnj17GvT1i+btxIkTPPXUU2zbts3boQjR6Oi9HYAQZ2P16tUMGzYMo9HImDFj6Nq1K2azmV9++YVHHnmE3bt3s2DBAufxPXv25KGHHgKgoKCAPXv28Mknn/DOO+/w4IMPMmvWrEr3uPLKKxkzZozLPpPJVKv47r//fi644AIsFgs7duxg/vz5bNiwgV27dp0xURJNS0lJCXq953+lnjhxgqeffpqkpCR69uzp8tw777yD3W73eExCNBaS5Igm6/Dhw9x66620bt2aH374gfj4eOdz9957LwcOHGD16tUu5yQkJHDbbbe57HvxxRcZOXIkr732Gh06dODuu+92ef6cc86pdE5tXXzxxdx8883O7zt27Mjdd9/NkiVLePTRR+t1TdE4+fv7ezuESgwGg7dDEMKrpLtKNFkvvfQShYWFvPfeey4JjkP79u154IEHzngdk8nEBx98QEREBM899xyKorgjXEBNekDtYqvolVdeoX///kRGRmIymejVqxeffvpppfM1Gg2TJk3is88+o2vXrhiNRs4991zWrFlT6dhffvmFCy64AH9/f9q1a8fbb79dZUxWq5Vnn32Wdu3aYTQaSUpK4vHHH6esrMzluKSkJK699lo2bNhA7969MZlMdOvWjQ0bNgCwcuVKunXrhr+/P7169WLr1q1nfD8sFgtPP/00HTp0wN/fn8jISAYMGMDatWudx+zYsYNx48Y5uyPj4uK4/fbbycrKcrmWY7zRvn37uO222wgNDSU6Oppp06ahKApHjx7lhhtuICQkhLi4OF599VWX8x1djCtWrODxxx8nLi6OwMBArr/+eo4ePXrG13L6mBxHPAcOHGDcuHGEhYURGhrK+PHjKS4udjm3pKSE+++/n6ioKIKDg7n++us5fvz4Gcf5bNiwgQsuuACA8ePHO7tHFy9eDFQek5OcnIxGo+GVV15h7ty5tG3bloCAAK666iqOHj2Koig8++yztGzZEpPJxA033EB2dnal+37zzTdcfPHFBAYGEhwczDXXXMPu3bvP+B4J4WnSkiOarC+//JK2bdvSv3//s75WUFAQN954I++99x5///035557rvO50tJSMjMzXY4PDg7GaDTW+T7JyckAhIeHu+x//fXXuf766xk1ahRms5nly5czbNgwvvrqK6655hqXY3/55RdWrlzJPffcQ3BwMG+88QY33XQTKSkpREZGArBz506uuuoqoqOjeeqpp7BarcyYMYPY2NhKMd155528//773HzzzTz00ENs2rSJmTNnsmfPHlatWuVy7IEDBxg5ciT//ve/ue2223jllVe47rrrmD9/Po8//jj33HMPADNnzuSWW25h7969aLXV/1/qqaeeYubMmdx555306dOH/Px8/vrrL7Zs2cKVV14JwNq1azl06BDjx48nLi7O2QW5e/dufv/990oDqYcPH07nzp154YUXWL16Nf/973+JiIjg7bff5oorruDFF19k6dKlPPzww1xwwQVccsklLuc/99xzaDQaHnvsMdLT05k9ezaDBg1i27Ztte6mrOiWW26hTZs2zJw5ky1btvDuu+8SExPDiy++6Dxm3LhxfPzxx4wePZoLL7yQH3/8sdLnXpXOnTvzzDPPMH36dO666y5nEn2mfxNLly7FbDZz3333kZ2dzUsvvcQtt9zCFVdcwYYNG3jsscc4cOAAc+bM4eGHH2bhwoXOcz/44APGjh3L4MGDefHFFykuLmbevHkMGDCArVu3ykBn0bgoQjRBeXl5CqDccMMNtT6ndevWyjXXXFPt86+99poCKJ9//rlzH1Dl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HYcPH3ZbTBEREQwYMIDx48eTlpbG7Nmzad++PRMmTHDL/Xr16sVNN93E7NmzycrKck4h37dvH3Dmlpp27doRFhbG/PnzCQ4OJjAwkL59+1Ya49MQQkJCmDdvHqNHj+b888/n1ltvJTo6mpSUFFavXs1FF13Em2++2eD3FaK+JMkRTdr111/Pjh07ePnll/n888+ZN28eRqOR7t278+qrr1b6w7Rt2zZGjx6NRqMhODiYxMRErrvuOmedFk/o3bs3l112GfPmzWPq1KlcccUVvPfee7zwwgtMnjyZNm3a8OKLL5KcnFzvJKd79+58++23TJkyhenTp9OyZUuefvppTp48Wema7777Lm3btmXx4sWsWrWKuLg4pk6dyowZMxri5dbo/vvv54svvuC7776jrKyM1q1b89///pdHHnnEecyyZcu47777mDt3LoqicNVVV/HNN9/QokULt8T0+OOPs2PHDmbOnElBQQEDBw7krbfeIiAgwC33A7X1KC4ujo8++ohVq1YxaNAgVqxYQceOHc9YSdlgMPD+++8zdepUJk6ciNVqZdGiRW5JcgBGjhxJixYteOGFF3j55ZcpKysjISGBiy++mPHjx7vlnkLUl0bx5ug3IYRoJDZs2MDll1/OJ5984rIUh7ds27aN8847jw8//JBRo0Z5OxwhmiQZkyOEEF5WUlJSad/s2bPRarWVKjILIWpPuquEEMLLXnrpJTZv3szll1+OXq/nm2++4ZtvvuGuu+6qVLtGCFF7kuQIIYSX9e/fn7Vr1/Lss89SWFhIq1ateOqpp3jiiSe8HZoQTVqdx+T89NNPvPzyy2zevJmTJ0+yatUqhg4dWuM5GzZsYMqUKezevZvExESefPLJSrNehBBCCCEaUp3H5BQVFdGjRw/mzp1bq+MPHz7MNddcw+WXX862bduYPHkyd955Z6V6HUIIIYQQDemsZldpNJoztuQ89thjrF692qX8/q233kpubq5zYTohhBBCiIbm9jE5GzdurFT+e/DgwUyePLnac8rKylwWKbTb7WRnZxMZGenREuZCCCGEqD9FUSgoKKBFixZVLk7sbm5PclJTU4mNjXXZFxsbS35+PiUlJZhMpkrnzJw5k6efftrdoQkhhBDCA44ePUrLli09ft9GObtq6tSpTJkyxfl9Xl4erVq14ujRo4SEhHgxMuEpiqLw68Es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", "text/plain": [ "
" ] @@ -308,7 +295,7 @@ " ax4.plot(x, y,label=key)\n", "\n", "ax4.legend()\n", - "ax4.set_xlim([0,8000])\n", + "ax4.set_xlim([0,10000])\n", "ax4.set_ylim([0,1])\n", "\n", "ax4.set_title(\"CDF Random sampling time\")\n", @@ -316,18 +303,17 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "a3f8ed6f", "metadata": {}, "source": [ - "In this graph we observe the CDF of the nodes contacted required to complete the random sampling of the DAS protocol, with and without attackers in the simulation, from 0\\% to 50\\% of attackers in the simulation.\n", - "The hops required are between 50 and 75 for most of the cases , except for scenarios with 50\\%, that the nodes contacted can reach higher than 100, and without completing the sampling in some cases." + "In this graph we observe the CDF of the number of requests required to complete the random sampling process using the DAS protocol, with and without attackers in the simulation, from 0\\% to 75\\% of attackers in the simulation.\n", + "As we can see in the required time, we see a substantially increase when the number of malicious nodes in the network is very high (75\\%)" ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 6, "id": "666028c4", "metadata": { "vscode": { @@ -338,16 +324,16 @@ { "data": { "text/plain": [ - "Text(0.5, 0, '# hops')" + "Text(0.5, 0, '# Messages')" ] }, - "execution_count": 14, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjAAAAHHCAYAAAChjmJTAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABa5UlEQVR4nO3dd3xUZb4G8Gf6pBdSSaX3ZoAQEF00iogUG1gprnhVcFVcV7FQXDXgKotXUdaK7l4FQUFXiiISlQ6B0HtLKGmE9GTaee8fkxkyJIFMMpmZkzzfe+eTyZlTfjMnOM++73veoxBCCBARERHJiNLTBRARERE5iwGGiIiIZIcBhoiIiGSHAYaIiIhkhwGGiIiIZIcBhoiIiGSHAYaIiIhkhwGGiIiIZIcBhoiIiGSHAYaolZg9ezYUCoWny5C9SZMmITEx0WGZQqHA7Nmz3V5Leno6FAoFli9f7vZjE3kaAwzJ2okTJ/A///M/aN++PfR6PQIDAzFkyBC8++67qKystK+XmJgIhUIBhUIBpVKJ4OBg9OrVC4899hi2bdtW575t61/5iIqKumpNti8V20OlUiEiIgL33HMPDh065NL3T0TUWqk9XQBRY61atQr33nsvdDodJkyYgJ49e8JoNGLjxo14/vnnceDAAXz00Uf29fv27YvnnnsOAFBaWopDhw5h2bJl+Pjjj/Hss89i/vz5tY5xyy23YMKECQ7LfHx8GlTfX/7yFwwYMAAmkwl79+7FokWLkJ6ejv37918zBJG8VFZWQq3mf06J3In/4kiWTp06hfvuuw8JCQn49ddfER0dbX9t6tSpOH78OFatWuWwTUxMDB566CGHZfPmzcMDDzyAf/7zn+jUqROeeOIJh9c7d+5ca5uGGjp0KO655x777126dMETTzyBL7/8En/7298atU/yTnq93tMlELU67EIiWXrrrbdQVlaGTz/91CG82HTs2BFPP/30Nffj4+ODf//73wgNDcUbb7yB5rw5+9ChQwFYu71qevvttzF48GC0adMGPj4+SEpKqnNMg0KhwLRp07By5Ur07NkTOp0OPXr0wNq1a2utu3HjRgwYMAB6vR4dOnTAv/71rzprMpvN+Pvf/44OHTpAp9MhMTERL730EgwGg8N6iYmJuOOOO5Ceno7+/fvDx8cHvXr1Qnp6OgDgu+++Q69evaDX65GUlITdu3df8/MwmUyYM2cOOnXqBL1ejzZt2uD666/HunXr7Ovs3bsXkyZNsncRRkVF4ZFHHsHFixcd9mUb33P06FE89NBDCAoKQnh4OF599VUIIZCdnY0xY8YgMDAQUVFReOeddxy2t3X7LV26FC+99BKioqLg5+eH0aNHIzs7+5rv5coxMLZ6jh8/jkmTJiE4OBhBQUGYPHkyKioqHLatrKzEX/7yF4SFhSEgIACjR4/GuXPnnBpXI0kS3njjDcTGxkKv1+Pmm2/G8ePHa623bNkyJCUlwcfHB2FhYXjooYdw7tw5h3UmTZoEf39/nDx5EsOHD4efnx/atm2L1157rda/jyVLliApKQkBAQEIDAxEr1698O677zaoZqKmYoAhWfrvf/+L9u3bY/DgwU3el7+/P+68806cO3cOBw8edHitqqoKBQUFDo8rv9wb6vTp0wCAkJAQh+Xvvvsu+vXrh9deew1vvvkm1Go17r333lotSIA1mDz55JO477778NZbb6Gqqgp33323wxf6vn37cOuttyIvLw+zZ8/G5MmTMWvWLKxYsaLW/h599FHMnDkT1113Hf75z3/ixhtvRFpaGu67775a6x4/fhwPPPAARo0ahbS0NFy6dAmjRo3C//3f/+HZZ5/FQw89hDlz5uDEiRMYN24cJEm66ucxe/ZszJkzB8OGDcP777+Pl19+GfHx8di1a5d9nXXr1uHkyZOYPHky3nvvPdx3331YsmQJbr/99jrD5vjx4yFJEubOnYvk5GS8/vrrWLBgAW655RbExMRg3rx56NixI/7617/i999/r7X9G2+8gVWrVuGFF17AX/7yF6xbtw6pqakO46mcMW7cOJSWliItLQ3jxo3D4sWLMWfOHId1Jk2ahPfeew+333475s2bBx8fH4wcOdKp48ydOxcrVqzAX//6V8yYMQNbt27Fgw8+6LDO4sWLMW7cOKhUKqSlpWHKlCn47rvvcP3116OoqMhhXYvFgttuuw2RkZF46623kJSUhFmzZmHWrFn2ddatW4f7778fISEhmDdvHubOnYs//elP2LRpk3MfElFjCSKZKS4uFgDEmDFjGrxNQkKCGDlyZL2v//Of/xQAxPfff29fBqDOx+eff37VY23YsEEAEJ999pnIz88X58+fF2vXrhUdO3YUCoVCbN++3WH9iooKh9+NRqPo2bOnuOmmmxyW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fPTRRygqKsKNN96I7du344svvsDYsWMxbNgwV73tOnXv3h1/+tOfkJSUhNDQUOzcuRPLly+3Dx4NDAzEDTfcgLfeegsmkwkxMTH4+eefa7VWuFJoaCiuv/56TJ48Gbm5uViwYAE6duyIKVOmNMvxkpKScPfdd2PBggW4ePEiBg0ahN9++83e2uGqQK3RaDBv3jxMnjwZN954I+6//37k5ubi3XffRWJiIp599lmH9fV6PdauXYuJEyciOTkZa9aswapVq/DSSy8hPDwcgHXAdGFhIW666SbExsbizJkzeO+999C3b99mbckksmGAIdkaPXo09u7di3/84x/4/vvv8eGHH0Kn06F379545513an3pZGZm4uGHH4ZCoUBAQADi4uIwatQoPProoxg4cKBbau7fvz/+9Kc/4cMPP8SMGTNw00034dNPP8XcuXPxzDPPoF27dpg3bx5Onz7d6ADTu3dv/PTTT5g+fTpmzpyJ2NhYzJkzBxcuXKi1z08++QTt27fH4sWLsWLFCkRFRWHGjBkO8300l7/85S/44Ycf8PPPP8NgMCAhIQGvv/46nn/+efs6X331FZ566iksXLgQQgjceuutWLNmDdq2bdssNb300kvYu3cv0tLSUFpaiptvvhkffPABfH19m+V4gLXVJyoqCl9//TVWrFiB1NRULF26FF26dHHpDL+TJk2Cr68v5s6dixdeeAF+fn648847MW/ePAQHBzusq1KpsHbtWjzxxBN4/vnnERAQgFmzZmHmzJn2dR566CF89NFH+OCDD1BUVISoqCiMHz8es2fPrnOwOpGrKYQ7RrIREXmx9PR0DBs2DMuWLXO4/YOnZGZmol+/fvjPf/5Ta0K65jZp0iQsX77cfmUekbdiTCYi8qC6ZvldsGABlEolbrjhBg9URCQP7EIiIvKgt956CxkZGRg2bBjUajXWrFmDNWvW4LHHHqs1xw4RXcYAQ0TkQYMHD8a6devw97//HWVlZYiPj8fs2bPx8ssve7o0Iq/m9BiY33//Hf/4xz+QkZGBCxcuYMWKFRg7duxVt0lPT8f06dNx4MABxMXF4ZVXXql1hQgRERFRQzk9Bqa8vBx9+vTBwoULG7T+qVOnMHLkSAwbNgyZmZl45pln8Oijj9aak4KIiIiooZp0FZJCobhmC8wLL7yAVatWOUz7ft9996GoqIj3zSAi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iFWrVomjR4+KI0eOiJdeekloNBqxf/9+IQTPg6ds375dJCYmit69e4unn37avpznw31mzZolevToIS5cuGB/5Ofn219317nw6gAzcOBAMXXqVPvvFotFtG3bVqSlpXmwqpbtygAjSZKIiooS//jHP+zLioqKhE6nE19//bUQQoiDBw8KAGLHjh32ddasWSMUCoU4d+6c22pvifLy8gQA8dtvvwkhrJ+9RqMRy5Yts69z6NAhAUBs2bJFCGENpEqlUuTk5NjX+fDDD0VgYKAwGAzufQMtTEhIiPjkk094HjyktLRUdOrUSaxbt07ceOON9gDD8+Fes2bNEn369KnzNXeeC6/tQjIajcjIyEBqaqp9mVKpRGpqKrZs2eLBylqXU6dOIScnx+E8BAUFITk52X4etmzZguDgYPTv39++TmpqKpRKJbZt2+b2mluS4uJiALDfCC0jIwMmk8nhfHTt2hXx8fEO56NXr1722bEBYPjw4SgpKcGBAwfcWH3LYbFYsGTJEpSXlyMlJYXnwUOmTp2KkSNHOnzuAP9deMKxY8fQtm1btG/fHg8++CCysrIAuPdcNGomXncoKCiAxWJxeIMAEBkZicOHD3uoqtYnJycHAOo8D7bXcnJyEBER4fC6Wq1GaGiofR1yniRJeOaZZzBkyBD7rTdycnKg1WoRHBzssO6V56Ou82V7jRpu3759SElJQVVVFfz9/bFixQp0794dmZmZPA9utmTJEuzatQs7duyo9Rr/XbhXcnIyFi9ejC5duuDChQuYM2cOhg4div3797v1XHhtgCFq7aZOnYr9+/dj48aNni6l1erSpQsyMzNRXFyM5cuXY+LEifjtt988XVark52djaeffhrr1q2DXq/3dDmt3ogRI+zPe/fujeTkZCQkJOCbb76Bj4+P2+rw2i6ksLAwqFSqWiOXc3NzERUV5aGqWh/bZ3218xAVFYW8vDyH181mMwoLC3muGmnatGn48ccfsWHDBsTGxtqXR0VFwWg0oqioyGH9K89HXefL9ho1nFarRceOHZGUlIS0tDT06dMH7777Ls+Dm2VkZCAvLw/XXXcd1Go11Go1fvvtN/zv//4v1Go1IiMjeT48KDg4GJ07d8bx48fd+m/DawOMVqtFUlIS1q9fb18mSRLWr1+PlJQUD1bWurRr1w5RUVEO56GkpATbtm2zn4eUlBQU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", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAHHCAYAAABtF1i4AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAByo0lEQVR4nO3dd3hTZfsH8G920t3SPaDsJUMFKgIC0pciiuAE9RVEBEVQFCcOhgsVQfypiKCI4gTcgijbVwVkI5uyVxd0rzTJ8/sjzaGhM22Sk6Tfz3X1ysnJOc9z52TdPecZCiGEABEREZFMlHIHQERERI0bkxEiIiKSFZMRIiIikhWTESIiIpIVkxEiIiKSFZMRIiIikhWTESIiIpIVkxEiIiKSFZMRIiIikhWTEaqzEydOQKFQ4K233pI7lDopKCjAAw88gOjoaCgUCjz22GNyh0Q+aPHixVAoFDhx4oTcoXi16dOnQ6FQ2K1LTEzEfffdJ09A5FZMRgAcPXoUDz74IFq0aAG9Xo+goCD06tUL77zzDoqLi6XtEhMToVAooFAooFQqERISgk6dOmHcuHHYsmVLlWXbtr/8Lzo62l1Pr9F67bXXsHjxYowfPx5LlizBvffeK3dIsjl37hymT5+OXbt2yR0KEVElarkDkNuKFStwxx13QKfTYeTIkbjiiitgNBrx559/4qmnnsK+ffuwYMECafuuXbviiSeeAADk5+fjwIEDWLZsGRYuXIjHH38cc+bMqVTHf/7zH4wcOdJuncFgcO0TI6xbtw7XXHMNpk2bJncosjt37hxmzJiBxMREdO3aVe5wiOrk0KFDUCr5P3Nj0KiTkePHj2PEiBFo1qwZ1q1bh5iYGOmxCRMmIDU1FStWrLDbJy4uDv/973/t1r3xxhu4++678fbbb6N169YYP3683eNt2rSptA9Vr7CwEP7+/g0uJyMjAx06dKjXvhaLBUajEXq9vsFxUP05+joIIVBSUsJk30fodDq5Q6gXZ32HNSaNOuV88803UVBQgI8//tguEbFp1aoVJk2aVGs5BoMBS5YsQVhYGF599VU4YyJk23Xov/76C5MnT0ZERAT8/f1xyy23IDMz025bhUKB6dOnVyrj8uuttjL//PNPPProo4iIiEBISAgefPBBGI1G5OTkYOTIkQgNDUVoaCiefvrpap/L22+/jWbNmsFgMKBv377Yu3dvpW0OHjyI22+/HWFhYdDr9ejWrRt++umnKp/nxo0b8fDDDyMyMhLx8fE1HpuMjAyMGTMGUVFR0Ov16NKlCz799FPp8Q0bNkChUOD48eNYsWKFdGmspmv6CoUCEydOxBdffIGOHTtCp9Nh1apVAICzZ8/i/vvvR1RUFHQ6HTp27IhFixZVKuPMmTMYNmwY/P39ERkZiccffxy//fYbFAoFNmzYIG1X3XXwfv36oV+/fnbrSktLMW3aNLRq1Qo6nQ4JCQl4+umnUVpaarfd6tWr0bt3b4SEhCAgIABt27bFc889Jx2P7t27AwBGjx4tHY/FixcDAI4cOYLbbrsN0dHR0Ov1iI+Px4gRI5Cbm1vt8bLFe8UVV2D79u249tprYTAY0Lx5c8yfP7/StnV9HjW9DlVJTEzETTfdhN9++w3dunWDwWDAhx9+CAD45JNPcP311yMyMhI6nQ4dOnTABx98UG0Zf/75J3r06AG9Xo8WLVrgs88+q7Ttvn37cP3118NgMCA+Ph6vvPIKLBZLlbHNmzdPeg6xsbGYMGECcnJyqjyGe/bsQd++feHn54dWrVph+fLlAICNGzciKSkJBoMBbdu2xZo1a6o9FhW9++676NixI/z8/BAaGopu3brhyy+/lB4/efIkHn74YbRt2xYGgwFNmjTBHXfcUekz0tDvjIrtzOrynXG56r7D6vK9aLFYMH36dMTGxsLPzw/9+/fH/v3769QOxZG477vvPgQEBODo0aMYPHgwAgMDcc899wCwJiVPPPEEEhISoNPp0LZtW7z11ltVfq9+/vnn6NGjh/SaXXfddfj999/ttvn111/Rp08f+Pv7IzAwEDfeeCP27dtnt01aWhpGjx6N+Ph46HQ6xMTEYOjQoXav7bZt25CSkoLw8HDpc3v//ffXeExcrVGfGfn555/RokULXHvttQ0uKyAgALfccgs+/vhj7N+/Hx07dpQeKykpQVZWlt32gYGBdcr6H3nkEYSGhmLatGk4ceIE5s6di4kTJ+Kbb76pd6yPPPIIoqOjMWPGDGzevBkLFixASEgI/v77bzRt2hSvvfYaVq5ciVmzZuGKK66odInps88+Q35+PiZMmICSkhK88847uP766/Hvv/8iKioKgPVLu1evXoiLi8Ozzz4Lf39/LF26FMOGDcO3336LW265xa7Mhx9+GBEREZg6dSoKCwurjb24uBj9+vVDamoqJk6ciObNm2PZsmW47777kJOTg0mTJqF9+/ZYsmQJHn/8ccTHx0uX1SIiImo8LuvWrcPSpUsxceJEhIeHIzExEenp6bjmmmukH8mIiAj8+uuvGDNmDPLy8qRGscXFxRgwYABOnTqFRx99FLGxsViyZAnWrVvn6MsjsVgsuPnmm/Hnn39i3LhxaN++Pf7991+8/fbbOHz4MH744QfpWN90003o3LkzXnrpJeh0OqSmpuKvv/4CALRv3x4vvfQSpk6dinHjxqFPnz4AgGuvvRZGoxEpKSkoLS2V3hdnz57FL7/8gpycHAQHB9cYY3Z2NgYPHow777wTd911F5YuXYrx48dDq9VKX251fR41vQ41OXToEO666y48+OCDGDt2LNq2bQsA+OCDD9CxY0fcfPPNUKvV+Pnnn/Hwww/DYrFgwoQJdmWkpqbi9ttvx5gxYzBq1CgsWrQI9913H66++mrps5yWlob+/fvDZDJJ7+kFCxZUeRZm+vTpmDFjBpKTkzF+/HgcOnQIH3zwAbZu3Yq//voLGo3G7hjedNNNGDFiBO644w588MEHGDFiBL744gs89thjeOihh3D33Xdj1qxZuP3223H69GkEBgZWezwWLlyIRx99FLfffjsmTZqEkpIS7NmzB1u2bMHdd98NANi6dSv+/vtvjBgxAvHx8Thx4gQ++OAD9OvXD/v374efn59dme74znBEXb4Xp0yZgjfffBNDhgxBSkoKdu/ejZSUFJSUlNS5nrrGbTKZkJKSgt69e+Ott96Cn58fhBC4+eabsX79eowZMwZdu3bFb7/9hqeeegpnz57F22+/Le0/Y8YMTJ8+Hddeey1eeuklaLVabNmyBevWrcPAgQMBAEuWLMGoUaOQkpKCN954A0VFRfjggw/Qu3dv7Ny5U/qc3Hbbbdi3bx8eeeQRJCYmIiMjA6tXr8apU6ek+wMHDkRERASeffZZhISE4MSJE/juu+8cfh2cSjRSubm5AoAYOnRonfdp1qyZuPHGG6t9/O233xYAxI8//iitA1Dl3yeffFJjXZ988okAIJKTk4XFYpHWP/7440KlUomcnBy7OqZNm1ZlvKNGjapUZkpKil2ZPXv2FAqFQjz00EPSOpPJJOLj40Xfvn2ldcePHxcAhMFgEGfOnJHWb9myRQAQjz/+uLRuwIABolOnTqKkpERaZ7FYxLXXXitat25dKabevXsLk8lU4zERQoi5c+cKAOLzzz+X1hmNRtGzZ08REBAg8vLy7J5/Ta9XRQCEUqkU+/bts1s/ZswYERMTI7KysuzWjxgxQgQHB4uioiK7uJYuXSptU1hYKFq1aiUAiPXr19vFVfF1senbt6/d8V6yZIlQKpXif//7n9128+fPFwDEX3/9JYS49L7LzMys9vlt3bq1yvfdzp07BQCxbNmyavetTt++fQUAMXv2bGldaWmp6Nq1q4iMjBRGo9Gh5yFE9a9DdZo1ayYAiFWrVlV6zPbaVJSSkiJatGhRZRl//PGHtC4jI0PodDrxxBNPSOsee+wxAUBs2bLFbrvg4GABQBw/flxap9VqxcCBA4XZbJa2fe+99wQAsWjRImmd7Rh++eWX0rqDBw9Kx2Hz5s3S+t9++61O3x1Dhw4VHTt2rHGbqo7Npk2bBADx2WefSevc+Z0xbdo0cflPUnXfYbV9L6alpQm1Wi2GDRtmV9706dMFgCo/fxU5EveoUaMEAPHss8/alfHDDz8IAOKVV16xW3/77bcLhUIhUlNThRBCHDlyRCiVSnHLLbfYvV+EENJzzM/PFyEhIWLs2LF2j6elpYng4GBpfXZ2tgAgZs2aVe1z+/777wUAsXXr1hqPgbs12ss0eXl5AFDjfxiOCggIAGBt2FrR0KFDsXr1aru/lJSUOpU5btw4u+5uffr0gdlsxsmTJ+sd55gxY+zKTEpKghACY8aMkdapVCp069YNx44dq7T/sGHDEBcXJ93v0aMHkpKSsHLlSgDAxYsXsW7dOtx5553Iz89HVlYWsrKycOHCBaSkpODIkSM4e/asXZljx46FSqWqNfaVK1ciOjoad911l7ROo9Hg0UcfRUFBATZu3Fj3A3GZvn372rUxEULg22+/xZAhQyCEkJ5HVlYWUlJSkJubix07dkhxxcTE4Pbbb5f29/Pzw7hx4+odz7Jly9C+fXu0a9fOru7rr78eALB+/XoAQEhICADgxx9/rPaSQXVsZz5+++03FBUVORyjWq3Ggw8+KN3XarV48MEHkZGRge3btzv0PGwufx1q07x58yo/TxXPWOTm5iIrKwt9+/bFsWPHKl2C6tChg3TGCLCeRWvbtq3d+3/lypW45ppr0KNHD7vtbKfkbdasWQOj0YjHHnvMrvHl2LFjERQUVKkdWkBAAEaMGCHdb9u2LUJCQtC+fXskJSVJ623LVX0mKwoJCcGZM2ewdevWarepeGzKyspw4cIFtGrVCiEhIdJ7uiJXf2c4qrbvxbVr18JkMuHhhx+22++RRx5xqB5H4r68reDKlSuhUqnw6KOP2q1/4oknIITAr7/+CgD44YcfYLFYMHXq1EqNdW3PcfXq1cjJycFdd91l9xlSqVRISkqSPkMGgwFarRYbNmxAdnZ2lc/J9n3xyy+/oKyszIGj4VqNNhkJCgoCUDlxaIiCggIAlROc+Ph4JCcn2/1V1UalKk2bNrW7HxoaCgDVvtHqU6btBykhIaHS+qrqad26daV1bdq0ka5JpqamQgiBF198EREREXZ/tp4tGRkZdvs3b968TrGfPHkSrVu3rvShbd++vfR4fV0eQ2ZmJnJycrBgwYJKz2P06NEALj2PkydPolWrVpXGSbBdMqiPI0eOYN++fZXqbtOmjV3dw4cPR69evfDAAw8gKioKI0aMwNKlS+uUmDRv3hyTJ0/GRx99hPDwcKSkpOD999+vtb2ITWxsbKWGerb4bO+Huj6PijE5orrt//rrLyQnJ8Pf3x8hISGIiIiQ2tFc/vwu/0wA1s9axfe/7b13uctfY9t78PL1Wq0WLVq0qPQejY+Pr/S+CQ4OrvLzCNT+2X/mmWcQEBCAHj16oHXr1pgwYYJ0yc6muLgYU6dOldoyhIeHIyIiAjk5OVW+9q7+znBUbd+LtmPcqlUru+3CwsKkbeuirnGr1epKbd1OnjyJ2NjYSr8Hl39XHT16FEqlssYE/MiRIwCA66+/vtLn6Pfff5c+QzqdDm+88QZ+/fVXREVF4brrrsObb76JtLQ0qay+ffvitttuw4wZMxAeHo6hQ4fik08+qdR+y90abZuRoKAgxMbG1qkRVV3Zyrr8A9AQ1Z0tEHVoJGs2mx0qs6r1danncrYfwSeffLLaM0CXHyNP6P1weQy25/Hf//4Xo0aNqnKfzp07O1zP5T88Nmaz2e41sFgs6NSpU5XdxYFLPwQGgwF//PEH1q9fjxUrVmDVqlX45ptvcP311+P333+v9YzT7Nmzcd999+HHH3/E77//jkcffRQzZ87E5s2ba21MXBd1fR42jr4Xqtr+6NGjGDBgANq1a4c5c+YgISEBWq0WK1euxNtvv10pUWvI56yhHPk8ArXH1L59exw6dAi//PILVq1ahW+//Rbz5s3D1KlTMWPGDADWMwSffPIJHnvsMfTs2RPBwcFQKBQYMWJElUmsq78zHCXn61UVnU7n0i7IttdkyZIlVY5RpVZf+il/7LHHMGTIEPzwww/47bff8OKLL2LmzJlYt24drrzySigUCixfvhybN2/Gzz//jN9++w33338/Zs+ejc2bN0tn+N2t0SYjAHDTTTdhwYIF2LRpE3r27NmgsgoKCvD9998jISFBynzdJTQ0tFIrfaPRiPPnz7ukPluWXtHhw4elBlQtWrQAYL18kpyc7NS6mzVrhj179sBisdh9+A8ePCg97iwREREIDAyE2Wyu9Xk0a9YMe/fuhRDCLtk4dOhQpW2rer0A639KtmMHAC1btsTu3bsxYMCAahMYG6VSiQEDBmDAgAGYM2cOXnvtNTz//PNYv349kpOTa92/U6dO6NSpE1544QX8/fff6NWrF+bPn49XXnmlxv3OnTtXqRvj4cOHAUB6PzjyPJzl559/RmlpKX766Se7/6IvvyTkiGbNmlX53r/8Nba9Bw8dOmT3ehqNRhw/ftzpn4mq+Pv7Y/jw4Rg+fDiMRiNuvfVWvPrqq5gyZQr0ej2WL1+OUaNGYfbs2dI+JSUlVb4vnaG27wxns70GqampdmfOLly44NBZ5YbE3axZM6xZswb5+fl2Z0cu/65q2bIlLBYL9u/fX+0YQC1btgQAREZG1un907JlSzzxxBN44okncOTIEXTt2hWzZ8/G559/Lm1zzTXX4JprrsGrr76KL7/8Evfccw++/vprPPDAA7WW7wqN9jINADz99NPw9/fHAw88gPT09EqPHz16FO+8806t5RQXF+Pee+/FxYsX8fzzz7vtC9emZcuW+OOPP+zWLViwoNozIw31ww8/2LX5+Oeff7BlyxbccMMNAKwfmH79+uHDDz+sMiG6vAueIwYPHoy0tDS7VvMmkwnvvvsuAgIC0Ldv33qXfTmVSoXbbrsN3377bZVn0Co+j8GDB+PcuXNSl0wAKCoqshswz6Zly5bYvHkzjEajtO6XX37B6dOn7ba78847cfbsWSxcuLBSGcXFxVKvo4sXL1Z63PalZjv1aksWLv+xycvLg8lkslvXqVMnKJXKOp22NZlMUldawPqD++GHHyIiIgJXX321Q8/DmWz/OVf8Tzk3NxeffPJJvcscPHgwNm/ejH/++Udal5mZiS+++MJuu+TkZGi1Wvzf//2fXf0ff/wxcnNzceONN9Y7hrq4cOGC3X2tVosOHTpACCG1EVCpVJXOIrz77ruyfWc424ABA6BWqyt15X7vvfccKqchcQ8ePBhms7lSnW+//TYUCoVUxrBhw6BUKvHSSy9VOitle41SUlIQFBSE1157rcp2HrbvoqKiokq9hVq2bInAwEDp85ydnV3ptb/8+0IOjfrMSMuWLfHll19i+PDhaN++vd0IrH///bfUZbSis2fPStllQUEB9u/fj2XLliEtLQ1PPPGEXWM+d3nggQfw0EMP4bbbbsN//vMf7N69G7/99hvCw8NdUl+rVq3Qu3dvjB8/HqWlpZg7dy6aNGmCp59+Wtrm/fffR+/evdGpUyeMHTsWLVq0QHp6OjZt2oQzZ85g9+7d9ap73Lhx+PDDD3Hfffdh+/btSExMxPLly/HXX39h7ty5Tm2QDACvv/461q9fj6SkJIwdOxYdOnTAxYsXsWPHDqxZs0ZKBMaOHYv33nsPI0eOxPbt2xETE4MlS5ZU6iIJWF+v5cuXY9CgQbjzzjtx9OhRfP7559J/Pzb33nsvli5dioceegjr169Hr169YDabcfDgQSxdulQaW+Oll17CH3/8gRtvvBHNmjVDRkYG5s2bh/j4ePTu3RuA9b0eEhKC+fPnIzAwEP7+/khKSsLu3bsxceJE3HHHHWjTpg1MJhOWLFkiJWK1iY2NxRtvvIETJ06gTZs2+Oabb7Br1y4sWLBA6r5a1+fhTAMHDoRWq8WQIUPw4IMPoqCgAAsXLkRkZGS9zxg+/fTTWLJkCQYNGoRJkyZJXXttZ+tsIiIiMGXKFMyYMQODBg3CzTffjEOHDmHevHno3r27ywdAHDhwIKKjo9GrVy9ERUXhwIEDeO+993DjjTdKn4+bbroJS5YsQXBwMDp06IBNmzZhzZo1aNKkiUtiqst3hjNFRUVh0qRJmD17Nm6++WYMGjQIu3fvxq+//orw8PA6/8PYkLiHDBmC/v374/nnn8eJEyfQpUsX/P777/jxxx/x2GOPSZ/3Vq1a4fnnn8fLL7+MPn364NZbb4VOp8PWrVsRGxuLmTNnIigoCB988AHuvfdeXHXVVRgxYgQiIiJw6tQprFixAr169cJ7772Hw4cPY8CAAbjzzjvRoUMHqNVqfP/990hPT5caSX/66aeYN28ebrnlFrRs2RL5+flYuHAhgoKCMHjw4Pof9IZyc+8dj3T48GExduxYkZiYKLRarQgMDBS9evUS7777rl3XVFsXQABCoVCIoKAg0bFjRzF27Fi77n4VARATJkxwOCZbF7bLu1+tX7++UldRs9ksnnnmGREeHi78/PxESkqKSE1NrbZb3OVl2rrUXd41dNSoUcLf31+6b+vuNmvWLDF79myRkJAgdDqd6NOnj9i9e3el53D06FExcuRIER0dLTQajYiLixM33XSTWL58ea0x1SQ9PV2MHj1ahIeHC61WKzp16lRld0dHu/ZW9zqlp6eLCRMmiISEBKHRaER0dLQYMGCAWLBggd12J0+eFDfffLPw8/MT4eHhYtKkSWLVqlWVXi8hhJg9e7aIi4sTOp1O9OrVS2zbtq1S114hrN2W33jjDdGxY0eh0+lEaGiouPrqq8WMGTNEbm6uEEKItWvXiqFDh4rY2Fih1WpFbGysuOuuu8Thw4ftyvrxxx9Fhw4dhFqtlrqIHjt2TNx///2iZcuWQq/Xi7CwMNG/f3+xZs2aWo9Z3759RceOHcW2bdtEz549hV6vF82aNRPvvfdepW3r8jxqex2qUtNr/NNPP4nOnTsLvV4vEhMTxRtvvCEWLVpk1w23pjKqej327Nkj+vbtK/R6vYiLixMvv/yy+PjjjyuVKYS1K2+7du2ERqMRUVFRYvz48SI7O7tSHVV1w60uprocnw8//FBcd911okmTJkKn04mWLVuKp556yu44Z2dnS5+hgIAAkZKSIg4ePCjrd4YjXXvr8r1oMpnEiy++KKKjo4XBYBDXX3+9OHDggGjSpIldl+SqOBL35c+5ovz8fPH444+L2NhYodFoROvWrcWsWbPsuiXbLFq0SFx55ZXS56Nv375i9erVlZ5nSkqKCA4OFnq9XrRs2VLcd999Ytu2bUIIIbKyssSECRNEu3bthL+/vwgODhZJSUl2Qw7s2LFD3HXXXaJp06ZCp9OJyMhIcdNNN0llyEUhhEwtfogagQ0bNqB///5Yv359pdFVvV2/fv2QlZXl1Ebg5FtOnDiB5s2bY9asWXjyySflDgc5OTkIDQ3FK6+8gueff77a7Twt7sagUbcZISIi31RxxnWbuXPnAoDP/WPgCxp1mxEiIvJN33zzDRYvXozBgwcjICAAf/75J7766isMHDgQvXr1kjs8ugyTESIi8jmdO3eGWq3Gm2++iby8PKlRa23d1UkeDrcZ+eOPPzBr1ixs374d58+fx/fff49hw4bVuM+GDRswefJk7Nu3DwkJCXjhhRdqnTWRiIiIGgeH24wUFhaiS5cueP/99+u0/fHjx3HjjTeif//+2LVrFx577DE88MAD+O233xwOloiIiHxPg3rTKBSKWs+MPPPMM1ixYoVdi/sRI0YgJycHq1atqm/VRERE5CNc3mZk06ZNlYavTUlJwWOPPVbtPqWlpXYjwVksFly8eBFNmjRx++imREREVD9CCOTn5yM2NrbG+XtcnoykpaUhKirKbl1UVBTy8vJQXFxc5SRXM2fOlCZ0IiIiIu92+vTpGife9MjeNFOmTMHkyZOl+7m5uWjatClOnz6NoKAgt8fz9dZTeOWXAwCA1pEBmDywDUIMGrT95VZos62TguE/LwExVwJRHQC1zuUxmS1mfHHgC8zbPa/SYwaVAaH6UOjVeuhVeuhUOujUOuhVeujVeuuysnxZpZNutSot1Ao11Eo1VEoVVAoV1Eo11ArrfbVSjRj/GET5R1URERHVh6WkBObcXJhzcmDOy7Pe5ubCkpsLc06u9bHcXJhyL6235OUDco1XqVJBodFAodVCoVZDodEAFZYvf0yh0ViXVSrrvkql9ValAlRKKBRKQK2CQll+X6my3lcorfdVaihUSqB8PZRKaxnK8pl7FQDKz5grFAppGaiwrFBYt7t8G4UCFR4o36XiY6iirGrqsyurlm0qlGVXn13sFWqvapvL6qu0TZXHoeaytPFxUDp5BvW8vDwkJCTUOlWHy5OR6OjoSpPQpaenIygoqNqpwnU6HXS6yj/oQUFBsiQjP+3PhlLnh0EdozH/XuvkX9j5OVB0BNApgHEbgNgr3RrTA78/gC3nt0BlsH4gb29zO3pE90CXiC6I8Y/h5SwimYmyMpSdPw9zdjbK0tNhOn8ewmRG8e7dMB4/BlPWBZjrOIOsAoCm/A8AUH66W+nnB2VwMFSBgVAFBUEZGAhVUCCUgUFQGgzWpMCWHNgSg4r3K67XaqDQaMtvq9nHllQQOai23ySXJyM9e/bEypUr7datXr0aPXv2dHXVTrP3bB4AYNS1idYVpfnAjxOsy837uj0Rmb97Prac3wIAGNZqGF685kVoVVq3xkBEgKWwEKXHjqNo2zZY8vNhPHUKhZs2QaHRwJSWVveClErAYoEmNhbqmBioQkKgCg2BOiTEulzVX3Cw9awEkQ9wOBkpKChAamqqdP/48ePYtWsXwsLC0LRpU0yZMgVnz57FZ599BgB46KGH8N577+Hpp5/G/fffj3Xr1mHp0qVYsWKF856FC528cGl68y4JwdaFA79c2uCeZW6NZ2fGTry/y9qtulN4J7zc62W31k/U2IiyMhjPnEHpkSMo2bMHJfv3w3QxG6UHD9a5DH3HjlBotYBCAX379lCoVTB06QJd27ZQR0ZC6e9vvfRA1Eg5nIxs27YN/fv3l+7b2naMGjUKixcvxvnz53Hq1Cnp8ebNm2PFihV4/PHH8c477yA+Ph4fffQRUlJSnBC+6x1MywcARAbq4KctP1zndlhv29/slvYhNoVlhRi9arR0f96Ayu1FiKjuhNmMsnPnYMrIgCkzE6aMTOttZiZK9u9H2ZkzsBQV1VqOX7dugEIB/169oImLgzq8CXStWkHVpAmTDKI6cDgZ6devH2oammTx4sVV7rNz505Hq/IIpy9av4gSm/hfWpn2r/U2prNbY1l6aCnMwmxdvmkpQvQhbq2fyJuJsjIU79mDwr/+QtGOnSjZvx+WvLw676+OioKuVSuow8Ph170btC1aQts8EerQUBdGTdQ4eGRvGk9yodAIAIgJ0VtXCHEpGXFjWxEhBD7f/zkAYGjLoWjfpL3b6ibyJpaSEpTs3YuiHTthSktD/ob1UKjUKDt9utp9FDod9FdcAXVEhPUvPLz8tgm0LVpAExvLMxxELsRkpBbncqzTUEcElF+OKc0HjAXW5bhubotjT9YeZBRnAADGdx3vtnqJPJkwm1Gybx8KN21G0Y7tKPpnK0QVU8dXpPT3R0D//tC1aYOA6/pA17o1e4gQyYzJSC2KjNbLItHB5WdGCsq7KSuUgNa/mr2cb9Vx69D57cLaIS4gzm31EnkSYTQif9065Hz7HUwZGSg9dKjabTXx8dA2bYrAgQOhjoyAvkMHqCMimHgQeSAmI7XILSoDAPjryg9VYZb1NiAaULmvW93m85sBAH3i+ritTiJPUHr8OHK/+x45y5dXOy6HMiAA/r17w9C5MwL6XgdtixYca4fIizAZqUVGfgkAINSvPPEoLW/wpvVzWwwmiwmpOdbu1H3imYyQb7MUF6NwyxZkf/UVCjf+UeU2mvh4hAy/E/5JSdaushxvg8irMRmpRUmZBQAQGVR+mSb3jPXWEOa2GHZl7JKWO4e7twcPkTuYCwqR/eWXuDB/frVdaf1790bYyHvh36sXL7UQ+RgmIzUwmS3SmRGDpvzLT1iTEwRGuy2O/539HwCgfVh7qJT8EibfkbN8OdJnvQVLbm6lxwxXXQV9u7ZoMmYMNHFsJ0Xky5iM1MBotsBSPqSKNM6IrSeNGx28aB3psXt0d7fXTeRspampSJs+A0XbtlV6TNehPSImTkRA//5s80HUiDAZcVTuWeutIcRtVe6/sB8AOLYIebXsr79B+quvQpSV2a1XGAyIfe1VBA4axASEqJFiMlIDk6WKkWazj1tvQ5u7JYY8Yx5ySnMAANfEXOOWOomcRQiBCx9+iMy571R6LOz++9Fk7AMcwZSImIzU5GiG9ZKMVqWETl0++mKpda4aBMe7JYbDFw8DANQKNcIN4W6pk6ihLIWFSHvpZeT++KPdeoWfH+LeegsB/fvxLAgRSZiM1MB2YiQ6WA+l8rIvTo3BLTH8k/YPAKB5iHvOxBA1hKW0FOeeehr5v/9ut14dEYH499+DoTN7gxFRZUxGapBdPi+N3T9wxVUPuuQqtvFFroq8yq31Ejmi9MgRnH/hRRTv3m233q97d8S+9RY0UZEyRUZE3oDJSA3Sy7v1htvmpQGAvPPW26BYt8RwIu8EAKBlSEu31EfkCCEEzj/3PHK//95uvX+fPoh/Zy6Ufu4bHJCIvBeTkTpo4q+1LpSVAMbyNiN+7mm/cST7CACgbWhbt9RHVFfZS5cibeo0u3Vh99+PiEmPQqnTVbMXEVFlTEZqYLm8N41tkjwACGnq8vrTCtOk5XZh7VxeH1Fd5P32O85OmmS3ThMfj+bffQtVUJBMURGRN2MyUoOzOdbLNBqV0v4Bjd9lDUlcw5aM+Gv84afh6W6SV1laGo4OvhHisuHaE5cthaFTJ5miIiJfwGSkBkVGEwAgMqj8lHNZsVvr33dhHwAgxj/GrfUSVSSEwNnHJyN/1Sq79YlffwVD167yBEVEPoXJSB0E6stnBM05ab110yR5/2b9CwBoFdLKLfURXS53xQqce+JJu3URkx5F+PjxMkVERL6IyYgjLGbrrZsmyTtXcA4A0Cmcp8DJvYp37cKJEXfZrdO2aonm330HpVYrU1RE5KuYjNSg2Gi2X1Ga59b6M4syAQDxge4Z7ZXInJeHE3cOh/HECbv1id98DUOXLvIERUQ+j8lIDc7nWhuw6jXlDVjzyifJ83dPt94LJRcAgMPAk1tkzJ2LC/M/tFsX+8brCB46VKaIiKixYDJSA6PJAgCIDS4f+l1Y7yMgyuV1F5YVothkbTDbNND13Yip8SrauhUn7x1pty7o5iGInTkTCpVKpqiIqDFhMlIHWtskeVVM4usqJ3JPALBOkBeoDXRfxdRoWIqLcXLkKJT8+6+0TmEwoOWqX6GJcn3CTURkw2TEEbbLNErXH7a0IusYI9H+0VAp+d8pOY8QAplz3saFhQvt1sd/MA+B/fvLFBURNWZMRmqQX2qyX1GSY711w7w0p/JOAQAi/TjBGDmHsFiQOWcOLnz0sd36wIEDEff2HF6SISLZMBmpQUaetQFrsEFj/4DO9ZdNMooyAABxAXEur4t8X1XjhahCQpC4fDm08XyPEZG8mIzUoMxsbbAaE6x3e93nC62zA0f7u2dME/JNposXcWzoUJgzs6R16pgYJHw4H/o2bWSMjIjoEiYjjigtcFtVmcXWMUaYjFB9CCGQOXt2pUsyHC+EiDwRkxFH5FlHRIU+xOVVnS+wnhlhmxFyVNGOnTh5991268JGjUTks89C4YYJHomIHMVkxBGW8gatwa69xl5iKpHOjLQIbuHSush3mC5cwPFbb4MpPV1aZ+2quwqaKCa1ROS5lHIH4MmKLh8O3k2yS7Kl5aZBHPCMape/di2O9Optl4jEvfMO2u3cwUSEiDwez4xU42KhESaLdZSzMH/3Tgx2puAMACBQw8HOqHbpM2fi4qefSfdD770XUc9N4SUZIvIaTEaqUVJmPSuiUAAhfu5NRnJLcwEAUf4cBZOqZ87NxeGka+zWJS5bCkMnzvJMRN6Fl2lqoVFVOES2uWlczNatN0gb5Jb6yPtkzf/QLhFRhYai7fZtTESIyCvxzEhdWSxA7mnrskrn0qouFFtn643y45kRsifKynCkdx+Yc3OldU3GjUPk5MdljIqIqGGYjNSVsAAm64isaNLSpVXZetKEGcJcWg95l6IdO3Dy7nvs1rVcs4YjqBKR1+NlmmrUOEGvixsG5hvzAQAx/jEurYe8R9b8D+0SkaCbbkL7gweYiBCRT+CZkWqcyCoEAOjV7s/X0gqtM/b6afzcXjd5nuO33oaS/ful+wkLPkTAddfJGBERkXMxGalGqcnamyY2xOD2urNLreOMxPq7fnZg8lzmgkIc7tbNbl2bLZuhCg6WKSIiItfgZZpaaG1nRgouDSYFleu6+gohkFlkbTPCoeAbr7K0NLtERN+xI9od2M9EhIh8EpORuiq0JgjQhwBaf9dVU1YIs7CelWEy0jiVpacjtV9/6X74xIlo/u1yDmJGRD6Ll2kc5eJ2HGcLzlqrUWoQrON/wY2NKCtDat9+0v2Ixx9H+IPj5AuIiMgNeGbEwxjNRgBAiC5E3kBIFqkDU6TliMceYyJCRI0Ck5FqFBvdM9rq5WxnRgxq9zecJfkIIXBixF0wnbeOvuvfpw/CH3pQ5qiIiNyDyUg1zucWAwAMGpV1hbHALfXmlOYAAKL9o91SH3mG0w89hOJduwAAyoAAJCz4UN6AiIjciMlINYxm65kRqWtvrvWMBfxcOypqRlEGACBQyxl7G4sLiz5B4cY/AACq4GC02foPG6sSUaPCZKQWGlX5j0J5DxcEunZU1CJTEQCOvtpY5Hz3PTLefFO63/p/fzARIaJGh8mIh7GNvso2I77PXFCI8889J91vuWY1FFrXjWFDROSpmIx4mJLyyfg4Y6/vO3rDIGm5+Y8/QhsfL2M0RETyYTLiYWyT5Bk0PDPiy8499zzMmVkAgKDBN0Dfto3MERERyYfJSF2VFbulmsxi60ivwVoOeOarcpYvR+5330n3Y2fPljEaIiL5MRmpq9wz1luta0dgNVlMAIAof16m8UXmnBycf+FF6X7bPbvZYJWIGj0mI9W4UGC0X1E+MipCmrqsTpPFJJ0ZUSr40viiY7feKi03//EHKNlglYiIyUh1MvNLAQBh/jr7BxQql9VZUGFgtRbBLVxWD8kja+FCmM5ZR1gNvGEQ9G3byhwREZFnYDJSi8hAXe0bOUmJuURa5pkR31J69CgyZ8+R7sfNmVPD1kREjQt/8TzIqbxTAIBgXTCTER9z8t6R0nLLNWvYToSIqAL+4tWVxezyKtKL0gEAkX6RLq+L3Ofip5/CfPEiACBs9Gho4+NkjoiIyLMwGamr3NPWW7XrLtvYJsmLMES4rA5yLyEE0me+Lt2PfPopGaMhIvJMTEbqylhovQ123SiZ5wrOAQDC9K6djI/cJ33mTGm56Wef8vIMEVEVmIw4Sq13WdG2SfIi/HhmxBeUpWcg+7MlAAB1VBT8e/SQOSIiIs/EZMQDBWoC5Q6BnOD40KHSctNPPpExEiIiz8ZkpBp5JWVur7OwrNDtdZJr5CxfDnNODgAgZPhw6Fo0lzcgIiIPVq9k5P3330diYiL0ej2SkpLwzz//1Lj93Llz0bZtWxgMBiQkJODxxx9HSUlJjfvILSPPOuhZgF7ttjozi6yjrxrUnCTPm4myMrsh32NmTJcvGCIiL+BwMvLNN99g8uTJmDZtGnbs2IEuXbogJSUFGRkZVW7/5Zdf4tlnn8W0adNw4MABfPzxx/jmm2/w3HPPNTh4VzJbBAAgLsR9iUGZxXo2JiYgxm11kvOdeeRRaTl+3jwZIyEi8g4OJyNz5szB2LFjMXr0aHTo0AHz58+Hn58fFi1aVOX2f//9N3r16oW7774biYmJGDhwIO66665az6Z4ikt9H4TL6yoqszZgVSvcdzaGnMt04QIKNmwAAGibNUPg9f3lDYiIyAs4lIwYjUZs374dycnJlwpQKpGcnIxNmzZVuc+1116L7du3S8nHsWPHsHLlSgwePLjaekpLS5GXl2f3J7s865wiULpubhrboGcB2gCX1UGudf6556XlxG+/lTESIiLv4dC/4FlZWTCbzYiKsp/ePioqCgcPHqxyn7vvvhtZWVno3bs3hBAwmUx46KGHarxMM3PmTMyYMcOR0FyvONt6G5zgsipsl2li/WNdVge5jik7GwUbNwIADFdeCVWAv8wRERF5B5f3ptmwYQNee+01zJs3Dzt27MB3332HFStW4OWXX652nylTpiA3N1f6O336tKvDrDut635gSs2lLiubXO/0gw9Jy/Hz3pcxEiIi7+LQmZHw8HCoVCqkp6fbrU9PT0d0dHSV+7z44ou499578cADDwAAOnXqhMLCQowbNw7PP/88lMrK+ZBOp4NO577Zcj1BWmGatBysC5YxEqoPc0EBSvbsAQD4970O6tBQmSMiIvIeDp0Z0Wq1uPrqq7F27VppncViwdq1a9GzZ88q9ykqKqqUcKhU1nYXQri+Uai3sJ0V0av08NP4yRwNOersoxV60MydK18gREReyOFuG5MnT8aoUaPQrVs39OjRA3PnzkVhYSFGjx4NABg5ciTi4uIws3xOjiFDhmDOnDm48sorkZSUhNTUVLz44osYMmSIlJTQpWRErWRPGm9jKSlB4d/WBtz6zp2hNHCcGCIiRzj8yzd8+HBkZmZi6tSpSEtLQ9euXbFq1SqpUeupU6fszoS88MILUCgUeOGFF3D27FlERERgyJAhePXVV533LFwgq8C97TfO5J8BAPhr2OjR26S/+pq03HTBhzJGQkTkner1b/jEiRMxceLEKh/bUD7GglSBWo1p06Zh2rRp9alKFkIIXCg0AgCaNim/ZFKa79I6LcICAIjx54Bn3kSYTMhZtgwAoO/QAaqQEHkDIiLyQpybphZ+WjVQdBEwFVtXuKhrb4nZOjy+UsGXxJukv/6GtBzzmmef7SMi8lT85asLi/nSsj7IJVXYetPoVI2rF5E3sxiNyP78cwCANjER+nbtZI6IiMg7MRnxEEaz9bJQlH9ULVuSp8iocFYk7u05MkZCROTdmIx4CNvoqzwz4h2EEMj+8ksAgLZVS+jbt5c5IiIi78VkxEPYLtNoVVqZI6G6yKowG2/01KkyRkJE5P2YjHiIEpO1AWuUHy/TeIOsd98DACiDguDfo4fM0RAReTcmIx6iyFQEADCoOWCWp7v4xRfScvz//Z+MkRAR+QYmI3VRmufyKtILrfP96NV6l9dFDZM529pYVWEwwP+aJJmjISLyfkxG6iK3fNbgwFiXVWFrwBoXEOeyOqjhSg4cgKXIehYr+vnnZI6GiMg3MBmpwokLRdKyn7bC/DkG183EmlOaAwBQKThfjyfLLG8rAgDBt90mYyRERL6DyUgVio3WQc5C/TTQa1yfHJSaS5FntF4KivaPdnl9VD9CCBSsWwcACBgwAAqFQuaIiIh8A5ORGqhV7jk8QghpOVAb6JY6yXE5X38tLUc+MVnGSIiIfAuTEaI6ynhrNgBAFRoKXYsWMkdDROQ7mIx4gHMF5wAACiigVXLQM09U8NdfsBQWAgDCJ0yQORoiIt/CZMQDFJZZf+SaGJpAo9LIHA1V5fxzz0vLoffcLWMkRES+h8mIB8guzQbAeWk8VfHefTClW8eBaTJuHBuuEhE5GZORujCbXFp8ZlEmAOuZEfI86S+/LC1HPP6YfIEQEfkoJiN1kXvKeqtx7eioYfowl5ZPjrOUlqJ4924AQPDQoTwrQkTkAkxG6qKs2HobHO+S4nONuS4plxruwsKPpOXo6dNkjISIyHcxGamCyWKp+gEXtemwXaYJ1HCMEU9z4eOPAQCapk2hNHASQyIiV2AyUoXTF61nQgxuGH0VACzCmvxw9FXPUrBxI0Sx9b0Q/tBDMkdDROS7mIxUwWi2DgcfG+KeGXTPF54HAKiUnJfGk6S/OUtaDr5lmHyBEBH5OCYjNdC4aTj4grICAECEIcIt9VHtTBcuwHj0KAAgbNQoNlwlInIhJiMewGSxdh0O0gXJHAnZnHvuOWk5gvPQEBG5FJMRD2C7TKNRcvRVT2AxGlG48Q8AgN8110Cp5RD9RESuxGSkLirMqusKxSZrI8n4ANd0HSbHZL0/T1qOfeMNGSMhImocmIzURe5p662L543hmRHPcOHDDwEAutatoImKlDkaIiLfx2SkLkrzrbdBcU4vWgiB3FIOeuYpcr79VloOf+QRGSMhImo8mIw4Quvn9CKzirOk5diAWKeXT45Jm/ESAECh0SBo4ECZoyEiahyYjMhMwNoeRa1QQ692z7gmVLW8Vb9BGI0AgKipL8ocDRFR48FkpAqlZdUMB08+Lf3NS41VQ++4Q8ZIiIgaFyYjVTiXWwIA0KldPyKqbSh4kldZWhpM56xdrMMfmShzNEREjQuTkSqUllmHg48Jdv1lk1N5pwCAl2hkdvaJJ6Xl8AcflDESIqLGh8lIDQxa158ZMVqsbRQ4SZ58zLm5KN6+HQDg3/c6KNRqmSMiImpcmIzIzNatl2OMyCft1Vel5bi33pIxEiKixonJiMwyizIBcF4auQghkPfTzwAAv+7doQoMlDkiIqLGh8lIXRTnuKxoC6wNWKP8olxWB1Xv4qefSsuRzzwjYyRERI0Xk5G6yD9nvQ1wfsKQb8x3eplUdxmvW7vzqiMjYbiio8zREBE1TkxG6sI2UZ5/hNOLtl2mCdAEOL1sqlnuzz9LyxGTJskYCRFR48ZkRGZmUd6N2D9G5kgan4w3Z1kXlEqE3HarvMEQETViTEY8hEKhkDuERqXkwAGYMq1npSKfmCxzNEREjRuTEZlxxl552CbEA4Cw+++XMRIiImIyIrPM4vKuvVp27XUXS0kJinftAgAE3TyEZ6WIiGTGZERmtrlpovzZtdddzj5+6bJM1LPPyhgJEREBTEaqlFlQ6ra62LXXvYQQKFi/HgCg79wZ6rAwmSMiIiImI1W4UGCdL6aJv9blddku0zTRN3F5XQRc+HCBtBz7xusyRkJERDZMRmoQHqBzeR1mi7VrbxMDkxFXE0Igc+5cAIAqJAS65s3lDYiIiAAwGambEvZ48QXpr82UlmNnzZIxEiIiqojJSF3klQ8HH+jcgclKzaUQEE4tk6omLBZkL1kCAFDHxCCgT2+ZIyIiIhsmI3VR3uMFhlCnFnsq7xQAQAEF24y4WObbc6XluDmz5QuEiIgqYTLiAUL1oRzrwsUuLFwIAFBHR8PvyitljoaIiCpiMkI+7+Jnn0nLsa+zBw0RkadhMiIjjjHiHumz3gIAKIOD4X9NkszREBHR5ZiMyOh84XkAQJieA2+5St6vvwJlZQCAqCkcbZWIyBMxGfEAHGPEddJee01aDhk2TL5AiIioWkxGyGeVHjsOc2YWACDi8cdljoaIiKrDZERGRaYiuUPwaWkvvSQtNxk3VsZIiIioJkxGqmC2uGcgsoyiDACAQW1wS32NiSgrQ9HmzQCAgH792HWaiMiDMRmpwrmcYgCARu3aw1NmtjasjPaLdmk9jVHm/70rLce8+oqMkRARUW2YjFSh0GgCAMSHlp+xsJS5tD6NSuPS8huj7C+/BABo4uOhbsIGwkREnozJSA10auWleWkAQBfo1PIzizMBWIeDJ+cxnjkDS2EhACDyickyR0NERLVhMlIbo/VHDdpAQB/k1KKzS7IBAOGGcKeW29idf/FFaTlw0CAZIyEiorpgMlJXSpXLig7Rhbis7MZGmEwo2mRtuOrfpw8brhIReYF6JSPvv/8+EhMTodfrkZSUhH/++afG7XNycjBhwgTExMRAp9OhTZs2WLlyZb0C9iVGi1HuEHxO+htvSssxr7DhKhGRN1A7usM333yDyZMnY/78+UhKSsLcuXORkpKCQ4cOITIystL2RqMR//nPfxAZGYnly5cjLi4OJ0+eREhIiDPi92rphekAAJ1KJ3MkviN7yRIAgLZFC2iiKr8fiYjI8zicjMyZMwdjx47F6NGjAQDz58/HihUrsGjRIjz7bOW5PxYtWoSLFy/i77//hkZj7TWSmJjYsKh9RIm5BAAQFxgncyS+oeDPv6Tl6Kkv1rAlERF5Eocu0xiNRmzfvh3JycmXClAqkZycjE2bNlW5z08//YSePXtiwoQJiIqKwhVXXIHXXnsNZrO52npKS0uRl5dn9+fL1EqHc0KqQubcudKy/zXXyBcIERE5xKFkJCsrC2azGVFRUXbro6KikJaWVuU+x44dw/Lly2E2m7Fy5Uq8+OKLmD17Nl6p4Xr+zJkzERwcLP0lJCQ4EqZXEEIgqyhL7jB8hjCZULJ3LwAg+LZbZY6GiIgc4fLeNBaLBZGRkViwYAGuvvpqDB8+HM8//zzmz59f7T5TpkxBbm6u9Hf69GlXh+l2+WX5MAnr4GrNg5rLHI33y1qwQFqOevppGSMhIiJHOXR9IDw8HCqVCunp6Xbr09PTER1d9ZDmMTEx0Gg0UKkudY1t37490tLSYDQaodVqK+2j0+mg0zWeRp0cgbXhLnxgTW7VMTFQBQfLHA0RETnCoTMjWq0WV199NdauXSuts1gsWLt2LXr27FnlPr169UJqaiosFou07vDhw4iJiakyEWksisuK5Q7BZ5SmpkKUWYfsj3rqSZmjISIiRzl8mWby5MlYuHAhPv30Uxw4cADjx49HYWGh1Ltm5MiRmDJlirT9+PHjcfHiRUyaNAmHDx/GihUr8Nprr2HChAnOexaulHPKeqtybuJ0Ot966SlIGwSNkmdGGqLiJZqgwYNljISIiOrD4W4cw4cPR2ZmJqZOnYq0tDR07doVq1atkhq1njp1CkrlpRwnISEBv/32Gx5//HF07twZcXFxmDRpEp555hnnPQsnEkIgq6DCYGSl5T15guNdUl+YPswl5TYWQgjk/fQzAMC/Vy+ZoyEiovqoV5/SiRMnYuLEiVU+tmHDhkrrevbsic2bN9enKrfLKSqD2SIAAC3CA4Ds8gc0fvIFRdXKX7VKWo6Y9KiMkRARUX1xbpoaaNWuOzxZJdZuvZw7pWEufLwIAKD094ehc2eZoyEiovpgMiIT24y9EYYImSPxXsJsvjS2yLBh8gZDRET1xmREZpyxt/6yv/5aWg5/eLyMkRARUUMwGZFJUVmR3CF4vfw1awAA6qgoqJs0kTkaIiKqLyYjMkkvsg4cp1frZY7EOwkhULTJ2ig6aFCKzNEQEVFDMBmRSZnFOkhXtH/VI9dSzYq3bZOWw0aNkjESIiJqKCYjtSnOrn2bBuCAZ/Vz8bPPAAAKjQaa2FiZoyEiooZgMlKbvPPW24BIpxZrtpidWl5jU/j3JgCAf+/eMkdCREQNxWSkVtYB0OAf7tRSzxdakxy1sl7jzjVqZekZsBQWAuAlGiIiX8BkRCbFJutEeVF+UTJH4n1yv/tWWvZL6iFjJERE5AxMRmRiEdZZjP01/jJH4n1yV6wAABi6dOEItkREPoDJiEzOFZwDwMs0jhIWC4ypRwFwYjwiIl/BZOQy2UXWGXtd/Q93kck66FnTwKaurcjH5P/2m7QcNmqkjJEQEZGzMBm5THpeKQAgIkAHldL1lwB4ZsQxeStXAgBUISFQBQfLHA0RETkDk5FqBBtcO/6H0Wx0afm+qmDDRgBAQP/+MkdCRETOwmREBrmluTAL6zgjbMBad8aTJyHKrCPXBt8yTN5giIjIaZiMyCDPmAcAUECBUH2ozNF4j4uffyEt+/dgl14iIl/BZKQ2QrisaE6S5xjbLL2Gq66SORIiInImJiO1yT1tvVVpnVem6/IbnyWMRpjOW0etDb75ZpmjISIiZ2IyUpvSAuttUJzTijxTcAYAoFPpnFamr7OdFQHYXoSIyNcwGakrrZ/TiuJQ8I6zJSPqqCgodUziiIh8CZMRGbHNSN2VHD4MAPDr3l3mSIiIyNmYjJDHsxsCvjeHgCci8jVMRsjjlew/IC0H9usnXyBEROQSTEZkkG/MlzsEr1Kwbh0AQKHXQxUSIm8wRETkdExGZJBZnAmAo6/WVeGmTQAAffv2MkdCRESuwGREBiaLCQAQGxArcyTeoXjnTgCAXxJHXSUi8kVMRi6TXeT6CexsyYgCrp8V2NuVlQ90BgDBN94oYyREROQqTEYuk55XAgAI83fiiKuXSStMAwBolK6dGdgX5Je3FwEAbatWMkZCRESuwmSkGpFBrhsDxDboWaRfpMvq8BWlBw8BAHRt20Kh4JkkIiJfxGSkNsUXXVa0n8Z5o7r6qpID1m69+g4dZI6EiIhchclIbfLOWW8DY+SNoxESQqBk714ATEaIiHwZk5G6MoQ5raiLJa472+JLys6elZYDBw6UMRIiInIlJiMyuFByAQDQRN9E5kg8W/7vq6VlTRTb1xAR+SomIzIQQgAAmhiYjNSkaNs2ALxEQ0Tk65iMyIDDwdeN1Hi1UyeZIyEiIldiMuJmZZYyqc1IhCFC5mg8l8VohKl8wLOAfn1ljoaIiFyJyYi7CUDAepkmRB8ibywerHT/fmk5oFcvGSMhIiJXYzJCHqngz78AAEo/Pyi0rhsNl4iI5MdkhDySNFMv24sQEfk8JiO1MRY6tbizBZfGztCpdE4t25eUnT4NANC3by9zJERE5GpMRi5TUGK6dKesBCjKsi4HRjml/EKTNbkJ04cxGamGMJthysgAAAT0vU7maIiIyNWYjFwmrXzWXn+tChDmSw/4hTu1Hq2K7SCqYxsCHgAMnTvLGAkREbkDk5HLmMzWni4xwQaXlG+xWFxSri8p/PtvAIDCYIDS31/maIiIyNWYjFRDrXLNdPVnCs4AYHuRmpQeOQKAZ0WIiBoLJiNuVmKyXgaK8nNOGxRfZDx5CgCga9VK5kiIiMgdmIzIRK/Wyx2Cxyo9ehQAoGvXVuZIiIjIHZiMkEcx5+dDlFjPHvl17SpvMERE5BZMRsij2GbqBQBtixYyRkJERO7CZMTNMoszAQAKuKaBrLcr3rUbAKCOioJCpZI5GiIicgcmI26WXZINAAg3OHfcEl9hPHUSAKBr00bmSIiIyF2YjMgkRBcidwgeqWT3HgCAno1XiYgaDSYjNREcoMydhMWCsnPnAAD6Dh1kjoaIiNyFyUhNsqyDb0GlBdTOGaSsyFTklHJ8ken8eWnZ/9prZYyEiIjciclITSzlk+YFxQJK5zSmzCiyTgBnULtmuHlvVrzb2ngVCgVUwcHyBkNERG7DZKROnNfzpcxSBgCICYhxWpm+ouTAAQCApmmCzJEQEZE7MRlxM7PFOhOwWqGWORLPU7znXwCAnj1piIgaFSYjbna+0NouQq1kMnK50tRUAIC2OQc7IyJqTJiMXCa3uMyl5RebigEAcYFxLq3H2wiLBeYLFwAA/tf2lDkaIiJyJyYjl8nIt86LEqh37ZkLrVLr0vK9jfHYMWlZf8UVMkZCRETuxmTkMmZhvY0Ndk1vl1JzqUvK9XYV56RRBQTIGAkREbkbk5FqKFwwdUxRWREKywoBAIHaQOdX4MWK9+4FABg4Uy8RUaPDZMSNKg54Fu0fLWMknsd47DgAQNusqcyREBGRu9UrGXn//feRmJgIvV6PpKQk/PPPP3Xa7+uvv4ZCocCwYcPqU63P4Iy9lZWUnxnRd2R7ESKixsbhZOSbb77B5MmTMW3aNOzYsQNdunRBSkoKMjIyatzvxIkTePLJJ9GnT596B+t2Zuf2rDHZRnQlO5bCQgijEQBguPJKmaMhIiJ3czgZmTNnDsaOHYvRo0ejQ4cOmD9/Pvz8/LBo0aJq9zGbzbjnnnswY8YMtGjhRWNI5J623mqc05j1VN4pAIC/xt8p5fkK48mT0rK+IyfIIyJqbBxKRoxGI7Zv347k5ORLBSiVSE5OxqZNm6rd76WXXkJkZCTGjBlTp3pKS0uRl5dn9yeLsvI2HsHxTinOJKxnRmIDYp1Snq8o3rMHAKAwGKBQshkTEVFj49A3f1ZWFsxmM6KiouzWR0VFIS0trcp9/vzzT3z88cdYuHBhneuZOXMmgoODpb+EBJnnKlE5d0wQthmxV3LwIABA17y5zJEQEZEcXPpvaH5+Pu69914sXLgQ4eHhdd5vypQpyM3Nlf5Onz7twijdxyIscofgkYypRwEA2lYtZY6EiIjk4NAwo+Hh4VCpVEhPT7dbn56ejujoyl1Vjx49ihMnTmDIkCHSOovF+oOsVqtx6NAhtGxZ+QdIp9NBp9M5EppXOFdwDgDnpblcyeHDADhBHhFRY+XQmRGtVourr74aa9euldZZLBasXbsWPXtWnk+kXbt2+Pfff7Fr1y7p7+abb0b//v2xa9cu+S+/uJltXpoIvwiZI/EcwmSCpbxNkOGqq2SOhoiI5ODwv+iTJ0/GqFGj0K1bN/To0QNz585FYWEhRo8eDQAYOXIk4uLiMHPmTOj1elxx2TwjISEhAFBpfWMSoOFw5zbGU6ekZX27djJGQkREcnE4GRk+fDgyMzMxdepUpKWloWvXrli1apXUqPXUqVNQenOPCCFcVrRZmF1WtrcqPXQIgLUnjdLPT+ZoiIhIDvVqvDBx4kRMnDixysc2bNhQ476LFy+uT5VuczbHOmuvUun8Hi/nC84DAFQKldPL9lYl5cmItlkzmSMhIiK5ePEpDNfIL7GOutoszPn/pdvmpon0i3R62d7KNieNJiZG5kiIiEguTEaqoVUrARd1xeWMvZfYxhjRNuUEeUREjRWTkZrknrHeqjROKS67JNsp5fgKIQTKyhuwGrp2kTkaIiKSC5ORmpQWWG+dNBx8VnEWACBMH+aU8ryd6fx5adnQtat8gRARkayYjNSFxrntR5oYmji1PG9VtHWrtKyuYtA8IiJqHJiMkGxK9h8AYB0GXqHgfD1ERI0VkxE3yinNkTsEj2I8eRIAoGvBOWmIiBozJiNuZGszEu3HSxIAUHb2LABAy9l6iYgaNSYjbiTKR3cN0gXJHIlnsA0Fr2/LCfKIiBozJiMkC3NBAURpKQBA37GjzNEQEZGcmIy4iRACJmGSOwyPUXr4iLSsaWSzNxMRkT0mI25yKv/S7LShulAZI/EMxTu2AwCUQUFQePPEikRE1GD8FahJ8UWnFWW2WGfsDdYFQ+OkEV29ma1br651a5kjISIiuTEZuUypqcJ8NHnlI4QGNrz3i61br5KHHABQmpoKANB37CBzJEREJDf+MlZwLqdYWg7z1156wNDw4dszijIAcPRVGykZacOeNEREjR2TkQqM5WdF/LQq+GnVLqkjVM/2IhajEbBYjzXnpCEiIiYjVVC5YGjyMkuZ08v0ViV79kjL2qZNZYyEiIg8AZMRN0krTAMAaJRsvFr8714AgCo4GAqttpatiYjI1zEZcZNik7U9SpRflMyRyK/04EEAgLYl56QhIiImI25TaraONuqn8ZM5EvmVHj0KANC1aiVzJERE5AmYjLhJelE6AECr4mUJaU6a9u1kjoSIiDwBkxE3KTVZz4w09ss0lpISWPLyAACGK6+UORoiIvIETEbcTK/Syx2CrMrOnJGWdS1ayBgJERF5CiYjNSnKclpRthFYGztbTxoolexJQ0REAJiM1KzA2s4DIQ2fVTar2JrYhOkbPpqrNys9aJ2TRtuiucyREBGRp2AyUhe64AYXISAAAOGG8AaX5c2MJ62NV3Ut2K2XiIismIyQW5kuXADAbr1ERHQJkxE3MZqNcofgEUoPHQIA6Du0lzkSIiLyFExGKjhbPmuvRu3cw1JmLpPajDTmQc+E2QxhtCZlmthYmaMhIiJPwWSkgvwS62R2UUHO7X5rtBilNiPxgfFOLdublKYelZY1TZvJGAkREXkSJiNVCNCp5A7BJ5X8a52tV6HRQBXgL3M0RETkKZiMuMG5gnMAAJVCBZWi8SY6xpMnAQBaNl4lIqIKmIy4QUFZAQCgib4J1Eq1zNHIp3jPvwAAfZvWMkdCRESehMlIdcwmoCTXuqxQOKVIvbqRDwV//jwAQM3Gq0REVAGTkeoUpF1aDk1sUFFphdayVMrGe4lGCIGy8tl6/bp1kzkaIiLyJExGaqPSAQ1MIvKN+QCASEOkMyLySpbCQmlZ27SpjJEQEZGnYTLiBkJYu/UGagNljkQ+pQcPSsuamBgZIyEiIk/DZMQNzhda20ooFY33cBft3AkAUIWHQ6FuvI14iYiossb76+hGtt40EX4RMkcin7JTpwHwEg0REVXGZMSNgrRBcocgm5J9+wAA+g4dZI6EiIg8DZMRNzBZTHKHIDvj6fIzIwmNdzh8IiKqGpORCizCNeXauvZqlBrXVODhLKWlsORbexT59eghczRERORpmIxUcDbbOmuvWuncw1JsspYb6dc4u/Yajx2TlnUtW8oYCREReSImIxUUlFovp0QG6QBjYS1bO85f0zgnhyvevRsAoNBqodBqZY6GiIg8DZORKgTq1UC2dVI3BDT8bMbFkosNLsObFe+2ztara805aYiIqDImI9Uqb0DiH97gkrKKswAA0f7RDS7LG9ku0+jatZU5EiIi8kRMRtyosXbtNZ60nmXSt2kjcyREROSJmIyQy5lzcgAA+k6d5A2EiIg8EpMRNygsc35jWG9hG18EYE8aIiKqGpMRF8sqzoIob38Sqg+VORr3K9q2XVpWBQfLGAkREXkqJiMuZjQbAQBqhbpRztpbmnoEAKBry8arRERUNSYjbqJSquQOQRbG1KMAAF3LFjJHQkREnorJiIuVmkvlDkFWtp40mgTO1ktERFVjMlKBRVSYnKYwq3xB0aAyz+SfAQAEaAIaVI63Mp44AQDQteGAZ0REVDUmIxWczakwN01BunVlUGyDyrQICwAgxj+mQeV4o7L0dGnZ0LmzjJEQEZEnYzJSQVGpGQAQHay/tNIQ0qAyTcI6341C0bAzLN6o6J9/pGVNfLyMkRARkSdjMlKFAJ3aaWWdLzgPAFArnVemtyjeuQsAoG3RolEmY0REVDdMRlys2GS99BPp1/AJ97xNafmcNPp27WSOhIiIPBmTETdpjA1YLzVe5Zw0RERUPSYjLmYbfbWxEULAlJYGANB3aC9zNERE5MmYjLhYRlEGgMbXgLWswpw07ElDREQ1YTJSHSeNM5JXmgcACDeENzAg71K8519pWRUSIl8gRETk8ZiMVEcaZyTOKcWF6EKcUo63KD18GACgbcWZeomIqGb1Skbef/99JCYmQq/XIykpCf9UGE/icgsXLkSfPn0QGhqK0NBQJCcn17i9x2ngOCONldR4tWUreQMhIiKP53Ay8s0332Dy5MmYNm0aduzYgS5duiAlJQUZGRlVbr9hwwbcddddWL9+PTZt2oSEhAQMHDgQZ8+ebXDw3uBi6UW5Q5CFLRnRNk+UNQ4iIvJ8Dicjc+bMwdixYzF69Gh06NAB8+fPh5+fHxYtWlTl9l988QUefvhhdO3aFe3atcNHH30Ei8WCtWvXNjh4ZysqMzu9zAvFFwAAobpQp5ftqYQQly7TcORVIiKqhUPJiNFoxPbt25GcnHypAKUSycnJ2LRpU53KKCoqQllZGcLCwqrdprS0FHl5eXZ/7pCWax2gzKBROa1MUT75XoRfhNPK9HSW3Fxp2e+anjJGQkRE3sChZCQrKwtmsxlRUVF266OiopBWPqZEbZ555hnExsbaJTSXmzlzJoKDg6W/hIQER8KsN6PJOqldfKjBaWXmlOY4rSxvUbh1q7SsiW18EwQSEZFj3Nqb5vXXX8fXX3+N77//Hnq9vtrtpkyZgtzcXOnvdIUxK9xBpVQAxoIGl2O2mHGhxHqZJto/usHleYuSvfsAAJq4OCiU7LBFREQ1c2j2tvDwcKhUKqRXmBoeANLT0xEdXfOP7VtvvYXXX38da9asQedaBsHS6XTQ6XSOhOZ8eeUNbPXBTikuUBPolHK8QcnevQAAXSv2pCEioto59G+rVqvF1Vdfbdf41NYYtWfP6tsGvPnmm3j55ZexatUqdOvWrf7RupOlvDFrUGy9iyg0FUrLjWkEVmmCvI4dZY6EiIi8gcPz2k+ePBmjRo1Ct27d0KNHD8ydOxeFhYUYPXo0AGDkyJGIi4vDzJkzAQBvvPEGpk6dii+//BKJiYlS25KAgAAEBHjD5HH1TyLOFZwDAGiVWgTrnHOGxdOJsjKYzp8HAOg7XSFzNERE5A0cTkaGDx+OzMxMTJ06FWlpaejatStWrVolNWo9deoUlBXaCXzwwQcwGo24/fbb7cqZNm0apk+f3rDoPZzJYgLQuEZfLT16VFr2r+FsGRERkY3DyQgATJw4ERMnTqzysQ0bNtjdP1E++FVjdCb/DABAp5a5/YsbFe/ZAwBQaDRQ1tBImYiIyIZdHVzIaDECAGL8G0/31uIdOwEAWjZeJSKiOmIyUh1zWYOLyC7JBgBoVJoGl+UtSg4eBADoO7SXORIiIvIWTEbKCSGQnlcKAFBAALnlY5to/OpdZlZxFgAgWNs4Gq8Cl2brNXTpInMkRETkLZiMlCs1WVBcPjdNi/AAwFRifSCseb3LtA0FH+UXVcuWvsGckwNYrKPY+l11lbzBEBGR12AyUgWNuuJhqX/X3jyje+bU8RRFO3ZIy9qWLWWMhIiIvAmTERfKLM4EAPhr/GWOxD2Ktm0HAGhiYxvVIG9ERNQwTEZcyFw+imtsQP1HcfUmxbt2AQB0bdrIGwgREXkVJiMulF5kncNHqWgch9nWeFXXvp3MkRARkTdpHL+SMrG1GWkM44xYiothKbDOdBzYr5+8wRARkVdhMlKVsksT3MEJbR8aQ5uRio1X9R06yBgJERF5GyYjVVBmn7AuqPWAIbTe5di69jYGxTt3AQBUYWFQaBrPIG9ERNRwTEbK5RZfGnFVaTsbog+u95kRs8WMCyUXAKBR9CwpPZoKANC1ZeNVIiJyDJORcudzrYOcBerV0GsaflgqjjHSMtj3x9wo2bcfAKBv01bmSIiIyNswGblMsMH5lxh8vTeNEAJlp04BAPSdOskcDREReRvf/pWUUZGpSO4Q3MaWiACAf69rZYyEiIi8EZMRFzmTfwYAEKYP8/k2I4V//y0tq0Pr3+CXiIgaJyYjLmKymABYkxFfV7znXwCAri3bixARkeOYjFSlrKTBRZwrPAcA0Kl0DS7L0xX/uwcAYOjM9iJEROQ4JiNVyS1vA6ELrHcRJSZrQhPpF+mMiDyWEALG1KMAAEPXrvIGQ0REXonJSFXM1kssCE6odxEFRuvQ6Hq13hkReayS3bul5YDrrpMxEiIi8lZMRsplFxorr2xAw9OM4gwAgJ/ar95leIP8jRsBAAqtFuqICJmjISIib8RkpFx6nvWySkSgc9p4mC1mAEBsQKxTyvNURVv+AQD4de8ucyREROStmIxcpom/1inlZJdmA/D9Ac+KyyfIM3TpLHMkRETkrXz7l7K+jPkNLiKrKAsAEKILaXBZnqosLU1aDrrhBhkjISIib8ZkpCq5Z623+pB6F5FTmgPAt3vT5K1aJS1rW7WSMRIiIvJmTEaqUj5gGYLq397DNmNvhMF3G3UWrFkLANC1bu3zo8wSEZHrMBmpSQN+YG0NWEP1vjs8esl+60y9/n36yBwJERF5MyYjLmC2mGG0VNFV2IeYLl6Epcg6GWDQoBSZoyEiIm/GZKRcQanp0h2LqfoN6+B0/mlp2Vcv0+R+/4O0rO/YUb5AiIjI6zEZKWcbZ8RPqwZyy5OJeo6eWmgqBAAEagOhUqqcEp+nyf/9dwCArl07KFS++RyJiMg9mIyUKzMLAEBsiAEoK7auDI6vV1ln8629cUJ1vttepLh8GHj/XtfKHAkREXk7JiOXUSsrNFqt54y7xSZrMhNuCHdGSB6ncPMWaTl0+HAZIyEiIl/AZMQFMoqs89IY1AaZI3GNi0uWWBdUKmibNpU3GCIi8npMRqpSnNOg3fPLR3CN9o92QjCep2DDBgBAUAp70RARUcMxGalK3jnrbWBUvXZPK7QOkx6oDXRWRB6jeO8+wGwdQyVs5L0yR0NERL6AyUg5s0VUuFe+7Fe/Nh95xjwAQJRf/ZIZT5b91ZfSsqFrV/kCISIin8FkpNzZHGujU7Wq4cOapxelAwCCdEENLsvT5K9eAwAISB4gcyREROQrmIyUKzJaBzqLDtIDQtSydc1KTNYxS+IC4hoclycp3rsPljzrWZ/gwYNljoaIiHwFk5HLBGgsQIG1zQdUWof3twgL0oqs++vq2TXYU2V/eekSTRCTESIichImI5dRlxVeutOklcP7F5uKYSofTr55cHNnheURcr/7DgAQcP31MkdCRES+hMlITeoxa+/h7MMAALVC7VPjjOSvXy8th40cKWMkRETka5iMlCsuszilHNskeYnBiVAqfOfwXlj4kXVBqYT/NUnyBkNERD7Fd34tGyg919roNMSUZV2hVANw/MxIdkk2ACDK33e69QqLBcU7dgAAQkdw+HciInIuJiPlSk3Wgbzi9dakBEGxgNLxw2MbCj5YG+y02OSW+c7/SctNHnxQxkiIiMgXMRm5jNRMRONXr/1tA57F+Mc4KSJ5CSFw4cMPAQCa+HhoonznjA8REXkGJiNOdjLvJAAgQBsgcyTOkfXuu9Jy9LSpMkZCRES+islIufwSk1PKOZV3CgDQMrilU8qTW9a8DwAAqiZNENCnj8zREBGRL2IyAuBioRGm8rlpQlBQ73KEELhQcgEA0Cy4mVNik1POt99Ky7Gvz5QxEiIi8mVMRgCUma3dehUKwL8007oyKNbhcmxz0gBAfEC8U2KTU9qMlwAACo2GZ0WIiMhlmIxUoKo4yJkh1OH9bZdoAjWB0NZjKHlPkrdyJYTRCACIeuEFmaMhIiJfxmTkcsb6X6axDXgWE+DdPWmE2Yyzk5+Q7ocOv1PGaIiIyNcxGQGQU1QGAFAqFEDuGetKXZDD5Ry8eBCA98/We2L4CGk55tVXZYyEiIgaAyYjAM7nFgMAIgJ1QGm+dWWw4wnF8dzjAIBWIY5PsOcpLn72GUr27gUA6Nq3R8htt8ocERER+TomIxWE+GmAvLPWO/U4M3Iy3zrGSJvQNs4My23KMjKQ/tqlXjPNv10uYzRERNRYMBkBUGqqMEme2dpoEyFNHS7HNhS8N54ZERYLUq/rK91P/HY5FPUYDp+IiMhR/LUBcD7HeplGr1EBFtvgZ45NkpdnzINFWJOaCL8IZ4bncmVnz+Jgh47S/SbjxsHQsWMNexARETkPkxFcOjMSE6wHcqzdc6HWOVTG5nObAQB+aj8E67xnkrzCf/5B6oBk6b7/tdcicvLjMkZERESNDZMRACVl1mREp1YBxiLrytBEh8o4mnMUANChSQdnhuZS2d8sxamRo6T7kU89iaaLPpYxIiIiaozUcgfgCWy9aYKUJYC51LpSY3CojCM5RwAALYJbODU2VzBlZuLY0GEwX7worUv4+CME9OolY1RERNRYMRkBkJlvTUDa6LOtKxRKIDC6zvtbhAXrT60HALQObe30+JxFCIG0adORs3Sp3fqWq3+HNiFBpqiIiKix42UaABnlyUicSLOuCHRsBNU9mXtgEtaGr8NaDXNmaE4hhMCFTxbjYPsOdolI6Mh70e7AfiYiREQkK54ZAXA629pOJMFyzrqiiWNdc1efXA3AelZEr9Y7NbaGKEtPx4UFC5H9xRd263Ud2iNxyRIo/f1lioyIiOiSep0Zef/995GYmAi9Xo+kpCT8888/NW6/bNkytGvXDnq9Hp06dcLKlSvrFayr2IaDj87dZV3hYOPVX4//CgDoF9/PeUHVk7mgEJnz5uFAu/ZI7dvPLhFRR0ej+fffocV33zERISIij+FwMvLNN99g8uTJmDZtGnbs2IEuXbogJSUFGRkZVW7/999/46677sKYMWOwc+dODBs2DMOGDcPe8iHH5ZaaYR3+XQMTDMd+s65slVzDHvb+Pvs3MoszAQC3tL7F6fHVRpSVoXjfPqTPmoUjfa7D4W7dkPV/79pt49/3OrRYuRKtN6yHvn17t8dIRERUE4UQQjiyQ1JSErp374733nsPAGCxWJCQkIBHHnkEzz77bKXthw8fjsLCQvzyyy/SumuuuQZdu3bF/Pnz61RnXl4egoODkZubi6Agx4dpr8mbqw5i3oajmBC4EU+VfQgoNcDzaYCq9itYuzN3478r/wvA2ovmx2E/OjW2y1mKilC4aRNKDh5EwfoN1jlkVCrAbK60rV/37ggbcz8C+/VzaUxERETVqevvt0NtRoxGI7Zv344pU6ZI65RKJZKTk7Fp06Yq99m0aRMmT55sty4lJQU//PCDI1W7xOkLhdiycSWGq87hqbKF1pVX/rfKRCQ1OxXH844jtzQXx3OP4/vU75FvzJcef7nXyw7VXfjPPzBfzIYwmSBMZYDJZF0uM8F4/BiUAYEwZWbClJEBU0YGys6fh6WgoHJB5YmI0s8P/r16IejGwQj8z3+gUKkcioeIiEguDiUjWVlZMJvNiIqKslsfFRWFgwcPVrlPWlpaldunpaVVW09paSlKS0ul+7m5uQCsGZazmMwWDHhjLdYq30CwpRh5tura3A5UUc+SnUuw7PCySusjDBH48D8fIlYX61B8J15/HaX/1u9SlTo+Hv5JSdB37Ai/q66EJi7Obh6Z/MLCepVLRETkTLbfxdouwnhkb5qZM2dixowZldYnuKALaqXp8F7v49D+B3AA7eHmdhipR4AN691bJxERUT3l5+cjOLj6qVIcSkbCw8OhUqmQnp5utz49PR3R0VUPEhYdHe3Q9gAwZcoUu0s7FosFFy9eRJMmTaBQ2E9gl5eXh4SEBJw+fdrp7UnIisfY9XiMXY/H2PV4jF3P246xEAL5+fmIjY2tcTuHkhGtVourr74aa9euxbBhwwBYE4W1a9di4sSJVe7Ts2dPrF27Fo899pi0bvXq1ejZs2e19eh0Ouh09hPVhYSE1BhbUFCQV7ww3ozH2PV4jF2Px9j1eIxdz5uOcU1nRGwcvkwzefJkjBo1Ct26dUOPHj0wd+5cFBYWYvTo0QCAkSNHIi4uDjNnzgQATJo0CX379sXs2bNx44034uuvv8a2bduwYMECR6smIiIiH+RwMjJ8+HBkZmZi6tSpSEtLQ9euXbFq1SqpkeqpU6egrNCY8tprr8WXX36JF154Ac899xxat26NH374AVdccYXzngURERF5rXo1YJ04cWK1l2U2bNhQad0dd9yBO+64oz5V1Uqn02HatGmVLuuQ8/AYux6PsevxGLsej7Hr+eoxdnjQMyIiIiJn4qy9REREJCsmI0RERCQrJiNEREQkKyYjREREJCuvTkbef/99JCYmQq/XIykpCf/884/cIXmN6dOnQ6FQ2P21a9dOerykpAQTJkxAkyZNEBAQgNtuu63SSLqnTp3CjTfeCD8/P0RGRuKpp56CyWRy91PxGH/88QeGDBmC2NhYKBSKSpNBCiEwdepUxMTEwGAwIDk5GUeOHLHb5uLFi7jnnnsQFBSEkJAQjBkzBgWXTZC4Z88e9OnTB3q9HgkJCXjzzTdd/dQ8Rm3H+L777qv0vh40aJDdNjzGNZs5cya6d++OwMBAREZGYtiwYTh06JDdNs76ftiwYQOuuuoq6HQ6tGrVCosXL3b10/MIdTnG/fr1q/Refuihh+y28aljLLzU119/LbRarVi0aJHYt2+fGDt2rAgJCRHp6elyh+YVpk2bJjp27CjOnz8v/WVmZkqPP/TQQyIhIUGsXbtWbNu2TVxzzTXi2muvlR43mUziiiuuEMnJyWLnzp1i5cqVIjw8XEyZMkWOp+MRVq5cKZ5//nnx3XffCQDi+++/t3v89ddfF8HBweKHH34Qu3fvFjfffLNo3ry5KC4ulrYZNGiQ6NKli9i8ebP43//+J1q1aiXuuusu6fHc3FwRFRUl7rnnHrF3717x1VdfCYPBID788EN3PU1Z1XaMR40aJQYNGmT3vr548aLdNjzGNUtJSRGffPKJ2Lt3r9i1a5cYPHiwaNq0qSgoKJC2ccb3w7Fjx4Sfn5+YPHmy2L9/v3j33XeFSqUSq1atcuvzlUNdjnHfvn3F2LFj7d7Lubm50uO+doy9Nhnp0aOHmDBhgnTfbDaL2NhYMXPmTBmj8h7Tpk0TXbp0qfKxnJwcodFoxLJly6R1Bw4cEADEpk2bhBDWHwWlUinS0tKkbT744AMRFBQkSktLXRq7N7j8h9JisYjo6Ggxa9YsaV1OTo7Q6XTiq6++EkIIsX//fgFAbN26Vdrm119/FQqFQpw9e1YIIcS8efNEaGio3TF+5plnRNu2bV38jDxPdcnI0KFDq92Hx9hxGRkZAoDYuHGjEMJ53w9PP/206Nixo11dw4cPFykpKa5+Sh7n8mMshDUZmTRpUrX7+Nox9srLNEajEdu3b0dycrK0TqlUIjk5GZs2bZIxMu9y5MgRxMbGokWLFrjnnntw6tQpAMD27dtRVlZmd3zbtWuHpk2bSsd306ZN6NSpkzTyLgCkpKQgLy8P+/btc+8T8QLHjx9HWlqa3TENDg5GUlKS3TENCQlBt27dpG2Sk5OhVCqxZcsWaZvrrrsOWq1W2iYlJQWHDh1Cdna2m56NZ9uwYQMiIyPRtm1bjB8/HhcuXJAe4zF2XG5uLgAgLCwMgPO+HzZt2mRXhm2bxvgdfvkxtvniiy8QHh6OK664AlOmTEFRUZH0mK8d43qNwCq3rKwsmM1muxcBAKKionDw4EGZovIuSUlJWLx4Mdq2bYvz589jxowZ6NOnD/bu3Yu0tDRotdpKkxNGRUUhLS0NAJCWllbl8bc9RvZsx6SqY1bxmEZGRto9rlarERYWZrdN8+bNK5Vheyw0NNQl8XuLQYMG4dZbb0Xz5s1x9OhRPPfcc7jhhhuwadMmqFQqHmMHWSwWPPbYY+jVq5c0hYezvh+q2yYvLw/FxcUwGAyueEoep6pjDAB33303mjVrhtjYWOzZswfPPPMMDh06hO+++w6A7x1jr0xGqOFuuOEGablz585ISkpCs2bNsHTpUo96gxI5YsSIEdJyp06d0LlzZ7Rs2RIbNmzAgAEDZIzMO02YMAF79+7Fn3/+KXcoPqu6Yzxu3DhpuVOnToiJicGAAQNw9OhRtGzZ0t1hupxXXqYJDw+HSqWq1Ho7PT0d0dHRMkXl3UJCQtCmTRukpqYiOjoaRqMROTk5dttUPL7R0dFVHn/bY2TPdkxqes9GR0cjIyPD7nGTyYSLFy/yuNdTixYtEB4ejtTUVAA8xo6YOHEifvnlF6xfvx7x8fHSemd9P1S3TVBQUKP5h6i6Y1yVpKQkALB7L/vSMfbKZESr1eLqq6/G2rVrpXUWiwVr165Fz549ZYzMexUUFODo0aOIiYnB1VdfDY1GY3d8Dx06hFOnTknHt2fPnvj333/tvthXr16NoKAgdOjQwe3xe7rmzZsjOjra7pjm5eVhy5Ytdsc0JycH27dvl7ZZt24dLBaL9EXUs2dP/PHHHygrK5O2Wb16Ndq2bduoLh/U1ZkzZ3DhwgXExMQA4DGuCyEEJk6ciO+//x7r1q2rdMnKWd8PPXv2tCvDtk1j+A6v7RhXZdeuXQBg9172qWMsdwva+vr666+FTqcTixcvFvv37xfjxo0TISEhdi2LqXpPPPGE2LBhgzh+/Lj466+/RHJysggPDxcZGRlCCGvXvaZNm4p169aJbdu2iZ49e4qePXtK+9u6lQ0cOFDs2rVLrFq1SkRERDTqrr35+fli586dYufOnQKAmDNnjti5c6c4efKkEMLatTckJET8+OOPYs+ePWLo0KFVdu298sorxZYtW8Sff/4pWrdubdftNCcnR0RFRYl7771X7N27V3z99dfCz8+v0XQ7rekY5+fniyeffFJs2rRJHD9+XKxZs0ZcddVVonXr1qKkpEQqg8e4ZuPHjxfBwcFiw4YNdt1Ki4qKpG2c8f1g63b61FNPiQMHDoj333/fY7udOlttxzg1NVW89NJLYtu2beL48ePixx9/FC1atBDXXXedVIavHWOvTUaEEOLdd98VTZs2FVqtVvTo0UNs3rxZ7pC8xvDhw0VMTIzQarUiLi5ODB8+XKSmpkqPFxcXi4cffliEhoYKPz8/ccstt4jz58/blXHixAlxww03CIPBIMLDw8UTTzwhysrK3P1UPMb69esFgEp/o0aNEkJYu/e++OKLIioqSuh0OjFgwABx6NAhuzIuXLgg7rrrLhEQECCCgoLE6NGjRX5+vt02u3fvFr179xY6nU7ExcWJ119/3V1PUXY1HeOioiIxcOBAERERITQajWjWrJkYO3ZspX9QeIxrVtXxBSA++eQTaRtnfT+sX79edO3aVWi1WtGiRQu7OnxZbcf41KlT4rrrrhNhYWFCp9OJVq1aiaeeespunBEhfOsYK4QQwn3nYYiIiIjseWWbESIiIvIdTEaIiIhIVkxGiIiISFZMRoiIiEhWTEaIiIhIVkxGiIiISFZMRoiIiEhWTEaIiIhIVkxGiBqRzMxMaLVaFBYWoqysDP7+/jh16lSN+0yfPh0KhQKDBg2q9NisWbOgUCjQr18/F0VMRI0BkxGiRmTTpk3o0qUL/P39sWPHDoSFhaFp06a17hcTE4P169fjzJkzdusXLVpUp/2JiGrCZISoEfn777/Rq1cvAMCff/4pLdcmMjISAwcOxKeffmpXVlZWFm688cZK23/00Udo37499Ho92rVrh3nz5kmPGY1GTJw4ETExMdDr9WjWrBlmzpwJwDqb6fTp09G0aVPodDrExsbi0UcflfZdsmQJunXrhsDAQERHR+Puu++2m7UUAH766Se0bt0aer0e/fv3x6effgqFQmE35f2ff/6JPn36wGAwICEhAY8++igKCwulx+fNmyeVERUVhdtvv71Ox4mI6knmuXGIyMVOnjwpgoODRXBwsNBoNEKv14vg4GCh1WqFTqcTwcHBYvz48dXuP23aNNGlSxfx3XffiVatWknrx4wZIyZNmiQmTZok+vbtK63//PPPRUxMjPj222/FsWPHxLfffivCwsLE4sWLhRBCzJo1SyQkJIg//vhDnDhxQvzvf/8TX375pRBCiGXLlomgoCCxcuVKcfLkSbFlyxaxYMECqeyPP/5YrFy5Uhw9elRs2rRJ9OzZU9xwww3S48eOHRMajUY8+eST4uDBg+Krr74ScXFxAoDIzs4WQlhnRPX39xdvv/22OHz4sPjrr7/ElVdeKe677z4hhBBbt24VKpVKfPnll+LEiRNix44d4p133mnw60BE1WMyQuTjysrKxPHjx8Xu3buFRqMRu3fvFqmpqSIgIEBs3LhRHD9+XGRmZla7vy0ZMRqNIjIyUmzcuFEUFBSIwMBAsXv37krJSMuWLaXkwubll1+Wpph/5JFHxPXXXy8sFkulumbPni3atGkjjEZjnZ7b1q1bBQBp1t1nnnlGXHHFFXbbPP/883bJyJgxY8S4cePstvnf//4nlEqlKC4uFt9++60ICgoSeXl5dYqBiBqOl2mIfJxarUZiYiIOHjyI7t27o3PnzkhLS0NUVBSuu+46JCYmIjw8vNZyNBoN/vvf/+KTTz7BsmXL0KZNG3Tu3Nlum8LCQhw9ehRjxoxBQECA9PfKK6/g6NGjAID77rsPu3btQtu2bfHoo4/i999/l/a/4447UFxcjBYtWmDs2LH4/vvvYTKZpMe3b9+OIUOGoGnTpggMDETfvn0BQGqEe+jQIXTv3t0uph49etjd3717NxYvXmwXX0pKCiwWC44fP47//Oc/aNasGVq0aIF7770XX3zxBYqKihw44kTkKLXcARCRa3Xs2BEnT55EWVkZLBYLAgICYDKZYDKZEBAQgGbNmmHfvn11Kuv+++9HUlIS9u7di/vvv7/S4wUFBQCAhQsXIikpye4xlUoFALjqqqtw/Phx/Prrr1izZg3uvPNOJCcnY/ny5UhISMChQ4ewZs0arF69Gg8//DBmzZqFjRs3wmg0IiUlBSkpKfjiiy8QERGBU6dOISUlBUajsc7Ho6CgAA8++KBdWxSbpk2bQqvVYseOHdiwYQN+//13TJ06FdOnT8fWrVsREhJS53qIqO6YjBD5uJUrV6KsrAwDBgzAm2++iauvvhojRozAfffdh0GDBkGj0dS5rI4dO6Jjx47Ys2cP7r777kqPR0VFITY2FseOHcM999xTbTlBQUEYPnw4hg8fjttvvx2DBg3CxYsXERYWBoPBgCFDhmDIkCGYMGEC2rVrh3///RdCCFy4cAGvv/46EhISAADbtm2zK7dt27ZYuXKl3bqtW7fa3b/qqquwf/9+tGrVqtr41Go1kpOTkZycjGnTpiEkJATr1q3DrbfeWusxIiLHMRkh8nHNmjVDWloa0tPTMXToUCgUCuzbtw+33XYbYmJiHC5v3bp1KCsrq/YswYwZM/Doo48iODgYgwYNQmlpKbZt24bs7GxMnjwZc+bMQUxMDK688koolUosW7YM0dHRCAkJweLFi2E2m5GUlAQ/Pz98/vnnMBgMaNasGSwWC7RaLd5991089NBD2Lt3L15++WW7uh988EHMmTMHzzzzDMaMGYNdu3Zh8eLFAACFQgEAeOaZZ3DNNddg4sSJeOCBB+Dv74/9+/dj9erVeO+99/DLL7/g2LFjuO666xAaGoqVK1fCYrGgbdu2Dh8rIqobthkhagQ2bNiA7t27Q6/X459//kF8fHy9EhEA8Pf3r/FyxQMPPICPPvoIn3zyCTp16oS+ffti8eLFaN68OQAgMDAQb775Jrp164bu3bvjxIkTWLlyJZRKJUJCQrBw4UL06tULnTt3xpo1a/Dzzz+jSZMmiIiIwOLFi7Fs2TJ06NABr7/+Ot566y27ups3b47ly5fju+++Q+fOnfHBBx/g+eefBwDodDoAQOfOnbFx40YcPnwYffr0wZVXXompU6ciNjYWABASEoLvvvsO119/Pdq3b4/58+fjq6++QseOHet1vIiodgohhJA7CCIiV3n11Vcxf/58nD59Wu5QiKgavExDRD5l3rx56N69O5o0aYK//voLs2bNwsSJE+UOi4hqwGSEiHzKkSNH8Morr+DixYto2rQpnnjiCUyZMkXusIioBrxMQ0RERLJiA1YiIiKSFZMRIiIikhWTESIiIpIVkxEiIiKSFZMRIiIikhWTESIiIpIVkxEiIiKSFZMRIiIikhWTESIiIpLV/wPI9PDqOnLR8wAAAABJRU5ErkJggg==", "text/plain": [ "
" ] @@ -363,19 +349,19 @@ "\n", " rsdf = op_df[key].loc[(op_df[key]['type'] == 'RandomSamplingOperation')]\n", "\n", - " x = np.sort(rsdf['hops'])\n", - " N = rsdf['hops'].count()\n", + " x = np.sort(rsdf['num_messages'])\n", + " N = rsdf['num_messages'].count()\n", " # get the cdf values of y\n", " y = np.arange(N) / float(N)\n", "\n", " ax9.plot(x, y,label=key)\n", "\n", "ax9.legend\n", - "ax9.set_xlim([0,500])\n", + "#ax9.set_xlim([0,500])\n", "ax9.set_ylim([0,1])\n", "\n", - "ax9.set_title(\"CDF Random sampling hops\")\n", - "ax9.set_xlabel(\"# hops\")" + "ax9.set_title(\"CDF number of requests per random sampling process\")\n", + "ax9.set_xlabel(\"# Messages\")" ] }, { @@ -396,6 +382,18 @@ "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" } }, "nbformat": 4, diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index d6476f04..963ecf79 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -94,6 +94,8 @@ public abstract class DASProtocol implements Cloneable, EDProtocol, KademliaEven protected HashMap> missingSamples; + protected boolean first; + /** * Replicate this object by returning an identical copy.
* It is called by the initializer and do not fill any particular field. @@ -110,6 +112,7 @@ public abstract class DASProtocol implements Cloneable, EDProtocol, KademliaEven */ public DASProtocol(String prefix) { + first = true; DASProtocol.prefix = prefix; isEvil = false; _init(); @@ -339,11 +342,11 @@ protected void handleGetSample(Message m, int myPid) { sampleFound = true;*/ samplesToSend.add(sample); } else { - if (missingSamples.containsKey(id)) missingSamples.get(id).add(m); + if (missingSamples.get(id) != null) missingSamples.get(id).add(m); else { - List nodeIds = new ArrayList<>(); - nodeIds.add(m); - missingSamples.put(id, nodeIds); + List requests = new ArrayList<>(); + requests.add(m); + missingSamples.put(id, requests); } // logger.warning("Sample request missing"); } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java index 3f8049ab..7cfd81ce 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java @@ -48,9 +48,17 @@ protected void handleInitGetSample(Message m, int myPid) { @Override protected void handleInitNewBlock(Message m, int myPid) { logger.warning("Init block non-validator node - start sampling " + this); - super.handleInitNewBlock(m, myPid); + // super.handleInitNewBlock(m, myPid); validatorsContacted.clear(); - if (!isEvil) startRandomSampling(); + if (first) super.handleInitNewBlock(m, myPid); + if (!isEvil) { + if (first) { + first = false; + } else { + startRandomSampling(); + first = true; + } + } } public void setEvilIds(List evilIds) { diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index 97997ac2..7eadea4e 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -35,10 +35,15 @@ protected void handleInitGetSample(Message m, int myPid) { @Override protected void handleInitNewBlock(Message m, int myPid) { - super.handleInitNewBlock(m, myPid); + if (first) super.handleInitNewBlock(m, myPid); if (!isEvil) { - startRowsandColumnsSampling(); - startRandomSampling(); + if (first) { + startRowsandColumnsSampling(); + first = false; + } else { + startRandomSampling(); + first = true; + } } } diff --git a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java index 8a5b8ebe..685fa224 100644 --- a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java @@ -48,10 +48,10 @@ public class KademliaCommonConfigDas { public static int MAX_HOPS = 5000; /** Default upload bandwith of a validator in Mbits/sec */ - public static int VALIDATOR_UPLOAD_RATE = 10000; + public static int VALIDATOR_UPLOAD_RATE = 1000; /** Default upload bandwith of a non-validator in Mbits/sec */ - public static int NON_VALIDATOR_UPLOAD_RATE = 10000; + public static int NON_VALIDATOR_UPLOAD_RATE = 100; public static int BUILDER_UPLOAD_RATE = 10000; diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index 2c272053..0902a435 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -133,6 +133,12 @@ public List getNodesbySample(Set samples, BigInteger rad return result; } + public List getAllNeighbours() { + + List result = new ArrayList<>(neighbours.keySet()); + return result; + } + public Neighbour[] getNeighbours(int n) { List result = new ArrayList<>(); diff --git a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java index d8e73bb7..5c7f61ba 100755 --- a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java @@ -110,8 +110,10 @@ public boolean execute() { n, kadpid);*/ - if (n.isUp()) + if (n.isUp()) { EDSimulator.add(0, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); + EDSimulator.add(1000, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); + } } ID_GENERATOR++; second = false; diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index a7cf033f..0e3fb78e 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -2,6 +2,7 @@ import java.math.BigInteger; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; @@ -69,11 +70,13 @@ public boolean completed() { public void elaborateResponse(Sample[] sam) { for (Sample s : sam) { - if (samples.containsKey(s.getId()) || samples.containsKey(s.getIdByColumn())) { + if (samples.containsKey(s.getId()) /*|| samples.containsKey(s.getIdByColumn())*/) { FetchingSample fs = samples.get(s.getId()); - if (!fs.isDownloaded()) { - samplesCount++; - fs.setDownloaded(); + if (fs != null) { + if (!fs.isDownloaded()) { + samplesCount++; + fs.setDownloaded(); + } } } } @@ -94,13 +97,23 @@ public void elaborateResponse(Sample[] sam, BigInteger node) { if (sam != null) { for (Sample s : sam) { - if (samples.containsKey(s.getId()) || samples.containsKey(s.getIdByColumn())) { + if (samples.containsKey(s.getId()) /*|| samples.containsKey(s.getIdByColumn())*/) { FetchingSample fs = samples.get(s.getId()); - if (!fs.isDownloaded()) { + // FetchingSample fs2 = samples.get(s.getIdByColumn()); + if (fs != null) { + if (!fs.isDownloaded()) { + samplesCount++; + fs.setDownloaded(); + fs.removeFetchingNode(nodes.get(node)); + } + } /*else if(fs2!=null){ + if(!fs2.isDownloaded()){ samplesCount++; - fs.setDownloaded(); - fs.removeFetchingNode(nodes.get(node)); - } + fs2.setDownloaded(); + fs2.removeFetchingNode(nodes.get(node)); + } + + }*/ } } } @@ -148,7 +161,15 @@ protected void createNodes() { } protected void addExtraNodes() { + /*if (radiusValidator.compareTo(Block.MAX_KEY) == -1) + ; + radiusValidator = radiusValidator.multiply(BigInteger.valueOf(2)); + if (radiusValidator.compareTo(Block.MAX_KEY) == 1) radiusValidator = Block.MAX_KEY; + + createNodes();*/ + // int max = 0; for (BigInteger sample : samples.keySet()) { + // if (max == 100) break; if (!samples.get(sample).isDownloaded()) { List nodesBySample = new ArrayList<>(); BigInteger radiusUsed = radiusValidator; @@ -165,6 +186,7 @@ protected void addExtraNodes() { nodesBySample.addAll(new ArrayList<>(new LinkedHashSet<>(nodesToAdd))); nodesBySample.removeAll(askedNodes); + int max = 0; if (nodesBySample != null && nodesBySample.size() > 0) { for (BigInteger id : nodesBySample) { if (!nodes.containsKey(id)) { @@ -173,19 +195,28 @@ protected void addExtraNodes() { } else { nodes.get(id).addSample(samples.get(sample)); } + max++; + if (max == 5) break; } + break; } } } - /*if (nodes.size() == 0 && getSamples().length > 0) { - Sample[] randomSamples = currentBlock.getNRandomSamples(getSamples().length * 10); + if (nodes.size() == 0 && getSamples().length > 0) { + List randomSamples = new ArrayList<>(); + while (randomSamples.size() < getSamples().length * 10) { + Sample[] sample = currentBlock.getNRandomSamples(1); + if (!Arrays.asList(getSamples()).contains(sample[0].getId())) randomSamples.add(sample[0]); + } + for (BigInteger id : getSamples()) samples.remove(id); + askedNodes.clear(); for (Sample rs : randomSamples) { FetchingSample s = new FetchingSample(rs); samples.put(rs.getIdByRow(), s); } createNodes(); - }*/ + } } public Map toMap() { diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index cc4be4ad..24d49dbe 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -45,7 +45,9 @@ public SamplingOperation( completed = false; this.isValidator = isValidator; currentBlock = block; - + radiusValidator = + currentBlock.computeRegionRadius( + KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, numValidators); radiusNonValidator = currentBlock.computeRegionRadius(KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); samples = new HashMap<>(); @@ -144,7 +146,19 @@ public BigInteger[] doSampling() { if (nodes.isEmpty()) { createNodes(); - // System.out.println("[" + srcNode + "] Repopulating nodes " + nodes.size()); + System.out.println( + "[" + + CommonState.getTime() + + "][" + + srcNode + + "] Adding nodes " + + this.getId() + + " " + + nodes.size() + + " " + + aggressiveness + + " " + + askedNodes.size()); } if (nodes.isEmpty()) { addExtraNodes(); @@ -154,6 +168,8 @@ public BigInteger[] doSampling() { + "][" + srcNode + "] Adding extra nodes " + + this.getId() + + " " + nodes.size() + " " + aggressiveness @@ -175,6 +191,11 @@ public BigInteger[] doSampling() { } } + /*if (result.size() == 0 && this instanceof RandomSamplingOperation && aggressiveness >= 5) { + result = searchTable.getAllNeighbours(); + result.remove(askedNodes); + pendingNodes.addAll(result); + }*/ askedNodes.addAll(result); return result.toArray(new BigInteger[0]); } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index 260489b8..ea7ba745 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -2,6 +2,7 @@ import java.math.BigInteger; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; @@ -179,7 +180,9 @@ protected void createNodes() { } protected void addExtraNodes() { + int max = 0; for (BigInteger sample : samples.keySet()) { + if (max >= (samples.size() - samplesCount) / 4) break; if (!samples.get(sample).isDownloaded()) { List nodesBySample = new ArrayList<>(); BigInteger radiusUsed = radiusValidator; @@ -189,8 +192,8 @@ protected void addExtraNodes() { for (Sample s : sRow) { nodes.addAll(searchTable.getNodesbySample(s.getId(), radiusUsed)); } - nodes.addAll( - searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusUsed)); + // nodes.addAll( + // searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusUsed)); nodesBySample.addAll(new ArrayList<>(new LinkedHashSet<>(nodes))); } else { Sample[] sColumn = @@ -199,11 +202,13 @@ protected void addExtraNodes() { for (Sample s : sColumn) { nodes.addAll(searchTable.getNodesbySample(s.getIdByColumn(), radiusUsed)); } - nodes.addAll(searchTable.getNodesbySample(samples.get(sample).getId(), radiusUsed)); + // nodes.addAll(searchTable.getNodesbySample(samples.get(sample).getId(), radiusUsed)); nodesBySample.addAll(new ArrayList<>(new LinkedHashSet<>(nodes))); } nodesBySample.removeAll(askedNodes); + Collections.shuffle(nodesBySample); + // int max = 0; if (nodesBySample != null && nodesBySample.size() > 0) { for (BigInteger id : nodesBySample) { if (!nodes.containsKey(id)) { @@ -212,6 +217,10 @@ protected void addExtraNodes() { } else { nodes.get(id).addSample(samples.get(sample)); } + max++; + // if (max == aggressiveness) break; + // System.out.println("Adding " + max); + break; } } } From de874cc9e090ba0a53c89c81bb53c823bb73f1ba Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Mon, 4 Dec 2023 09:41:42 +0100 Subject: [PATCH 59/98] adding extra nodes for missing samples progressively with aggressivenes steps --- .../config/malicious/dasprotocolevil.cfg | 10 +-- .../peersim/kademlia/das/DASProtocol.java | 4 +- .../kademlia/das/DASProtocolNonValidator.java | 3 +- .../kademlia/das/DASProtocolValidator.java | 3 +- .../kademlia/das/TrafficGeneratorSample.java | 3 +- .../operations/RandomSamplingOperation.java | 69 ++++++++--------- .../das/operations/SamplingOperation.java | 5 +- .../ValidatorSamplingOperation.java | 74 +++++++++---------- 8 files changed, 83 insertions(+), 88 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil.cfg b/simulator/config/malicious/dasprotocolevil.cfg index 9bb3ca17..7f061503 100644 --- a/simulator/config/malicious/dasprotocolevil.cfg +++ b/simulator/config/malicious/dasprotocolevil.cfg @@ -95,8 +95,8 @@ init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol init.1uniqueNodeID.protocolEvildas 8evildasprotocol init.1uniqueNodeID.validator_rate 0.5 -init.1uniqueNodeID.evilNodeRatioValidator 0 -init.1uniqueNodeID.evilNodeRatioNonValidator 0 +init.1uniqueNodeID.evilNodeRatioValidator 0.5 +init.1uniqueNodeID.evilNodeRatioNonValidator 0.5 #Adds initial state to the routing tables @@ -110,8 +110,8 @@ init.2statebuilder.transport 2unreltr control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 -control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 512 +control.0traffic.sample_copy_per_node 3 +control.0traffic.block_dim_size 100 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia @@ -150,4 +150,4 @@ control.3turbolenceAdd.p_add 0.05 control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logsDasEvil0WithNon +control.4.logfolder logsDasEvil0.5Test diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 963ecf79..98b0b7de 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -317,7 +317,7 @@ protected void handleSeedSample(Message m, int myPid) { protected void handleGetSample(Message m, int myPid) { // kv is for storing the sample you have - logger.warning("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); + logger.info("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); // sample IDs that are requested in the message List samples = Arrays.asList((BigInteger[]) m.body); @@ -587,7 +587,7 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { // add to sent msg this.sentMsg.put(m.id, m.timestamp); - EDSimulator.add(4 * 100, t, src, myPid); // set delay = 2*RTT + EDSimulator.add(250, t, src, myPid); // set delay = 2*RTT } } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java index 7cfd81ce..f9ff3bfe 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java @@ -53,9 +53,10 @@ protected void handleInitNewBlock(Message m, int myPid) { if (first) super.handleInitNewBlock(m, myPid); if (!isEvil) { if (first) { + startRandomSampling(); first = false; } else { - startRandomSampling(); + // startRandomSampling(); first = true; } } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index 7eadea4e..0cb01752 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -39,9 +39,10 @@ protected void handleInitNewBlock(Message m, int myPid) { if (!isEvil) { if (first) { startRowsandColumnsSampling(); + startRandomSampling(); first = false; } else { - startRandomSampling(); + // startRandomSampling(); first = true; } } diff --git a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java index 5c7f61ba..9fcd0994 100755 --- a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java @@ -112,7 +112,8 @@ public boolean execute() { if (n.isUp()) { EDSimulator.add(0, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); - EDSimulator.add(1000, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); + // EDSimulator.add(10, generateNewBlockMessage(b), n, + // n.getDASProtocol().getDASProtocolID()); } } ID_GENERATOR++; diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index 0e3fb78e..f11c26ba 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -3,6 +3,7 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; @@ -161,49 +162,41 @@ protected void createNodes() { } protected void addExtraNodes() { - /*if (radiusValidator.compareTo(Block.MAX_KEY) == -1) - ; - radiusValidator = radiusValidator.multiply(BigInteger.valueOf(2)); - if (radiusValidator.compareTo(Block.MAX_KEY) == 1) radiusValidator = Block.MAX_KEY; - createNodes();*/ - // int max = 0; - for (BigInteger sample : samples.keySet()) { - // if (max == 100) break; - if (!samples.get(sample).isDownloaded()) { - List nodesBySample = new ArrayList<>(); - BigInteger radiusUsed = radiusValidator; - Sample[] sRow = currentBlock.getSamplesByRow(samples.get(sample).getSample().getRow()); - List nodesToAdd = new ArrayList<>(); - for (Sample s : sRow) { - nodesToAdd.addAll(searchTable.getNodesbySample(s.getId(), radiusUsed)); - } - Sample[] sColumn = - currentBlock.getSamplesByColumn(samples.get(sample).getSample().getColumn()); - for (Sample s : sColumn) { - nodesToAdd.addAll(searchTable.getNodesbySample(s.getIdByColumn(), radiusUsed)); - } - nodesBySample.addAll(new ArrayList<>(new LinkedHashSet<>(nodesToAdd))); - - nodesBySample.removeAll(askedNodes); - int max = 0; - if (nodesBySample != null && nodesBySample.size() > 0) { - for (BigInteger id : nodesBySample) { - if (!nodes.containsKey(id)) { - nodes.put(id, new Node(id)); - nodes.get(id).addSample(samples.get(sample)); - } else { - nodes.get(id).addSample(samples.get(sample)); - } - max++; - if (max == 5) break; + int max = 0; + List missingSamples = Arrays.asList(getSamples()); + Collections.shuffle(missingSamples); + for (BigInteger sample : missingSamples) { + List nodesBySample = new ArrayList<>(); + BigInteger radiusUsed = radiusValidator; + Sample[] sRow = currentBlock.getSamplesByRow(samples.get(sample).getSample().getRow()); + List nodesToAdd = new ArrayList<>(); + for (Sample s : sRow) { + nodesToAdd.addAll(searchTable.getNodesbySample(s.getId(), radiusUsed)); + } + Sample[] sColumn = + currentBlock.getSamplesByColumn(samples.get(sample).getSample().getColumn()); + for (Sample s : sColumn) { + nodesToAdd.addAll(searchTable.getNodesbySample(s.getIdByColumn(), radiusUsed)); + } + nodesBySample.addAll(new ArrayList<>(new LinkedHashSet<>(nodesToAdd))); + + nodesBySample.removeAll(askedNodes); + if (nodesBySample != null && nodesBySample.size() > 0) { + for (BigInteger id : nodesBySample) { + if (!nodes.containsKey(id)) { + nodes.put(id, new Node(id)); + nodes.get(id).addSample(samples.get(sample)); + } else { + nodes.get(id).addSample(samples.get(sample)); } - break; + max++; + if (max == aggressiveness) return; } } } - if (nodes.size() == 0 && getSamples().length > 0) { + /*if (nodes.size() == 0 && getSamples().length > 0) { List randomSamples = new ArrayList<>(); while (randomSamples.size() < getSamples().length * 10) { Sample[] sample = currentBlock.getNRandomSamples(1); @@ -216,7 +209,7 @@ protected void addExtraNodes() { samples.put(rs.getIdByRow(), s); } createNodes(); - } + }*/ } public Map toMap() { diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index 24d49dbe..41260c22 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -146,6 +146,7 @@ public BigInteger[] doSampling() { if (nodes.isEmpty()) { createNodes(); + addExtraNodes(); System.out.println( "[" + CommonState.getTime() @@ -160,7 +161,7 @@ public BigInteger[] doSampling() { + " " + askedNodes.size()); } - if (nodes.isEmpty()) { + /*if (nodes.isEmpty()) { addExtraNodes(); System.out.println( "[" @@ -175,7 +176,7 @@ public BigInteger[] doSampling() { + aggressiveness + " " + askedNodes.size()); - } + }*/ for (Node n : nodes.values()) n.setAgressiveness(aggressiveness); List result = new ArrayList<>(); for (Node n : nodes.values()) { diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index ea7ba745..cd51d5f8 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -2,6 +2,7 @@ import java.math.BigInteger; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; @@ -181,47 +182,44 @@ protected void createNodes() { protected void addExtraNodes() { int max = 0; - for (BigInteger sample : samples.keySet()) { - if (max >= (samples.size() - samplesCount) / 4) break; - if (!samples.get(sample).isDownloaded()) { - List nodesBySample = new ArrayList<>(); - BigInteger radiusUsed = radiusValidator; - if (column > 0) { - Sample[] sRow = currentBlock.getSamplesByRow(samples.get(sample).getSample().getRow()); - List nodes = new ArrayList<>(); - for (Sample s : sRow) { - nodes.addAll(searchTable.getNodesbySample(s.getId(), radiusUsed)); - } - // nodes.addAll( - // searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusUsed)); - nodesBySample.addAll(new ArrayList<>(new LinkedHashSet<>(nodes))); - } else { - Sample[] sColumn = - currentBlock.getSamplesByColumn(samples.get(sample).getSample().getColumn()); - List nodes = new ArrayList<>(); - for (Sample s : sColumn) { - nodes.addAll(searchTable.getNodesbySample(s.getIdByColumn(), radiusUsed)); - } - // nodes.addAll(searchTable.getNodesbySample(samples.get(sample).getId(), radiusUsed)); - nodesBySample.addAll(new ArrayList<>(new LinkedHashSet<>(nodes))); + + List missingSamples = Arrays.asList(getSamples()); + Collections.shuffle(missingSamples); + for (BigInteger sample : missingSamples) { + + List nodesBySample = new ArrayList<>(); + BigInteger radiusUsed = radiusValidator; + if (column > 0) { + Sample[] sRow = currentBlock.getSamplesByRow(samples.get(sample).getSample().getRow()); + List nodes = new ArrayList<>(); + for (Sample s : sRow) { + nodes.addAll(searchTable.getNodesbySample(s.getId(), radiusUsed)); } - nodesBySample.removeAll(askedNodes); - Collections.shuffle(nodesBySample); - // int max = 0; - if (nodesBySample != null && nodesBySample.size() > 0) { - for (BigInteger id : nodesBySample) { - if (!nodes.containsKey(id)) { - nodes.put(id, new Node(id)); - nodes.get(id).addSample(samples.get(sample)); - } else { - nodes.get(id).addSample(samples.get(sample)); - } - max++; - // if (max == aggressiveness) break; - // System.out.println("Adding " + max); - break; + nodesBySample.addAll(new ArrayList<>(new LinkedHashSet<>(nodes))); + } else { + Sample[] sColumn = + currentBlock.getSamplesByColumn(samples.get(sample).getSample().getColumn()); + List nodes = new ArrayList<>(); + for (Sample s : sColumn) { + nodes.addAll(searchTable.getNodesbySample(s.getIdByColumn(), radiusUsed)); + } + nodesBySample.addAll(new ArrayList<>(new LinkedHashSet<>(nodes))); + } + + nodesBySample.removeAll(askedNodes); + Collections.shuffle(nodesBySample); + // int max = 0; + if (nodesBySample != null && nodesBySample.size() > 0) { + for (BigInteger id : nodesBySample) { + if (!nodes.containsKey(id)) { + nodes.put(id, new Node(id)); + nodes.get(id).addSample(samples.get(sample)); + } else { + nodes.get(id).addSample(samples.get(sample)); } + max++; + if (max == aggressiveness) return; } } } From 1f07393b6b79f2e9fdd4d8e9ad2c52144f2f2c7a Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Tue, 26 Dec 2023 08:31:53 +0100 Subject: [PATCH 60/98] reducing cached samples --- .../peersim/kademlia/das/DASProtocol.java | 126 ++++++++++++------ .../kademlia/das/DASProtocolBuilder.java | 14 +- .../das/DASProtocolEvilNonValidator.java | 4 +- .../das/DASProtocolEvilValidator.java | 4 +- .../kademlia/das/DASProtocolNonValidator.java | 2 +- .../kademlia/das/DASProtocolValidator.java | 2 +- .../kademlia/das/KademliaCommonConfigDas.java | 8 +- .../operations/RandomSamplingOperation.java | 29 ++-- .../das/operations/SamplingOperation.java | 36 +++-- .../ValidatorSamplingOperation.java | 86 ++++++++---- 10 files changed, 212 insertions(+), 99 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 98b0b7de..4844df89 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -341,6 +341,7 @@ protected void handleGetSample(Message m, int myPid) { sendMessage(response, m.src.getId(), myPid); sampleFound = true;*/ samplesToSend.add(sample); + if (isEvil && samplesToSend.size() > 0) break; } else { if (missingSamples.get(id) != null) missingSamples.get(id).add(m); else { @@ -352,14 +353,14 @@ protected void handleGetSample(Message m, int myPid) { } } if (samplesToSend.isEmpty()) { - Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, new Sample[] {}); + /*Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, new Sample[] {}); response.operationId = m.operationId; response.dst = m.src; response.src = this.kadProtocol.getKademliaNode(); response.ackId = m.id; // set ACK number response.value = searchTable.getNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED); - sendMessage(response, m.src.getId(), myPid); + sendMessage(response, m.src.getId(), myPid);*/ } else { Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, samplesToSend.toArray(new Sample[0])); @@ -370,6 +371,10 @@ protected void handleGetSample(Message m, int myPid) { response.value = searchTable.getNeighbours( KademliaCommonConfigDas.MAX_NODES_RETURNED * samplesToSend.size()); + if (isEvil) + response.value = + searchTable.getEvilNeighbours( + KademliaCommonConfigDas.MAX_NODES_RETURNED * samplesToSend.size()); sendMessage(response, m.src.getId(), myPid); } } @@ -382,7 +387,7 @@ private void reconstruct(Sample s) { Sample[] samples = currentBlock.getSamplesByColumn(s.getColumn()); for (Sample sam : samples) { kv.add((BigInteger) sam.getIdByRow(), sam); - kv.add((BigInteger) sam.getIdByColumn(), sam); + // kv.add((BigInteger) sam.getIdByColumn(), sam); } column[s.getColumn() - 1] = currentBlock.getSize(); } @@ -390,7 +395,7 @@ private void reconstruct(Sample s) { Sample[] samples = currentBlock.getSamplesByRow(s.getRow()); for (Sample sam : samples) { kv.add((BigInteger) sam.getIdByRow(), sam); - kv.add((BigInteger) sam.getIdByColumn(), sam); + // kv.add((BigInteger) sam.getIdByColumn(), sam); } row[s.getRow() - 1] = currentBlock.getSize(); } @@ -403,46 +408,56 @@ protected void handleGetSampleResponse(Message m, int myPid) { Sample[] samples = (Sample[]) m.body; // searchTable.addNodes((BigInteger[]) m.value); - if (samplingOp.get(m.operationId) != null) - logger.warning( - "Samples received " - + samples.length - + " from " - + m.src.getId() - + " " - + samplingOp.get(m.operationId).getPending()); - else logger.warning("Samples received " + samples.length + " from " + m.src.getId()); - if (reportDiscovery && !isEvil()) KademliaObserver.reportPeerDiscovery(m, searchTable); + // if (reportDiscovery && !isEvil()) KademliaObserver.reportPeerDiscovery(m, searchTable); for (Neighbour neigh : (Neighbour[]) m.value) { if (neigh.getId().compareTo(builderAddress) != 0) searchTable.addNeighbour(neigh); } for (Sample s : samples) { - logger.warning( - "Sample received " + s.getId() + " " + s.getIdByColumn() + " from " + m.src.getId()); + // logger.warning( + // "Sample received " + s.getId() + " " + s.getIdByColumn() + " from " + m.src.getId()); kv.add((BigInteger) s.getIdByRow(), s); - kv.add((BigInteger) s.getIdByColumn(), s); + // kv.add((BigInteger) s.getIdByColumn(), s); // count # of samples for each row and column and reconstruct if more than half received reconstruct(s); } + if (samplingOp.get(m.operationId) != null) + logger.warning( + "Samples received " + + samples.length + + " from " + + m.src.getId() + + " " + + samplingOp.get(m.operationId).getPending() + + " " + + kv.occupancy()); + else + logger.warning( + "Samples received " + samples.length + " from " + m.src.getId() + " " + kv.occupancy()); HashMap> toSend = findMissingSamples(samples); for (Message msg : toSend.keySet()) { - Message response = - new Message(Message.MSG_GET_SAMPLE_RESPONSE, toSend.get(msg).toArray(new Sample[0])); + Sample[] samplesToSend = toSend.get(msg).toArray(new Sample[0]); + if (isEvil) { + samplesToSend = new Sample[] {samplesToSend[0]}; + } + Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, samplesToSend); response.operationId = msg.operationId; response.dst = msg.src; response.src = this.kadProtocol.getKademliaNode(); response.ackId = msg.id; // set ACK number response.value = - searchTable.getNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED * toSend.size()); + searchTable.getNeighbours( + KademliaCommonConfigDas.MAX_NODES_RETURNED * toSend.get(msg).size()); + if (isEvil) + response.value = searchTable.getEvilNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED); // logger.warning("Sending sample to " + msg.src.getId()); sendMessage(response, msg.src.getId(), myPid); } toSend.clear(); - SamplingOperation op = (SamplingOperation) samplingOp.get(m.operationId); + // SamplingOperation op = (SamplingOperation) samplingOp.get(m.operationId); // We continue an existing operation logger.info( @@ -451,44 +466,72 @@ protected void handleGetSampleResponse(Message m, int myPid) { + " " + searchTable.getAllNeighboursCount() + " " - + searchTable.getValidatorsNeighboursCount() - + " " - + op); - if (op != null) { + + searchTable.getValidatorsNeighboursCount()); + // + " " + // + op); + List toRemove = new ArrayList<>(); + for (SamplingOperation op : samplingOp.values()) { + // if (op != null) { // keeping track of received samples op.elaborateResponse(samples, m.src.getId()); - op.elaborateResponse(kv.getAll().toArray(new Sample[0])); + // op.elaborateResponse(kv.getAll().toArray(new Sample[0])); + // logger.warning( + // "operation " + op.getId() + " " + op.samplesCount() + " " + op.getSamples().length); + // } + // SamplingOperation op = (SamplingOperation) samplingOp.get(m.operationId); + // if (op != null) { logger.warning( "Continue operation " + op.getId() + " " - + op.getHops() + + op.getAgressiveness() + " " + searchTable.nodesIndexed().size() + " " + ((SamplingOperation) op).samplesCount() + " " - + ((SamplingOperation) op).getPending()); + + ((SamplingOperation) op).getPending() + + " " + + op.completed()); if (!op.completed() - && op.getHops() < KademliaCommonConfigDas.MAX_HOPS + /*&& op.getHops() < KademliaCommonConfigDas.MAX_HOPS + && (op instanceof ValidatorSamplingOperation + && (CommonState.getTime() - op.getTimestamp()) + <= KademliaCommonConfigDas.VALIDATOR_DEADLINE + || op instanceof RandomSamplingOperation + && (CommonState.getTime() - op.getTimestamp()) + <= KademliaCommonConfigDas.RANDOM_SAMPLING_DEADLINE)*/ ) { + doSampling(op); + } // else { + /*if (!op.completed() && (op instanceof ValidatorSamplingOperation && (CommonState.getTime() - op.getTimestamp()) - <= KademliaCommonConfigDas.VALIDATOR_DEADLINE + > KademliaCommonConfigDas.VALIDATOR_DEADLINE || op instanceof RandomSamplingOperation && (CommonState.getTime() - op.getTimestamp()) - <= KademliaCommonConfigDas.RANDOM_SAMPLING_DEADLINE)) { - doSampling(op); - } // else { + > KademliaCommonConfigDas.RANDOM_SAMPLING_DEADLINE)) { + toRemove.add(op.getId()); + KademliaObserver.reportOperation(op); + if (op instanceof ValidatorSamplingOperation) + logger.warning("Sampling operation finished validator failed " + op.getId()); + else logger.warning("Sampling operation finished random failed " + op.getId()); + }*/ + if (op.completed()) { // logger.warning("Operation completed"); - samplingOp.remove(m.operationId); + // samplingOp.remove(m.operationId); + toRemove.add(op.getId()); if (op instanceof ValidatorSamplingOperation) logger.warning("Sampling operation finished validator completed " + op.getId()); else logger.warning("Sampling operation finished random completed " + op.getId()); KademliaObserver.reportOperation(op); } } + for (long id : toRemove) { + // logger.warning("Sampling operation finished validator completed " + op.getId()); + samplingOp.remove(id); + } } private HashMap> findMissingSamples(Sample[] samples) { @@ -587,7 +630,7 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { // add to sent msg this.sentMsg.put(m.id, m.timestamp); - EDSimulator.add(250, t, src, myPid); // set delay = 2*RTT + EDSimulator.add(400, t, src, myPid); // set delay = 2*RTT } } @@ -666,10 +709,8 @@ protected void startRandomSampling() { this); op.elaborateResponse(kv.getAll().toArray(new Sample[0])); samplingOp.put(op.getId(), op); - logger.warning("Sampling operation started random"); - /*while (!doSampling(op)) { - op.increaseRadius(2); - }*/ + logger.warning("Sampling operation started random " + op.getId()); + doSampling(op); } @@ -713,6 +754,13 @@ protected boolean doSampling(SamplingOperation sop) { sendMessage(msg, nextNode, dasID); sop.getMessages(); } + if (!success && !sop.getStarted()) { + Timeout t = new Timeout(this.getKademliaId(), sop.getId(), sop.getId()); + // add to sent msg + this.sentMsg.put(sop.getId(), CommonState.getTime()); + + EDSimulator.add(100, t, this.getKademliaProtocol().getNode(), dasID); // set delay = 2*RTT + } } return success; } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index f4646f48..7c4f38b8 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -35,12 +35,15 @@ protected void handleInitNewBlock(Message m, int myPid) { logger.warning("Builder new block:" + currentBlock.getBlockId()); int samplesWithinRegion = 0; // samples that are within at least one node's region + int samplesWithinRegionColumn = 0; // samples that are within at least one node's region + int samplesValidators = 0; int samplesNonValidators = 0; samplesToRequest.clear(); BigInteger radiusNonValidator = currentBlock.computeRegionRadius(KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); + int notInRegion = 0; while (currentBlock.hasNext()) { boolean inRegion = false; Sample s = currentBlock.next(); @@ -84,6 +87,7 @@ protected void handleInitNewBlock(Message m, int myPid) { } } } + // if (!inRegion) notInRegion++; if (!inRegion) radiusValidator = radiusValidator.multiply(BigInteger.valueOf(2)); } inRegion = false; @@ -118,11 +122,13 @@ protected void handleInitNewBlock(Message m, int myPid) { } samplesValidators++; if (inRegion == false) { - samplesWithinRegion++; + samplesWithinRegionColumn++; inRegion = true; } } } + // if (!inRegion) notInRegion++; + if (!inRegion) radiusValidator = radiusValidator.multiply(BigInteger.valueOf(2)); } @@ -173,13 +179,17 @@ protected void handleInitNewBlock(Message m, int myPid) { logger.warning( samplesWithinRegion + + " " + + samplesWithinRegionColumn + " samples out of " + currentBlock.getNumSamples() + " samples are within a node's region" + " " + samplesValidators + " " - + samplesNonValidators); + + samplesNonValidators + + " " + + notInRegion); } @Override diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilNonValidator.java index 45d25ea3..8a735e3f 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilNonValidator.java @@ -20,7 +20,7 @@ protected void handleInitGetSample(Message m, int myPid) { // super.handleInitGetSample(m, myPid); } - protected void handleGetSample(Message m, int myPid) { + /*protected void handleGetSample(Message m, int myPid) { // kv is for storing the sample you have logger.info("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); // sample IDs that are requested in the message @@ -32,7 +32,7 @@ protected void handleGetSample(Message m, int myPid) { response.ackId = m.id; // set ACK number response.value = searchTable.getEvilNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED); sendMessage(response, m.src.getId(), myPid); - } + }*/ /** * Replicate this object by returning an identical copy.
* It is called by the initializer and do not fill any particular field. diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilValidator.java index 7930e7d5..c6dc90ea 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilValidator.java @@ -22,7 +22,7 @@ protected void handleInitGetSample(Message m, int myPid) { // super.handleInitGetSample(m, myPid); } - protected void handleGetSample(Message m, int myPid) { + /*protected void handleGetSample(Message m, int myPid) { // kv is for storing the sample you have logger.info("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); // sample IDs that are requested in the message @@ -34,7 +34,7 @@ protected void handleGetSample(Message m, int myPid) { response.ackId = m.id; // set ACK number response.value = searchTable.getEvilNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED); sendMessage(response, m.src.getId(), myPid); - } + }*/ public void setEvilIds(List evilIds) { searchTable.setEvilIds(evilIds); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java index f9ff3bfe..0fc90331 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java @@ -54,7 +54,7 @@ protected void handleInitNewBlock(Message m, int myPid) { if (!isEvil) { if (first) { startRandomSampling(); - first = false; + // first = false; } else { // startRandomSampling(); first = true; diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index 0cb01752..4cac1ea5 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -40,7 +40,7 @@ protected void handleInitNewBlock(Message m, int myPid) { if (first) { startRowsandColumnsSampling(); startRandomSampling(); - first = false; + // first = false; } else { // startRandomSampling(); first = true; diff --git a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java index 685fa224..daac4aed 100644 --- a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java @@ -37,7 +37,7 @@ public class KademliaCommonConfigDas { public static double NODE_RECORD_SIZE = 0.0024; /** Size of a sample in Mbits - each cell contains 512 B of data + 48 B KZG commitment */ - public static double SAMPLE_SIZE = 0.00448; + public static double SAMPLE_SIZE = 0.004096; /** Number of samples returned by a single node */ public static int MAX_SAMPLES_RETURNED = 1000; @@ -48,12 +48,12 @@ public class KademliaCommonConfigDas { public static int MAX_HOPS = 5000; /** Default upload bandwith of a validator in Mbits/sec */ - public static int VALIDATOR_UPLOAD_RATE = 1000; + public static int VALIDATOR_UPLOAD_RATE = 100; /** Default upload bandwith of a non-validator in Mbits/sec */ - public static int NON_VALIDATOR_UPLOAD_RATE = 100; + public static int NON_VALIDATOR_UPLOAD_RATE = 1000; - public static int BUILDER_UPLOAD_RATE = 10000; + public static int BUILDER_UPLOAD_RATE = 50000; public static int VALIDATOR_DEADLINE = 4000; public static int RANDOM_SAMPLING_DEADLINE = 12000; diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index f11c26ba..c3aeb293 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -122,6 +122,16 @@ public void elaborateResponse(Sample[] sam, BigInteger node) { // askedNodes.add(node); } + public BigInteger[] getSamples() { + List result = new ArrayList<>(); + + for (FetchingSample sample : samples.values()) { + if (!sample.isDownloaded()) result.add(sample.getId()); + } + + return result.toArray(new BigInteger[0]); + } + protected void createNodes() { for (BigInteger sample : samples.keySet()) { if (!samples.get(sample).isDownloaded()) { @@ -130,14 +140,13 @@ protected void createNodes() { BigInteger radiusUsed = radiusValidator; - while (nodesBySample.isEmpty() && radiusUsed.compareTo(Block.MAX_KEY) == -1) { - nodesBySample.addAll( - searchTable.getNodesbySample(samples.get(sample).getId(), radiusUsed)); - nodesBySample.addAll( - searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusUsed)); + // while (nodesBySample.isEmpty() && radiusUsed.compareTo(Block.MAX_KEY) == -1) { + nodesBySample.addAll(searchTable.getNodesbySample(samples.get(sample).getId(), radiusUsed)); + nodesBySample.addAll( + searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusUsed)); - radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); - } + // radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); + // } boolean found = false; nodesBySample.removeAll(askedNodes); @@ -163,10 +172,10 @@ protected void createNodes() { protected void addExtraNodes() { - int max = 0; List missingSamples = Arrays.asList(getSamples()); Collections.shuffle(missingSamples); for (BigInteger sample : missingSamples) { + int count = 0; List nodesBySample = new ArrayList<>(); BigInteger radiusUsed = radiusValidator; Sample[] sRow = currentBlock.getSamplesByRow(samples.get(sample).getSample().getRow()); @@ -190,8 +199,8 @@ protected void addExtraNodes() { } else { nodes.get(id).addSample(samples.get(sample)); } - max++; - if (max == aggressiveness) return; + count++; + if (count == aggressiveness) return; } } } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index 41260c22..cb35a37e 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -34,6 +34,10 @@ public abstract class SamplingOperation extends FindOperation { protected List askedNodes; protected List pendingNodes; + protected boolean started; + + protected int aggressiveness_step; + public SamplingOperation( BigInteger srcNode, BigInteger destNode, @@ -57,6 +61,8 @@ public SamplingOperation( askedNodes = new ArrayList<>(); pendingNodes = new ArrayList<>(); timesIncreased = 0; + started = false; + aggressiveness_step = KademliaCommonConfigDas.aggressiveness_step; } public SamplingOperation( @@ -84,21 +90,15 @@ public SamplingOperation( askedNodes = new ArrayList<>(); timesIncreased = 0; pendingNodes = new ArrayList<>(); + started = false; + aggressiveness_step = KademliaCommonConfigDas.aggressiveness_step; // queried = new HashSet<>(); // TODO Auto-generated constructor stub } public abstract boolean completed(); - public BigInteger[] getSamples() { - List result = new ArrayList<>(); - - for (FetchingSample sample : samples.values()) { - if (!sample.isDownloaded()) result.add(sample.getId()); - } - - return result.toArray(new BigInteger[0]); - } + public abstract BigInteger[] getSamples(); public BigInteger getRadiusValidator() { return radiusValidator; @@ -114,7 +114,7 @@ public BigInteger getRadiusNonValidator() { public BigInteger[] doSampling() { - aggressiveness += KademliaCommonConfigDas.aggressiveness_step; + aggressiveness += aggressiveness_step; // System.out.println("[" + srcNode + "] nodes " + nodes.size()); List toRemove = new ArrayList<>(); for (BigInteger n : nodes.keySet()) { @@ -161,8 +161,8 @@ public BigInteger[] doSampling() { + " " + askedNodes.size()); } - /*if (nodes.isEmpty()) { - addExtraNodes(); + if (nodes.isEmpty()) { + // addExtraNodes(); System.out.println( "[" + CommonState.getTime() @@ -176,7 +176,7 @@ public BigInteger[] doSampling() { + aggressiveness + " " + askedNodes.size()); - }*/ + } for (Node n : nodes.values()) n.setAgressiveness(aggressiveness); List result = new ArrayList<>(); for (Node n : nodes.values()) { @@ -198,6 +198,8 @@ public BigInteger[] doSampling() { pendingNodes.addAll(result); }*/ askedNodes.addAll(result); + + if (result.size() > 0) started = true; return result.toArray(new BigInteger[0]); } @@ -216,4 +218,12 @@ public int samplesCount() { public int getPending() { return pendingNodes.size(); } + + public boolean getStarted() { + return started; + } + + public int getAgressiveness() { + return aggressiveness; + } } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index cd51d5f8..e60335fd 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -8,6 +8,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import peersim.core.CommonState; import peersim.kademlia.das.Block; import peersim.kademlia.das.MissingNode; import peersim.kademlia.das.Sample; @@ -54,7 +55,7 @@ public ValidatorSamplingOperation( } } else if (column > 0) { for (Sample sample : block.getSamplesByColumn(column)) { - samples.put(sample.getIdByColumn(), new FetchingSample(sample)); + samples.put(sample.getId(), new FetchingSample(sample)); } } this.searchTable = searchTable; @@ -64,15 +65,15 @@ public ValidatorSamplingOperation( public void elaborateResponse(Sample[] sam) { for (Sample s : sam) { - if (row > 0) { - if (samples.containsKey(s.getId())) { - FetchingSample fs = samples.get(s.getId()); - if (!fs.isDownloaded()) { - fs.setDownloaded(); - samplesCount++; - } + // if (row > 0) { + if (samples.containsKey(s.getId())) { + FetchingSample fs = samples.get(s.getId()); + if (!fs.isDownloaded()) { + fs.setDownloaded(); + samplesCount++; } - } else { + } + /*} else { if (samples.containsKey(s.getIdByColumn())) { FetchingSample fs = samples.get(s.getIdByColumn()); if (!fs.isDownloaded()) { @@ -80,9 +81,19 @@ public void elaborateResponse(Sample[] sam) { samplesCount++; } } - } + }*/ } - // System.out.println("Row " + samplesCount + " " + samples.size()); + /*System.out.println( + "[" + + CommonState.getTime() + + "][" + + srcNode + + "] Completed operation " + + this.getId() + + " " + + samplesCount + + " " + + samples.size());*/ if (samplesCount >= samples.size() / 2) completed = true; } @@ -100,15 +111,15 @@ public void elaborateResponse(Sample[] sam, BigInteger n) { } if (sam != null) { for (Sample s : sam) { - if (row > 0) { - if (samples.containsKey(s.getId())) { - FetchingSample fs = samples.get(s.getId()); - if (!fs.isDownloaded()) { - fs.setDownloaded(); - samplesCount++; - } + // if (row > 0) { + if (samples.containsKey(s.getId())) { + FetchingSample fs = samples.get(s.getId()); + if (!fs.isDownloaded()) { + fs.setDownloaded(); + samplesCount++; } - } else { + } + /*} else { if (samples.containsKey(s.getIdByColumn())) { FetchingSample fs = samples.get(s.getIdByColumn()); if (!fs.isDownloaded()) { @@ -116,9 +127,20 @@ public void elaborateResponse(Sample[] sam, BigInteger n) { samplesCount++; } } - } + }*/ } } + /*System.out.println( + "[" + + CommonState.getTime() + + "][" + + srcNode + + "] Completed operation " + + this.getId() + + " " + + samplesCount + + " " + + samples.size());*/ // System.out.println("Row " + samplesCount + " " + samples.size()); if (samplesCount >= samples.size() / 2) completed = true; @@ -180,13 +202,27 @@ protected void createNodes() { } } - protected void addExtraNodes() { - int max = 0; + public BigInteger[] getSamples() { + List result = new ArrayList<>(); + + for (FetchingSample sample : samples.values()) { + if (!sample.isDownloaded()) { + // if (column > 0) result.add(sample.getIdByColumn()); + // else + result.add(sample.getId()); + } + } + return result.toArray(new BigInteger[0]); + } + + protected void addExtraNodes() { + if (CommonState.getTime() - this.getTimestamp() > 1000) + aggressiveness_step = aggressiveness_step * 2; List missingSamples = Arrays.asList(getSamples()); Collections.shuffle(missingSamples); for (BigInteger sample : missingSamples) { - + int count = 0; List nodesBySample = new ArrayList<>(); BigInteger radiusUsed = radiusValidator; if (column > 0) { @@ -218,8 +254,8 @@ protected void addExtraNodes() { } else { nodes.get(id).addSample(samples.get(sample)); } - max++; - if (max == aggressiveness) return; + count++; + if (count > aggressiveness - 2) return; } } } From 01bb4b45feca42eacbc83c6bddaec3148b6b1816 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Tue, 26 Dec 2023 08:48:14 +0100 Subject: [PATCH 61/98] configs --- .../config/malicious/dasprotocolevil0.25.cfg | 154 ++++++++++++++++++ .../config/malicious/dasprotocolevil0.5.cfg | 153 +++++++++++++++++ .../config/malicious/dasprotocolevil0.75.cfg | 154 ++++++++++++++++++ .../config/malicious/dasprotocolevil0.9.cfg | 154 ++++++++++++++++++ .../config/malicious/dasprotocolevil0.cfg | 154 ++++++++++++++++++ 5 files changed, 769 insertions(+) create mode 100644 simulator/config/malicious/dasprotocolevil0.25.cfg create mode 100644 simulator/config/malicious/dasprotocolevil0.5.cfg create mode 100644 simulator/config/malicious/dasprotocolevil0.75.cfg create mode 100644 simulator/config/malicious/dasprotocolevil0.9.cfg create mode 100644 simulator/config/malicious/dasprotocolevil0.cfg diff --git a/simulator/config/malicious/dasprotocolevil0.25.cfg b/simulator/config/malicious/dasprotocolevil0.25.cfg new file mode 100644 index 00000000..ecd9b35d --- /dev/null +++ b/simulator/config/malicious/dasprotocolevil0.25.cfg @@ -0,0 +1,154 @@ +# :::::::::::::::::::::::::::::::::`::::::::::::::::::::: +# :: Kademlia Default Configuration +# :::::::::::::::::::::::::::::::::::::::::::::::::::::: + +# ::::: GLOBAL :::::: + +# Network size +SIZE 5000 + +# Random seed +K 5 + +MINDELAY 5 +MAXDELAY 100 + +#Simulation time in ms +SIM_TIME 60001 + + +#Traffic generator is executed every TRAFFIC_STEP +TRAFFIC_STEP 12000 #10000000/SIZE +#Tracing module is executed every OBSERVER_STEP +OBSERVER_STEP 1000 +#Turbulence module is executed every TURBULENCE_STEP enabling churning +TURBULENCE_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 +REFRESH_STEP 1000 + +# add network config parameters to simulation +random.seed 24680 +simulation.experiments 1 +simulation.endtime SIM_TIME +network.size SIZE + + +# Peersim protocols enabled in each node + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.0link peersim.core.IdleProtocol + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.1pairwiselattr peersim.transport.PairwiseFixedLatencyTransport +protocol.1pairwiselattr.mindelay MINDELAY +protocol.1pairwiselattr.maxdelay MAXDELAY +protocol.1pairwiselattr.size SIZE + + +#transport layer that reliably delivers messages with a random delay, emulating TCP +protocol.2unreltr peersim.transport.UnreliableTransport +protocol.2unreltr.drop 0 +protocol.2unreltr.transport 1pairwiselattr + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.3kademlia peersim.kademlia.KademliaProtocol +protocol.3kademlia.transport 2unreltr +protocol.3kademlia.BITS 256 +protocol.3kademlia.NBUCKETS 17 +protocol.3kademlia.FINDMODE 1 + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.4dasprotocol peersim.kademlia.das.DASProtocolBuilder +protocol.4dasprotocol.transport 2unreltr +protocol.4dasprotocol.kademlia 3kademlia +protocol.4dasprotocol.reportDiscovery false + +protocol.5dasprotocol peersim.kademlia.das.DASProtocolValidator +protocol.5dasprotocol.transport 2unreltr +protocol.5dasprotocol.kademlia 3kademlia +protocol.5dasprotocol.reportDiscovery false + +protocol.6dasprotocol peersim.kademlia.das.DASProtocolNonValidator +protocol.6dasprotocol.transport 2unreltr +protocol.6dasprotocol.kademlia 3kademlia +protocol.6dasprotocol.reportDiscovery false + +protocol.7evildasprotocol peersim.kademlia.das.DASProtocolEvilValidator +protocol.7evildasprotocol.transport 2unreltr +protocol.7evildasprotocol.kademlia 3kademlia +protocol.7evildasprotocol.reportDiscovery false + +protocol.8evildasprotocol peersim.kademlia.das.DASProtocolEvilNonValidator +protocol.8evildasprotocol.transport 2unreltr +protocol.8evildasprotocol.kademlia 3kademlia +protocol.8evildasprotocol.reportDiscovery false + +# ::::: INITIALIZERS ::::: +#Class that initializes nodes with kademlia protocol and generates uniform ids +init.1uniqueNodeID peersim.kademlia.das.CustomDistributionDas +init.1uniqueNodeID.protocolkad 3kademlia +init.1uniqueNodeID.protocoldasbuilder 4dasprotocol +init.1uniqueNodeID.protocoldasvalidator 5dasprotocol +init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol +init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol +init.1uniqueNodeID.protocolEvildas 8evildasprotocol +init.1uniqueNodeID.validator_rate 0.5 +init.1uniqueNodeID.evilNodeRatioValidator 0.25 +init.1uniqueNodeID.evilNodeRatioNonValidator 0.25 + + +#Adds initial state to the routing tables +init.2statebuilder peersim.kademlia.StateBuilder +init.2statebuilder.protocol 3kademlia +init.2statebuilder.transport 2unreltr + +# ::::: CONTROLS ::::: + +#TrafficGenerator class sends and initial +control.0traffic peersim.kademlia.das.TrafficGeneratorSample +control.0traffic.step TRAFFIC_STEP +control.0traffic.mapping_fn 2 +control.0traffic.sample_copy_per_node 3 +control.0traffic.block_dim_size 100 +control.0traffic.num_samples 75 +control.0traffic.kadprotocol 3kademlia + +#TrafficGenerator class sends and initial +control.1refresh peersim.kademlia.das.RefreshSearchTable +control.1refresh.step REFRESH_STEP + +# turbulence non-validator + +#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +#control.2turbolenceAdd.protocolkad 3kademlia +#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.2turbolenceAdd.protocolEvildas 7evildasprotocol +#control.2turbolenceAdd.transport 2unreltr +#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +#control.2turbolenceAdd.p_idle 0.1 +#control.2turbolenceAdd.p_rem 0.45 +#control.2turbolenceAdd.p_add 0.45 + +# turbulence validators +#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +#control.3turbolenceAdd.protocolkad 3kademlia +#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.3turbolenceAdd.protocolEvildas 7evildasprotocol +#control.3turbolenceAdd.transport 2unreltr +#control.3turbolenceAdd.step TURBULENCE_STEP +#control.3turbolenceAdd.p_idle 0.9 +#control.3turbolenceAdd.p_rem 0.05 +#control.3turbolenceAdd.p_add 0.05 + +# ::::: OBSERVER ::::: +#The observer is executed every OBSERVER_STEP and will generate data traces +control.4 peersim.kademlia.KademliaObserver +control.4.protocol 3kademlia +control.4.step OBSERVER_STEP +control.4.logfolder logsDasEvil0.25 diff --git a/simulator/config/malicious/dasprotocolevil0.5.cfg b/simulator/config/malicious/dasprotocolevil0.5.cfg new file mode 100644 index 00000000..449d0878 --- /dev/null +++ b/simulator/config/malicious/dasprotocolevil0.5.cfg @@ -0,0 +1,153 @@ +# :::::::::::::::::::::::::::::::::`::::::::::::::::::::: +# :: Kademlia Default Configuration +# :::::::::::::::::::::::::::::::::::::::::::::::::::::: + +# ::::: GLOBAL :::::: + +# Network size +SIZE 10000 + +# Random seed +K 5 + +MINDELAY 5 +MAXDELAY 100 + +#Simulation time in ms +SIM_TIME 60001 + + +#Traffic generator is executed every TRAFFIC_STEP +TRAFFIC_STEP 12000 #10000000/SIZE +#Tracing module is executed every OBSERVER_STEP +OBSERVER_STEP 1000 +#Turbulence module is executed every TURBULENCE_STEP enabling churning +TURBULENCE_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 +REFRESH_STEP 1000 + +# add network config parameters to simulation +random.seed 24680 +simulation.experiments 1 +simulation.endtime SIM_TIME +network.size SIZE + + +# Peersim protocols enabled in each node + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.0link peersim.core.IdleProtocol + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.1pairwiselattr peersim.transport.PairwiseFixedLatencyTransport +protocol.1pairwiselattr.mindelay MINDELAY +protocol.1pairwiselattr.maxdelay MAXDELAY +protocol.1pairwiselattr.size SIZE + + +#transport layer that reliably delivers messages with a random delay, emulating TCP +protocol.2unreltr peersim.transport.UnreliableTransport +protocol.2unreltr.drop 0 +protocol.2unreltr.transport 1pairwiselattr + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.3kademlia peersim.kademlia.KademliaProtocol +protocol.3kademlia.transport 2unreltr +protocol.3kademlia.BITS 256 +protocol.3kademlia.NBUCKETS 17 +protocol.3kademlia.FINDMODE 1 + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.4dasprotocol peersim.kademlia.das.DASProtocolBuilder +protocol.4dasprotocol.transport 2unreltr +protocol.4dasprotocol.kademlia 3kademlia +protocol.4dasprotocol.reportDiscovery false + +protocol.5dasprotocol peersim.kademlia.das.DASProtocolValidator +protocol.5dasprotocol.transport 2unreltr +protocol.5dasprotocol.kademlia 3kademlia +protocol.5dasprotocol.reportDiscovery false + +protocol.6dasprotocol peersim.kademlia.das.DASProtocolNonValidator +protocol.6dasprotocol.transport 2unreltr +protocol.6dasprotocol.kademlia 3kademlia +protocol.6dasprotocol.reportDiscovery false + +protocol.7evildasprotocol peersim.kademlia.das.DASProtocolEvilValidator +protocol.7evildasprotocol.transport 2unreltr +protocol.7evildasprotocol.kademlia 3kademlia +protocol.7evildasprotocol.reportDiscovery false + +protocol.8evildasprotocol peersim.kademlia.das.DASProtocolEvilNonValidator +protocol.8evildasprotocol.transport 2unreltr +protocol.8evildasprotocol.kademlia 3kademlia +protocol.8evildasprotocol.reportDiscovery false + +# ::::: INITIALIZERS ::::: +#Class that initializes nodes with kademlia protocol and generates uniform ids +init.1uniqueNodeID peersim.kademlia.das.CustomDistributionDas +init.1uniqueNodeID.protocolkad 3kademlia +init.1uniqueNodeID.protocoldasbuilder 4dasprotocol +init.1uniqueNodeID.protocoldasvalidator 5dasprotocol +init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol +init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol +init.1uniqueNodeID.protocolEvildas 8evildasprotocol +init.1uniqueNodeID.validator_rate 0.5 +init.1uniqueNodeID.evilNodeRatioValidator 0.5 +init.1uniqueNodeID.evilNodeRatioNonValidator 0.5 + + +#Adds initial state to the routing tables +init.2statebuilder peersim.kademlia.StateBuilder +init.2statebuilder.protocol 3kademlia +init.2statebuilder.transport 2unreltr + +# ::::: CONTROLS ::::: + +#TrafficGenerator class sends and initial +control.0traffic peersim.kademlia.das.TrafficGeneratorSample +control.0traffic.step TRAFFIC_STEP +control.0traffic.mapping_fn 2 +control.0traffic.sample_copy_per_node 3 +control.0traffic.block_dim_size 512 +control.0traffic.num_samples 75 +control.0traffic.kadprotocol 3kademlia + +#TrafficGenerator class sends and initial +control.1refresh peersim.kademlia.das.RefreshSearchTable +control.1refresh.step REFRESH_STEP + +# turbulence non-validator +control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +control.2turbolenceAdd.protocolkad 3kademlia +control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +control.2turbolenceAdd.protocolEvildas 7evildasprotocol +control.2turbolenceAdd.transport 2unreltr +control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +control.2turbolenceAdd.p_idle 0.1 +control.2turbolenceAdd.p_rem 0.45 +control.2turbolenceAdd.p_add 0.45 + +# turbulence validators +control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +control.3turbolenceAdd.protocolkad 3kademlia +control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +control.3turbolenceAdd.protocolEvildas 7evildasprotocol +control.3turbolenceAdd.transport 2unreltr +control.3turbolenceAdd.step TURBULENCE_STEP +control.3turbolenceAdd.p_idle 0.9 +control.3turbolenceAdd.p_rem 0.05 +control.3turbolenceAdd.p_add 0.05 + +# ::::: OBSERVER ::::: +#The observer is executed every OBSERVER_STEP and will generate data traces +control.4 peersim.kademlia.KademliaObserver +control.4.protocol 3kademlia +control.4.step OBSERVER_STEP +control.4.logfolder logsDasEvil0.5 diff --git a/simulator/config/malicious/dasprotocolevil0.75.cfg b/simulator/config/malicious/dasprotocolevil0.75.cfg new file mode 100644 index 00000000..a473b6e8 --- /dev/null +++ b/simulator/config/malicious/dasprotocolevil0.75.cfg @@ -0,0 +1,154 @@ +# :::::::::::::::::::::::::::::::::`::::::::::::::::::::: +# :: Kademlia Default Configuration +# :::::::::::::::::::::::::::::::::::::::::::::::::::::: + +# ::::: GLOBAL :::::: + +# Network size +SIZE 5000 + +# Random seed +K 5 + +MINDELAY 5 +MAXDELAY 100 + +#Simulation time in ms +SIM_TIME 60001 + + +#Traffic generator is executed every TRAFFIC_STEP +TRAFFIC_STEP 12000 #10000000/SIZE +#Tracing module is executed every OBSERVER_STEP +OBSERVER_STEP 1000 +#Turbulence module is executed every TURBULENCE_STEP enabling churning +TURBULENCE_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 +REFRESH_STEP 1000 + +# add network config parameters to simulation +random.seed 24680 +simulation.experiments 1 +simulation.endtime SIM_TIME +network.size SIZE + + +# Peersim protocols enabled in each node + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.0link peersim.core.IdleProtocol + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.1pairwiselattr peersim.transport.PairwiseFixedLatencyTransport +protocol.1pairwiselattr.mindelay MINDELAY +protocol.1pairwiselattr.maxdelay MAXDELAY +protocol.1pairwiselattr.size SIZE + + +#transport layer that reliably delivers messages with a random delay, emulating TCP +protocol.2unreltr peersim.transport.UnreliableTransport +protocol.2unreltr.drop 0 +protocol.2unreltr.transport 1pairwiselattr + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.3kademlia peersim.kademlia.KademliaProtocol +protocol.3kademlia.transport 2unreltr +protocol.3kademlia.BITS 256 +protocol.3kademlia.NBUCKETS 17 +protocol.3kademlia.FINDMODE 1 + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.4dasprotocol peersim.kademlia.das.DASProtocolBuilder +protocol.4dasprotocol.transport 2unreltr +protocol.4dasprotocol.kademlia 3kademlia +protocol.4dasprotocol.reportDiscovery false + +protocol.5dasprotocol peersim.kademlia.das.DASProtocolValidator +protocol.5dasprotocol.transport 2unreltr +protocol.5dasprotocol.kademlia 3kademlia +protocol.5dasprotocol.reportDiscovery false + +protocol.6dasprotocol peersim.kademlia.das.DASProtocolNonValidator +protocol.6dasprotocol.transport 2unreltr +protocol.6dasprotocol.kademlia 3kademlia +protocol.6dasprotocol.reportDiscovery false + +protocol.7evildasprotocol peersim.kademlia.das.DASProtocolEvilValidator +protocol.7evildasprotocol.transport 2unreltr +protocol.7evildasprotocol.kademlia 3kademlia +protocol.7evildasprotocol.reportDiscovery false + +protocol.8evildasprotocol peersim.kademlia.das.DASProtocolEvilNonValidator +protocol.8evildasprotocol.transport 2unreltr +protocol.8evildasprotocol.kademlia 3kademlia +protocol.8evildasprotocol.reportDiscovery false + +# ::::: INITIALIZERS ::::: +#Class that initializes nodes with kademlia protocol and generates uniform ids +init.1uniqueNodeID peersim.kademlia.das.CustomDistributionDas +init.1uniqueNodeID.protocolkad 3kademlia +init.1uniqueNodeID.protocoldasbuilder 4dasprotocol +init.1uniqueNodeID.protocoldasvalidator 5dasprotocol +init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol +init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol +init.1uniqueNodeID.protocolEvildas 8evildasprotocol +init.1uniqueNodeID.validator_rate 0.5 +init.1uniqueNodeID.evilNodeRatioValidator 0.75 +init.1uniqueNodeID.evilNodeRatioNonValidator 0.75 + + +#Adds initial state to the routing tables +init.2statebuilder peersim.kademlia.StateBuilder +init.2statebuilder.protocol 3kademlia +init.2statebuilder.transport 2unreltr + +# ::::: CONTROLS ::::: + +#TrafficGenerator class sends and initial +control.0traffic peersim.kademlia.das.TrafficGeneratorSample +control.0traffic.step TRAFFIC_STEP +control.0traffic.mapping_fn 2 +control.0traffic.sample_copy_per_node 3 +control.0traffic.block_dim_size 100 +control.0traffic.num_samples 75 +control.0traffic.kadprotocol 3kademlia + +#TrafficGenerator class sends and initial +control.1refresh peersim.kademlia.das.RefreshSearchTable +control.1refresh.step REFRESH_STEP + +# turbulence non-validator + +#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +#control.2turbolenceAdd.protocolkad 3kademlia +#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.2turbolenceAdd.protocolEvildas 7evildasprotocol +#control.2turbolenceAdd.transport 2unreltr +#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +#control.2turbolenceAdd.p_idle 0.1 +#control.2turbolenceAdd.p_rem 0.45 +#control.2turbolenceAdd.p_add 0.45 + +# turbulence validators +#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +#control.3turbolenceAdd.protocolkad 3kademlia +#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.3turbolenceAdd.protocolEvildas 7evildasprotocol +#control.3turbolenceAdd.transport 2unreltr +#control.3turbolenceAdd.step TURBULENCE_STEP +#control.3turbolenceAdd.p_idle 0.9 +#control.3turbolenceAdd.p_rem 0.05 +#control.3turbolenceAdd.p_add 0.05 + +# ::::: OBSERVER ::::: +#The observer is executed every OBSERVER_STEP and will generate data traces +control.4 peersim.kademlia.KademliaObserver +control.4.protocol 3kademlia +control.4.step OBSERVER_STEP +control.4.logfolder logsDasEvil0.75 diff --git a/simulator/config/malicious/dasprotocolevil0.9.cfg b/simulator/config/malicious/dasprotocolevil0.9.cfg new file mode 100644 index 00000000..cb9c93f7 --- /dev/null +++ b/simulator/config/malicious/dasprotocolevil0.9.cfg @@ -0,0 +1,154 @@ +# :::::::::::::::::::::::::::::::::`::::::::::::::::::::: +# :: Kademlia Default Configuration +# :::::::::::::::::::::::::::::::::::::::::::::::::::::: + +# ::::: GLOBAL :::::: + +# Network size +SIZE 10000 + +# Random seed +K 5 + +MINDELAY 5 +MAXDELAY 100 + +#Simulation time in ms +SIM_TIME 60001 + + +#Traffic generator is executed every TRAFFIC_STEP +TRAFFIC_STEP 12000 #10000000/SIZE +#Tracing module is executed every OBSERVER_STEP +OBSERVER_STEP 1000 +#Turbulence module is executed every TURBULENCE_STEP enabling churning +TURBULENCE_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 +REFRESH_STEP 1000 + +# add network config parameters to simulation +random.seed 24680 +simulation.experiments 1 +simulation.endtime SIM_TIME +network.size SIZE + + +# Peersim protocols enabled in each node + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.0link peersim.core.IdleProtocol + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.1pairwiselattr peersim.transport.PairwiseFixedLatencyTransport +protocol.1pairwiselattr.mindelay MINDELAY +protocol.1pairwiselattr.maxdelay MAXDELAY +protocol.1pairwiselattr.size SIZE + + +#transport layer that reliably delivers messages with a random delay, emulating TCP +protocol.2unreltr peersim.transport.UnreliableTransport +protocol.2unreltr.drop 0 +protocol.2unreltr.transport 1pairwiselattr + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.3kademlia peersim.kademlia.KademliaProtocol +protocol.3kademlia.transport 2unreltr +protocol.3kademlia.BITS 256 +protocol.3kademlia.NBUCKETS 17 +protocol.3kademlia.FINDMODE 1 + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.4dasprotocol peersim.kademlia.das.DASProtocolBuilder +protocol.4dasprotocol.transport 2unreltr +protocol.4dasprotocol.kademlia 3kademlia +protocol.4dasprotocol.reportDiscovery false + +protocol.5dasprotocol peersim.kademlia.das.DASProtocolValidator +protocol.5dasprotocol.transport 2unreltr +protocol.5dasprotocol.kademlia 3kademlia +protocol.5dasprotocol.reportDiscovery false + +protocol.6dasprotocol peersim.kademlia.das.DASProtocolNonValidator +protocol.6dasprotocol.transport 2unreltr +protocol.6dasprotocol.kademlia 3kademlia +protocol.6dasprotocol.reportDiscovery false + +protocol.7evildasprotocol peersim.kademlia.das.DASProtocolEvilValidator +protocol.7evildasprotocol.transport 2unreltr +protocol.7evildasprotocol.kademlia 3kademlia +protocol.7evildasprotocol.reportDiscovery false + +protocol.8evildasprotocol peersim.kademlia.das.DASProtocolEvilNonValidator +protocol.8evildasprotocol.transport 2unreltr +protocol.8evildasprotocol.kademlia 3kademlia +protocol.8evildasprotocol.reportDiscovery false + +# ::::: INITIALIZERS ::::: +#Class that initializes nodes with kademlia protocol and generates uniform ids +init.1uniqueNodeID peersim.kademlia.das.CustomDistributionDas +init.1uniqueNodeID.protocolkad 3kademlia +init.1uniqueNodeID.protocoldasbuilder 4dasprotocol +init.1uniqueNodeID.protocoldasvalidator 5dasprotocol +init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol +init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol +init.1uniqueNodeID.protocolEvildas 8evildasprotocol +init.1uniqueNodeID.validator_rate 0.5 +init.1uniqueNodeID.evilNodeRatioValidator 0.9 +init.1uniqueNodeID.evilNodeRatioNonValidator 0.9 + + +#Adds initial state to the routing tables +init.2statebuilder peersim.kademlia.StateBuilder +init.2statebuilder.protocol 3kademlia +init.2statebuilder.transport 2unreltr + +# ::::: CONTROLS ::::: + +#TrafficGenerator class sends and initial +control.0traffic peersim.kademlia.das.TrafficGeneratorSample +control.0traffic.step TRAFFIC_STEP +control.0traffic.mapping_fn 2 +control.0traffic.sample_copy_per_node 3 +control.0traffic.block_dim_size 512 +control.0traffic.num_samples 75 +control.0traffic.kadprotocol 3kademlia + +#TrafficGenerator class sends and initial +control.1refresh peersim.kademlia.das.RefreshSearchTable +control.1refresh.step REFRESH_STEP + +# turbulence non-validator + +#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +#control.2turbolenceAdd.protocolkad 3kademlia +#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.2turbolenceAdd.protocolEvildas 7evildasprotocol +#control.2turbolenceAdd.transport 2unreltr +#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +#control.2turbolenceAdd.p_idle 0.1 +#control.2turbolenceAdd.p_rem 0.45 +#control.2turbolenceAdd.p_add 0.45 + +# turbulence validators +#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +#control.3turbolenceAdd.protocolkad 3kademlia +#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.3turbolenceAdd.protocolEvildas 7evildasprotocol +#control.3turbolenceAdd.transport 2unreltr +#control.3turbolenceAdd.step TURBULENCE_STEP +#control.3turbolenceAdd.p_idle 0.9 +#control.3turbolenceAdd.p_rem 0.05 +#control.3turbolenceAdd.p_add 0.05 + +# ::::: OBSERVER ::::: +#The observer is executed every OBSERVER_STEP and will generate data traces +control.4 peersim.kademlia.KademliaObserver +control.4.protocol 3kademlia +control.4.step OBSERVER_STEP +control.4.logfolder logsDasEvil0.9Test diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg new file mode 100644 index 00000000..078b8fab --- /dev/null +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -0,0 +1,154 @@ +# :::::::::::::::::::::::::::::::::`::::::::::::::::::::: +# :: Kademlia Default Configuration +# :::::::::::::::::::::::::::::::::::::::::::::::::::::: + +# ::::: GLOBAL :::::: + +# Network size +SIZE 1000 + +# Random seed +K 5 + +MINDELAY 5 +MAXDELAY 100 + +#Simulation time in ms +SIM_TIME 60001 + + +#Traffic generator is executed every TRAFFIC_STEP +TRAFFIC_STEP 12000 #10000000/SIZE +#Tracing module is executed every OBSERVER_STEP +OBSERVER_STEP 1000 +#Turbulence module is executed every TURBULENCE_STEP enabling churning +TURBULENCE_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 +REFRESH_STEP 1000 + +# add network config parameters to simulation +random.seed 24680 +simulation.experiments 1 +simulation.endtime SIM_TIME +network.size SIZE + + +# Peersim protocols enabled in each node + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.0link peersim.core.IdleProtocol + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.1pairwiselattr peersim.transport.PairwiseFixedLatencyTransport +protocol.1pairwiselattr.mindelay MINDELAY +protocol.1pairwiselattr.maxdelay MAXDELAY +protocol.1pairwiselattr.size SIZE + + +#transport layer that reliably delivers messages with a random delay, emulating TCP +protocol.2unreltr peersim.transport.UnreliableTransport +protocol.2unreltr.drop 0 +protocol.2unreltr.transport 1pairwiselattr + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.3kademlia peersim.kademlia.KademliaProtocol +protocol.3kademlia.transport 2unreltr +protocol.3kademlia.BITS 256 +protocol.3kademlia.NBUCKETS 17 +protocol.3kademlia.FINDMODE 1 + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.4dasprotocol peersim.kademlia.das.DASProtocolBuilder +protocol.4dasprotocol.transport 2unreltr +protocol.4dasprotocol.kademlia 3kademlia +protocol.4dasprotocol.reportDiscovery false + +protocol.5dasprotocol peersim.kademlia.das.DASProtocolValidator +protocol.5dasprotocol.transport 2unreltr +protocol.5dasprotocol.kademlia 3kademlia +protocol.5dasprotocol.reportDiscovery false + +protocol.6dasprotocol peersim.kademlia.das.DASProtocolNonValidator +protocol.6dasprotocol.transport 2unreltr +protocol.6dasprotocol.kademlia 3kademlia +protocol.6dasprotocol.reportDiscovery false + +protocol.7evildasprotocol peersim.kademlia.das.DASProtocolEvilValidator +protocol.7evildasprotocol.transport 2unreltr +protocol.7evildasprotocol.kademlia 3kademlia +protocol.7evildasprotocol.reportDiscovery false + +protocol.8evildasprotocol peersim.kademlia.das.DASProtocolEvilNonValidator +protocol.8evildasprotocol.transport 2unreltr +protocol.8evildasprotocol.kademlia 3kademlia +protocol.8evildasprotocol.reportDiscovery false + +# ::::: INITIALIZERS ::::: +#Class that initializes nodes with kademlia protocol and generates uniform ids +init.1uniqueNodeID peersim.kademlia.das.CustomDistributionDas +init.1uniqueNodeID.protocolkad 3kademlia +init.1uniqueNodeID.protocoldasbuilder 4dasprotocol +init.1uniqueNodeID.protocoldasvalidator 5dasprotocol +init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol +init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol +init.1uniqueNodeID.protocolEvildas 8evildasprotocol +init.1uniqueNodeID.validator_rate 0.5 +init.1uniqueNodeID.evilNodeRatioValidator 0.0 +init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 + + +#Adds initial state to the routing tables +init.2statebuilder peersim.kademlia.StateBuilder +init.2statebuilder.protocol 3kademlia +init.2statebuilder.transport 2unreltr + +# ::::: CONTROLS ::::: + +#TrafficGenerator class sends and initial +control.0traffic peersim.kademlia.das.TrafficGeneratorSample +control.0traffic.step TRAFFIC_STEP +control.0traffic.mapping_fn 2 +control.0traffic.sample_copy_per_node 2 +control.0traffic.block_dim_size 100 +control.0traffic.num_samples 75 +control.0traffic.kadprotocol 3kademlia + +#TrafficGenerator class sends and initial +control.1refresh peersim.kademlia.das.RefreshSearchTable +control.1refresh.step REFRESH_STEP + +# turbulence non-validator + +#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +#control.2turbolenceAdd.protocolkad 3kademlia +#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.2turbolenceAdd.protocolEvildas 7evildasprotocol +#control.2turbolenceAdd.transport 2unreltr +#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +#control.2turbolenceAdd.p_idle 0.1 +#control.2turbolenceAdd.p_rem 0.45 +#control.2turbolenceAdd.p_add 0.45 + +# turbulence validators +#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +#control.3turbolenceAdd.protocolkad 3kademlia +#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.3turbolenceAdd.protocolEvildas 7evildasprotocol +#control.3turbolenceAdd.transport 2unreltr +#control.3turbolenceAdd.step TURBULENCE_STEP +#control.3turbolenceAdd.p_idle 0.9 +#control.3turbolenceAdd.p_rem 0.05 +#control.3turbolenceAdd.p_add 0.05 + +# ::::: OBSERVER ::::: +#The observer is executed every OBSERVER_STEP and will generate data traces +control.4 peersim.kademlia.KademliaObserver +control.4.protocol 3kademlia +control.4.step OBSERVER_STEP +control.4.logfolder logsDasEvil0 From 137bc86e318e03b25190125a42a03b73aa04f301 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Fri, 29 Dec 2023 20:14:01 +0100 Subject: [PATCH 62/98] cleaning --- .../config/malicious/dasprotocolevil0.cfg | 4 +- .../peersim/kademlia/das/DASProtocol.java | 2 +- .../kademlia/das/DASProtocolBuilder.java | 122 +++++++++--------- .../kademlia/das/DASProtocolNonValidator.java | 10 +- .../kademlia/das/TrafficGeneratorSample.java | 34 ----- 5 files changed, 66 insertions(+), 106 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg index 078b8fab..f8f8ced1 100644 --- a/simulator/config/malicious/dasprotocolevil0.cfg +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -94,7 +94,7 @@ init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol init.1uniqueNodeID.protocolEvildas 8evildasprotocol -init.1uniqueNodeID.validator_rate 0.5 +init.1uniqueNodeID.validator_rate 1.0 init.1uniqueNodeID.evilNodeRatioValidator 0.0 init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 @@ -111,7 +111,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 100 +control.0traffic.block_dim_size 512 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 4844df89..aa9e8f48 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -626,7 +626,7 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { if (m.getType() == Message.MSG_GET_SAMPLE) { // is a request Timeout t = new Timeout(destId, m.id, m.operationId); long latency = transport.getLatency(src, dest); - logger.warning("Send message added " + m.id + " " + latency + " " + destId); + logger.info("Send message added " + m.id + " " + latency + " " + destId); // add to sent msg this.sentMsg.put(m.id, m.timestamp); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index 7c4f38b8..e74e3975 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -54,83 +54,83 @@ protected void handleInitNewBlock(Message m, int myPid) { KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, searchTable.getValidatorsIndexed().size()); - while (!inRegion) { + // while (!inRegion) { - List idsValidators = - searchTable.getValidatorNodesbySample(s.getIdByRow(), radiusValidator); + List idsValidators = + searchTable.getValidatorNodesbySample(s.getIdByRow(), radiusValidator); - for (BigInteger id : idsValidators) { + for (BigInteger id : idsValidators) { - logger.info( - "Sending sample to validator " - + s.getIdByRow() - + " " - + s.getIdByColumn() - + " to " - + id); - Node n = Util.nodeIdtoNode(id, kademliaId); - DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); - if (dasProt.isBuilder()) continue; - if (n.isUp()) { + logger.info( + "Sending sample to validator " + + s.getIdByRow() + + " " + + s.getIdByColumn() + + " to " + + id); + Node n = Util.nodeIdtoNode(id, kademliaId); + DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); + if (dasProt.isBuilder()) continue; + if (n.isUp()) { - if (!samplesToRequest.containsKey(id)) { - List samples = new ArrayList<>(); - samples.add(s.getId()); - samplesToRequest.put(id, samples); - } else { - samplesToRequest.get(id).add(s.getId()); - } - samplesValidators++; - if (inRegion == false) { - samplesWithinRegion++; - inRegion = true; - } + if (!samplesToRequest.containsKey(id)) { + List samples = new ArrayList<>(); + samples.add(s.getId()); + samplesToRequest.put(id, samples); + } else { + samplesToRequest.get(id).add(s.getId()); + } + samplesValidators++; + if (inRegion == false) { + samplesWithinRegion++; + inRegion = true; } } - // if (!inRegion) notInRegion++; - if (!inRegion) radiusValidator = radiusValidator.multiply(BigInteger.valueOf(2)); } + // if (!inRegion) notInRegion++; + // if (!inRegion) radiusValidator = radiusValidator.multiply(BigInteger.valueOf(2)); + // } inRegion = false; - while (!inRegion) { + // while (!inRegion) { - List idsValidators = - searchTable.getValidatorNodesbySample(s.getIdByColumn(), radiusValidator); + // List idsValidators = + idsValidators = searchTable.getValidatorNodesbySample(s.getIdByColumn(), radiusValidator); - /* + " " - + +idsNonValidators.size());*/ + /* + " " + + +idsNonValidators.size());*/ - for (BigInteger id : idsValidators) { + for (BigInteger id : idsValidators) { - logger.info( - "Sending sample to validator " - + s.getIdByRow() - + " " - + s.getIdByColumn() - + " to " - + id); - Node n = Util.nodeIdtoNode(id, kademliaId); - DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); - if (dasProt.isBuilder()) continue; - if (n.isUp()) { + logger.info( + "Sending sample to validator " + + s.getIdByRow() + + " " + + s.getIdByColumn() + + " to " + + id); + Node n = Util.nodeIdtoNode(id, kademliaId); + DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); + if (dasProt.isBuilder()) continue; + if (n.isUp()) { - if (!samplesToRequest.containsKey(id)) { - List samples = new ArrayList<>(); - samples.add(s.getId()); - samplesToRequest.put(id, samples); - } else { - samplesToRequest.get(id).add(s.getId()); - } - samplesValidators++; - if (inRegion == false) { - samplesWithinRegionColumn++; - inRegion = true; - } + if (!samplesToRequest.containsKey(id)) { + List samples = new ArrayList<>(); + samples.add(s.getId()); + samplesToRequest.put(id, samples); + } else { + samplesToRequest.get(id).add(s.getId()); + } + samplesValidators++; + if (inRegion == false) { + samplesWithinRegionColumn++; + inRegion = true; } } - // if (!inRegion) notInRegion++; - - if (!inRegion) radiusValidator = radiusValidator.multiply(BigInteger.valueOf(2)); } + // if (!inRegion) notInRegion++; + + // if (!inRegion) radiusValidator = radiusValidator.multiply(BigInteger.valueOf(2)); + // } List idsNonValidators = searchTable.getNonValidatorNodesbySample(s.getIdByRow(), radiusNonValidator); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java index 0fc90331..60356023 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java @@ -50,15 +50,9 @@ protected void handleInitNewBlock(Message m, int myPid) { logger.warning("Init block non-validator node - start sampling " + this); // super.handleInitNewBlock(m, myPid); validatorsContacted.clear(); - if (first) super.handleInitNewBlock(m, myPid); + super.handleInitNewBlock(m, myPid); if (!isEvil) { - if (first) { - startRandomSampling(); - // first = false; - } else { - // startRandomSampling(); - first = true; - } + startRandomSampling(); } } diff --git a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java index 9fcd0994..6633418b 100755 --- a/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java +++ b/simulator/src/main/java/peersim/kademlia/das/TrafficGeneratorSample.java @@ -40,7 +40,6 @@ public class TrafficGeneratorSample implements Control { Block b; private long ID_GENERATOR = 0; long lastTime = 0; - private boolean first = true, second = false; // ______________________________________________________________________________________________ public TrafficGeneratorSample(String prefix) { @@ -78,47 +77,14 @@ private Message generateNewBlockMessage(Block b) { */ public boolean execute() { Block b = new Block(KademliaCommonConfigDas.BLOCK_DIM_SIZE, ID_GENERATOR); - System.out.println(CommonState.getTime() + " next"); - /*if (first) { - for (int i = 0; i < Network.size(); i++) { - Node start = Network.get(i); - if (start.isUp()) { - for (int j = 0; j < 3; j++) { - // send message - EDSimulator.add( - CommonState.r.nextInt(12000), Util.generateFindNodeMessage(), start, kadpid); - } - EDSimulator.add( - 0, - Util.generateFindNodeMessage(start.getKademliaProtocol().getKademliaNode().getId()), - start, - kadpid); - } - } - first = false; - second = true; - } else if (second) {*/ - // SearchTable.createSampleMap(b); for (int i = 0; i < Network.size(); i++) { Node n = Network.get(i); - // b.initIterator(); - // we add 1 ms delay to be sure the builder starts before validators. - /*EDSimulator.add( - CommonState.r.nextLong(CommonState.getTime() - lastTime), - Util.generateFindNodeMessage(), - n, - kadpid);*/ - if (n.isUp()) { EDSimulator.add(0, generateNewBlockMessage(b), n, n.getDASProtocol().getDASProtocolID()); - // EDSimulator.add(10, generateNewBlockMessage(b), n, - // n.getDASProtocol().getDASProtocolID()); } } ID_GENERATOR++; - second = false; - // } lastTime = CommonState.getTime(); return false; } From 94795f60d468deffd4fa823c1a266f4783a081a9 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sat, 30 Dec 2023 18:42:49 +0100 Subject: [PATCH 63/98] all nodes known --- .../config/malicious/dasprotocolevil0.cfg | 8 +-- .../main/java/peersim/kademlia/das/Block.java | 3 +- .../kademlia/das/CustomDistributionDas.java | 6 ++- .../peersim/kademlia/das/DASProtocol.java | 28 +++++----- .../kademlia/das/DASProtocolBuilder.java | 52 ++----------------- .../kademlia/das/DASProtocolNonValidator.java | 5 +- .../kademlia/das/DASProtocolValidator.java | 12 ++--- .../kademlia/das/KademliaCommonConfigDas.java | 4 +- .../operations/RandomSamplingOperation.java | 18 +++++-- .../ValidatorSamplingOperation.java | 36 ++++++++----- 10 files changed, 74 insertions(+), 98 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg index f8f8ced1..1df7cbcb 100644 --- a/simulator/config/malicious/dasprotocolevil0.cfg +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 1000 +SIZE 5000 # Random seed K 5 @@ -14,7 +14,7 @@ MINDELAY 5 MAXDELAY 100 #Simulation time in ms -SIM_TIME 60001 +SIM_TIME 11999 #Traffic generator is executed every TRAFFIC_STEP @@ -24,7 +24,7 @@ OBSERVER_STEP 1000 #Turbulence module is executed every TURBULENCE_STEP enabling churning TURBULENCE_STEP 1000 TURBULENCE_STEP_NONVAL 1000 -REFRESH_STEP 1000 +REFRESH_STEP 10000000 # add network config parameters to simulation random.seed 24680 @@ -94,7 +94,7 @@ init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol init.1uniqueNodeID.protocolEvildas 8evildasprotocol -init.1uniqueNodeID.validator_rate 1.0 +init.1uniqueNodeID.validator_rate 0.5 init.1uniqueNodeID.evilNodeRatioValidator 0.0 init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 diff --git a/simulator/src/main/java/peersim/kademlia/das/Block.java b/simulator/src/main/java/peersim/kademlia/das/Block.java index a87ad93a..98ccba15 100644 --- a/simulator/src/main/java/peersim/kademlia/das/Block.java +++ b/simulator/src/main/java/peersim/kademlia/das/Block.java @@ -283,7 +283,8 @@ public int findClosestRow(BigInteger nodeid, BigInteger radius) { for (BigInteger id : subSet) { rows.add(sampleMap.get(id).getRow()); } - System.out.println(rows.size() + " " + KademliaCommonConfigDas.validatorsSize + " " + radius); + // System.out.println(rows.size() + " " + KademliaCommonConfigDas.validatorsSize + " " + + // radius); return Util.mostCommon(rows); } diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index bc7850b0..160b52ca 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -163,9 +163,11 @@ public boolean execute() { dasEvil.setEvilIds(evilNodes); } } - int k = 0; + /*int k = 0; while (k < 100) { + // while (k> missingSamples; - protected boolean first; - /** * Replicate this object by returning an identical copy.
* It is called by the initializer and do not fill any particular field. @@ -112,7 +110,6 @@ public abstract class DASProtocol implements Cloneable, EDProtocol, KademliaEven */ public DASProtocol(String prefix) { - first = true; DASProtocol.prefix = prefix; isEvil = false; _init(); @@ -195,7 +192,7 @@ public void processEvent(Node myNode, int myPid, Object event) { break; case Message.MSG_GET_SAMPLE_RESPONSE: m = (Message) event; - // logger.warning("Send message removed " + m.ackId); + logger.warning("Send message removed " + m.ackId); sentMsg.remove(m.ackId); handleGetSampleResponse(m, myPid); break; @@ -205,7 +202,7 @@ public void processEvent(Node myNode, int myPid, Object event) { SamplingOperation sop = samplingOp.get(t.opID); if (sentMsg.containsKey(t.msgID)) { // the response msg isn't arrived // remove form sentMsg - logger.warning("Timeouuuuut! " + t.msgID); + logger.warning("Timeouuuuut! " + t.msgID + " " + t.node); sentMsg.remove(t.msgID); // this.searchTable.removeNode(t.node); if (sop != null) { @@ -414,8 +411,8 @@ protected void handleGetSampleResponse(Message m, int myPid) { } for (Sample s : samples) { - // logger.warning( - // "Sample received " + s.getId() + " " + s.getIdByColumn() + " from " + m.src.getId()); + logger.info( + "Sample received " + s.getId() + " " + s.getIdByColumn() + " from " + m.src.getId()); kv.add((BigInteger) s.getIdByRow(), s); // kv.add((BigInteger) s.getIdByColumn(), s); @@ -423,7 +420,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { reconstruct(s); } if (samplingOp.get(m.operationId) != null) - logger.warning( + logger.info( "Samples received " + samples.length + " from " @@ -433,7 +430,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { + " " + kv.occupancy()); else - logger.warning( + logger.info( "Samples received " + samples.length + " from " + m.src.getId() + " " + kv.occupancy()); HashMap> toSend = findMissingSamples(samples); @@ -452,7 +449,8 @@ protected void handleGetSampleResponse(Message m, int myPid) { KademliaCommonConfigDas.MAX_NODES_RETURNED * toSend.get(msg).size()); if (isEvil) response.value = searchTable.getEvilNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED); - // logger.warning("Sending sample to " + msg.src.getId()); + for (Sample s : samplesToSend) + logger.info("Sending sample cached " + s.getId() + " to " + msg.src.getId() + " " + msg.id); sendMessage(response, msg.src.getId(), myPid); } toSend.clear(); @@ -630,7 +628,7 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { // add to sent msg this.sentMsg.put(m.id, m.timestamp); - EDSimulator.add(400, t, src, myPid); // set delay = 2*RTT + EDSimulator.add(latency * 8 + 200, t, src, myPid); // set delay = 2*RTT } } @@ -677,12 +675,14 @@ public void addKnownValidator(BigInteger[] ids) { logger.info("Adding validator list " + ids.length); // validatorsList = ids; // if (validatorsList != null && isBuilder()) searchTable.addValidatorNodes(validatorsList); - if (isBuilder()) searchTable.addValidatorNodes(ids); + // if (isBuilder()) + searchTable.addValidatorNodes(ids); } public void setNonValidators(List nonValidators) { - if (isBuilder()) searchTable.addNodes(nonValidators.toArray(new BigInteger[0])); + // if (isBuilder()) + searchTable.addNodes(nonValidators.toArray(new BigInteger[0])); } public SearchTable getSearchTable() { @@ -732,7 +732,7 @@ protected boolean doSampling(SamplingOperation sop) { BigInteger[] nextNodes = sop.doSampling(); for (BigInteger nextNode : nextNodes) { BigInteger[] reqSamples = sop.getSamples(); - logger.warning( + logger.info( "sending to node " + nextNode + " " diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index e74e3975..77035a1e 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -43,7 +43,6 @@ protected void handleInitNewBlock(Message m, int myPid) { BigInteger radiusNonValidator = currentBlock.computeRegionRadius(KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); - int notInRegion = 0; while (currentBlock.hasNext()) { boolean inRegion = false; Sample s = currentBlock.next(); @@ -58,7 +57,8 @@ protected void handleInitNewBlock(Message m, int myPid) { List idsValidators = searchTable.getValidatorNodesbySample(s.getIdByRow(), radiusValidator); - + idsValidators.addAll( + searchTable.getValidatorNodesbySample(s.getIdByColumn(), radiusValidator)); for (BigInteger id : idsValidators) { logger.info( @@ -87,50 +87,6 @@ protected void handleInitNewBlock(Message m, int myPid) { } } } - // if (!inRegion) notInRegion++; - // if (!inRegion) radiusValidator = radiusValidator.multiply(BigInteger.valueOf(2)); - // } - inRegion = false; - // while (!inRegion) { - - // List idsValidators = - idsValidators = searchTable.getValidatorNodesbySample(s.getIdByColumn(), radiusValidator); - - /* + " " - + +idsNonValidators.size());*/ - - for (BigInteger id : idsValidators) { - - logger.info( - "Sending sample to validator " - + s.getIdByRow() - + " " - + s.getIdByColumn() - + " to " - + id); - Node n = Util.nodeIdtoNode(id, kademliaId); - DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); - if (dasProt.isBuilder()) continue; - if (n.isUp()) { - - if (!samplesToRequest.containsKey(id)) { - List samples = new ArrayList<>(); - samples.add(s.getId()); - samplesToRequest.put(id, samples); - } else { - samplesToRequest.get(id).add(s.getId()); - } - samplesValidators++; - if (inRegion == false) { - samplesWithinRegionColumn++; - inRegion = true; - } - } - } - // if (!inRegion) notInRegion++; - - // if (!inRegion) radiusValidator = radiusValidator.multiply(BigInteger.valueOf(2)); - // } List idsNonValidators = searchTable.getNonValidatorNodesbySample(s.getIdByRow(), radiusNonValidator); @@ -187,9 +143,7 @@ protected void handleInitNewBlock(Message m, int myPid) { + " " + samplesValidators + " " - + samplesNonValidators - + " " - + notInRegion); + + samplesNonValidators); } @Override diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java index 60356023..aafa0d89 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java @@ -23,7 +23,6 @@ public DASProtocolNonValidator(String prefix) { @Override protected void handleInitGetSample(Message m, int myPid) { if (!init) return; - logger.warning("Init block non-validator node - getting samples " + this); if (currentBlock == null) System.err.println("Error block not init yet"); BigInteger[] samples = (BigInteger[]) m.body; BigInteger radius = @@ -31,6 +30,7 @@ protected void handleInitGetSample(Message m, int myPid) { KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, searchTable.getValidatorsIndexed().size()); for (BigInteger sample : samples) { + logger.warning("Init block non-validator node - getting samples " + sample); for (BigInteger id : searchTable.getValidatorNodesbySample(sample, radius)) { if (!validatorsContacted.contains(id)) { Message msg = generateGetSampleMessage(samples); @@ -40,6 +40,7 @@ protected void handleInitGetSample(Message m, int myPid) { msg.dst = n.getKademliaProtocol().getKademliaNode(); sendMessage(msg, id, myPid); validatorsContacted.add(id); + break; } } } @@ -52,7 +53,7 @@ protected void handleInitNewBlock(Message m, int myPid) { validatorsContacted.clear(); super.handleInitNewBlock(m, myPid); if (!isEvil) { - startRandomSampling(); + // startRandomSampling(); } } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index 4cac1ea5..ac0d250f 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -35,16 +35,10 @@ protected void handleInitGetSample(Message m, int myPid) { @Override protected void handleInitNewBlock(Message m, int myPid) { - if (first) super.handleInitNewBlock(m, myPid); + super.handleInitNewBlock(m, myPid); if (!isEvil) { - if (first) { - startRowsandColumnsSampling(); - startRandomSampling(); - // first = false; - } else { - // startRandomSampling(); - first = true; - } + startRowsandColumnsSampling(); + // startRandomSampling(); } } diff --git a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java index daac4aed..0817206b 100644 --- a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java @@ -48,10 +48,10 @@ public class KademliaCommonConfigDas { public static int MAX_HOPS = 5000; /** Default upload bandwith of a validator in Mbits/sec */ - public static int VALIDATOR_UPLOAD_RATE = 100; + public static int VALIDATOR_UPLOAD_RATE = 1000; /** Default upload bandwith of a non-validator in Mbits/sec */ - public static int NON_VALIDATOR_UPLOAD_RATE = 1000; + public static int NON_VALIDATOR_UPLOAD_RATE = 100; public static int BUILDER_UPLOAD_RATE = 50000; diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index c3aeb293..58b51a15 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -138,12 +138,24 @@ protected void createNodes() { List nodesBySample = new ArrayList<>(); - BigInteger radiusUsed = radiusValidator; + // BigInteger radiusUsed = radiusValidator; // while (nodesBySample.isEmpty() && radiusUsed.compareTo(Block.MAX_KEY) == -1) { - nodesBySample.addAll(searchTable.getNodesbySample(samples.get(sample).getId(), radiusUsed)); + // nodesBySample.addAll(searchTable.getNodesbySample(samples.get(sample).getId(), + // radiusUsed)); + // nodesBySample.addAll( + // searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusUsed)); nodesBySample.addAll( - searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusUsed)); + searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusValidator)); + nodesBySample.addAll( + searchTable.getValidatorNodesbySample( + samples.get(sample).getIdByColumn(), radiusValidator)); + nodesBySample.addAll( + searchTable.getNonValidatorNodesbySample( + samples.get(sample).getId(), radiusNonValidator)); + nodesBySample.addAll( + searchTable.getNonValidatorNodesbySample( + samples.get(sample).getIdByColumn(), radiusNonValidator)); // radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); // } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index e60335fd..f23bdf5c 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -168,20 +168,32 @@ protected void createNodes() { List nodesBySample = new ArrayList<>(); if (row > 0) { - BigInteger radiusUsed = radiusValidator; - while (nodesBySample.isEmpty() && radiusUsed.compareTo(Block.MAX_KEY) == -1) { - nodesBySample.addAll( - searchTable.getNodesbySample(samples.get(sample).getId(), radiusUsed)); - radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); - } + // BigInteger radiusUsed = radiusValidator; + // while (nodesBySample.isEmpty() && radiusUsed.compareTo(Block.MAX_KEY) == -1) { + // nodesBySample.addAll( + // searchTable.getNodesbySample(samples.get(sample).getId(), radiusUsed)); + nodesBySample.addAll( + searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusValidator)); + nodesBySample.addAll( + searchTable.getNonValidatorNodesbySample( + samples.get(sample).getId(), radiusNonValidator)); + + // radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); + // } } else { - BigInteger radiusUsed = radiusValidator; - while (nodesBySample.isEmpty() && radiusUsed.compareTo(Block.MAX_KEY) == -1) { - nodesBySample.addAll( - searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusUsed)); + // BigInteger radiusUsed = radiusValidator; + // while (nodesBySample.isEmpty() && radiusUsed.compareTo(Block.MAX_KEY) == -1) { + // nodesBySample.addAll( + // searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusUsed)); + nodesBySample.addAll( + searchTable.getValidatorNodesbySample( + samples.get(sample).getIdByColumn(), radiusValidator)); + nodesBySample.addAll( + searchTable.getNonValidatorNodesbySample( + samples.get(sample).getIdByColumn(), radiusNonValidator)); - radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); - } + // radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); + // } } boolean found = false; nodesBySample.removeAll(askedNodes); From bd8ee8410619e5f87caad9e0df3d54ea3b3d7c4f Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sat, 30 Dec 2023 19:05:03 +0100 Subject: [PATCH 64/98] adding extra nodes disables --- simulator/config/malicious/dasprotocolevil0.cfg | 2 +- simulator/src/main/java/peersim/kademlia/das/DASProtocol.java | 2 +- .../src/main/java/peersim/kademlia/das/operations/Node.java | 1 - .../java/peersim/kademlia/das/operations/SamplingOperation.java | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg index 1df7cbcb..0f527cdf 100644 --- a/simulator/config/malicious/dasprotocolevil0.cfg +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 5000 +SIZE 1000 # Random seed K 5 diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index b7afe07e..e2b587aa 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -192,7 +192,7 @@ public void processEvent(Node myNode, int myPid, Object event) { break; case Message.MSG_GET_SAMPLE_RESPONSE: m = (Message) event; - logger.warning("Send message removed " + m.ackId); + logger.info("Send message removed " + m.ackId); sentMsg.remove(m.ackId); handleGetSampleResponse(m, myPid); break; diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/Node.java b/simulator/src/main/java/peersim/kademlia/das/operations/Node.java index 8d39898d..de41bad5 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/Node.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/Node.java @@ -46,7 +46,6 @@ public int getScore() { int score = 0; for (FetchingSample s : samples) { - if (!s.isDownloaded() && s.beingFetchedFrom.size() < aggressiveness) { score += 1; } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index cb35a37e..d371faac 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -146,7 +146,7 @@ public BigInteger[] doSampling() { if (nodes.isEmpty()) { createNodes(); - addExtraNodes(); + // addExtraNodes(); System.out.println( "[" + CommonState.getTime() From a5b8ce24a2757b1c0893995e693fca6210a6a8d3 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sun, 31 Dec 2023 11:02:53 +0100 Subject: [PATCH 65/98] minor --- simulator/config/malicious/dasprotocolevil0.cfg | 2 +- .../src/main/java/peersim/kademlia/das/DASProtocolBuilder.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg index 0f527cdf..7302cfcc 100644 --- a/simulator/config/malicious/dasprotocolevil0.cfg +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -20,7 +20,7 @@ SIM_TIME 11999 #Traffic generator is executed every TRAFFIC_STEP TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP -OBSERVER_STEP 1000 +OBSERVER_STEP 100000 #Turbulence module is executed every TURBULENCE_STEP enabling churning TURBULENCE_STEP 1000 TURBULENCE_STEP_NONVAL 1000 diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index 77035a1e..d9ee82ba 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -47,7 +47,7 @@ protected void handleInitNewBlock(Message m, int myPid) { boolean inRegion = false; Sample s = currentBlock.next(); kv.add(s.getId(), s); - kv.add(s.getIdByColumn(), s); + // kv.add(s.getIdByColumn(), s); BigInteger radiusValidator = currentBlock.computeRegionRadius( KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, From 13039a446827179a0fc4b4822d4bf999841986f2 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sun, 31 Dec 2023 23:08:54 +0100 Subject: [PATCH 66/98] single search table --- .../kademlia/das/CustomDistributionDas.java | 15 ++++++---- .../peersim/kademlia/das/DASProtocol.java | 29 ++++++++++--------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index 160b52ca..db1042dc 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -146,13 +146,18 @@ public boolean execute() { System.out.println("Validators " + validatorsIds.size()); System.out.println("Non-Validators " + nonValidatorsIds.size()); + SearchTable searchTable = new SearchTable(); + searchTable.addNodes(nonValidatorsIds.toArray(new BigInteger[0])); + searchTable.addValidatorNodes(validatorsIds.toArray(new BigInteger[0])); + searchTable.setEvilIds(evilNodes); + // for (DASProtocol validator : validators) { for (int i = 0; i < Network.size(); i++) { Node generalNode = Network.get(i); - generalNode.getDASProtocol().setNonValidators(nonValidatorsIds); - generalNode.getDASProtocol().addKnownValidator(validatorsIds.toArray(new BigInteger[0])); - - if (generalNode.getDASProtocol().isEvil()) { + //generalNode.getDASProtocol().setNonValidators(nonValidatorsIds); + //generalNode.getDASProtocol().addKnownValidator(validatorsIds.toArray(new BigInteger[0])); + generalNode.getDASProtocol().setSearchTable(searchTable); + /*if (generalNode.getDASProtocol().isEvil()) { if (generalNode.getDASProtocol() instanceof DASProtocolEvilValidator) { DASProtocolEvilValidator dasEvil = (DASProtocolEvilValidator) generalNode.getDASProtocol(); @@ -162,7 +167,7 @@ public boolean execute() { (DASProtocolEvilNonValidator) generalNode.getDASProtocol(); dasEvil.setEvilIds(evilNodes); } - } + }*/ /*int k = 0; while (k < 100) { // while (k(); - searchTable = new SearchTable(); + //searchTable = new SearchTable(); isBuilder = false; missingSamples = new HashMap<>(); init = false; @@ -152,6 +152,9 @@ private void _init() { _ALREADY_INSTALLED = true; } + public void setSearchTable(SearchTable searchTable){ + this.searchTable = searchTable; + } /** * manage the peersim receiving of the events * @@ -167,10 +170,10 @@ public void processEvent(Node myNode, int myPid, Object event) { m = (Message) event; // m.dst = this.kadProtocol.getKademliaNode(); if (msgReport) KademliaObserver.reportMsg(m, false); - if (m.src != null) { + /*if (m.src != null) { Node n = Util.nodeIdtoNode(m.src.getId(), kademliaId); searchTable.addNeighbour(new Neighbour(m.src.getId(), n, n.getDASProtocol().isEvil())); - } + }*/ } switch (((SimpleEvent) event).getType()) { @@ -365,13 +368,13 @@ protected void handleGetSample(Message m, int myPid) { response.dst = m.src; response.src = this.kadProtocol.getKademliaNode(); response.ackId = m.id; // set ACK number - response.value = + /*response.value = searchTable.getNeighbours( KademliaCommonConfigDas.MAX_NODES_RETURNED * samplesToSend.size()); if (isEvil) response.value = searchTable.getEvilNeighbours( - KademliaCommonConfigDas.MAX_NODES_RETURNED * samplesToSend.size()); + KademliaCommonConfigDas.MAX_NODES_RETURNED * samplesToSend.size());*/ sendMessage(response, m.src.getId(), myPid); } } @@ -671,7 +674,7 @@ protected int columnWithHighestNumSamples() { return max; } - public void addKnownValidator(BigInteger[] ids) { + /*public void addKnownValidator(BigInteger[] ids) { logger.info("Adding validator list " + ids.length); // validatorsList = ids; // if (validatorsList != null && isBuilder()) searchTable.addValidatorNodes(validatorsList); @@ -683,7 +686,7 @@ public void setNonValidators(List nonValidators) { // if (isBuilder()) searchTable.addNodes(nonValidators.toArray(new BigInteger[0])); - } + }*/ public SearchTable getSearchTable() { return searchTable; @@ -786,10 +789,10 @@ public void operationComplete(Operation op) { List list = fop.getNeighboursList(); list.remove(builderAddress); // searchTable.addNodes(list.toArray(new BigInteger[0])); - for (BigInteger id : list) { + /*for (BigInteger id : list) { Node n = Util.nodeIdtoNode(id, kademliaId); searchTable.addNeighbour(new Neighbour(id, n, n.getDASProtocol().isEvil())); - } + }*/ } } @@ -807,10 +810,10 @@ public void nodesFound(Operation op, BigInteger[] neighbours) { return; } // searchTable.addNodes(list.toArray(new BigInteger[0])); - for (BigInteger id : list) { + /*for (BigInteger id : list) { Node n = Util.nodeIdtoNode(id, kademliaId); searchTable.addNeighbour(new Neighbour(id, n, n.getDASProtocol().isEvil())); - } + }*/ } @Override @@ -848,7 +851,7 @@ protected Message generateNewSampleMessage(BigInteger[] s) { return m; } - public void refreshSearchTable() { + /*public void refreshSearchTable() { searchTable.refresh(); - } + }*/ } From c1874861bb51b6678fd88cf3ec2bac29ebe2f732 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sun, 31 Dec 2023 23:25:09 +0100 Subject: [PATCH 67/98] fixing --- .../kademlia/das/CustomDistributionDas.java | 9 +++-- .../peersim/kademlia/das/DASProtocol.java | 36 +++++++++---------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index db1042dc..9dc44e56 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -128,7 +128,7 @@ public boolean execute() { dasProt.setKademliaProtocol(kadProt); kadProt.setEventsCallback(dasProt); - dasProt.setBuilderAddress(builderAddress); + // dasProt.setBuilderAddress(builderAddress); if (dasProt instanceof DASProtocolBuilder) System.out.println("DASProtocol Builder " + i); generalNode.setProtocol(protocolKadID, kadProt); @@ -147,6 +147,7 @@ public boolean execute() { System.out.println("Non-Validators " + nonValidatorsIds.size()); SearchTable searchTable = new SearchTable(); + searchTable.setBuilderAddress(builderAddress); searchTable.addNodes(nonValidatorsIds.toArray(new BigInteger[0])); searchTable.addValidatorNodes(validatorsIds.toArray(new BigInteger[0])); searchTable.setEvilIds(evilNodes); @@ -154,9 +155,11 @@ public boolean execute() { // for (DASProtocol validator : validators) { for (int i = 0; i < Network.size(); i++) { Node generalNode = Network.get(i); - //generalNode.getDASProtocol().setNonValidators(nonValidatorsIds); - //generalNode.getDASProtocol().addKnownValidator(validatorsIds.toArray(new BigInteger[0])); + // generalNode.getDASProtocol().setNonValidators(nonValidatorsIds); + // generalNode.getDASProtocol().addKnownValidator(validatorsIds.toArray(new BigInteger[0])); generalNode.getDASProtocol().setSearchTable(searchTable); + generalNode.getDASProtocol().setBuilderAddress(builderAddress); + /*if (generalNode.getDASProtocol().isEvil()) { if (generalNode.getDASProtocol() instanceof DASProtocolEvilValidator) { DASProtocolEvilValidator dasEvil = diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index a111847a..f5fe9ed0 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -135,7 +135,7 @@ public DASProtocol(String prefix) { sentMsg = new TreeMap(); - //searchTable = new SearchTable(); + // searchTable = new SearchTable(); isBuilder = false; missingSamples = new HashMap<>(); init = false; @@ -152,7 +152,7 @@ private void _init() { _ALREADY_INSTALLED = true; } - public void setSearchTable(SearchTable searchTable){ + public void setSearchTable(SearchTable searchTable) { this.searchTable = searchTable; } /** @@ -409,9 +409,9 @@ protected void handleGetSampleResponse(Message m, int myPid) { // searchTable.addNodes((BigInteger[]) m.value); // if (reportDiscovery && !isEvil()) KademliaObserver.reportPeerDiscovery(m, searchTable); - for (Neighbour neigh : (Neighbour[]) m.value) { + /*for (Neighbour neigh : (Neighbour[]) m.value) { if (neigh.getId().compareTo(builderAddress) != 0) searchTable.addNeighbour(neigh); - } + }*/ for (Sample s : samples) { logger.info( @@ -447,11 +447,11 @@ protected void handleGetSampleResponse(Message m, int myPid) { response.dst = msg.src; response.src = this.kadProtocol.getKademliaNode(); response.ackId = msg.id; // set ACK number - response.value = + /*response.value = searchTable.getNeighbours( KademliaCommonConfigDas.MAX_NODES_RETURNED * toSend.get(msg).size()); if (isEvil) - response.value = searchTable.getEvilNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED); + response.value = searchTable.getEvilNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED);*/ for (Sample s : samplesToSend) logger.info("Sending sample cached " + s.getId() + " to " + msg.src.getId() + " " + msg.id); sendMessage(response, msg.src.getId(), myPid); @@ -461,13 +461,13 @@ protected void handleGetSampleResponse(Message m, int myPid) { // SamplingOperation op = (SamplingOperation) samplingOp.get(m.operationId); // We continue an existing operation - logger.info( - "Nodes discovered " - + ((Neighbour[]) m.value).length - + " " - + searchTable.getAllNeighboursCount() - + " " - + searchTable.getValidatorsNeighboursCount()); + /*logger.info( + "Nodes discovered " + + ((Neighbour[]) m.value).length + + " " + + searchTable.getAllNeighboursCount() + + " " + + searchTable.getValidatorsNeighboursCount());*/ // + " " // + op); List toRemove = new ArrayList<>(); @@ -587,11 +587,11 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { // interface // Timeout t = new Timeout(destId, m.id, m.operationId); Sample[] samples = (Sample[]) m.body; - Neighbour[] nghbrs = (Neighbour[]) m.value; + // Neighbour[] nghbrs = (Neighbour[]) m.value; double samplesSize = 0.0; if (samples != null) samplesSize = samples.length * KademliaCommonConfigDas.SAMPLE_SIZE; double nghbrsSize = 0.0; - if (nghbrs != null) nghbrsSize = nghbrs.length * KademliaCommonConfigDas.NODE_RECORD_SIZE; + // if (nghbrs != null) nghbrsSize = nghbrs.length * KademliaCommonConfigDas.NODE_RECORD_SIZE; double msgSize = samplesSize + nghbrsSize; long propagationLatency = transport.getLatency(src, dest); // Add the transmission time of the message (upload) @@ -851,7 +851,7 @@ protected Message generateNewSampleMessage(BigInteger[] s) { return m; } - /*public void refreshSearchTable() { - searchTable.refresh(); - }*/ + public void refreshSearchTable() { + // searchTable.refresh(); + } } From d950cf5343a2601672bcb2aeaaf887b01490d856 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Mon, 1 Jan 2024 09:44:29 +0100 Subject: [PATCH 68/98] no kv --- .../main/java/peersim/kademlia/das/Block.java | 4 ++ .../peersim/kademlia/das/DASDHTProtocol.java | 3 +- .../peersim/kademlia/das/DASProtocol.java | 43 ++++++++++++------- .../kademlia/das/DASProtocolBuilder.java | 2 +- .../kademlia/das/DASProtocolValidator.java | 2 +- 5 files changed, 35 insertions(+), 19 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/Block.java b/simulator/src/main/java/peersim/kademlia/das/Block.java index 98ccba15..ca465cef 100644 --- a/simulator/src/main/java/peersim/kademlia/das/Block.java +++ b/simulator/src/main/java/peersim/kademlia/das/Block.java @@ -415,6 +415,10 @@ public BigInteger[] getSamplesIdsByColumn(int column) { return samples; } + public Sample getSample(BigInteger id) { + return sampleMap.get(id); + } + private void _init() { // execute once diff --git a/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocol.java index a2d535ed..e632fab5 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocol.java @@ -31,7 +31,8 @@ public Object clone() { protected void handleInitNewBlock(Message m, int myPid) { time = CommonState.getTime(); currentBlock = (Block) m.body; - kv.erase(); + // kv.erase(); + kv.clear(); // samplesRequested = 0; row = new int[KademliaCommonConfigDas.BLOCK_DIM_SIZE + 1]; column = new int[KademliaCommonConfigDas.BLOCK_DIM_SIZE + 1]; diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index f5fe9ed0..01360e03 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -24,7 +24,6 @@ import peersim.kademlia.KademliaEvents; import peersim.kademlia.KademliaObserver; import peersim.kademlia.KademliaProtocol; -import peersim.kademlia.KeyValueStore; import peersim.kademlia.Message; import peersim.kademlia.SimpleEvent; import peersim.kademlia.Timeout; @@ -67,7 +66,8 @@ public abstract class DASProtocol implements Cloneable, EDProtocol, KademliaEven protected boolean isValidator; - protected KeyValueStore kv; + // protected KeyValueStore kv; + protected List kv; protected Block currentBlock; @@ -126,7 +126,8 @@ public DASProtocol(String prefix) { reportDiscovery = Configuration.getBoolean(prefix + "." + PAR_DISC, false); msgReport = Configuration.getBoolean(prefix + "." + PAR_MSG, false); - kv = new KeyValueStore(); + // kv = new KeyValueStore(); + kv = new ArrayList<>(); samplingOp = new LinkedHashMap(); kadOps = new LinkedHashMap(); samplingStarted = false; @@ -276,7 +277,8 @@ protected void handleInitNewBlock(Message m, int myPid) { init = true; time = CommonState.getTime(); currentBlock = (Block) m.body; - kv.erase(); + // kv.erase(); + kv.clear(); missingSamples.clear(); // samplesRequested = 0; row = new int[currentBlock.getSize()]; @@ -317,7 +319,7 @@ protected void handleSeedSample(Message m, int myPid) { protected void handleGetSample(Message m, int myPid) { // kv is for storing the sample you have - logger.info("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); + // logger.info("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); // sample IDs that are requested in the message List samples = Arrays.asList((BigInteger[]) m.body); @@ -327,8 +329,9 @@ protected void handleGetSample(Message m, int myPid) { for (BigInteger id : samples) { logger.info("Requesting sample " + id + " from " + m.src.getId()); - Sample sample = (Sample) kv.get(id); - if (sample != null) { + // Sample sample = (Sample) kv.get(id); + // if (sample != null) { + if (kv.contains(id)) { // s.add(sample); /*Message response = new Message(Message.MSG_GET_SAMPLE_RESPONSE, new Sample[] {sample}); @@ -340,7 +343,8 @@ protected void handleGetSample(Message m, int myPid) { sendMessage(response, m.src.getId(), myPid); sampleFound = true;*/ - samplesToSend.add(sample); + // samplesToSend.add(sample); + samplesToSend.add(currentBlock.getSample(id)); if (isEvil && samplesToSend.size() > 0) break; } else { if (missingSamples.get(id) != null) missingSamples.get(id).add(m); @@ -386,7 +390,8 @@ private void reconstruct(Sample s) { && column[s.getColumn() - 1] != column.length) { Sample[] samples = currentBlock.getSamplesByColumn(s.getColumn()); for (Sample sam : samples) { - kv.add((BigInteger) sam.getIdByRow(), sam); + kv.add(sam.getIdByRow()); + // kv.add((BigInteger) sam.getIdByRow(), sam); // kv.add((BigInteger) sam.getIdByColumn(), sam); } column[s.getColumn() - 1] = currentBlock.getSize(); @@ -394,7 +399,8 @@ private void reconstruct(Sample s) { if (row[s.getRow() - 1] >= row.length / 2 && row[s.getRow() - 1] != row.length) { Sample[] samples = currentBlock.getSamplesByRow(s.getRow()); for (Sample sam : samples) { - kv.add((BigInteger) sam.getIdByRow(), sam); + kv.add(sam.getIdByRow()); + // kv.add((BigInteger) sam.getIdByRow(), sam); // kv.add((BigInteger) sam.getIdByColumn(), sam); } row[s.getRow() - 1] = currentBlock.getSize(); @@ -417,7 +423,8 @@ protected void handleGetSampleResponse(Message m, int myPid) { logger.info( "Sample received " + s.getId() + " " + s.getIdByColumn() + " from " + m.src.getId()); - kv.add((BigInteger) s.getIdByRow(), s); + kv.add((BigInteger) s.getIdByRow()); + // kv.add((BigInteger) s.getIdByRow(), s); // kv.add((BigInteger) s.getIdByColumn(), s); // count # of samples for each row and column and reconstruct if more than half received reconstruct(s); @@ -431,10 +438,12 @@ protected void handleGetSampleResponse(Message m, int myPid) { + " " + samplingOp.get(m.operationId).getPending() + " " - + kv.occupancy()); + + kv.size()); + // + kv.occupancy()); else logger.info( - "Samples received " + samples.length + " from " + m.src.getId() + " " + kv.occupancy()); + "Samples received " + samples.length + " from " + m.src.getId() + " " + kv.size()); + // "Samples received " + samples.length + " from " + m.src.getId() + " " + kv.occupancy()); HashMap> toSend = findMissingSamples(samples); for (Message msg : toSend.keySet()) { @@ -539,8 +548,10 @@ private HashMap> findMissingSamples(Sample[] samples) { HashMap> toSend = new HashMap<>(); List toRemove = new ArrayList<>(); for (BigInteger id : missingSamples.keySet()) { - if (kv.get(id) != null) { - Sample s = (Sample) kv.get(id); + if (kv.contains(id)) { + Sample s = currentBlock.getSample(id); + // if (kv.get(id) != null) { + // Sample s = (Sample) kv.get(id); for (Message msg : missingSamples.get(id)) { if (toSend.get(msg) != null) { @@ -710,7 +721,7 @@ protected void startRandomSampling() { this.isValidator, KademliaCommonConfigDas.validatorsSize, this); - op.elaborateResponse(kv.getAll().toArray(new Sample[0])); + // op.elaborateResponse(kv.getAll().toArray(new Sample[0])); samplingOp.put(op.getId(), op); logger.warning("Sampling operation started random " + op.getId()); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index d9ee82ba..d02b0c09 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -46,7 +46,7 @@ protected void handleInitNewBlock(Message m, int myPid) { while (currentBlock.hasNext()) { boolean inRegion = false; Sample s = currentBlock.next(); - kv.add(s.getId(), s); + // kv.add(s.getId(), s); // kv.add(s.getIdByColumn(), s); BigInteger radiusValidator = currentBlock.computeRegionRadius( diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index ac0d250f..485a334c 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -98,7 +98,7 @@ private void createValidatorSamplingOperation(int row, int column, long timestam samplingOp.put(op.getId(), op); logger.warning("Sampling operation started validator " + op.getId()); - op.elaborateResponse(kv.getAll().toArray(new Sample[0])); + // op.elaborateResponse(kv.getAll().toArray(new Sample[0])); doSampling(op); } From 5712199c613a8d3ab64987aca1aa3610de48a019 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Tue, 2 Jan 2024 22:11:36 +0100 Subject: [PATCH 69/98] minor edit --- .../config/malicious/dasprotocolevil0.cfg | 8 +-- .../peersim/kademlia/das/DASProtocol.java | 58 ++++++++++++++----- .../kademlia/das/DASProtocolBuilder.java | 1 + .../kademlia/das/DASProtocolNonValidator.java | 2 +- .../kademlia/das/DASProtocolValidator.java | 2 +- .../ValidatorSamplingOperation.java | 12 ++-- 6 files changed, 57 insertions(+), 26 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg index 7302cfcc..a44582ed 100644 --- a/simulator/config/malicious/dasprotocolevil0.cfg +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -20,10 +20,10 @@ SIM_TIME 11999 #Traffic generator is executed every TRAFFIC_STEP TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP -OBSERVER_STEP 100000 +OBSERVER_STEP 10000 #Turbulence module is executed every TURBULENCE_STEP enabling churning TURBULENCE_STEP 1000 -TURBULENCE_STEP_NONVAL 1000 +TURBULENCE_STEP_NONVAL 1000 REFRESH_STEP 10000000 # add network config parameters to simulation @@ -110,8 +110,8 @@ init.2statebuilder.transport 2unreltr control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 -control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 512 +control.0traffic.sample_copy_per_node 3 +control.0traffic.block_dim_size 100 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 01360e03..be0e97d1 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.TreeMap; @@ -67,7 +68,7 @@ public abstract class DASProtocol implements Cloneable, EDProtocol, KademliaEven protected boolean isValidator; // protected KeyValueStore kv; - protected List kv; + protected HashSet kv; protected Block currentBlock; @@ -127,7 +128,7 @@ public DASProtocol(String prefix) { msgReport = Configuration.getBoolean(prefix + "." + PAR_MSG, false); // kv = new KeyValueStore(); - kv = new ArrayList<>(); + kv = new HashSet<>(); samplingOp = new LinkedHashMap(); kadOps = new LinkedHashMap(); samplingStarted = false; @@ -319,7 +320,7 @@ protected void handleSeedSample(Message m, int myPid) { protected void handleGetSample(Message m, int myPid) { // kv is for storing the sample you have - // logger.info("KV size " + kv.occupancy() + " from:" + m.src.getId() + " " + m.id); + logger.warning("KV size " + kv.size() + " from:" + m.src.getId() + " " + m.id); // sample IDs that are requested in the message List samples = Arrays.asList((BigInteger[]) m.body); @@ -420,8 +421,15 @@ protected void handleGetSampleResponse(Message m, int myPid) { }*/ for (Sample s : samples) { - logger.info( - "Sample received " + s.getId() + " " + s.getIdByColumn() + " from " + m.src.getId()); + logger.warning( + "Sample received " + + s.getId() + + " " + + s.getIdByColumn() + + " from " + + m.src.getId() + + " " + + m.id); kv.add((BigInteger) s.getIdByRow()); // kv.add((BigInteger) s.getIdByRow(), s); @@ -430,7 +438,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { reconstruct(s); } if (samplingOp.get(m.operationId) != null) - logger.info( + logger.warning( "Samples received " + samples.length + " from " @@ -438,15 +446,18 @@ protected void handleGetSampleResponse(Message m, int myPid) { + " " + samplingOp.get(m.operationId).getPending() + " " - + kv.size()); + + kv.size() + + " " + + samplingOp.get(m.operationId).getId()); // + kv.occupancy()); else - logger.info( + logger.warning( "Samples received " + samples.length + " from " + m.src.getId() + " " + kv.size()); // "Samples received " + samples.length + " from " + m.src.getId() + " " + kv.occupancy()); HashMap> toSend = findMissingSamples(samples); for (Message msg : toSend.keySet()) { + if (msg.src.getId().compareTo(m.src.getId()) == 0) continue; Sample[] samplesToSend = toSend.get(msg).toArray(new Sample[0]); if (isEvil) { samplesToSend = new Sample[] {samplesToSend[0]}; @@ -462,7 +473,8 @@ protected void handleGetSampleResponse(Message m, int myPid) { if (isEvil) response.value = searchTable.getEvilNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED);*/ for (Sample s : samplesToSend) - logger.info("Sending sample cached " + s.getId() + " to " + msg.src.getId() + " " + msg.id); + logger.warning( + "Sending sample cached " + s.getId() + " to " + msg.src.getId() + " " + msg.id); sendMessage(response, msg.src.getId(), myPid); } toSend.clear(); @@ -533,8 +545,17 @@ protected void handleGetSampleResponse(Message m, int myPid) { // samplingOp.remove(m.operationId); toRemove.add(op.getId()); if (op instanceof ValidatorSamplingOperation) - logger.warning("Sampling operation finished validator completed " + op.getId()); - else logger.warning("Sampling operation finished random completed " + op.getId()); + logger.warning( + "Sampling operation finished validator completed " + + op.getId() + + " " + + op.getMessages().size()); + else + logger.warning( + "Sampling operation finished random completed " + + op.getId() + + " " + + op.getMessages().size()); KademliaObserver.reportOperation(op); } } @@ -736,8 +757,17 @@ protected boolean doSampling(SamplingOperation sop) { KademliaObserver.reportOperation(sop); // logger.warning("Sampling operation finished " + sop.getId()); if (sop instanceof ValidatorSamplingOperation) - logger.warning("Sampling operation completed validator dosampling " + sop.getId()); - else logger.warning("Sampling operation completed random dosampling " + sop.getId()); + logger.warning( + "Sampling operation completed validator dosampling " + + sop.getId() + + " " + + sop.getMessages().size()); + else + logger.warning( + "Sampling operation completed random dosampling " + + sop.getId() + + " " + + sop.getMessages().size()); return true; } else { boolean success = false; @@ -746,7 +776,7 @@ protected boolean doSampling(SamplingOperation sop) { BigInteger[] nextNodes = sop.doSampling(); for (BigInteger nextNode : nextNodes) { BigInteger[] reqSamples = sop.getSamples(); - logger.info( + logger.warning( "sending to node " + nextNode + " " diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index d02b0c09..82625755 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -46,6 +46,7 @@ protected void handleInitNewBlock(Message m, int myPid) { while (currentBlock.hasNext()) { boolean inRegion = false; Sample s = currentBlock.next(); + kv.add(s.getId()); // kv.add(s.getId(), s); // kv.add(s.getIdByColumn(), s); BigInteger radiusValidator = diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java index aafa0d89..7f36dbdc 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java @@ -53,7 +53,7 @@ protected void handleInitNewBlock(Message m, int myPid) { validatorsContacted.clear(); super.handleInitNewBlock(m, myPid); if (!isEvil) { - // startRandomSampling(); + startRandomSampling(); } } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index 485a334c..06da612b 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -38,7 +38,7 @@ protected void handleInitNewBlock(Message m, int myPid) { super.handleInitNewBlock(m, myPid); if (!isEvil) { startRowsandColumnsSampling(); - // startRandomSampling(); + startRandomSampling(); } } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index f23bdf5c..f14fd8a9 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -174,9 +174,9 @@ protected void createNodes() { // searchTable.getNodesbySample(samples.get(sample).getId(), radiusUsed)); nodesBySample.addAll( searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusValidator)); - nodesBySample.addAll( - searchTable.getNonValidatorNodesbySample( - samples.get(sample).getId(), radiusNonValidator)); + /*nodesBySample.addAll( + searchTable.getNonValidatorNodesbySample( + samples.get(sample).getId(), radiusNonValidator));*/ // radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); // } @@ -188,9 +188,9 @@ protected void createNodes() { nodesBySample.addAll( searchTable.getValidatorNodesbySample( samples.get(sample).getIdByColumn(), radiusValidator)); - nodesBySample.addAll( - searchTable.getNonValidatorNodesbySample( - samples.get(sample).getIdByColumn(), radiusNonValidator)); + /*nodesBySample.addAll( + searchTable.getNonValidatorNodesbySample( + samples.get(sample).getIdByColumn(), radiusNonValidator));*/ // radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); // } From 80bc792d6a3d3925c45d6dc04514df2901dedba1 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Wed, 3 Jan 2024 08:41:04 +0100 Subject: [PATCH 70/98] random col/row sampling --- .../config/malicious/dasprotocolevil0.cfg | 2 +- .../main/java/peersim/kademlia/das/Block.java | 56 ++++++++----------- .../peersim/kademlia/das/DASProtocol.java | 1 - .../kademlia/das/DASProtocolValidator.java | 8 ++- .../peersim/kademlia/das/operations/Node.java | 6 +- .../das/operations/SamplingOperation.java | 3 + .../ValidatorSamplingOperation.java | 15 +++++ 7 files changed, 53 insertions(+), 38 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg index a44582ed..e061f277 100644 --- a/simulator/config/malicious/dasprotocolevil0.cfg +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 1000 +SIZE 5000 # Random seed K 5 diff --git a/simulator/src/main/java/peersim/kademlia/das/Block.java b/simulator/src/main/java/peersim/kademlia/das/Block.java index ca465cef..4399b804 100644 --- a/simulator/src/main/java/peersim/kademlia/das/Block.java +++ b/simulator/src/main/java/peersim/kademlia/das/Block.java @@ -2,16 +2,13 @@ import java.math.BigInteger; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Stack; -import java.util.TreeSet; import peersim.core.CommonState; import peersim.core.Network; import peersim.kademlia.KademliaCommonConfig; -import peersim.kademlia.Util; public class Block implements Iterator, Cloneable { @@ -40,8 +37,8 @@ public class Block implements Iterator, Cloneable { private int numSamples; // private TreeSet samples; - private TreeSet samplesByRow; - private TreeSet samplesByColumn; + // private TreeSet samplesByRow; + // private TreeSet samplesByColumn; private HashMap parcelMap; private HashMap> parcelByRow; private HashMap> parcelByColumn; @@ -55,9 +52,9 @@ public Block(long id) { this.numSamples = this.SIZE * this.SIZE; _init(); - samplesByRow = new TreeSet<>(); - samplesByColumn = new TreeSet<>(); - // sampleMap = new HashMap<>(); + // samplesByRow = new TreeSet<>(); + // samplesByColumn = new TreeSet<>(); + sampleMap = new HashMap<>(); this.blockId = id; blockSamples = new Sample[SIZE][SIZE]; @@ -69,8 +66,8 @@ public Block(long id) { for (int i = 1; i <= blockSamples.length; i++) { for (int j = 1; j <= blockSamples[0].length; j++) { blockSamples[i][j] = new Sample(blockId, i + 1, j + 1, this); - samplesByRow.add(blockSamples[i][j].getIdByRow()); - samplesByColumn.add(blockSamples[i][j].getIdByColumn()); + // samplesByRow.add(blockSamples[i][j].getIdByRow()); + // samplesByColumn.add(blockSamples[i][j].getIdByColumn()); sampleMap.put(blockSamples[i][j].getIdByRow(), blockSamples[i][j]); sampleMap.put(blockSamples[i][j].getIdByColumn(), blockSamples[i][j]); } @@ -83,9 +80,9 @@ public Block(int size, long id) { SIZE = size; this.numSamples = this.SIZE * this.SIZE; _init(); - samplesByRow = new TreeSet<>(); - samplesByColumn = new TreeSet<>(); - // sampleMap = new HashMap<>(); + // samplesByRow = new TreeSet<>(); + // samplesByColumn = new TreeSet<>(); + sampleMap = new HashMap<>(); this.blockId = id; blockSamples = new Sample[SIZE][SIZE]; @@ -98,8 +95,8 @@ public Block(int size, long id) { for (int i = 0; i < blockSamples.length; i++) { for (int j = 0; j < blockSamples[0].length; j++) { blockSamples[i][j] = new Sample(blockId, i + 1, j + 1, this); - samplesByRow.add(blockSamples[i][j].getIdByRow()); - samplesByColumn.add(blockSamples[i][j].getIdByColumn()); + // samplesByRow.add(blockSamples[i][j].getIdByRow()); + // samplesByColumn.add(blockSamples[i][j].getIdByColumn()); sampleMap.put(blockSamples[i][j].getIdByRow(), blockSamples[i][j]); sampleMap.put(blockSamples[i][j].getIdByColumn(), blockSamples[i][j]); } @@ -115,15 +112,15 @@ public Block(Sample[][] blockSamples, int size, long id) { row = column = 0; this.blockId = id; // samples = new TreeSet<>(); - samplesByRow = new TreeSet<>(); - samplesByColumn = new TreeSet<>(); + // samplesByRow = new TreeSet<>(); + // samplesByColumn = new TreeSet<>(); sampleMap = new HashMap<>(); for (int i = 0; i < blockSamples.length; i++) { for (int j = 0; j < blockSamples[0].length; j++) { blockSamples[i][j] = new Sample(blockId, i + 1, j + 1, this); - samplesByRow.add(blockSamples[i][j].getIdByRow()); - samplesByColumn.add(blockSamples[i][j].getIdByColumn()); + // samplesByRow.add(blockSamples[i][j].getIdByRow()); + // samplesByColumn.add(blockSamples[i][j].getIdByColumn()); sampleMap.put(blockSamples[i][j].getIdByRow(), blockSamples[i][j]); sampleMap.put(blockSamples[i][j].getIdByColumn(), blockSamples[i][j]); } @@ -271,7 +268,7 @@ public BigInteger[] getNRandomSamplesIds(int n) { return samples; } - public int findClosestRow(BigInteger nodeid, BigInteger radius) { + /*public int findClosestRow(BigInteger nodeid, BigInteger radius) { BigInteger bottom = nodeid.subtract(radius); if (radius.compareTo(nodeid) == 1) bottom = BigInteger.ZERO; @@ -302,7 +299,7 @@ public int findClosestColumn(BigInteger nodeid, BigInteger radius) { column.add(sampleMap.get(id).getColumn()); } return Util.mostCommon(column); - } + }*/ /* Returns n random selected samples */ public Sample[] getNRandomSamples(int n) { @@ -365,16 +362,16 @@ public int getNumSamples() { } /* Returns the total number of samples in the block */ - public BigInteger[] getSamplesByRadius(BigInteger peerId, BigInteger radius) { + /*public BigInteger[] getSamplesByRadius(BigInteger peerId, BigInteger radius) { BigInteger top = peerId.add(radius); BigInteger bottom = peerId.subtract(radius); Collection subSet = samplesByRow.subSet(bottom, true, top, true); return (BigInteger[]) subSet.toArray(new BigInteger[0]); - } + }*/ - /* Returns the ids of the samples within the radius to the peerId specified*/ - public BigInteger[] getSamplesByRadiusByRow(BigInteger peerId, BigInteger radius) { + // Returns the ids of the samples within the radius to the peerId specified + /*public BigInteger[] getSamplesByRadiusByRow(BigInteger peerId, BigInteger radius) { BigInteger top = peerId.add(radius); BigInteger bottom = peerId.subtract(radius); @@ -382,20 +379,15 @@ public BigInteger[] getSamplesByRadiusByRow(BigInteger peerId, BigInteger radius return (BigInteger[]) subSet.toArray(new BigInteger[0]); } - /* Returns the ids of the samples within the radius to the peerId specified, using sample column id*/ + // Returns the ids of the samples within the radius to the peerId specified, using sample column id public BigInteger[] getSamplesByRadiusByColumn(BigInteger peerId, BigInteger radius) { BigInteger top = peerId.add(radius); BigInteger bottom = peerId.subtract(radius); Collection subSet = samplesByColumn.subSet(bottom, true, top, true); - /*List result = new ArrayList<>(); - for (BigInteger sampleId : subSet) { - result.add(sampleMap.get(sampleId)); - } - return (BigInteger[]) result.toArray(new BigInteger[0]);*/ return (BigInteger[]) subSet.toArray(new BigInteger[0]); - } + }*/ /* Returns the ids of the all the samples in a specific row*/ public BigInteger[] getSamplesIdsByRow(int row) { diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index be0e97d1..8084408f 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -584,7 +584,6 @@ private HashMap> findMissingSamples(Sample[] samples) { } } toRemove.add(s.getId()); - toRemove.add(s.getIdByColumn()); } } for (BigInteger id : toRemove) { diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index 06da612b..f1502f6d 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -61,7 +61,7 @@ protected void startRowsandColumnsSampling() { // start 2 row 2 column Validator operation (1 row/column with the highest number of samples // already downloaded and another random) - createValidatorSamplingOperation( + /*createValidatorSamplingOperation( currentBlock.findClosestRow( this.getKademliaId(), currentBlock.computeRegionRadius( @@ -76,7 +76,11 @@ protected void startRowsandColumnsSampling() { currentBlock.computeRegionRadius( KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, KademliaCommonConfigDas.validatorsSize)), - time); + time);*/ + createValidatorSamplingOperation( + CommonState.r.nextInt(KademliaCommonConfigDas.BLOCK_DIM_SIZE) + 1, 0, time); + createValidatorSamplingOperation( + 0, CommonState.r.nextInt(KademliaCommonConfigDas.BLOCK_DIM_SIZE) + 1, time); createValidatorSamplingOperation( CommonState.r.nextInt(KademliaCommonConfigDas.BLOCK_DIM_SIZE) + 1, 0, time); createValidatorSamplingOperation( diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/Node.java b/simulator/src/main/java/peersim/kademlia/das/operations/Node.java index de41bad5..eb7a5f8e 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/Node.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/Node.java @@ -59,8 +59,10 @@ public void setAgressiveness(int agr) { @Override public int compareTo(Node n) { - if (this.getScore() < n.getScore()) return 1; - else if (this.getScore() > n.getScore()) return -1; + //if (this.getScore() < n.getScore()) return 1; + //else if (this.getScore() > n.getScore()) return -1; + if(this.samples.size() > n.samples.size()) return 1; + else if (this.samples.size() < n.samples.size()) return -1; else return 0; } } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index d371faac..a6677785 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -3,6 +3,7 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; @@ -178,6 +179,8 @@ public BigInteger[] doSampling() { + askedNodes.size()); } for (Node n : nodes.values()) n.setAgressiveness(aggressiveness); + Collection ns = this.getNodes(); + Collections.sort(ns); List result = new ArrayList<>(); for (Node n : nodes.values()) { diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index f14fd8a9..6a376d9d 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -212,6 +212,21 @@ protected void createNodes() { if (!found && callback != null) callback.missing(sample, this); } } + + for (BigInteger id : nodes.keySet()) { + for (FetchingSample s : nodes.get(id).getSamples()) + System.out.println( + "[" + + CommonState.getTime() + + "][" + + srcNode + + "] Nodes created " + + this.getId() + + " " + + id + + " " + + s.getId()); + } } public BigInteger[] getSamples() { From c2329fcaf1386af408fa93440a1a1bd61e1b040a Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Wed, 3 Jan 2024 08:49:32 +0100 Subject: [PATCH 71/98] sorting sampling nodes --- .../main/java/peersim/kademlia/das/operations/Node.java | 6 +++--- .../peersim/kademlia/das/operations/SamplingOperation.java | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/Node.java b/simulator/src/main/java/peersim/kademlia/das/operations/Node.java index eb7a5f8e..5a804ba1 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/Node.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/Node.java @@ -59,9 +59,9 @@ public void setAgressiveness(int agr) { @Override public int compareTo(Node n) { - //if (this.getScore() < n.getScore()) return 1; - //else if (this.getScore() > n.getScore()) return -1; - if(this.samples.size() > n.samples.size()) return 1; + // if (this.getScore() < n.getScore()) return 1; + // else if (this.getScore() > n.getScore()) return -1; + if (this.samples.size() > n.samples.size()) return 1; else if (this.samples.size() < n.samples.size()) return -1; else return 0; } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index a6677785..e845df52 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -179,10 +179,11 @@ public BigInteger[] doSampling() { + askedNodes.size()); } for (Node n : nodes.values()) n.setAgressiveness(aggressiveness); - Collection ns = this.getNodes(); - Collections.sort(ns); + List sortedNodes = new ArrayList<>(nodes.values()); + Collections.sort(sortedNodes); List result = new ArrayList<>(); - for (Node n : nodes.values()) { + // for (Node n : nodes.values()) { + for (Node n : sortedNodes) { if (!n.isBeingAsked() && n.getScore() > 0) { // break; n.setBeingAsked(true); From 80b2d6d159e7b080c45163c7f58432fb40ed5934 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Wed, 3 Jan 2024 19:50:07 +0100 Subject: [PATCH 72/98] minor edit --- simulator/config/malicious/dasprotocolevil0.cfg | 4 ++-- .../src/main/java/peersim/kademlia/das/DASProtocol.java | 7 +++---- .../das/operations/ValidatorSamplingOperation.java | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg index e061f277..1870fea6 100644 --- a/simulator/config/malicious/dasprotocolevil0.cfg +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 5000 +SIZE 50000 # Random seed K 5 @@ -111,7 +111,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 3 -control.0traffic.block_dim_size 100 +control.0traffic.block_dim_size 512 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 8084408f..295461c1 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -320,7 +320,7 @@ protected void handleSeedSample(Message m, int myPid) { protected void handleGetSample(Message m, int myPid) { // kv is for storing the sample you have - logger.warning("KV size " + kv.size() + " from:" + m.src.getId() + " " + m.id); + logger.info("KV size " + kv.size() + " from:" + m.src.getId() + " " + m.id); // sample IDs that are requested in the message List samples = Arrays.asList((BigInteger[]) m.body); @@ -421,7 +421,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { }*/ for (Sample s : samples) { - logger.warning( + logger.info( "Sample received " + s.getId() + " " @@ -473,8 +473,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { if (isEvil) response.value = searchTable.getEvilNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED);*/ for (Sample s : samplesToSend) - logger.warning( - "Sending sample cached " + s.getId() + " to " + msg.src.getId() + " " + msg.id); + logger.info("Sending sample cached " + s.getId() + " to " + msg.src.getId() + " " + msg.id); sendMessage(response, msg.src.getId(), myPid); } toSend.clear(); diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index 6a376d9d..bec46926 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -213,7 +213,7 @@ protected void createNodes() { } } - for (BigInteger id : nodes.keySet()) { + /*for (BigInteger id : nodes.keySet()) { for (FetchingSample s : nodes.get(id).getSamples()) System.out.println( "[" @@ -226,7 +226,7 @@ protected void createNodes() { + id + " " + s.getId()); - } + }*/ } public BigInteger[] getSamples() { From 21f2a1a6b9fd481edcdd9c7a4f29f0325764bd22 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Wed, 3 Jan 2024 09:05:44 +0100 Subject: [PATCH 73/98] sorting sampling nodes --- .../java/peersim/kademlia/das/operations/Node.java | 4 ++-- .../kademlia/das/operations/SamplingOperation.java | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/Node.java b/simulator/src/main/java/peersim/kademlia/das/operations/Node.java index 5a804ba1..ada7da64 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/Node.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/Node.java @@ -61,8 +61,8 @@ public void setAgressiveness(int agr) { public int compareTo(Node n) { // if (this.getScore() < n.getScore()) return 1; // else if (this.getScore() > n.getScore()) return -1; - if (this.samples.size() > n.samples.size()) return 1; - else if (this.samples.size() < n.samples.size()) return -1; + if (this.samples.size() > n.samples.size()) return -1; + else if (this.samples.size() < n.samples.size()) return 1; else return 0; } } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index e845df52..f64fe04c 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -184,6 +184,17 @@ public BigInteger[] doSampling() { List result = new ArrayList<>(); // for (Node n : nodes.values()) { for (Node n : sortedNodes) { + /*System.out.println( + "[" + + CommonState.getTime() + + "][" + + srcNode + + "] Sampling nodes " + + this.getId() + + " " + + n.getScore() + + " " + + n.getSamples().size());*/ if (!n.isBeingAsked() && n.getScore() > 0) { // break; n.setBeingAsked(true); From c27c3b9f8d0516ac6ca9198d2eefe6735ad77215 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Wed, 3 Jan 2024 19:54:00 +0100 Subject: [PATCH 74/98] sorting sampling nodes --- simulator/config/malicious/dasprotocolevil0.cfg | 6 +++--- .../java/peersim/kademlia/das/DASProtocolValidator.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg index 1870fea6..5c60be8d 100644 --- a/simulator/config/malicious/dasprotocolevil0.cfg +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 50000 +SIZE 1000 # Random seed K 5 @@ -94,7 +94,7 @@ init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol init.1uniqueNodeID.protocolEvildas 8evildasprotocol -init.1uniqueNodeID.validator_rate 0.5 +init.1uniqueNodeID.validator_rate 1.0 init.1uniqueNodeID.evilNodeRatioValidator 0.0 init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 @@ -110,7 +110,7 @@ init.2statebuilder.transport 2unreltr control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 -control.0traffic.sample_copy_per_node 3 +control.0traffic.sample_copy_per_node 2 control.0traffic.block_dim_size 512 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index f1502f6d..0da096a9 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -38,7 +38,7 @@ protected void handleInitNewBlock(Message m, int myPid) { super.handleInitNewBlock(m, myPid); if (!isEvil) { startRowsandColumnsSampling(); - startRandomSampling(); + //startRandomSampling(); } } From cbad094030e51664bbdb01cc30188ebfa24fc283 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Thu, 4 Jan 2024 00:09:54 +0100 Subject: [PATCH 75/98] fixing non found samples in non-validator --- simulator/config/malicious/dasprotocolevil0.cfg | 4 ++-- .../main/java/peersim/kademlia/das/DASProtocol.java | 12 +++++++++--- .../kademlia/das/DASProtocolNonValidator.java | 12 +++++++++--- .../peersim/kademlia/das/DASProtocolValidator.java | 4 ++-- .../kademlia/das/KademliaCommonConfigDas.java | 6 +++--- 5 files changed, 25 insertions(+), 13 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg index 5c60be8d..97086647 100644 --- a/simulator/config/malicious/dasprotocolevil0.cfg +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -94,7 +94,7 @@ init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol init.1uniqueNodeID.protocolEvildas 8evildasprotocol -init.1uniqueNodeID.validator_rate 1.0 +init.1uniqueNodeID.validator_rate 0.5 init.1uniqueNodeID.evilNodeRatioValidator 0.0 init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 @@ -111,7 +111,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 512 +control.0traffic.block_dim_size 100 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 295461c1..0caf56ce 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -10,6 +10,7 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -320,7 +321,7 @@ protected void handleSeedSample(Message m, int myPid) { protected void handleGetSample(Message m, int myPid) { // kv is for storing the sample you have - logger.info("KV size " + kv.size() + " from:" + m.src.getId() + " " + m.id); + logger.warning("KV size " + kv.size() + " from:" + m.src.getId() + " " + m.id); // sample IDs that are requested in the message List samples = Arrays.asList((BigInteger[]) m.body); @@ -421,7 +422,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { }*/ for (Sample s : samples) { - logger.info( + logger.warning( "Sample received " + s.getId() + " " @@ -473,7 +474,8 @@ protected void handleGetSampleResponse(Message m, int myPid) { if (isEvil) response.value = searchTable.getEvilNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED);*/ for (Sample s : samplesToSend) - logger.info("Sending sample cached " + s.getId() + " to " + msg.src.getId() + " " + msg.id); + logger.warning( + "Sending sample cached " + s.getId() + " to " + msg.src.getId() + " " + msg.id); sendMessage(response, msg.src.getId(), myPid); } toSend.clear(); @@ -744,6 +746,10 @@ protected void startRandomSampling() { samplingOp.put(op.getId(), op); logger.warning("Sampling operation started random " + op.getId()); + List samples = Arrays.asList(op.getSamples()); + Collections.sort(samples); + for (BigInteger id : samples) logger.warning("Sampling operation sample " + id); + doSampling(op); } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java index 7f36dbdc..ae84f252 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java @@ -28,10 +28,16 @@ protected void handleInitGetSample(Message m, int myPid) { BigInteger radius = currentBlock.computeRegionRadius( KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, - searchTable.getValidatorsIndexed().size()); + KademliaCommonConfigDas.validatorsSize); for (BigInteger sample : samples) { logger.warning("Init block non-validator node - getting samples " + sample); - for (BigInteger id : searchTable.getValidatorNodesbySample(sample, radius)) { + List nodes = searchTable.getValidatorNodesbySample(sample, radius); + if (nodes.size() == 0) { + // logger.warning("Sample not found"); + nodes = new ArrayList<>(); + nodes.add(builderAddress); + } + for (BigInteger id : nodes) { if (!validatorsContacted.contains(id)) { Message msg = generateGetSampleMessage(samples); msg.operationId = -1; @@ -40,7 +46,7 @@ protected void handleInitGetSample(Message m, int myPid) { msg.dst = n.getKademliaProtocol().getKademliaNode(); sendMessage(msg, id, myPid); validatorsContacted.add(id); - break; + // break; } } } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index 0da096a9..756d0a77 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -37,8 +37,8 @@ protected void handleInitGetSample(Message m, int myPid) { protected void handleInitNewBlock(Message m, int myPid) { super.handleInitNewBlock(m, myPid); if (!isEvil) { - startRowsandColumnsSampling(); - //startRandomSampling(); + // startRowsandColumnsSampling(); + startRandomSampling(); } } diff --git a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java index 0817206b..a0dcf65a 100644 --- a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java @@ -48,12 +48,12 @@ public class KademliaCommonConfigDas { public static int MAX_HOPS = 5000; /** Default upload bandwith of a validator in Mbits/sec */ - public static int VALIDATOR_UPLOAD_RATE = 1000; + public static int VALIDATOR_UPLOAD_RATE = 100000; /** Default upload bandwith of a non-validator in Mbits/sec */ - public static int NON_VALIDATOR_UPLOAD_RATE = 100; + public static int NON_VALIDATOR_UPLOAD_RATE = 100000; - public static int BUILDER_UPLOAD_RATE = 50000; + public static int BUILDER_UPLOAD_RATE = 100000; public static int VALIDATOR_DEADLINE = 4000; public static int RANDOM_SAMPLING_DEADLINE = 12000; From ffb88fc4cc363d8605bf8732f26a27cbcfc36711 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Thu, 4 Jan 2024 00:15:25 +0100 Subject: [PATCH 76/98] fixing non found samples in non-validator --- .../peersim/kademlia/das/DASProtocolValidator.java | 2 +- .../das/operations/ValidatorSamplingOperation.java | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index 756d0a77..f1502f6d 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -37,7 +37,7 @@ protected void handleInitGetSample(Message m, int myPid) { protected void handleInitNewBlock(Message m, int myPid) { super.handleInitNewBlock(m, myPid); if (!isEvil) { - // startRowsandColumnsSampling(); + startRowsandColumnsSampling(); startRandomSampling(); } } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index bec46926..abaf4c99 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -174,9 +174,9 @@ protected void createNodes() { // searchTable.getNodesbySample(samples.get(sample).getId(), radiusUsed)); nodesBySample.addAll( searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusValidator)); - /*nodesBySample.addAll( - searchTable.getNonValidatorNodesbySample( - samples.get(sample).getId(), radiusNonValidator));*/ + nodesBySample.addAll( + searchTable.getNonValidatorNodesbySample( + samples.get(sample).getId(), radiusNonValidator)); // radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); // } @@ -188,9 +188,9 @@ protected void createNodes() { nodesBySample.addAll( searchTable.getValidatorNodesbySample( samples.get(sample).getIdByColumn(), radiusValidator)); - /*nodesBySample.addAll( - searchTable.getNonValidatorNodesbySample( - samples.get(sample).getIdByColumn(), radiusNonValidator));*/ + nodesBySample.addAll( + searchTable.getNonValidatorNodesbySample( + samples.get(sample).getIdByColumn(), radiusNonValidator)); // radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); // } From 42ff296d0e06f48cce2471ec410a05431ef4da3f Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Thu, 4 Jan 2024 00:18:46 +0100 Subject: [PATCH 77/98] logs --- .../main/java/peersim/kademlia/das/DASProtocol.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 0caf56ce..a9bb58ed 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -321,7 +321,7 @@ protected void handleSeedSample(Message m, int myPid) { protected void handleGetSample(Message m, int myPid) { // kv is for storing the sample you have - logger.warning("KV size " + kv.size() + " from:" + m.src.getId() + " " + m.id); + logger.info("KV size " + kv.size() + " from:" + m.src.getId() + " " + m.id); // sample IDs that are requested in the message List samples = Arrays.asList((BigInteger[]) m.body); @@ -422,7 +422,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { }*/ for (Sample s : samples) { - logger.warning( + logger.info( "Sample received " + s.getId() + " " @@ -474,7 +474,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { if (isEvil) response.value = searchTable.getEvilNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED);*/ for (Sample s : samplesToSend) - logger.warning( + logger.info( "Sending sample cached " + s.getId() + " to " + msg.src.getId() + " " + msg.id); sendMessage(response, msg.src.getId(), myPid); } @@ -746,9 +746,9 @@ protected void startRandomSampling() { samplingOp.put(op.getId(), op); logger.warning("Sampling operation started random " + op.getId()); - List samples = Arrays.asList(op.getSamples()); + /*List samples = Arrays.asList(op.getSamples()); Collections.sort(samples); - for (BigInteger id : samples) logger.warning("Sampling operation sample " + id); + for (BigInteger id : samples) logger.warning("Sampling operation sample " + id);*/ doSampling(op); } From a7931dd4978a023c007992666862edeaeef7602d Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sat, 6 Jan 2024 15:08:39 +0100 Subject: [PATCH 78/98] extra nodes sampling --- .../config/malicious/dasprotocolevil0.5.cfg | 59 ++++++++++--------- .../config/malicious/dasprotocolevil0.75.cfg | 16 ++--- .../config/malicious/dasprotocolevil0.cfg | 4 +- .../peersim/kademlia/das/DASProtocol.java | 10 ++-- .../kademlia/das/KademliaCommonConfigDas.java | 6 +- .../operations/RandomSamplingOperation.java | 14 ++++- .../das/operations/SamplingOperation.java | 5 +- .../ValidatorSamplingOperation.java | 38 ++++++++---- 8 files changed, 90 insertions(+), 62 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil0.5.cfg b/simulator/config/malicious/dasprotocolevil0.5.cfg index 449d0878..df35a025 100644 --- a/simulator/config/malicious/dasprotocolevil0.5.cfg +++ b/simulator/config/malicious/dasprotocolevil0.5.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 10000 +SIZE 50000 # Random seed K 5 @@ -14,17 +14,17 @@ MINDELAY 5 MAXDELAY 100 #Simulation time in ms -SIM_TIME 60001 +SIM_TIME 11999 #Traffic generator is executed every TRAFFIC_STEP TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP -OBSERVER_STEP 1000 +OBSERVER_STEP 10000 #Turbulence module is executed every TURBULENCE_STEP enabling churning TURBULENCE_STEP 1000 -TURBULENCE_STEP_NONVAL 1000 -REFRESH_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 +REFRESH_STEP 10000000 # add network config parameters to simulation random.seed 24680 @@ -110,7 +110,7 @@ init.2statebuilder.transport 2unreltr control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 -control.0traffic.sample_copy_per_node 3 +control.0traffic.sample_copy_per_node 2 control.0traffic.block_dim_size 512 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia @@ -120,34 +120,35 @@ control.1refresh peersim.kademlia.das.RefreshSearchTable control.1refresh.step REFRESH_STEP # turbulence non-validator -control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas -control.2turbolenceAdd.protocolkad 3kademlia -control.2turbolenceAdd.protocoldasbuilder 4dasprotocol -control.2turbolenceAdd.protocoldasvalidator 5dasprotocol -control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol -control.2turbolenceAdd.protocolEvildas 7evildasprotocol -control.2turbolenceAdd.transport 2unreltr -control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL -control.2turbolenceAdd.p_idle 0.1 -control.2turbolenceAdd.p_rem 0.45 -control.2turbolenceAdd.p_add 0.45 + +#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +#control.2turbolenceAdd.protocolkad 3kademlia +#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.2turbolenceAdd.protocolEvildas 7evildasprotocol +#control.2turbolenceAdd.transport 2unreltr +#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +#control.2turbolenceAdd.p_idle 0.1 +#control.2turbolenceAdd.p_rem 0.45 +#control.2turbolenceAdd.p_add 0.45 # turbulence validators -control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator -control.3turbolenceAdd.protocolkad 3kademlia -control.3turbolenceAdd.protocoldasbuilder 4dasprotocol -control.3turbolenceAdd.protocoldasvalidator 5dasprotocol -control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol -control.3turbolenceAdd.protocolEvildas 7evildasprotocol -control.3turbolenceAdd.transport 2unreltr -control.3turbolenceAdd.step TURBULENCE_STEP -control.3turbolenceAdd.p_idle 0.9 -control.3turbolenceAdd.p_rem 0.05 -control.3turbolenceAdd.p_add 0.05 +#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +#control.3turbolenceAdd.protocolkad 3kademlia +#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.3turbolenceAdd.protocolEvildas 7evildasprotocol +#control.3turbolenceAdd.transport 2unreltr +#control.3turbolenceAdd.step TURBULENCE_STEP +#control.3turbolenceAdd.p_idle 0.9 +#control.3turbolenceAdd.p_rem 0.05 +#control.3turbolenceAdd.p_add 0.05 # ::::: OBSERVER ::::: #The observer is executed every OBSERVER_STEP and will generate data traces control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logsDasEvil0.5 +control.4.logfolder logsDasEvil0 diff --git a/simulator/config/malicious/dasprotocolevil0.75.cfg b/simulator/config/malicious/dasprotocolevil0.75.cfg index a473b6e8..ed05f4ce 100644 --- a/simulator/config/malicious/dasprotocolevil0.75.cfg +++ b/simulator/config/malicious/dasprotocolevil0.75.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 5000 +SIZE 50000 # Random seed K 5 @@ -14,17 +14,17 @@ MINDELAY 5 MAXDELAY 100 #Simulation time in ms -SIM_TIME 60001 +SIM_TIME 11999 #Traffic generator is executed every TRAFFIC_STEP TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP -OBSERVER_STEP 1000 +OBSERVER_STEP 10000 #Turbulence module is executed every TURBULENCE_STEP enabling churning TURBULENCE_STEP 1000 -TURBULENCE_STEP_NONVAL 1000 -REFRESH_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 +REFRESH_STEP 10000000 # add network config parameters to simulation random.seed 24680 @@ -110,8 +110,8 @@ init.2statebuilder.transport 2unreltr control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 -control.0traffic.sample_copy_per_node 3 -control.0traffic.block_dim_size 100 +control.0traffic.sample_copy_per_node 2 +control.0traffic.block_dim_size 512 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia @@ -151,4 +151,4 @@ control.1refresh.step REFRESH_STEP control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logsDasEvil0.75 +control.4.logfolder logsDasEvil0 diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg index 97086647..0c975227 100644 --- a/simulator/config/malicious/dasprotocolevil0.cfg +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 1000 +SIZE 50000 # Random seed K 5 @@ -111,7 +111,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 100 +control.0traffic.block_dim_size 512 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index a9bb58ed..59173f8c 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -10,7 +10,6 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -474,8 +473,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { if (isEvil) response.value = searchTable.getEvilNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED);*/ for (Sample s : samplesToSend) - logger.info( - "Sending sample cached " + s.getId() + " to " + msg.src.getId() + " " + msg.id); + logger.info("Sending sample cached " + s.getId() + " to " + msg.src.getId() + " " + msg.id); sendMessage(response, msg.src.getId(), myPid); } toSend.clear(); @@ -663,7 +661,11 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { // add to sent msg this.sentMsg.put(m.id, m.timestamp); - EDSimulator.add(latency * 8 + 200, t, src, myPid); // set delay = 2*RTT + /// BigInteger[] samples = (Sample[]) m.body; + + long timeout = latency * 4; + if (timeout < 200) timeout = 200; + EDSimulator.add(timeout, t, src, myPid); // set delay = 2*RTT } } diff --git a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java index a0dcf65a..e8c05253 100644 --- a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java @@ -48,12 +48,12 @@ public class KademliaCommonConfigDas { public static int MAX_HOPS = 5000; /** Default upload bandwith of a validator in Mbits/sec */ - public static int VALIDATOR_UPLOAD_RATE = 100000; + public static int VALIDATOR_UPLOAD_RATE = 10000; /** Default upload bandwith of a non-validator in Mbits/sec */ - public static int NON_VALIDATOR_UPLOAD_RATE = 100000; + public static int NON_VALIDATOR_UPLOAD_RATE = 100; - public static int BUILDER_UPLOAD_RATE = 100000; + public static int BUILDER_UPLOAD_RATE = 50000; public static int VALIDATOR_DEADLINE = 4000; public static int RANDOM_SAMPLING_DEADLINE = 12000; diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index 58b51a15..8e4cca64 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -8,6 +8,8 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; + +import peersim.core.CommonState; import peersim.kademlia.das.Block; import peersim.kademlia.das.KademliaCommonConfigDas; import peersim.kademlia.das.MissingNode; @@ -183,7 +185,11 @@ protected void createNodes() { } protected void addExtraNodes() { - + aggressiveness_step = KademliaCommonConfigDas.aggressiveness_step * 2; + if (CommonState.getTime() - this.getTimestamp() > 1000) + aggressiveness_step = KademliaCommonConfigDas.aggressiveness_step * 4; + if (CommonState.getTime() - this.getTimestamp() > 2000) + aggressiveness_step = KademliaCommonConfigDas.aggressiveness_step * 8; List missingSamples = Arrays.asList(getSamples()); Collections.shuffle(missingSamples); for (BigInteger sample : missingSamples) { @@ -193,12 +199,14 @@ protected void addExtraNodes() { Sample[] sRow = currentBlock.getSamplesByRow(samples.get(sample).getSample().getRow()); List nodesToAdd = new ArrayList<>(); for (Sample s : sRow) { - nodesToAdd.addAll(searchTable.getNodesbySample(s.getId(), radiusUsed)); + // nodesToAdd.addAll(searchTable.getNodesbySample(s.getId(), radiusUsed)); + nodesToAdd.addAll(searchTable.getValidatorNodesbySample(s.getId(), radiusUsed)); } Sample[] sColumn = currentBlock.getSamplesByColumn(samples.get(sample).getSample().getColumn()); for (Sample s : sColumn) { - nodesToAdd.addAll(searchTable.getNodesbySample(s.getIdByColumn(), radiusUsed)); + // nodesToAdd.addAll(searchTable.getNodesbySample(s.getIdByColumn(), radiusUsed)); + nodesToAdd.addAll(searchTable.getValidatorNodesbySample(s.getId(), radiusUsed)); } nodesBySample.addAll(new ArrayList<>(new LinkedHashSet<>(nodesToAdd))); diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index f64fe04c..cf43aa03 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -115,7 +115,8 @@ public BigInteger getRadiusNonValidator() { public BigInteger[] doSampling() { - aggressiveness += aggressiveness_step; + if(CommonState.getTime()<200)aggressiveness=aggressiveness_step; + else aggressiveness += aggressiveness_step; // System.out.println("[" + srcNode + "] nodes " + nodes.size()); List toRemove = new ArrayList<>(); for (BigInteger n : nodes.keySet()) { @@ -147,7 +148,6 @@ public BigInteger[] doSampling() { if (nodes.isEmpty()) { createNodes(); - // addExtraNodes(); System.out.println( "[" + CommonState.getTime() @@ -163,6 +163,7 @@ public BigInteger[] doSampling() { + askedNodes.size()); } if (nodes.isEmpty()) { + if (this instanceof ValidatorSamplingOperation) addExtraNodes(); // addExtraNodes(); System.out.println( "[" diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index abaf4c99..95627633 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -10,6 +10,7 @@ import java.util.Map; import peersim.core.CommonState; import peersim.kademlia.das.Block; +import peersim.kademlia.das.KademliaCommonConfigDas; import peersim.kademlia.das.MissingNode; import peersim.kademlia.das.Sample; import peersim.kademlia.das.SearchTable; @@ -244,8 +245,12 @@ public BigInteger[] getSamples() { } protected void addExtraNodes() { + // if (CommonState.getTime() - this.getTimestamp() > 1000) + aggressiveness_step = KademliaCommonConfigDas.aggressiveness_step * 2; if (CommonState.getTime() - this.getTimestamp() > 1000) - aggressiveness_step = aggressiveness_step * 2; + aggressiveness_step = KademliaCommonConfigDas.aggressiveness_step * 4; + if (CommonState.getTime() - this.getTimestamp() > 2000) + aggressiveness_step = KademliaCommonConfigDas.aggressiveness_step * 8; List missingSamples = Arrays.asList(getSamples()); Collections.shuffle(missingSamples); for (BigInteger sample : missingSamples) { @@ -253,20 +258,31 @@ protected void addExtraNodes() { List nodesBySample = new ArrayList<>(); BigInteger radiusUsed = radiusValidator; if (column > 0) { - Sample[] sRow = currentBlock.getSamplesByRow(samples.get(sample).getSample().getRow()); + // Sample[] sRow = currentBlock.getSamplesByRow(samples.get(sample).getSample().getRow()); List nodes = new ArrayList<>(); - for (Sample s : sRow) { - nodes.addAll(searchTable.getNodesbySample(s.getId(), radiusUsed)); - } + // for (Sample s : sRow) { + // nodes.addAll(searchTable.getNodesbySample(s.getId(), radiusUsed)); + nodes.addAll( + searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusValidator)); + nodes.addAll( + searchTable.getNonValidatorNodesbySample( + samples.get(sample).getId(), radiusNonValidator)); + // } nodesBySample.addAll(new ArrayList<>(new LinkedHashSet<>(nodes))); } else { - Sample[] sColumn = - currentBlock.getSamplesByColumn(samples.get(sample).getSample().getColumn()); + // Sample[] sColumn = + // currentBlock.getSamplesByColumn(samples.get(sample).getSample().getColumn()); List nodes = new ArrayList<>(); - for (Sample s : sColumn) { - nodes.addAll(searchTable.getNodesbySample(s.getIdByColumn(), radiusUsed)); - } + // for (Sample s : sColumn) { + // nodes.addAll(searchTable.getNodesbySample(s.getIdByColumn(), radiusUsed)); + nodes.addAll( + searchTable.getValidatorNodesbySample( + samples.get(sample).getIdByColumn(), radiusValidator)); + nodes.addAll( + searchTable.getNonValidatorNodesbySample( + samples.get(sample).getIdByColumn(), radiusNonValidator)); + // } nodesBySample.addAll(new ArrayList<>(new LinkedHashSet<>(nodes))); } @@ -282,7 +298,7 @@ protected void addExtraNodes() { nodes.get(id).addSample(samples.get(sample)); } count++; - if (count > aggressiveness - 2) return; + if (count == aggressiveness) return; } } } From 01f0a07ed2c18a8d91f3796a065839a94cfdb5eb Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sat, 13 Jan 2024 11:17:40 +0100 Subject: [PATCH 79/98] canceling pending requests --- .../config/malicious/dasprotocolevil0.75.cfg | 6 +- simulator/run.sh | 2 +- .../main/java/peersim/kademlia/Message.java | 8 +++ .../peersim/kademlia/das/DASProtocol.java | 66 ++++++++++++++----- .../kademlia/das/KademliaCommonConfigDas.java | 2 +- .../operations/RandomSamplingOperation.java | 1 - .../das/operations/SamplingOperation.java | 2 +- .../ValidatorSamplingOperation.java | 27 +++++--- 8 files changed, 81 insertions(+), 33 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil0.75.cfg b/simulator/config/malicious/dasprotocolevil0.75.cfg index ed05f4ce..628285af 100644 --- a/simulator/config/malicious/dasprotocolevil0.75.cfg +++ b/simulator/config/malicious/dasprotocolevil0.75.cfg @@ -5,12 +5,12 @@ # ::::: GLOBAL :::::: # Network size -SIZE 50000 +SIZE 5000 # Random seed K 5 -MINDELAY 5 +MINDELAY 10 MAXDELAY 100 #Simulation time in ms @@ -151,4 +151,4 @@ control.1refresh.step REFRESH_STEP control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logsDasEvil0 +control.4.logfolder logsDasEvil0.75 diff --git a/simulator/run.sh b/simulator/run.sh index ee1bc43b..f3b9f152 100755 --- a/simulator/run.sh +++ b/simulator/run.sh @@ -4,4 +4,4 @@ if [ "$#" -ne 1 ]; then fi mkdir -p logs rm -f logs/*.csv -java -Xmx200000m -cp lib/djep-1.0.0.jar:lib/jep-2.3.0.jar:target/service-discovery-1.0-SNAPSHOT.jar:lib/gs-core-2.0.jar:lib/pherd-1.0.jar:lib/mbox2-1.0.jar:lib/gs-ui-swing-2.0.jar -ea peersim.Simulator $1 +java -Xmx300000m -cp lib/djep-1.0.0.jar:lib/jep-2.3.0.jar:target/service-discovery-1.0-SNAPSHOT.jar:lib/gs-core-2.0.jar:lib/pherd-1.0.jar:lib/mbox2-1.0.jar:lib/gs-ui-swing-2.0.jar -ea peersim.Simulator $1 diff --git a/simulator/src/main/java/peersim/kademlia/Message.java b/simulator/src/main/java/peersim/kademlia/Message.java index f1faa2ee..18e4f985 100755 --- a/simulator/src/main/java/peersim/kademlia/Message.java +++ b/simulator/src/main/java/peersim/kademlia/Message.java @@ -76,6 +76,8 @@ public class Message extends SimpleEvent { public static final int MSG_SEED_SAMPLE = 17; + public static final int MSG_CANCEL_SAMPLE = 18; + /** * Message Type: INIT_FIND_REGION_BASED (command to a node to start looking for node within a * region) @@ -225,6 +227,10 @@ public static final Message makeSeedSample(Object body) { return new Message(MSG_SEED_SAMPLE, body); } + public static final Message makeCancelSample(Object body) { + return new Message(MSG_CANCEL_SAMPLE, body); + } + // ______________________________________________________________________________________________ /** * Encapsulates the creation of a find value request @@ -289,6 +295,8 @@ public String typeToString() { return "MSG_GET_ANY_SAMPLE_RESPONSE"; case MSG_SEED_SAMPLE: return "MSG_SEED_SAMPLE"; + case MSG_CANCEL_SAMPLE: + return "MSG_CANCEL_SAMPLE"; default: return "UNKNOW:" + type; } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 59173f8c..ac66b467 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -85,7 +85,7 @@ public abstract class DASProtocol implements Cloneable, EDProtocol, KademliaEven protected int dasID; /** trace message sent for timeout purpose */ - protected TreeMap sentMsg; + protected TreeMap sentMsg; protected long time; @@ -95,6 +95,8 @@ public abstract class DASProtocol implements Cloneable, EDProtocol, KademliaEven protected HashMap> missingSamples; + protected List opsToRemove; + /** * Replicate this object by returning an identical copy.
* It is called by the initializer and do not fill any particular field. @@ -135,8 +137,9 @@ public DASProtocol(String prefix) { uploadInterfaceBusyUntil = 0; - sentMsg = new TreeMap(); + sentMsg = new TreeMap(); + opsToRemove = new ArrayList(); // searchTable = new SearchTable(); isBuilder = false; missingSamples = new HashMap<>(); @@ -195,6 +198,10 @@ public void processEvent(Node myNode, int myPid, Object event) { m = (Message) event; handleSeedSample(m, myPid); break; + case Message.MSG_CANCEL_SAMPLE: + m = (Message) event; + handleCancelSampling(m, myPid); + break; case Message.MSG_GET_SAMPLE_RESPONSE: m = (Message) event; logger.info("Send message removed " + m.ackId); @@ -204,11 +211,11 @@ public void processEvent(Node myNode, int myPid, Object event) { case Timeout.TIMEOUT: // timeout Timeout t = (Timeout) event; - SamplingOperation sop = samplingOp.get(t.opID); if (sentMsg.containsKey(t.msgID)) { // the response msg isn't arrived // remove form sentMsg logger.warning("Timeouuuuut! " + t.msgID + " " + t.node); - sentMsg.remove(t.msgID); + SamplingOperation sop = samplingOp.get(t.opID); + // sentMsg.remove(t.msgID); // this.searchTable.removeNode(t.node); if (sop != null) { if (!sop.completed()) { @@ -303,6 +310,7 @@ protected void handleInitNewBlock(Message m, int myPid) { } samplingOp.clear(); kadOps.clear(); + opsToRemove.clear(); } protected void handleSeedSample(Message m, int myPid) { @@ -408,6 +416,11 @@ private void reconstruct(Sample s) { } } + protected void handleCancelSampling(Message m, int myPid) { + logger.warning("Canceling pending samples requests from " + m.src.getId()); + opsToRemove.add(m.operationId); + } + protected void handleGetSampleResponse(Message m, int myPid) { if (m.body == null) return; @@ -542,6 +555,24 @@ protected void handleGetSampleResponse(Message m, int myPid) { if (op.completed()) { // logger.warning("Operation completed"); // samplingOp.remove(m.operationId); + List sentMsgsOp = new ArrayList<>(); + for (Message msg : sentMsg.values()) { + if (msg.operationId == op.getId()) sentMsgsOp.add(msg); + } + for (Message msg : sentMsgsOp) { + Message response = new Message(Message.MSG_CANCEL_SAMPLE); + response.operationId = op.getId(); + response.dst = msg.dst; + response.src = this.kadProtocol.getKademliaNode(); + // response.ackId = msg.id; // set ACK number*/ + /*response.value = + searchTable.getNeighbours( + KademliaCommonConfigDas.MAX_NODES_RETURNED * toSend.get(msg).size()); + if (isEvil) + response.value = searchTable.getEvilNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED);*/ + sendMessage(response, response.dst.getId(), myPid); + sentMsg.remove(msg.id); + } toRemove.add(op.getId()); if (op instanceof ValidatorSamplingOperation) logger.warning( @@ -573,13 +604,16 @@ private HashMap> findMissingSamples(Sample[] samples) { // if (kv.get(id) != null) { // Sample s = (Sample) kv.get(id); for (Message msg : missingSamples.get(id)) { - - if (toSend.get(msg) != null) { - toSend.get(msg).add(s); + if (!opsToRemove.contains(msg.operationId)) { + if (toSend.get(msg) != null) { + toSend.get(msg).add(s); + } else { + List sToSend = new ArrayList<>(); + sToSend.add(s); + toSend.put(msg, sToSend); + } } else { - List sToSend = new ArrayList<>(); - sToSend.add(s); - toSend.put(msg, sToSend); + opsToRemove.remove(msg.operationId); } } toRemove.add(s.getId()); @@ -649,7 +683,7 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { } logger.info("Transmission " + latency + " " + transDelay); // add to sent msg - this.sentMsg.put(m.id, m.timestamp); + // this.sentMsg.put(m.id, m.timestamp); EDSimulator.add(latency, m, dest, myPid); } @@ -660,11 +694,11 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { logger.info("Send message added " + m.id + " " + latency + " " + destId); // add to sent msg - this.sentMsg.put(m.id, m.timestamp); + this.sentMsg.put(m.id, m); /// BigInteger[] samples = (Sample[]) m.body; - long timeout = latency * 4; - if (timeout < 200) timeout = 200; + long timeout = latency * 2 * 4; // 4 RTT + // if (timeout < 200) timeout = 200; EDSimulator.add(timeout, t, src, myPid); // set delay = 2*RTT } } @@ -804,13 +838,13 @@ protected boolean doSampling(SamplingOperation sop) { sendMessage(msg, nextNode, dasID); sop.getMessages(); } - if (!success && !sop.getStarted()) { + /*if (!success && !sop.getStarted()) { Timeout t = new Timeout(this.getKademliaId(), sop.getId(), sop.getId()); // add to sent msg this.sentMsg.put(sop.getId(), CommonState.getTime()); EDSimulator.add(100, t, this.getKademliaProtocol().getNode(), dasID); // set delay = 2*RTT - } + }*/ } return success; } diff --git a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java index e8c05253..78bca390 100644 --- a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java @@ -53,7 +53,7 @@ public class KademliaCommonConfigDas { /** Default upload bandwith of a non-validator in Mbits/sec */ public static int NON_VALIDATOR_UPLOAD_RATE = 100; - public static int BUILDER_UPLOAD_RATE = 50000; + public static int BUILDER_UPLOAD_RATE = 100000; public static int VALIDATOR_DEADLINE = 4000; public static int RANDOM_SAMPLING_DEADLINE = 12000; diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index 8e4cca64..03543437 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -8,7 +8,6 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; - import peersim.core.CommonState; import peersim.kademlia.das.Block; import peersim.kademlia.das.KademliaCommonConfigDas; diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index cf43aa03..2912bd8b 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -115,7 +115,7 @@ public BigInteger getRadiusNonValidator() { public BigInteger[] doSampling() { - if(CommonState.getTime()<200)aggressiveness=aggressiveness_step; + if (CommonState.getTime() < 200) aggressiveness = aggressiveness_step; else aggressiveness += aggressiveness_step; // System.out.println("[" + srcNode + "] nodes " + nodes.size()); List toRemove = new ArrayList<>(); diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index 95627633..b0cf8cf4 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -8,9 +8,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import peersim.core.CommonState; import peersim.kademlia.das.Block; -import peersim.kademlia.das.KademliaCommonConfigDas; import peersim.kademlia.das.MissingNode; import peersim.kademlia.das.Sample; import peersim.kademlia.das.SearchTable; @@ -25,6 +23,7 @@ public class ValidatorSamplingOperation extends SamplingOperation { // private RoutingTable rou; protected int row, column; + protected HashMap extras; /** * default constructor * @@ -60,6 +59,7 @@ public ValidatorSamplingOperation( } } this.searchTable = searchTable; + this.extras = new HashMap<>(); // createNodes(); } @@ -74,6 +74,7 @@ public void elaborateResponse(Sample[] sam) { samplesCount++; } } + this.extras.remove(s.getId()); /*} else { if (samples.containsKey(s.getIdByColumn())) { FetchingSample fs = samples.get(s.getIdByColumn()); @@ -120,6 +121,8 @@ public void elaborateResponse(Sample[] sam, BigInteger n) { samplesCount++; } } + this.extras.remove(s.getId()); + /*} else { if (samples.containsKey(s.getIdByColumn())) { FetchingSample fs = samples.get(s.getIdByColumn()); @@ -246,17 +249,18 @@ public BigInteger[] getSamples() { protected void addExtraNodes() { // if (CommonState.getTime() - this.getTimestamp() > 1000) - aggressiveness_step = KademliaCommonConfigDas.aggressiveness_step * 2; - if (CommonState.getTime() - this.getTimestamp() > 1000) + // aggressiveness_step = KademliaCommonConfigDas.aggressiveness_step * 2; + /*if (CommonState.getTime() - this.getTimestamp() > 1000) aggressiveness_step = KademliaCommonConfigDas.aggressiveness_step * 4; - if (CommonState.getTime() - this.getTimestamp() > 2000) - aggressiveness_step = KademliaCommonConfigDas.aggressiveness_step * 8; + if (CommonState.getTime() - this.getTimestamp() > 2000)*/ + // aggressiveness_step = KademliaCommonConfigDas.aggressiveness_step * 4; + int globalcount = 0; List missingSamples = Arrays.asList(getSamples()); Collections.shuffle(missingSamples); + // int totalcount = 0; for (BigInteger sample : missingSamples) { - int count = 0; List nodesBySample = new ArrayList<>(); - BigInteger radiusUsed = radiusValidator; + // BigInteger radiusUsed = radiusValidator; if (column > 0) { // Sample[] sRow = currentBlock.getSamplesByRow(samples.get(sample).getSample().getRow()); List nodes = new ArrayList<>(); @@ -288,7 +292,7 @@ protected void addExtraNodes() { nodesBySample.removeAll(askedNodes); Collections.shuffle(nodesBySample); - // int max = 0; + int count = 0; if (nodesBySample != null && nodesBySample.size() > 0) { for (BigInteger id : nodesBySample) { if (!nodes.containsKey(id)) { @@ -298,9 +302,12 @@ protected void addExtraNodes() { nodes.get(id).addSample(samples.get(sample)); } count++; - if (count == aggressiveness) return; + globalcount++; + if (count >= aggressiveness) break; + // if (count >= 256) return; } } + if (globalcount > 256) break; } } From 101c9be1e08634891d11a234310e776afd486cc4 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sat, 13 Jan 2024 17:39:18 +0100 Subject: [PATCH 80/98] fix --- simulator/config/dasprotocol.cfg | 65 ++++++++++--------- .../peersim/kademlia/das/DASProtocol.java | 24 +++---- .../kademlia/das/KademliaCommonConfigDas.java | 4 +- 3 files changed, 47 insertions(+), 46 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 83d9254e..00330f52 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -1,4 +1,4 @@ -# :::::::::::::::::::::::::::::::::::::::::::::::::::::: +# :::::::::::::::::::::::::::::::::`::::::::::::::::::::: # :: Kademlia Default Configuration # :::::::::::::::::::::::::::::::::::::::::::::::::::::: @@ -11,20 +11,20 @@ SIZE 5000 K 5 MINDELAY 5 -MAXDELAY 100 +MAXDELAY 200 #Simulation time in ms -SIM_TIME 1000*60*1 +SIM_TIME 11999 #Traffic generator is executed every TRAFFIC_STEP TRAFFIC_STEP 12000 #10000000/SIZE #Tracing module is executed every OBSERVER_STEP -OBSERVER_STEP 20000 +OBSERVER_STEP 10000 #Turbulence module is executed every TURBULENCE_STEP enabling churning TURBULENCE_STEP 1000 -TURBULENCE_STEP_NONVAL 1000 -REFRESH_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 +REFRESH_STEP 10000000 # add network config parameters to simulation random.seed 24680 @@ -94,9 +94,9 @@ init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol init.1uniqueNodeID.protocolEvildas 8evildasprotocol -init.1uniqueNodeID.validator_rate 0.5 -init.1uniqueNodeID.evilNodeRatioValidator 0 -init.1uniqueNodeID.evilNodeRatioNonValidator 0 +init.1uniqueNodeID.validator_rate 0.2 +init.1uniqueNodeID.evilNodeRatioValidator 0.0 +init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 #Adds initial state to the routing tables @@ -120,34 +120,35 @@ control.1refresh peersim.kademlia.das.RefreshSearchTable control.1refresh.step REFRESH_STEP # turbulence non-validator -control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas -control.2turbolenceAdd.protocolkad 3kademlia -control.2turbolenceAdd.protocoldasbuilder 4dasprotocol -control.2turbolenceAdd.protocoldasvalidator 5dasprotocol -control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol -control.2turbolenceAdd.protocolEvildas 7evildasprotocol -control.2turbolenceAdd.transport 2unreltr -control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL -control.2turbolenceAdd.p_idle 0.1 -control.2turbolenceAdd.p_rem 0.45 -control.2turbolenceAdd.p_add 0.45 + +#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +#control.2turbolenceAdd.protocolkad 3kademlia +#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.2turbolenceAdd.protocolEvildas 7evildasprotocol +#control.2turbolenceAdd.transport 2unreltr +#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +#control.2turbolenceAdd.p_idle 0.1 +#control.2turbolenceAdd.p_rem 0.45 +#control.2turbolenceAdd.p_add 0.45 # turbulence validators -control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator -control.3turbolenceAdd.protocolkad 3kademlia -control.3turbolenceAdd.protocoldasbuilder 4dasprotocol -control.3turbolenceAdd.protocoldasvalidator 5dasprotocol -control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol -control.3turbolenceAdd.protocolEvildas 7evildasprotocol -control.3turbolenceAdd.transport 2unreltr -control.3turbolenceAdd.step TURBULENCE_STEP -control.3turbolenceAdd.p_idle 0.9 -control.3turbolenceAdd.p_rem 0.05 -control.3turbolenceAdd.p_add 0.05 +#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +#control.3turbolenceAdd.protocolkad 3kademlia +#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.3turbolenceAdd.protocolEvildas 7evildasprotocol +#control.3turbolenceAdd.transport 2unreltr +#control.3turbolenceAdd.step TURBULENCE_STEP +#control.3turbolenceAdd.p_idle 0.9 +#control.3turbolenceAdd.p_rem 0.05 +#control.3turbolenceAdd.p_add 0.05 # ::::: OBSERVER ::::: #The observer is executed every OBSERVER_STEP and will generate data traces control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logsDas2 +control.4.logfolder logs5000 diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index ac66b467..c3453a84 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -215,7 +215,7 @@ public void processEvent(Node myNode, int myPid, Object event) { // remove form sentMsg logger.warning("Timeouuuuut! " + t.msgID + " " + t.node); SamplingOperation sop = samplingOp.get(t.opID); - // sentMsg.remove(t.msgID); + sentMsg.remove(t.msgID); // this.searchTable.removeNode(t.node); if (sop != null) { if (!sop.completed()) { @@ -555,7 +555,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { if (op.completed()) { // logger.warning("Operation completed"); // samplingOp.remove(m.operationId); - List sentMsgsOp = new ArrayList<>(); + /*List sentMsgsOp = new ArrayList<>(); for (Message msg : sentMsg.values()) { if (msg.operationId == op.getId()) sentMsgsOp.add(msg); } @@ -563,16 +563,16 @@ protected void handleGetSampleResponse(Message m, int myPid) { Message response = new Message(Message.MSG_CANCEL_SAMPLE); response.operationId = op.getId(); response.dst = msg.dst; - response.src = this.kadProtocol.getKademliaNode(); - // response.ackId = msg.id; // set ACK number*/ - /*response.value = - searchTable.getNeighbours( - KademliaCommonConfigDas.MAX_NODES_RETURNED * toSend.get(msg).size()); - if (isEvil) - response.value = searchTable.getEvilNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED);*/ - sendMessage(response, response.dst.getId(), myPid); + response.src = this.kadProtocol.getKademliaNode();*/ + // response.ackId = msg.id; // set ACK number*/ + /*response.value = + searchTable.getNeighbours( + KademliaCommonConfigDas.MAX_NODES_RETURNED * toSend.get(msg).size()); + if (isEvil) + response.value = searchTable.getEvilNeighbours(KademliaCommonConfigDas.MAX_NODES_RETURNED);*/ + /*sendMessage(response, response.dst.getId(), myPid); sentMsg.remove(msg.id); - } + }*/ toRemove.add(op.getId()); if (op instanceof ValidatorSamplingOperation) logger.warning( @@ -698,7 +698,7 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { /// BigInteger[] samples = (Sample[]) m.body; long timeout = latency * 2 * 4; // 4 RTT - // if (timeout < 200) timeout = 200; + if (timeout < 250) timeout = 250; EDSimulator.add(timeout, t, src, myPid); // set delay = 2*RTT } } diff --git a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java index 78bca390..b6f6a643 100644 --- a/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/KademliaCommonConfigDas.java @@ -48,12 +48,12 @@ public class KademliaCommonConfigDas { public static int MAX_HOPS = 5000; /** Default upload bandwith of a validator in Mbits/sec */ - public static int VALIDATOR_UPLOAD_RATE = 10000; + public static int VALIDATOR_UPLOAD_RATE = 1000; /** Default upload bandwith of a non-validator in Mbits/sec */ public static int NON_VALIDATOR_UPLOAD_RATE = 100; - public static int BUILDER_UPLOAD_RATE = 100000; + public static int BUILDER_UPLOAD_RATE = 10000; public static int VALIDATOR_DEADLINE = 4000; public static int RANDOM_SAMPLING_DEADLINE = 12000; From 3492c01ec9281e1d408f57fd4ed327b5afd2348f Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sat, 13 Jan 2024 22:51:36 +0100 Subject: [PATCH 81/98] messages report --- simulator/config/dasprotocol.cfg | 9 ++- .../peersim/kademlia/KademliaObserver.java | 67 +++++++++++++++++-- .../peersim/kademlia/KademliaProtocol.java | 2 +- .../main/java/peersim/kademlia/Message.java | 20 ++++++ .../peersim/kademlia/das/DASProtocol.java | 6 +- 5 files changed, 93 insertions(+), 11 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 00330f52..4137138b 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 5000 +SIZE 1000 # Random seed K 5 @@ -64,26 +64,31 @@ protocol.4dasprotocol peersim.kademlia.das.DASProtocolBuilder protocol.4dasprotocol.transport 2unreltr protocol.4dasprotocol.kademlia 3kademlia protocol.4dasprotocol.reportDiscovery false +protocol.4dasprotocol.reportMsg true protocol.5dasprotocol peersim.kademlia.das.DASProtocolValidator protocol.5dasprotocol.transport 2unreltr protocol.5dasprotocol.kademlia 3kademlia protocol.5dasprotocol.reportDiscovery false +protocol.5dasprotocol.reportMsg true protocol.6dasprotocol peersim.kademlia.das.DASProtocolNonValidator protocol.6dasprotocol.transport 2unreltr protocol.6dasprotocol.kademlia 3kademlia protocol.6dasprotocol.reportDiscovery false +protocol.6dasprotocol.reportMsg true protocol.7evildasprotocol peersim.kademlia.das.DASProtocolEvilValidator protocol.7evildasprotocol.transport 2unreltr protocol.7evildasprotocol.kademlia 3kademlia protocol.7evildasprotocol.reportDiscovery false +protocol.7evildasprotocol.reportMsg true protocol.8evildasprotocol peersim.kademlia.das.DASProtocolEvilNonValidator protocol.8evildasprotocol.transport 2unreltr protocol.8evildasprotocol.kademlia 3kademlia protocol.8evildasprotocol.reportDiscovery false +protocol.8evildasprotocol.reportMsg true # ::::: INITIALIZERS ::::: #Class that initializes nodes with kademlia protocol and generates uniform ids @@ -111,7 +116,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 512 +control.0traffic.block_dim_size 100 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia diff --git a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java index 69bdf130..12e12910 100755 --- a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java +++ b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java @@ -3,6 +3,7 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.math.BigInteger; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -60,6 +61,10 @@ public class KademliaObserver implements Control { private static HashMap> peerDiscoveries = new HashMap>(); + private static HashMap msgsIn = new HashMap<>(); + private static HashMap msgsOut = new HashMap<>(); + private static HashMap bytesIn = new HashMap<>(); + private static HashMap bytesOut = new HashMap<>(); /** Name of the folder where experiment logs are written */ private static String logFolderName; @@ -123,9 +128,11 @@ public static void writeOut() { if (!directory.exists()) { directory.mkdir(); } + + HashMap> msgsInOut = writeMessages(); // Write messages log to file if not empty - if (!messages.isEmpty()) { - writeLogs(messages, logFolderName + "/" + "messages.csv"); + if (!msgsInOut.isEmpty()) { + writeLogs(msgsInOut, logFolderName + "/" + "messages.csv"); } if (!operations.isEmpty()) { writeLogs(operations, logFolderName + "/" + "operation.csv"); @@ -180,14 +187,44 @@ public boolean execute() { * @param m The message to report * @param sent a boolean indicating whether the message was sent or received. */ - public static void reportMsg(Message m, boolean sent) { + public static void reportMsg(Message m, boolean sent, BigInteger id) { // Messages without a source are control messages sent by the traffic control, // so we don't want to log them. - if (m.src == null) return; + + if (m.src == null) { + // System.exit(-1); + return; + } + // System.out.println("Reporting msg " + m); // Add the message to the message log, but first check if it hasn't already been added - assert (!messages.keySet().contains(m.id)); - messages.put(m.id, m.toMap(sent)); + // assert (!messages.keySet().contains(m.id)); + // messages.put(m.id, m.toMap(sent)); + if (sent) { + if (msgsOut.get(id) == null) { + msgsOut.put(id, 1); + bytesOut.put(id, m.getSize()); + } else { + Integer msgs = msgsOut.get(id); + Integer bytes = bytesOut.get(id); + bytes += m.getSize(); + msgs++; + msgsOut.put(id, msgs); + bytesOut.put(id, bytes); + } + } else { + if (msgsIn.get(id) == null) { + msgsIn.put(id, 1); + bytesIn.put(id, m.getSize()); + } else { + Integer msgs = msgsIn.get(id); + Integer bytes = bytesOut.get(id); + msgs++; + bytes += m.getSize(); + msgsIn.put(id, msgs); + bytesIn.put(id, bytes); + } + } } /** @@ -227,4 +264,22 @@ public static void reportPeerDiscovery(Message m, SearchTable st) { result.put("validators_discovered", st.getValidatorsNeighboursCount()); peerDiscoveries.put(m.id, result); } + + private static HashMap> writeMessages() { + HashMap> msgs = new HashMap<>(); + + Long msgId = (long) 0; + for (BigInteger id : msgsIn.keySet()) { + System.out.println("Writing messages log " + id); + Map result = new HashMap(); + result.put("id", id); + result.put("msgsIn", msgsIn.get(id)); + result.put("msgsOut", msgsOut.get(id)); + result.put("bytesIn", bytesIn.get(id)); + result.put("bytesOut", bytesOut.get(id)); + msgs.put(msgId, result); + msgId++; + } + return msgs; + } } diff --git a/simulator/src/main/java/peersim/kademlia/KademliaProtocol.java b/simulator/src/main/java/peersim/kademlia/KademliaProtocol.java index 6fe4c3d9..7ee61169 100755 --- a/simulator/src/main/java/peersim/kademlia/KademliaProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/KademliaProtocol.java @@ -557,7 +557,7 @@ public void processEvent(Node myNode, int myPid, Object event) { // If the event is a message, report the message to the Kademlia observer. if (event instanceof Message) { m = (Message) event; - KademliaObserver.reportMsg(m, false); + // KademliaObserver.reportMsg(m, false); } // Handle the event based on its type. diff --git a/simulator/src/main/java/peersim/kademlia/Message.java b/simulator/src/main/java/peersim/kademlia/Message.java index 18e4f985..27adea52 100755 --- a/simulator/src/main/java/peersim/kademlia/Message.java +++ b/simulator/src/main/java/peersim/kademlia/Message.java @@ -1,7 +1,9 @@ package peersim.kademlia; +import java.math.BigInteger; import java.util.HashMap; import java.util.Map; +import peersim.kademlia.das.Sample; /** * Message class provide all functionalities to magage the various messages, principally LOOKUP @@ -110,6 +112,8 @@ public class Message extends SimpleEvent { /** Available to count the number of hops the message did. */ protected int nrHops = 0; + protected int size = 0; + // ______________________________________________________________________________________________ /** * Creates an empty message by using default values (message type = MSG_LOOKUP and @@ -139,6 +143,19 @@ public Message(int messageType, Object body) { super(messageType); this.id = (ID_GENERATOR++); this.body = body; + + if (body instanceof BigInteger[]) { + BigInteger[] reqs = (BigInteger[]) body; + size += 32 * reqs.length; + size += 64; + size += 4; + } else if (body instanceof Sample[]) { + Sample[] samples = (Sample[]) body; + size += 512 * samples.length; + size += 15 * 32; + size += 64; + size += 4; + } } // ______________________________________________________________________________________________ @@ -248,6 +265,9 @@ public String toString() { return s + "[Type=" + typeToString() + "] BODY=(...)"; } + public int getSize() { + return size; + } // ______________________________________________________________________________________________ public Message copy() { Message dolly = new Message(); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index c3453a84..60fdaf00 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -129,6 +129,7 @@ public DASProtocol(String prefix) { reportDiscovery = Configuration.getBoolean(prefix + "." + PAR_DISC, false); msgReport = Configuration.getBoolean(prefix + "." + PAR_MSG, false); + // System.out.println("Msgreport " + msgReport + " " + prefix); // kv = new KeyValueStore(); kv = new HashSet<>(); samplingOp = new LinkedHashMap(); @@ -174,7 +175,7 @@ public void processEvent(Node myNode, int myPid, Object event) { if (s instanceof Message) { m = (Message) event; // m.dst = this.kadProtocol.getKademliaNode(); - if (msgReport) KademliaObserver.reportMsg(m, false); + if (msgReport) KademliaObserver.reportMsg(m, false, this.getKademliaId()); /*if (m.src != null) { Node n = Util.nodeIdtoNode(m.src.getId(), kademliaId); searchTable.addNeighbour(new Neighbour(m.src.getId(), n, n.getDASProtocol().isEvil())); @@ -428,7 +429,7 @@ protected void handleGetSampleResponse(Message m, int myPid) { Sample[] samples = (Sample[]) m.body; // searchTable.addNodes((BigInteger[]) m.value); - // if (reportDiscovery && !isEvil()) KademliaObserver.reportPeerDiscovery(m, searchTable); + if (reportDiscovery && !isEvil()) KademliaObserver.reportPeerDiscovery(m, searchTable); /*for (Neighbour neigh : (Neighbour[]) m.value) { if (neigh.getId().compareTo(builderAddress) != 0) searchTable.addNeighbour(neigh); }*/ @@ -643,6 +644,7 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { Node src = this.kadProtocol.getNode(); Node dest = Util.nodeIdtoNode(destId, kademliaId); transport = (UnreliableTransport) (Network.prototype).getProtocol(tid); + if (msgReport) KademliaObserver.reportMsg(m, true, this.getKademliaId()); if (m.getType() != Message.MSG_GET_SAMPLE_RESPONSE && m.getType() != Message.MSG_SEED_SAMPLE) { transport.send(src, dest, m, myPid); From 06025229cbf52ee15bb760f58b1f9721982c57f0 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sun, 14 Jan 2024 12:06:36 +0100 Subject: [PATCH 82/98] assignig samples when missing nodes in id space --- simulator/config/dasprotocol.cfg | 2 +- .../peersim/kademlia/KademliaObserver.java | 2 +- .../kademlia/das/DASProtocolBuilder.java | 63 ++++++++++--------- .../operations/RandomSamplingOperation.java | 33 +++++----- .../PairwiseFixedLatencyTransport.java | 2 +- 5 files changed, 50 insertions(+), 52 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index 4137138b..bec53095 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -156,4 +156,4 @@ control.1refresh.step REFRESH_STEP control.4 peersim.kademlia.KademliaObserver control.4.protocol 3kademlia control.4.step OBSERVER_STEP -control.4.logfolder logs5000 +control.4.logfolder logs diff --git a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java index 12e12910..5a52decc 100755 --- a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java +++ b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java @@ -270,7 +270,7 @@ private static HashMap> writeMessages() { Long msgId = (long) 0; for (BigInteger id : msgsIn.keySet()) { - System.out.println("Writing messages log " + id); + // System.out.println("Writing messages log " + id); Map result = new HashMap(); result.put("id", id); result.put("msgsIn", msgsIn.get(id)); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index 82625755..a0350829 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -53,40 +53,41 @@ protected void handleInitNewBlock(Message m, int myPid) { currentBlock.computeRegionRadius( KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, searchTable.getValidatorsIndexed().size()); + BigInteger radiusUsed = radiusValidator; + while (!inRegion) { + + List idsValidators = + searchTable.getValidatorNodesbySample(s.getIdByRow(), radiusUsed); + idsValidators.addAll(searchTable.getValidatorNodesbySample(s.getIdByColumn(), radiusUsed)); + for (BigInteger id : idsValidators) { + + logger.info( + "Sending sample to validator " + + s.getIdByRow() + + " " + + s.getIdByColumn() + + " to " + + id); + Node n = Util.nodeIdtoNode(id, kademliaId); + DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); + if (dasProt.isBuilder()) continue; + if (n.isUp()) { - // while (!inRegion) { - - List idsValidators = - searchTable.getValidatorNodesbySample(s.getIdByRow(), radiusValidator); - idsValidators.addAll( - searchTable.getValidatorNodesbySample(s.getIdByColumn(), radiusValidator)); - for (BigInteger id : idsValidators) { - - logger.info( - "Sending sample to validator " - + s.getIdByRow() - + " " - + s.getIdByColumn() - + " to " - + id); - Node n = Util.nodeIdtoNode(id, kademliaId); - DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); - if (dasProt.isBuilder()) continue; - if (n.isUp()) { - - if (!samplesToRequest.containsKey(id)) { - List samples = new ArrayList<>(); - samples.add(s.getId()); - samplesToRequest.put(id, samples); - } else { - samplesToRequest.get(id).add(s.getId()); - } - samplesValidators++; - if (inRegion == false) { - samplesWithinRegion++; - inRegion = true; + if (!samplesToRequest.containsKey(id)) { + List samples = new ArrayList<>(); + samples.add(s.getId()); + samplesToRequest.put(id, samples); + } else { + samplesToRequest.get(id).add(s.getId()); + } + samplesValidators++; + if (inRegion == false) { + samplesWithinRegion++; + inRegion = true; + } } } + if (!inRegion) radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); } List idsNonValidators = diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index 03543437..6c6e2031 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -139,18 +139,18 @@ protected void createNodes() { List nodesBySample = new ArrayList<>(); - // BigInteger radiusUsed = radiusValidator; + BigInteger radiusUsed = radiusValidator; - // while (nodesBySample.isEmpty() && radiusUsed.compareTo(Block.MAX_KEY) == -1) { - // nodesBySample.addAll(searchTable.getNodesbySample(samples.get(sample).getId(), - // radiusUsed)); - // nodesBySample.addAll( - // searchTable.getNodesbySample(samples.get(sample).getIdByColumn(), radiusUsed)); - nodesBySample.addAll( - searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusValidator)); - nodesBySample.addAll( - searchTable.getValidatorNodesbySample( - samples.get(sample).getIdByColumn(), radiusValidator)); + boolean notInRegion = false; + while (!notInRegion) { + nodesBySample.addAll( + searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusUsed)); + nodesBySample.addAll( + searchTable.getValidatorNodesbySample( + samples.get(sample).getIdByColumn(), radiusUsed)); + if (!nodesBySample.isEmpty()) notInRegion = true; + if (!notInRegion) radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); + } nodesBySample.addAll( searchTable.getNonValidatorNodesbySample( samples.get(sample).getId(), radiusNonValidator)); @@ -158,10 +158,7 @@ protected void createNodes() { searchTable.getNonValidatorNodesbySample( samples.get(sample).getIdByColumn(), radiusNonValidator)); - // radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); - // } - - boolean found = false; + // boolean found = false; nodesBySample.removeAll(askedNodes); if (nodesBySample != null && nodesBySample.size() > 0) { @@ -173,12 +170,12 @@ protected void createNodes() { nodes.get(id).addSample(samples.get(sample)); } } - found = true; + // found = true; } - if (!found && callback != null) { + /*if (!found && callback != null) { callback.missing(sample, this); - } + }*/ } } } diff --git a/simulator/src/main/java/peersim/transport/PairwiseFixedLatencyTransport.java b/simulator/src/main/java/peersim/transport/PairwiseFixedLatencyTransport.java index 554884ea..adc8cedb 100644 --- a/simulator/src/main/java/peersim/transport/PairwiseFixedLatencyTransport.java +++ b/simulator/src/main/java/peersim/transport/PairwiseFixedLatencyTransport.java @@ -4,7 +4,7 @@ import peersim.core.*; import peersim.edsim.*; -public final class PairwiseFixedLatencyTransport extends UniformRandomTransport { +public class PairwiseFixedLatencyTransport extends UniformRandomTransport { /** Size of the network. */ private int size; From b7ea351cda23625d10a18a8fb32a98379567c48a Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sun, 14 Jan 2024 12:14:26 +0100 Subject: [PATCH 83/98] node type in msg report --- .../java/peersim/kademlia/KademliaObserver.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java index 5a52decc..9754142d 100755 --- a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java +++ b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java @@ -12,6 +12,7 @@ import peersim.core.CommonState; import peersim.core.Control; import peersim.core.Network; +import peersim.core.Node; import peersim.kademlia.das.Neighbour; import peersim.kademlia.das.SearchTable; import peersim.kademlia.operations.Operation; @@ -31,6 +32,8 @@ public class KademliaObserver implements Control { private static final String PAR_FOLDER = "logfolder"; + private static final String PAR_PROTOCOL = "protocol"; + /** keep statistics of the number of hops of every message delivered. */ public static IncrementalStats hopStore = new IncrementalStats(); @@ -71,6 +74,7 @@ public class KademliaObserver implements Control { /** The time granularity of reporting metrics */ private static int observerStep; + private static int kademliaid; /** * Constructor to initialize the observer. * @@ -80,8 +84,8 @@ public KademliaObserver(String prefix) { observerStep = Configuration.getInt(prefix + "." + PAR_STEP); logFolderName = Configuration.getString(prefix + "." + PAR_FOLDER, "./logs"); - - System.out.println("Logfolder: " + logFolderName); + kademliaid = Configuration.getPid(prefix + "." + PAR_PROTOCOL); + // System.out.println("Logfolder: " + logFolderName); } private static void writeLogs(Map> map, String filename) { @@ -273,10 +277,16 @@ private static HashMap> writeMessages() { // System.out.println("Writing messages log " + id); Map result = new HashMap(); result.put("id", id); + Node n = Util.nodeIdtoNode(id, kademliaid); + boolean builder = n.getDASProtocol().isBuilder(); + boolean validator = n.getDASProtocol().isValidator(); result.put("msgsIn", msgsIn.get(id)); result.put("msgsOut", msgsOut.get(id)); result.put("bytesIn", bytesIn.get(id)); result.put("bytesOut", bytesOut.get(id)); + if (builder) result.put("nodeType", "builder"); + else if (validator) result.put("nodeType", "validator"); + else result.put("nodeType", "regular"); msgs.put(msgId, result); msgId++; } From 155377d704c012ee479d13a56247ae8093fa751e Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sun, 14 Jan 2024 12:20:28 +0100 Subject: [PATCH 84/98] reporting only related messages --- simulator/config/dasprotocol1000.cfg | 159 ++++++++++++++++++ simulator/config/dasprotocol10000.cfg | 159 ++++++++++++++++++ simulator/config/dasprotocol5000.cfg | 159 ++++++++++++++++++ .../peersim/kademlia/das/DASProtocol.java | 10 +- 4 files changed, 485 insertions(+), 2 deletions(-) create mode 100644 simulator/config/dasprotocol1000.cfg create mode 100644 simulator/config/dasprotocol10000.cfg create mode 100644 simulator/config/dasprotocol5000.cfg diff --git a/simulator/config/dasprotocol1000.cfg b/simulator/config/dasprotocol1000.cfg new file mode 100644 index 00000000..ca47dfa8 --- /dev/null +++ b/simulator/config/dasprotocol1000.cfg @@ -0,0 +1,159 @@ +# :::::::::::::::::::::::::::::::::`::::::::::::::::::::: +# :: Kademlia Default Configuration +# :::::::::::::::::::::::::::::::::::::::::::::::::::::: + +# ::::: GLOBAL :::::: + +# Network size +SIZE 1000 + +# Random seed +K 5 + +MINDELAY 5 +MAXDELAY 200 + +#Simulation time in ms +SIM_TIME 11999 + + +#Traffic generator is executed every TRAFFIC_STEP +TRAFFIC_STEP 12000 #10000000/SIZE +#Tracing module is executed every OBSERVER_STEP +OBSERVER_STEP 10000 +#Turbulence module is executed every TURBULENCE_STEP enabling churning +TURBULENCE_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 +REFRESH_STEP 10000000 + +# add network config parameters to simulation +random.seed 24680 +simulation.experiments 1 +simulation.endtime SIM_TIME +network.size SIZE + + +# Peersim protocols enabled in each node + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.0link peersim.core.IdleProtocol + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.1pairwiselattr peersim.transport.PairwiseFixedLatencyTransport +protocol.1pairwiselattr.mindelay MINDELAY +protocol.1pairwiselattr.maxdelay MAXDELAY +protocol.1pairwiselattr.size SIZE + + +#transport layer that reliably delivers messages with a random delay, emulating TCP +protocol.2unreltr peersim.transport.UnreliableTransport +protocol.2unreltr.drop 0 +protocol.2unreltr.transport 1pairwiselattr + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.3kademlia peersim.kademlia.KademliaProtocol +protocol.3kademlia.transport 2unreltr +protocol.3kademlia.BITS 256 +protocol.3kademlia.NBUCKETS 17 +protocol.3kademlia.FINDMODE 1 + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.4dasprotocol peersim.kademlia.das.DASProtocolBuilder +protocol.4dasprotocol.transport 2unreltr +protocol.4dasprotocol.kademlia 3kademlia +protocol.4dasprotocol.reportDiscovery false +protocol.4dasprotocol.reportMsg true + +protocol.5dasprotocol peersim.kademlia.das.DASProtocolValidator +protocol.5dasprotocol.transport 2unreltr +protocol.5dasprotocol.kademlia 3kademlia +protocol.5dasprotocol.reportDiscovery false +protocol.5dasprotocol.reportMsg true + +protocol.6dasprotocol peersim.kademlia.das.DASProtocolNonValidator +protocol.6dasprotocol.transport 2unreltr +protocol.6dasprotocol.kademlia 3kademlia +protocol.6dasprotocol.reportDiscovery false +protocol.6dasprotocol.reportMsg true + +protocol.7evildasprotocol peersim.kademlia.das.DASProtocolEvilValidator +protocol.7evildasprotocol.transport 2unreltr +protocol.7evildasprotocol.kademlia 3kademlia +protocol.7evildasprotocol.reportDiscovery false +protocol.7evildasprotocol.reportMsg true + +protocol.8evildasprotocol peersim.kademlia.das.DASProtocolEvilNonValidator +protocol.8evildasprotocol.transport 2unreltr +protocol.8evildasprotocol.kademlia 3kademlia +protocol.8evildasprotocol.reportDiscovery false +protocol.8evildasprotocol.reportMsg true + +# ::::: INITIALIZERS ::::: +#Class that initializes nodes with kademlia protocol and generates uniform ids +init.1uniqueNodeID peersim.kademlia.das.CustomDistributionDas +init.1uniqueNodeID.protocolkad 3kademlia +init.1uniqueNodeID.protocoldasbuilder 4dasprotocol +init.1uniqueNodeID.protocoldasvalidator 5dasprotocol +init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol +init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol +init.1uniqueNodeID.protocolEvildas 8evildasprotocol +init.1uniqueNodeID.validator_rate 0.2 +init.1uniqueNodeID.evilNodeRatioValidator 0.0 +init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 + + +#Adds initial state to the routing tables +init.2statebuilder peersim.kademlia.StateBuilder +init.2statebuilder.protocol 3kademlia +init.2statebuilder.transport 2unreltr + +# ::::: CONTROLS ::::: + +#TrafficGenerator class sends and initial +control.0traffic peersim.kademlia.das.TrafficGeneratorSample +control.0traffic.step TRAFFIC_STEP +control.0traffic.mapping_fn 2 +control.0traffic.sample_copy_per_node 2 +control.0traffic.block_dim_size 512 +control.0traffic.num_samples 75 +control.0traffic.kadprotocol 3kademlia + +#TrafficGenerator class sends and initial +control.1refresh peersim.kademlia.das.RefreshSearchTable +control.1refresh.step REFRESH_STEP + +# turbulence non-validator + +#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +#control.2turbolenceAdd.protocolkad 3kademlia +#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.2turbolenceAdd.protocolEvildas 7evildasprotocol +#control.2turbolenceAdd.transport 2unreltr +#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +#control.2turbolenceAdd.p_idle 0.1 +#control.2turbolenceAdd.p_rem 0.45 +#control.2turbolenceAdd.p_add 0.45 + +# turbulence validators +#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +#control.3turbolenceAdd.protocolkad 3kademlia +#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.3turbolenceAdd.protocolEvildas 7evildasprotocol +#control.3turbolenceAdd.transport 2unreltr +#control.3turbolenceAdd.step TURBULENCE_STEP +#control.3turbolenceAdd.p_idle 0.9 +#control.3turbolenceAdd.p_rem 0.05 +#control.3turbolenceAdd.p_add 0.05 + +# ::::: OBSERVER ::::: +#The observer is executed every OBSERVER_STEP and will generate data traces +control.4 peersim.kademlia.KademliaObserver +control.4.protocol 3kademlia +control.4.step OBSERVER_STEP +control.4.logfolder logs1000 diff --git a/simulator/config/dasprotocol10000.cfg b/simulator/config/dasprotocol10000.cfg new file mode 100644 index 00000000..60b17848 --- /dev/null +++ b/simulator/config/dasprotocol10000.cfg @@ -0,0 +1,159 @@ +# :::::::::::::::::::::::::::::::::`::::::::::::::::::::: +# :: Kademlia Default Configuration +# :::::::::::::::::::::::::::::::::::::::::::::::::::::: + +# ::::: GLOBAL :::::: + +# Network size +SIZE 10000 + +# Random seed +K 5 + +MINDELAY 5 +MAXDELAY 200 + +#Simulation time in ms +SIM_TIME 11999 + + +#Traffic generator is executed every TRAFFIC_STEP +TRAFFIC_STEP 12000 #10000000/SIZE +#Tracing module is executed every OBSERVER_STEP +OBSERVER_STEP 10000 +#Turbulence module is executed every TURBULENCE_STEP enabling churning +TURBULENCE_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 +REFRESH_STEP 10000000 + +# add network config parameters to simulation +random.seed 24680 +simulation.experiments 1 +simulation.endtime SIM_TIME +network.size SIZE + + +# Peersim protocols enabled in each node + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.0link peersim.core.IdleProtocol + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.1pairwiselattr peersim.transport.PairwiseFixedLatencyTransport +protocol.1pairwiselattr.mindelay MINDELAY +protocol.1pairwiselattr.maxdelay MAXDELAY +protocol.1pairwiselattr.size SIZE + + +#transport layer that reliably delivers messages with a random delay, emulating TCP +protocol.2unreltr peersim.transport.UnreliableTransport +protocol.2unreltr.drop 0 +protocol.2unreltr.transport 1pairwiselattr + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.3kademlia peersim.kademlia.KademliaProtocol +protocol.3kademlia.transport 2unreltr +protocol.3kademlia.BITS 256 +protocol.3kademlia.NBUCKETS 17 +protocol.3kademlia.FINDMODE 1 + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.4dasprotocol peersim.kademlia.das.DASProtocolBuilder +protocol.4dasprotocol.transport 2unreltr +protocol.4dasprotocol.kademlia 3kademlia +protocol.4dasprotocol.reportDiscovery false +protocol.4dasprotocol.reportMsg true + +protocol.5dasprotocol peersim.kademlia.das.DASProtocolValidator +protocol.5dasprotocol.transport 2unreltr +protocol.5dasprotocol.kademlia 3kademlia +protocol.5dasprotocol.reportDiscovery false +protocol.5dasprotocol.reportMsg true + +protocol.6dasprotocol peersim.kademlia.das.DASProtocolNonValidator +protocol.6dasprotocol.transport 2unreltr +protocol.6dasprotocol.kademlia 3kademlia +protocol.6dasprotocol.reportDiscovery false +protocol.6dasprotocol.reportMsg true + +protocol.7evildasprotocol peersim.kademlia.das.DASProtocolEvilValidator +protocol.7evildasprotocol.transport 2unreltr +protocol.7evildasprotocol.kademlia 3kademlia +protocol.7evildasprotocol.reportDiscovery false +protocol.7evildasprotocol.reportMsg true + +protocol.8evildasprotocol peersim.kademlia.das.DASProtocolEvilNonValidator +protocol.8evildasprotocol.transport 2unreltr +protocol.8evildasprotocol.kademlia 3kademlia +protocol.8evildasprotocol.reportDiscovery false +protocol.8evildasprotocol.reportMsg true + +# ::::: INITIALIZERS ::::: +#Class that initializes nodes with kademlia protocol and generates uniform ids +init.1uniqueNodeID peersim.kademlia.das.CustomDistributionDas +init.1uniqueNodeID.protocolkad 3kademlia +init.1uniqueNodeID.protocoldasbuilder 4dasprotocol +init.1uniqueNodeID.protocoldasvalidator 5dasprotocol +init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol +init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol +init.1uniqueNodeID.protocolEvildas 8evildasprotocol +init.1uniqueNodeID.validator_rate 0.2 +init.1uniqueNodeID.evilNodeRatioValidator 0.0 +init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 + + +#Adds initial state to the routing tables +init.2statebuilder peersim.kademlia.StateBuilder +init.2statebuilder.protocol 3kademlia +init.2statebuilder.transport 2unreltr + +# ::::: CONTROLS ::::: + +#TrafficGenerator class sends and initial +control.0traffic peersim.kademlia.das.TrafficGeneratorSample +control.0traffic.step TRAFFIC_STEP +control.0traffic.mapping_fn 2 +control.0traffic.sample_copy_per_node 2 +control.0traffic.block_dim_size 512 +control.0traffic.num_samples 75 +control.0traffic.kadprotocol 3kademlia + +#TrafficGenerator class sends and initial +control.1refresh peersim.kademlia.das.RefreshSearchTable +control.1refresh.step REFRESH_STEP + +# turbulence non-validator + +#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +#control.2turbolenceAdd.protocolkad 3kademlia +#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.2turbolenceAdd.protocolEvildas 7evildasprotocol +#control.2turbolenceAdd.transport 2unreltr +#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +#control.2turbolenceAdd.p_idle 0.1 +#control.2turbolenceAdd.p_rem 0.45 +#control.2turbolenceAdd.p_add 0.45 + +# turbulence validators +#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +#control.3turbolenceAdd.protocolkad 3kademlia +#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.3turbolenceAdd.protocolEvildas 7evildasprotocol +#control.3turbolenceAdd.transport 2unreltr +#control.3turbolenceAdd.step TURBULENCE_STEP +#control.3turbolenceAdd.p_idle 0.9 +#control.3turbolenceAdd.p_rem 0.05 +#control.3turbolenceAdd.p_add 0.05 + +# ::::: OBSERVER ::::: +#The observer is executed every OBSERVER_STEP and will generate data traces +control.4 peersim.kademlia.KademliaObserver +control.4.protocol 3kademlia +control.4.step OBSERVER_STEP +control.4.logfolder logs10000 diff --git a/simulator/config/dasprotocol5000.cfg b/simulator/config/dasprotocol5000.cfg new file mode 100644 index 00000000..c6178eae --- /dev/null +++ b/simulator/config/dasprotocol5000.cfg @@ -0,0 +1,159 @@ +# :::::::::::::::::::::::::::::::::`::::::::::::::::::::: +# :: Kademlia Default Configuration +# :::::::::::::::::::::::::::::::::::::::::::::::::::::: + +# ::::: GLOBAL :::::: + +# Network size +SIZE 5000 + +# Random seed +K 5 + +MINDELAY 5 +MAXDELAY 200 + +#Simulation time in ms +SIM_TIME 11999 + + +#Traffic generator is executed every TRAFFIC_STEP +TRAFFIC_STEP 12000 #10000000/SIZE +#Tracing module is executed every OBSERVER_STEP +OBSERVER_STEP 10000 +#Turbulence module is executed every TURBULENCE_STEP enabling churning +TURBULENCE_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 +REFRESH_STEP 10000000 + +# add network config parameters to simulation +random.seed 24680 +simulation.experiments 1 +simulation.endtime SIM_TIME +network.size SIZE + + +# Peersim protocols enabled in each node + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.0link peersim.core.IdleProtocol + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.1pairwiselattr peersim.transport.PairwiseFixedLatencyTransport +protocol.1pairwiselattr.mindelay MINDELAY +protocol.1pairwiselattr.maxdelay MAXDELAY +protocol.1pairwiselattr.size SIZE + + +#transport layer that reliably delivers messages with a random delay, emulating TCP +protocol.2unreltr peersim.transport.UnreliableTransport +protocol.2unreltr.drop 0 +protocol.2unreltr.transport 1pairwiselattr + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.3kademlia peersim.kademlia.KademliaProtocol +protocol.3kademlia.transport 2unreltr +protocol.3kademlia.BITS 256 +protocol.3kademlia.NBUCKETS 17 +protocol.3kademlia.FINDMODE 1 + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.4dasprotocol peersim.kademlia.das.DASProtocolBuilder +protocol.4dasprotocol.transport 2unreltr +protocol.4dasprotocol.kademlia 3kademlia +protocol.4dasprotocol.reportDiscovery false +protocol.4dasprotocol.reportMsg true + +protocol.5dasprotocol peersim.kademlia.das.DASProtocolValidator +protocol.5dasprotocol.transport 2unreltr +protocol.5dasprotocol.kademlia 3kademlia +protocol.5dasprotocol.reportDiscovery false +protocol.5dasprotocol.reportMsg true + +protocol.6dasprotocol peersim.kademlia.das.DASProtocolNonValidator +protocol.6dasprotocol.transport 2unreltr +protocol.6dasprotocol.kademlia 3kademlia +protocol.6dasprotocol.reportDiscovery false +protocol.6dasprotocol.reportMsg true + +protocol.7evildasprotocol peersim.kademlia.das.DASProtocolEvilValidator +protocol.7evildasprotocol.transport 2unreltr +protocol.7evildasprotocol.kademlia 3kademlia +protocol.7evildasprotocol.reportDiscovery false +protocol.7evildasprotocol.reportMsg true + +protocol.8evildasprotocol peersim.kademlia.das.DASProtocolEvilNonValidator +protocol.8evildasprotocol.transport 2unreltr +protocol.8evildasprotocol.kademlia 3kademlia +protocol.8evildasprotocol.reportDiscovery false +protocol.8evildasprotocol.reportMsg true + +# ::::: INITIALIZERS ::::: +#Class that initializes nodes with kademlia protocol and generates uniform ids +init.1uniqueNodeID peersim.kademlia.das.CustomDistributionDas +init.1uniqueNodeID.protocolkad 3kademlia +init.1uniqueNodeID.protocoldasbuilder 4dasprotocol +init.1uniqueNodeID.protocoldasvalidator 5dasprotocol +init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol +init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol +init.1uniqueNodeID.protocolEvildas 8evildasprotocol +init.1uniqueNodeID.validator_rate 0.2 +init.1uniqueNodeID.evilNodeRatioValidator 0.0 +init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 + + +#Adds initial state to the routing tables +init.2statebuilder peersim.kademlia.StateBuilder +init.2statebuilder.protocol 3kademlia +init.2statebuilder.transport 2unreltr + +# ::::: CONTROLS ::::: + +#TrafficGenerator class sends and initial +control.0traffic peersim.kademlia.das.TrafficGeneratorSample +control.0traffic.step TRAFFIC_STEP +control.0traffic.mapping_fn 2 +control.0traffic.sample_copy_per_node 2 +control.0traffic.block_dim_size 512 +control.0traffic.num_samples 75 +control.0traffic.kadprotocol 3kademlia + +#TrafficGenerator class sends and initial +control.1refresh peersim.kademlia.das.RefreshSearchTable +control.1refresh.step REFRESH_STEP + +# turbulence non-validator + +#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +#control.2turbolenceAdd.protocolkad 3kademlia +#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.2turbolenceAdd.protocolEvildas 7evildasprotocol +#control.2turbolenceAdd.transport 2unreltr +#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +#control.2turbolenceAdd.p_idle 0.1 +#control.2turbolenceAdd.p_rem 0.45 +#control.2turbolenceAdd.p_add 0.45 + +# turbulence validators +#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +#control.3turbolenceAdd.protocolkad 3kademlia +#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.3turbolenceAdd.protocolEvildas 7evildasprotocol +#control.3turbolenceAdd.transport 2unreltr +#control.3turbolenceAdd.step TURBULENCE_STEP +#control.3turbolenceAdd.p_idle 0.9 +#control.3turbolenceAdd.p_rem 0.05 +#control.3turbolenceAdd.p_add 0.05 + +# ::::: OBSERVER ::::: +#The observer is executed every OBSERVER_STEP and will generate data traces +control.4 peersim.kademlia.KademliaObserver +control.4.protocol 3kademlia +control.4.step OBSERVER_STEP +control.4.logfolder logs5000 diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 60fdaf00..958fa175 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -175,7 +175,10 @@ public void processEvent(Node myNode, int myPid, Object event) { if (s instanceof Message) { m = (Message) event; // m.dst = this.kadProtocol.getKademliaNode(); - if (msgReport) KademliaObserver.reportMsg(m, false, this.getKademliaId()); + if (msgReport + && (m.getType() == Message.MSG_GET_SAMPLE + || m.getType() == Message.MSG_GET_SAMPLE_RESPONSE)) + KademliaObserver.reportMsg(m, false, this.getKademliaId()); /*if (m.src != null) { Node n = Util.nodeIdtoNode(m.src.getId(), kademliaId); searchTable.addNeighbour(new Neighbour(m.src.getId(), n, n.getDASProtocol().isEvil())); @@ -644,7 +647,10 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { Node src = this.kadProtocol.getNode(); Node dest = Util.nodeIdtoNode(destId, kademliaId); transport = (UnreliableTransport) (Network.prototype).getProtocol(tid); - if (msgReport) KademliaObserver.reportMsg(m, true, this.getKademliaId()); + if (msgReport + && (m.getType() == Message.MSG_GET_SAMPLE + || m.getType() == Message.MSG_GET_SAMPLE_RESPONSE)) + KademliaObserver.reportMsg(m, true, this.getKademliaId()); if (m.getType() != Message.MSG_GET_SAMPLE_RESPONSE && m.getType() != Message.MSG_SEED_SAMPLE) { transport.send(src, dest, m, myPid); From 8bc497b17fc7cc2fc244268c61e5c21ec68adc23 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sun, 14 Jan 2024 12:58:01 +0100 Subject: [PATCH 85/98] msg reporting fix --- .../peersim/kademlia/KademliaObserver.java | 22 ++++++++++++++----- .../main/java/peersim/kademlia/Message.java | 14 ++++++------ .../peersim/kademlia/das/DASProtocol.java | 2 ++ 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java index 9754142d..4e4b9ceb 100755 --- a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java +++ b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java @@ -195,8 +195,20 @@ public static void reportMsg(Message m, boolean sent, BigInteger id) { // Messages without a source are control messages sent by the traffic control, // so we don't want to log them. + // BigInteger id2 = new + // BigInteger("83814183170291850251680823880522715558189094423550585243365458794131648333116"); + // if(id.compareTo(id2)==0){ + /*if (sent) { + if (m.getType() == Message.MSG_GET_SAMPLE) + System.out.println(id + " sending sample request " + m.getSize()); + else System.out.println(id + " sending sample response " + m.getSize()); + } else { + if (m.getType() == Message.MSG_GET_SAMPLE) + System.out.println(id + " receiving sample request " + m.getSize()); + else System.out.println(id + " receiving sample response " + m.getSize()); + }*/ + // } if (m.src == null) { - // System.exit(-1); return; } // System.out.println("Reporting msg " + m); @@ -209,8 +221,8 @@ public static void reportMsg(Message m, boolean sent, BigInteger id) { msgsOut.put(id, 1); bytesOut.put(id, m.getSize()); } else { - Integer msgs = msgsOut.get(id); - Integer bytes = bytesOut.get(id); + int msgs = msgsOut.get(id); + int bytes = bytesOut.get(id); bytes += m.getSize(); msgs++; msgsOut.put(id, msgs); @@ -221,8 +233,8 @@ public static void reportMsg(Message m, boolean sent, BigInteger id) { msgsIn.put(id, 1); bytesIn.put(id, m.getSize()); } else { - Integer msgs = msgsIn.get(id); - Integer bytes = bytesOut.get(id); + int msgs = msgsIn.get(id); + int bytes = bytesOut.get(id); msgs++; bytes += m.getSize(); msgsIn.put(id, msgs); diff --git a/simulator/src/main/java/peersim/kademlia/Message.java b/simulator/src/main/java/peersim/kademlia/Message.java index 27adea52..c498baef 100755 --- a/simulator/src/main/java/peersim/kademlia/Message.java +++ b/simulator/src/main/java/peersim/kademlia/Message.java @@ -146,15 +146,15 @@ public Message(int messageType, Object body) { if (body instanceof BigInteger[]) { BigInteger[] reqs = (BigInteger[]) body; - size += 32 * reqs.length; - size += 64; - size += 4; + size += 32 * reqs.length; // req size + size += 64; // src / dst ids + size += 4; // msg type } else if (body instanceof Sample[]) { Sample[] samples = (Sample[]) body; - size += 512 * samples.length; - size += 15 * 32; - size += 64; - size += 4; + size += 512 * samples.length; // samples + size += 15 * 32; // neighbours + size += 64; // src dst id + size += 4; // message type } } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 958fa175..86c4d2ec 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -174,6 +174,8 @@ public void processEvent(Node myNode, int myPid, Object event) { SimpleEvent s = (SimpleEvent) event; if (s instanceof Message) { m = (Message) event; + logger.warning("Reporting " + msgReport + " " + m.getType() + " " + m.getSize()); + // m.dst = this.kadProtocol.getKademliaNode(); if (msgReport && (m.getType() == Message.MSG_GET_SAMPLE From 22075a635be30a57e6b6750fa335cee629ac27fd Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sun, 14 Jan 2024 13:03:16 +0100 Subject: [PATCH 86/98] fix --- simulator/src/main/java/peersim/kademlia/KademliaObserver.java | 2 +- simulator/src/main/java/peersim/kademlia/das/DASProtocol.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java index 4e4b9ceb..e551df19 100755 --- a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java +++ b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java @@ -234,7 +234,7 @@ public static void reportMsg(Message m, boolean sent, BigInteger id) { bytesIn.put(id, m.getSize()); } else { int msgs = msgsIn.get(id); - int bytes = bytesOut.get(id); + int bytes = bytesIn.get(id); msgs++; bytes += m.getSize(); msgsIn.put(id, msgs); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 86c4d2ec..3ec528a1 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -174,7 +174,7 @@ public void processEvent(Node myNode, int myPid, Object event) { SimpleEvent s = (SimpleEvent) event; if (s instanceof Message) { m = (Message) event; - logger.warning("Reporting " + msgReport + " " + m.getType() + " " + m.getSize()); + logger.info("Reporting " + msgReport + " " + m.getType() + " " + m.getSize()); // m.dst = this.kadProtocol.getKademliaNode(); if (msgReport From 42051f8d4825c478e979d30ce9612a0131df4d94 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sun, 14 Jan 2024 15:46:36 +0100 Subject: [PATCH 87/98] increasing radius for validator sampling --- simulator/config/dasprotocol1000.cfg | 2 +- simulator/config/dasprotocol10000.cfg | 2 +- .../ValidatorSamplingOperation.java | 22 ++++++++++++++----- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/simulator/config/dasprotocol1000.cfg b/simulator/config/dasprotocol1000.cfg index ca47dfa8..b02b7fa2 100644 --- a/simulator/config/dasprotocol1000.cfg +++ b/simulator/config/dasprotocol1000.cfg @@ -11,7 +11,7 @@ SIZE 1000 K 5 MINDELAY 5 -MAXDELAY 200 +MAXDELAY 125 #Simulation time in ms SIM_TIME 11999 diff --git a/simulator/config/dasprotocol10000.cfg b/simulator/config/dasprotocol10000.cfg index 60b17848..3f28a5b3 100644 --- a/simulator/config/dasprotocol10000.cfg +++ b/simulator/config/dasprotocol10000.cfg @@ -11,7 +11,7 @@ SIZE 10000 K 5 MINDELAY 5 -MAXDELAY 200 +MAXDELAY 125 #Simulation time in ms SIM_TIME 11999 diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index b0cf8cf4..8f7c687b 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -266,8 +266,14 @@ protected void addExtraNodes() { List nodes = new ArrayList<>(); // for (Sample s : sRow) { // nodes.addAll(searchTable.getNodesbySample(s.getId(), radiusUsed)); - nodes.addAll( - searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusValidator)); + BigInteger radiusUsed = radiusValidator; + boolean nodeInRegion = false; + while (!nodeInRegion) { + nodes.addAll( + searchTable.getValidatorNodesbySample(samples.get(sample).getId(), radiusUsed)); + if (!nodes.isEmpty()) nodeInRegion = true; + else radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); + } nodes.addAll( searchTable.getNonValidatorNodesbySample( samples.get(sample).getId(), radiusNonValidator)); @@ -280,9 +286,15 @@ protected void addExtraNodes() { List nodes = new ArrayList<>(); // for (Sample s : sColumn) { // nodes.addAll(searchTable.getNodesbySample(s.getIdByColumn(), radiusUsed)); - nodes.addAll( - searchTable.getValidatorNodesbySample( - samples.get(sample).getIdByColumn(), radiusValidator)); + BigInteger radiusUsed = radiusValidator; + boolean nodeInRegion = false; + while (!nodeInRegion) { + nodes.addAll( + searchTable.getValidatorNodesbySample( + samples.get(sample).getIdByColumn(), radiusUsed)); + if (!nodes.isEmpty()) nodeInRegion = true; + else radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); + } nodes.addAll( searchTable.getNonValidatorNodesbySample( samples.get(sample).getIdByColumn(), radiusNonValidator)); From a3256fb26b57ac6e2af0620a9055f280b101b81c Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sun, 14 Jan 2024 15:14:14 +0000 Subject: [PATCH 88/98] configs --- .../config/malicious/dasprotocolevil0.cfg | 2 +- simulator/config/scale/dasprotocol20000.cfg | 159 ++++++++++++++++++ simulator/config/scale/dasprotocol30000.cfg | 159 ++++++++++++++++++ simulator/config/scale/dasprotocol50000.cfg | 159 ++++++++++++++++++ 4 files changed, 478 insertions(+), 1 deletion(-) create mode 100644 simulator/config/scale/dasprotocol20000.cfg create mode 100644 simulator/config/scale/dasprotocol30000.cfg create mode 100644 simulator/config/scale/dasprotocol50000.cfg diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg index 0c975227..7ba1a3a3 100644 --- a/simulator/config/malicious/dasprotocolevil0.cfg +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 50000 +SIZE 1000 # Random seed K 5 diff --git a/simulator/config/scale/dasprotocol20000.cfg b/simulator/config/scale/dasprotocol20000.cfg new file mode 100644 index 00000000..49d0d52a --- /dev/null +++ b/simulator/config/scale/dasprotocol20000.cfg @@ -0,0 +1,159 @@ +# :::::::::::::::::::::::::::::::::`::::::::::::::::::::: +# :: Kademlia Default Configuration +# :::::::::::::::::::::::::::::::::::::::::::::::::::::: + +# ::::: GLOBAL :::::: + +# Network size +SIZE 20000 + +# Random seed +K 5 + +MINDELAY 5 +MAXDELAY 200 + +#Simulation time in ms +SIM_TIME 11999 + + +#Traffic generator is executed every TRAFFIC_STEP +TRAFFIC_STEP 12000 #10000000/SIZE +#Tracing module is executed every OBSERVER_STEP +OBSERVER_STEP 10000 +#Turbulence module is executed every TURBULENCE_STEP enabling churning +TURBULENCE_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 +REFRESH_STEP 10000000 + +# add network config parameters to simulation +random.seed 24680 +simulation.experiments 1 +simulation.endtime SIM_TIME +network.size SIZE + + +# Peersim protocols enabled in each node + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.0link peersim.core.IdleProtocol + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.1pairwiselattr peersim.transport.PairwiseFixedLatencyTransport +protocol.1pairwiselattr.mindelay MINDELAY +protocol.1pairwiselattr.maxdelay MAXDELAY +protocol.1pairwiselattr.size SIZE + + +#transport layer that reliably delivers messages with a random delay, emulating TCP +protocol.2unreltr peersim.transport.UnreliableTransport +protocol.2unreltr.drop 0 +protocol.2unreltr.transport 1pairwiselattr + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.3kademlia peersim.kademlia.KademliaProtocol +protocol.3kademlia.transport 2unreltr +protocol.3kademlia.BITS 256 +protocol.3kademlia.NBUCKETS 17 +protocol.3kademlia.FINDMODE 1 + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.4dasprotocol peersim.kademlia.das.DASProtocolBuilder +protocol.4dasprotocol.transport 2unreltr +protocol.4dasprotocol.kademlia 3kademlia +protocol.4dasprotocol.reportDiscovery false +protocol.4dasprotocol.reportMsg true + +protocol.5dasprotocol peersim.kademlia.das.DASProtocolValidator +protocol.5dasprotocol.transport 2unreltr +protocol.5dasprotocol.kademlia 3kademlia +protocol.5dasprotocol.reportDiscovery false +protocol.5dasprotocol.reportMsg true + +protocol.6dasprotocol peersim.kademlia.das.DASProtocolNonValidator +protocol.6dasprotocol.transport 2unreltr +protocol.6dasprotocol.kademlia 3kademlia +protocol.6dasprotocol.reportDiscovery false +protocol.6dasprotocol.reportMsg true + +protocol.7evildasprotocol peersim.kademlia.das.DASProtocolEvilValidator +protocol.7evildasprotocol.transport 2unreltr +protocol.7evildasprotocol.kademlia 3kademlia +protocol.7evildasprotocol.reportDiscovery false +protocol.7evildasprotocol.reportMsg true + +protocol.8evildasprotocol peersim.kademlia.das.DASProtocolEvilNonValidator +protocol.8evildasprotocol.transport 2unreltr +protocol.8evildasprotocol.kademlia 3kademlia +protocol.8evildasprotocol.reportDiscovery false +protocol.8evildasprotocol.reportMsg true + +# ::::: INITIALIZERS ::::: +#Class that initializes nodes with kademlia protocol and generates uniform ids +init.1uniqueNodeID peersim.kademlia.das.CustomDistributionDas +init.1uniqueNodeID.protocolkad 3kademlia +init.1uniqueNodeID.protocoldasbuilder 4dasprotocol +init.1uniqueNodeID.protocoldasvalidator 5dasprotocol +init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol +init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol +init.1uniqueNodeID.protocolEvildas 8evildasprotocol +init.1uniqueNodeID.validator_rate 0.5 +init.1uniqueNodeID.evilNodeRatioValidator 0.0 +init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 + + +#Adds initial state to the routing tables +init.2statebuilder peersim.kademlia.StateBuilder +init.2statebuilder.protocol 3kademlia +init.2statebuilder.transport 2unreltr + +# ::::: CONTROLS ::::: + +#TrafficGenerator class sends and initial +control.0traffic peersim.kademlia.das.TrafficGeneratorSample +control.0traffic.step TRAFFIC_STEP +control.0traffic.mapping_fn 2 +control.0traffic.sample_copy_per_node 2 +control.0traffic.block_dim_size 512 +control.0traffic.num_samples 75 +control.0traffic.kadprotocol 3kademlia + +#TrafficGenerator class sends and initial +control.1refresh peersim.kademlia.das.RefreshSearchTable +control.1refresh.step REFRESH_STEP + +# turbulence non-validator + +#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +#control.2turbolenceAdd.protocolkad 3kademlia +#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.2turbolenceAdd.protocolEvildas 7evildasprotocol +#control.2turbolenceAdd.transport 2unreltr +#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +#control.2turbolenceAdd.p_idle 0.1 +#control.2turbolenceAdd.p_rem 0.45 +#control.2turbolenceAdd.p_add 0.45 + +# turbulence validators +#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +#control.3turbolenceAdd.protocolkad 3kademlia +#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.3turbolenceAdd.protocolEvildas 7evildasprotocol +#control.3turbolenceAdd.transport 2unreltr +#control.3turbolenceAdd.step TURBULENCE_STEP +#control.3turbolenceAdd.p_idle 0.9 +#control.3turbolenceAdd.p_rem 0.05 +#control.3turbolenceAdd.p_add 0.05 + +# ::::: OBSERVER ::::: +#The observer is executed every OBSERVER_STEP and will generate data traces +control.4 peersim.kademlia.KademliaObserver +control.4.protocol 3kademlia +control.4.step OBSERVER_STEP +control.4.logfolder logs20000 diff --git a/simulator/config/scale/dasprotocol30000.cfg b/simulator/config/scale/dasprotocol30000.cfg new file mode 100644 index 00000000..53e9be60 --- /dev/null +++ b/simulator/config/scale/dasprotocol30000.cfg @@ -0,0 +1,159 @@ +# :::::::::::::::::::::::::::::::::`::::::::::::::::::::: +# :: Kademlia Default Configuration +# :::::::::::::::::::::::::::::::::::::::::::::::::::::: + +# ::::: GLOBAL :::::: + +# Network size +SIZE 30000 + +# Random seed +K 5 + +MINDELAY 5 +MAXDELAY 200 + +#Simulation time in ms +SIM_TIME 11999 + + +#Traffic generator is executed every TRAFFIC_STEP +TRAFFIC_STEP 12000 #10000000/SIZE +#Tracing module is executed every OBSERVER_STEP +OBSERVER_STEP 10000 +#Turbulence module is executed every TURBULENCE_STEP enabling churning +TURBULENCE_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 +REFRESH_STEP 10000000 + +# add network config parameters to simulation +random.seed 24680 +simulation.experiments 1 +simulation.endtime SIM_TIME +network.size SIZE + + +# Peersim protocols enabled in each node + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.0link peersim.core.IdleProtocol + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.1pairwiselattr peersim.transport.PairwiseFixedLatencyTransport +protocol.1pairwiselattr.mindelay MINDELAY +protocol.1pairwiselattr.maxdelay MAXDELAY +protocol.1pairwiselattr.size SIZE + + +#transport layer that reliably delivers messages with a random delay, emulating TCP +protocol.2unreltr peersim.transport.UnreliableTransport +protocol.2unreltr.drop 0 +protocol.2unreltr.transport 1pairwiselattr + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.3kademlia peersim.kademlia.KademliaProtocol +protocol.3kademlia.transport 2unreltr +protocol.3kademlia.BITS 256 +protocol.3kademlia.NBUCKETS 17 +protocol.3kademlia.FINDMODE 1 + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.4dasprotocol peersim.kademlia.das.DASProtocolBuilder +protocol.4dasprotocol.transport 2unreltr +protocol.4dasprotocol.kademlia 3kademlia +protocol.4dasprotocol.reportDiscovery false +protocol.4dasprotocol.reportMsg true + +protocol.5dasprotocol peersim.kademlia.das.DASProtocolValidator +protocol.5dasprotocol.transport 2unreltr +protocol.5dasprotocol.kademlia 3kademlia +protocol.5dasprotocol.reportDiscovery false +protocol.5dasprotocol.reportMsg true + +protocol.6dasprotocol peersim.kademlia.das.DASProtocolNonValidator +protocol.6dasprotocol.transport 2unreltr +protocol.6dasprotocol.kademlia 3kademlia +protocol.6dasprotocol.reportDiscovery false +protocol.6dasprotocol.reportMsg true + +protocol.7evildasprotocol peersim.kademlia.das.DASProtocolEvilValidator +protocol.7evildasprotocol.transport 2unreltr +protocol.7evildasprotocol.kademlia 3kademlia +protocol.7evildasprotocol.reportDiscovery false +protocol.7evildasprotocol.reportMsg true + +protocol.8evildasprotocol peersim.kademlia.das.DASProtocolEvilNonValidator +protocol.8evildasprotocol.transport 2unreltr +protocol.8evildasprotocol.kademlia 3kademlia +protocol.8evildasprotocol.reportDiscovery false +protocol.8evildasprotocol.reportMsg true + +# ::::: INITIALIZERS ::::: +#Class that initializes nodes with kademlia protocol and generates uniform ids +init.1uniqueNodeID peersim.kademlia.das.CustomDistributionDas +init.1uniqueNodeID.protocolkad 3kademlia +init.1uniqueNodeID.protocoldasbuilder 4dasprotocol +init.1uniqueNodeID.protocoldasvalidator 5dasprotocol +init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol +init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol +init.1uniqueNodeID.protocolEvildas 8evildasprotocol +init.1uniqueNodeID.validator_rate 0.333 +init.1uniqueNodeID.evilNodeRatioValidator 0.0 +init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 + + +#Adds initial state to the routing tables +init.2statebuilder peersim.kademlia.StateBuilder +init.2statebuilder.protocol 3kademlia +init.2statebuilder.transport 2unreltr + +# ::::: CONTROLS ::::: + +#TrafficGenerator class sends and initial +control.0traffic peersim.kademlia.das.TrafficGeneratorSample +control.0traffic.step TRAFFIC_STEP +control.0traffic.mapping_fn 2 +control.0traffic.sample_copy_per_node 2 +control.0traffic.block_dim_size 512 +control.0traffic.num_samples 75 +control.0traffic.kadprotocol 3kademlia + +#TrafficGenerator class sends and initial +control.1refresh peersim.kademlia.das.RefreshSearchTable +control.1refresh.step REFRESH_STEP + +# turbulence non-validator + +#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +#control.2turbolenceAdd.protocolkad 3kademlia +#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.2turbolenceAdd.protocolEvildas 7evildasprotocol +#control.2turbolenceAdd.transport 2unreltr +#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +#control.2turbolenceAdd.p_idle 0.1 +#control.2turbolenceAdd.p_rem 0.45 +#control.2turbolenceAdd.p_add 0.45 + +# turbulence validators +#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +#control.3turbolenceAdd.protocolkad 3kademlia +#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.3turbolenceAdd.protocolEvildas 7evildasprotocol +#control.3turbolenceAdd.transport 2unreltr +#control.3turbolenceAdd.step TURBULENCE_STEP +#control.3turbolenceAdd.p_idle 0.9 +#control.3turbolenceAdd.p_rem 0.05 +#control.3turbolenceAdd.p_add 0.05 + +# ::::: OBSERVER ::::: +#The observer is executed every OBSERVER_STEP and will generate data traces +control.4 peersim.kademlia.KademliaObserver +control.4.protocol 3kademlia +control.4.step OBSERVER_STEP +control.4.logfolder logs30000 diff --git a/simulator/config/scale/dasprotocol50000.cfg b/simulator/config/scale/dasprotocol50000.cfg new file mode 100644 index 00000000..74a1497e --- /dev/null +++ b/simulator/config/scale/dasprotocol50000.cfg @@ -0,0 +1,159 @@ +# :::::::::::::::::::::::::::::::::`::::::::::::::::::::: +# :: Kademlia Default Configuration +# :::::::::::::::::::::::::::::::::::::::::::::::::::::: + +# ::::: GLOBAL :::::: + +# Network size +SIZE 50000 + +# Random seed +K 5 + +MINDELAY 5 +MAXDELAY 200 + +#Simulation time in ms +SIM_TIME 11999 + + +#Traffic generator is executed every TRAFFIC_STEP +TRAFFIC_STEP 12000 #10000000/SIZE +#Tracing module is executed every OBSERVER_STEP +OBSERVER_STEP 10000 +#Turbulence module is executed every TURBULENCE_STEP enabling churning +TURBULENCE_STEP 1000 +TURBULENCE_STEP_NONVAL 1000 +REFRESH_STEP 10000000 + +# add network config parameters to simulation +random.seed 24680 +simulation.experiments 1 +simulation.endtime SIM_TIME +network.size SIZE + + +# Peersim protocols enabled in each node + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.0link peersim.core.IdleProtocol + +#A protocol that stores links. It does nothing apart from that. Use by default +protocol.1pairwiselattr peersim.transport.PairwiseFixedLatencyTransport +protocol.1pairwiselattr.mindelay MINDELAY +protocol.1pairwiselattr.maxdelay MAXDELAY +protocol.1pairwiselattr.size SIZE + + +#transport layer that reliably delivers messages with a random delay, emulating TCP +protocol.2unreltr peersim.transport.UnreliableTransport +protocol.2unreltr.drop 0 +protocol.2unreltr.transport 1pairwiselattr + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.3kademlia peersim.kademlia.KademliaProtocol +protocol.3kademlia.transport 2unreltr +protocol.3kademlia.BITS 256 +protocol.3kademlia.NBUCKETS 17 +protocol.3kademlia.FINDMODE 1 + +#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table. +#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P +protocol.4dasprotocol peersim.kademlia.das.DASProtocolBuilder +protocol.4dasprotocol.transport 2unreltr +protocol.4dasprotocol.kademlia 3kademlia +protocol.4dasprotocol.reportDiscovery false +protocol.4dasprotocol.reportMsg true + +protocol.5dasprotocol peersim.kademlia.das.DASProtocolValidator +protocol.5dasprotocol.transport 2unreltr +protocol.5dasprotocol.kademlia 3kademlia +protocol.5dasprotocol.reportDiscovery false +protocol.5dasprotocol.reportMsg true + +protocol.6dasprotocol peersim.kademlia.das.DASProtocolNonValidator +protocol.6dasprotocol.transport 2unreltr +protocol.6dasprotocol.kademlia 3kademlia +protocol.6dasprotocol.reportDiscovery false +protocol.6dasprotocol.reportMsg true + +protocol.7evildasprotocol peersim.kademlia.das.DASProtocolEvilValidator +protocol.7evildasprotocol.transport 2unreltr +protocol.7evildasprotocol.kademlia 3kademlia +protocol.7evildasprotocol.reportDiscovery false +protocol.7evildasprotocol.reportMsg true + +protocol.8evildasprotocol peersim.kademlia.das.DASProtocolEvilNonValidator +protocol.8evildasprotocol.transport 2unreltr +protocol.8evildasprotocol.kademlia 3kademlia +protocol.8evildasprotocol.reportDiscovery false +protocol.8evildasprotocol.reportMsg true + +# ::::: INITIALIZERS ::::: +#Class that initializes nodes with kademlia protocol and generates uniform ids +init.1uniqueNodeID peersim.kademlia.das.CustomDistributionDas +init.1uniqueNodeID.protocolkad 3kademlia +init.1uniqueNodeID.protocoldasbuilder 4dasprotocol +init.1uniqueNodeID.protocoldasvalidator 5dasprotocol +init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol +init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol +init.1uniqueNodeID.protocolEvildas 8evildasprotocol +init.1uniqueNodeID.validator_rate 0.2 +init.1uniqueNodeID.evilNodeRatioValidator 0.0 +init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 + + +#Adds initial state to the routing tables +init.2statebuilder peersim.kademlia.StateBuilder +init.2statebuilder.protocol 3kademlia +init.2statebuilder.transport 2unreltr + +# ::::: CONTROLS ::::: + +#TrafficGenerator class sends and initial +control.0traffic peersim.kademlia.das.TrafficGeneratorSample +control.0traffic.step TRAFFIC_STEP +control.0traffic.mapping_fn 2 +control.0traffic.sample_copy_per_node 2 +control.0traffic.block_dim_size 512 +control.0traffic.num_samples 75 +control.0traffic.kadprotocol 3kademlia + +#TrafficGenerator class sends and initial +control.1refresh peersim.kademlia.das.RefreshSearchTable +control.1refresh.step REFRESH_STEP + +# turbulence non-validator + +#control.2turbolenceAdd peersim.kademlia.das.TurbulenceDas +#control.2turbolenceAdd.protocolkad 3kademlia +#control.2turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.2turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.2turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.2turbolenceAdd.protocolEvildas 7evildasprotocol +#control.2turbolenceAdd.transport 2unreltr +#control.2turbolenceAdd.step TURBULENCE_STEP_NONVAL +#control.2turbolenceAdd.p_idle 0.1 +#control.2turbolenceAdd.p_rem 0.45 +#control.2turbolenceAdd.p_add 0.45 + +# turbulence validators +#control.3turbolenceAdd peersim.kademlia.das.TurbulenceDasValidator +#control.3turbolenceAdd.protocolkad 3kademlia +#control.3turbolenceAdd.protocoldasbuilder 4dasprotocol +#control.3turbolenceAdd.protocoldasvalidator 5dasprotocol +#control.3turbolenceAdd.protocoldasnonvalidator 6dasprotocol +#control.3turbolenceAdd.protocolEvildas 7evildasprotocol +#control.3turbolenceAdd.transport 2unreltr +#control.3turbolenceAdd.step TURBULENCE_STEP +#control.3turbolenceAdd.p_idle 0.9 +#control.3turbolenceAdd.p_rem 0.05 +#control.3turbolenceAdd.p_add 0.05 + +# ::::: OBSERVER ::::: +#The observer is executed every OBSERVER_STEP and will generate data traces +control.4 peersim.kademlia.KademliaObserver +control.4.protocol 3kademlia +control.4.step OBSERVER_STEP +control.4.logfolder logs50000 From 15e3146f52f1cd8097594038c472c7f83a4088af Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Fri, 19 Jan 2024 08:49:06 +0100 Subject: [PATCH 89/98] minor --- simulator/config/dasprotocol.cfg | 4 ++-- simulator/config/dasprotocol5000.cfg | 2 +- simulator/config/scale/dasprotocol20000.cfg | 4 ++-- simulator/config/scale/dasprotocol30000.cfg | 2 +- simulator/config/scale/dasprotocol50000.cfg | 4 ++-- .../kademlia/das/operations/RandomSamplingOperation.java | 2 +- .../peersim/kademlia/das/operations/SamplingOperation.java | 2 +- .../kademlia/das/operations/ValidatorSamplingOperation.java | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg index bec53095..9fcdece0 100644 --- a/simulator/config/dasprotocol.cfg +++ b/simulator/config/dasprotocol.cfg @@ -39,11 +39,11 @@ network.size SIZE protocol.0link peersim.core.IdleProtocol #A protocol that stores links. It does nothing apart from that. Use by default -protocol.1pairwiselattr peersim.transport.PairwiseFixedLatencyTransport +protocol.1pairwiselattr peersim.transport.PairwiseFixedLatencyTransportFile protocol.1pairwiselattr.mindelay MINDELAY protocol.1pairwiselattr.maxdelay MAXDELAY protocol.1pairwiselattr.size SIZE - +protocol.1pairwiselattr.file /home/sergi/workspace/kademlia-simulator/simulator/python/latencies.csv #transport layer that reliably delivers messages with a random delay, emulating TCP protocol.2unreltr peersim.transport.UnreliableTransport diff --git a/simulator/config/dasprotocol5000.cfg b/simulator/config/dasprotocol5000.cfg index c6178eae..8ad1b89c 100644 --- a/simulator/config/dasprotocol5000.cfg +++ b/simulator/config/dasprotocol5000.cfg @@ -11,7 +11,7 @@ SIZE 5000 K 5 MINDELAY 5 -MAXDELAY 200 +MAXDELAY 125 #Simulation time in ms SIM_TIME 11999 diff --git a/simulator/config/scale/dasprotocol20000.cfg b/simulator/config/scale/dasprotocol20000.cfg index 49d0d52a..03a8202a 100644 --- a/simulator/config/scale/dasprotocol20000.cfg +++ b/simulator/config/scale/dasprotocol20000.cfg @@ -11,7 +11,7 @@ SIZE 20000 K 5 MINDELAY 5 -MAXDELAY 200 +MAXDELAY 125 #Simulation time in ms SIM_TIME 11999 @@ -99,7 +99,7 @@ init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol init.1uniqueNodeID.protocolEvildas 8evildasprotocol -init.1uniqueNodeID.validator_rate 0.5 +init.1uniqueNodeID.validator_rate 0.2 init.1uniqueNodeID.evilNodeRatioValidator 0.0 init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 diff --git a/simulator/config/scale/dasprotocol30000.cfg b/simulator/config/scale/dasprotocol30000.cfg index 53e9be60..0ffb78cf 100644 --- a/simulator/config/scale/dasprotocol30000.cfg +++ b/simulator/config/scale/dasprotocol30000.cfg @@ -11,7 +11,7 @@ SIZE 30000 K 5 MINDELAY 5 -MAXDELAY 200 +MAXDELAY 125 #Simulation time in ms SIM_TIME 11999 diff --git a/simulator/config/scale/dasprotocol50000.cfg b/simulator/config/scale/dasprotocol50000.cfg index 74a1497e..915faa97 100644 --- a/simulator/config/scale/dasprotocol50000.cfg +++ b/simulator/config/scale/dasprotocol50000.cfg @@ -11,7 +11,7 @@ SIZE 50000 K 5 MINDELAY 5 -MAXDELAY 200 +MAXDELAY 125 #Simulation time in ms SIM_TIME 11999 @@ -99,7 +99,7 @@ init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol init.1uniqueNodeID.protocolEvildas 8evildasprotocol -init.1uniqueNodeID.validator_rate 0.2 +init.1uniqueNodeID.validator_rate 0.5 init.1uniqueNodeID.evilNodeRatioValidator 0.0 init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index 6c6e2031..309f6334 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -245,7 +245,7 @@ public Map toMap() { result.put("src", this.srcNode); result.put("type", "RandomSamplingOperation"); result.put("messages", getMessagesString()); - result.put("num_messages", getMessages().size()); + result.put("nodes_contacted", getMessages().size()); result.put("start", this.timestamp); result.put("completion_time", this.stopTime); result.put("hops", this.nrHops); diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index 2912bd8b..a90084c4 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -163,7 +163,7 @@ public BigInteger[] doSampling() { + askedNodes.size()); } if (nodes.isEmpty()) { - if (this instanceof ValidatorSamplingOperation) addExtraNodes(); + // if (this instanceof ValidatorSamplingOperation) addExtraNodes(); // addExtraNodes(); System.out.println( "[" diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index 8f7c687b..c97e8393 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -331,7 +331,7 @@ public Map toMap() { result.put("src", this.srcNode); result.put("type", "ValidatorSamplingOperation"); result.put("messages", getMessagesString()); - result.put("num_messages", getMessages().size()); + result.put("nodes_contacted", getMessages().size()); result.put("start", this.timestamp); result.put("completion_time", this.stopTime); result.put("hops", this.nrHops); From e1ed0ff76c1f030011ef8dbfe495f3a51c6ca2d6 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sat, 2 Mar 2024 10:03:25 +0000 Subject: [PATCH 90/98] adding evil ids --- simulator/config/scale/dasprotocol50000.cfg | 2 +- .../kademlia/das/CustomDistributionDas.java | 6 +++- .../das/DASProtocolEvilValidator.java | 4 +-- .../kademlia/das/DASProtocolNonValidator.java | 4 +-- .../peersim/kademlia/das/SearchTable.java | 20 ++++++++--- .../operations/RandomSamplingOperation.java | 35 ++++++++++++++----- .../das/operations/SamplingOperation.java | 2 +- 7 files changed, 52 insertions(+), 21 deletions(-) diff --git a/simulator/config/scale/dasprotocol50000.cfg b/simulator/config/scale/dasprotocol50000.cfg index 915faa97..971bfc86 100644 --- a/simulator/config/scale/dasprotocol50000.cfg +++ b/simulator/config/scale/dasprotocol50000.cfg @@ -99,7 +99,7 @@ init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol init.1uniqueNodeID.protocolEvildas 8evildasprotocol -init.1uniqueNodeID.validator_rate 0.5 +init.1uniqueNodeID.validator_rate 0.2 init.1uniqueNodeID.evilNodeRatioValidator 0.0 init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index 9dc44e56..95be590f 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -86,6 +86,7 @@ public boolean execute() { List nonValidatorsIds = new ArrayList<>(); List evilNodes = new ArrayList<>(); List validators = new ArrayList<>(); + List evilIds = new ArrayList<>(); numValidators = numValidators - numEvilValidatorNodes; for (int i = 0; i < Network.size(); ++i) { Node generalNode = Network.get(i); @@ -110,11 +111,13 @@ public boolean execute() { dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolEvilValDasID))); validatorsIds.add(kadProt.getKademliaNode().getId()); evilNodes.add(generalNode); + evilIds.add(id); } else if ((i > numEvilValidatorNodes) && (i < (numEvilValidatorNodes + numEvilNonValidatorNodes + 1))) { dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolEvilDasID))); nonValidatorsIds.add(kadProt.getKademliaNode().getId()); evilNodes.add(generalNode); + evilIds.add(id); } else if (i > (numEvilValidatorNodes + numEvilNonValidatorNodes) && i < (numEvilValidatorNodes + numEvilNonValidatorNodes + (numValidators) + 1)) { dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolDasValidatorID))); @@ -150,7 +153,8 @@ public boolean execute() { searchTable.setBuilderAddress(builderAddress); searchTable.addNodes(nonValidatorsIds.toArray(new BigInteger[0])); searchTable.addValidatorNodes(validatorsIds.toArray(new BigInteger[0])); - searchTable.setEvilIds(evilNodes); + searchTable.setEvil(evilNodes); + searchTable.setEvilIds(evilIds); // for (DASProtocol validator : validators) { for (int i = 0; i < Network.size(); i++) { diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilValidator.java index c6dc90ea..8115be81 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolEvilValidator.java @@ -36,8 +36,8 @@ protected void handleInitGetSample(Message m, int myPid) { sendMessage(response, m.src.getId(), myPid); }*/ - public void setEvilIds(List evilIds) { - searchTable.setEvilIds(evilIds); + public void setEvil(List evilIds) { + searchTable.setEvil(evilIds); } /** diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java index ae84f252..d9a72fa7 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java @@ -63,8 +63,8 @@ protected void handleInitNewBlock(Message m, int myPid) { } } - public void setEvilIds(List evilIds) { - searchTable.setEvilIds(evilIds); + public void setEvil(List evilIds) { + searchTable.setEvil(evilIds); } /** * Replicate this object by returning an identical copy.
diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index 0902a435..45dd2c15 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -25,7 +25,8 @@ public class SearchTable { private BigInteger builderAddress; - private List evilIds; + private List evilNodes; + private List evilIds; public SearchTable() { @@ -155,16 +156,25 @@ public Neighbour[] getNeighbours(int n) { return result.toArray(new Neighbour[0]); } - public void setEvilIds(List ids) { + public void setEvil(List nodes) { + this.evilNodes = nodes; + } + + public boolean isEvil(BigInteger id) { + if (evilIds.contains(id)) return true; + else return false; + } + + public void setEvilIds(List ids) { this.evilIds = ids; } public Neighbour[] getEvilNeighbours(int n) { List result = new ArrayList<>(); - if (evilIds != null) { - Collections.shuffle(evilIds); - for (Node neigh : evilIds) { + if (evilNodes != null) { + Collections.shuffle(evilNodes); + for (Node neigh : evilNodes) { if (result.size() < n) result.add(new Neighbour(neigh.getDASProtocol().getKademliaId(), neigh, true)); else break; diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java index 309f6334..58c61e2d 100755 --- a/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/RandomSamplingOperation.java @@ -134,6 +134,8 @@ public BigInteger[] getSamples() { } protected void createNodes() { + + List toRemove = new ArrayList<>(); for (BigInteger sample : samples.keySet()) { if (!samples.get(sample).isDownloaded()) { @@ -158,24 +160,39 @@ protected void createNodes() { searchTable.getNonValidatorNodesbySample( samples.get(sample).getIdByColumn(), radiusNonValidator)); - // boolean found = false; + boolean found = false; nodesBySample.removeAll(askedNodes); if (nodesBySample != null && nodesBySample.size() > 0) { for (BigInteger id : nodesBySample) { - if (!nodes.containsKey(id)) { - nodes.put(id, new Node(id)); - nodes.get(id).addSample(samples.get(sample)); - } else { - nodes.get(id).addSample(samples.get(sample)); + if (!searchTable.isEvil(id)) { + if (!nodes.containsKey(id)) { + nodes.put(id, new Node(id)); + nodes.get(id).addSample(samples.get(sample)); + } else { + nodes.get(id).addSample(samples.get(sample)); + } + found = true; } } - // found = true; } - /*if (!found && callback != null) { + if (!found && callback != null) { callback.missing(sample, this); - }*/ + toRemove.add(sample); + } + } + } + if (toRemove.size() > 0) { + System.out.println(CommonState.getTime() + "Removing sample " + toRemove.size()); + for (BigInteger sample : toRemove) { + samples.remove(sample); + } + Sample[] randomSamples = currentBlock.getNRandomSamples(toRemove.size()); + for (Sample rs : randomSamples) { + FetchingSample s = new FetchingSample(rs); + samples.put(rs.getIdByRow(), s); + // samples.put(rs.getIdByColumn(), s); } } } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java index a90084c4..ea474641 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/SamplingOperation.java @@ -164,7 +164,7 @@ public BigInteger[] doSampling() { } if (nodes.isEmpty()) { // if (this instanceof ValidatorSamplingOperation) addExtraNodes(); - // addExtraNodes(); + addExtraNodes(); System.out.println( "[" + CommonState.getTime() From f57351a9769b967b73b02dbce9a510ea93936cc0 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Thu, 5 Sep 2024 16:03:46 +0200 Subject: [PATCH 91/98] more results --- simulator/python/analysis_vs_evil.ipynb | 342 +++++++-- simulator/python/analysis_vs_evil_final.ipynb | 688 ++++++++++++++++++ simulator/python/analysis_withhold.ipynb | 352 +++++++++ 3 files changed, 1312 insertions(+), 70 deletions(-) create mode 100644 simulator/python/analysis_vs_evil_final.ipynb create mode 100644 simulator/python/analysis_withhold.ipynb diff --git a/simulator/python/analysis_vs_evil.ipynb b/simulator/python/analysis_vs_evil.ipynb index bc67e0f7..80c70e85 100644 --- a/simulator/python/analysis_vs_evil.ipynb +++ b/simulator/python/analysis_vs_evil.ipynb @@ -68,31 +68,27 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 24, "id": "2983fa0b", - "metadata": { - "vscode": { - "languageId": "python" - } - }, + "metadata": {}, "outputs": [], "source": [ "from matplotlib import pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", "\n", - "ops_path = {'DAS': '../logsDasEvil0WithNon/operation.csv', \n", - " 'Evil-0.25': '../logsDasEvil0.25WithNon/operation.csv',\n", - " 'Evil-0.5': '../logsDasEvil0.5WithNon/operation.csv',\n", - " 'Evil-0.75': '../logsDasEvil0.75WithNon/operation.csv'\n", + "ops_path = {'DAS': '../logsDasEvil0/operation.csv', \n", + " 'Evil-0.2': '../logsDasEvil0.2/operation.csv',\n", + " 'Evil-0.4': '../logsDasEvil0.5/operation.csv',\n", + " 'Evil-0.6': '../logsDasEvil0.6/operation.csv',\n", + " 'Evil-0.8': '../logsDasEvil0.8/operation.csv'\n", " }\n", - "#msgs_path = {'DAS': '../logsTest/messages.csv', \n", - "# 'Evil-0.1': '../logsEvil0.1/messages.csv',\n", - "# 'Evil-0.2': '../logsEvil0.2/messages.csv',\n", - "# 'Evil-0.3': '../logsEvil0.3/messages.csv',\n", - "# 'Evil-0.4': '../logsEvil0.4/messages.csv',\n", - "# 'Evil-0.5': '../logsEvil0.5/messages.csv'\n", - "# }\n", + "msgs_path = {'DAS': '../logsDasEvil0/messages.csv', \n", + " 'Evil-0.2': '../logsDasEvil0.2/messages.csv',\n", + " 'Evil-0.4': '../logsDasEvil0.5/messages.csv',\n", + " 'Evil-0.6': '../logsDasEvil0.6/messages.csv',\n", + " 'Evil-0.8': '../logsDasEvil0.8/messages.csv'\n", + " }\n", "\n", "\n", "builder_address = '83814183170291850251680823880522715558189094423550585243365458794131648333116'\n", @@ -101,8 +97,8 @@ "msg_df={}\n", "for key in ops_path:\n", " op_df[key] = pd.read_csv(ops_path[key],index_col=False,low_memory=False)\n", - "#for key in msgs_path:\n", - "# msg_df[key] = pd.read_csv(msgs_path[key],index_col=False,low_memory=False)\n" + "for key in msgs_path:\n", + " msg_df[key] = pd.read_csv(msgs_path[key],index_col=False,low_memory=False)\n" ] }, { @@ -122,13 +118,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 25, "id": "0c418d95", - "metadata": { - "vscode": { - "languageId": "python" - } - }, + "metadata": {}, "outputs": [ { "data": { @@ -136,13 +128,13 @@ "Text(0.5, 0, 'Operation complete time (ms)')" ] }, - "execution_count": 3, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjUAAAHHCAYAAABHp6kXAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAACPuElEQVR4nOzdd5hU1f348ff07b3DsoXeq3QEBQVULFFEJYhEIRaMisaWKJaf4tdEbCESjYgaERXFEhBFimJEkN6XtnS2s71NOb8/7szAsG0Wtu/n9Tzz3DvnnnvvuTPL7odTdUophRBCCCFEM6dv7AIIIYQQQtQFCWqEEEII0SJIUCOEEEKIFkGCGiGEEEK0CBLUCCGEEKJFkKBGCCGEEC2CBDVCCCGEaBEkqBFCCCFEiyBBjRBCCCFaBAlqhBAAHDlyBJ1Ox8KFCxu7KBeksLCQu+66i5iYGHQ6HQ8++GCD3XvhwoXodDo2bdpUY95Ro0YxatSo+i9ULbjKf+TIkcYuihAXRYIa0WQdOnSIP/7xjyQnJ+Pj40NQUBDDhg3j9ddfp6SkxJ0vMTERnU6HTqdDr9cTEhJCz549mTFjBhs2bKj02q78579iYmIa6vEu2MMPP0y3bt0auxhNzosvvsjChQu55557+PDDD5kyZUqtz//yyy/rp3BNRGt4RtG6GRu7AEJUZtmyZUycOBGLxcLtt99Ojx49KC8v5+eff+bPf/4zu3fv5u2333bn79OnDw8//DAABQUF7N27l88++4x33nmHhx56iLlz51a4xxVXXMHtt9/ukebr61u/D1YHli1bxoQJExq7GE3O6tWrGTx4MLNnz76g81988UVuuukmrr/++rot2Hm+//77er1+dap6xilTpnDLLbdgsVgap2BC1BEJakSTk5qayi233EJCQgKrV68mNjbWfey+++7j4MGDLFu2zOOcNm3a8Pvf/94j7f/+7/+47bbbePXVV+nYsSP33HOPx/FOnTpVOOdCFBUV4e/vf9HX8cbhw4dJSUlh/vz5DXK/5iQjI6NZ1GCZzebGLkIFBoMBg8HQ2MUQ4qJJ85Nocl5++WUKCwt59913PQIalw4dOvDAAw/UeB1fX18+/PBDwsLCeOGFF6iLBeldfQ9+/PFH7r33XqKiomjbtq37+D//+U+6d++OxWIhLi6O++67j9zcXPfxN954A4PB4JH2yiuvoNPpmDVrljvNbrcTGBjIY4895nH/ZcuWERwczPDhw91pJ0+e5M477yQuLg6LxUJSUhL33HMP5eXl7jyHDx9m4sSJhIWF4efnx+DBgysEhpWpqv/HHXfcQWJiovu9qz/O3//+d+bNm0dycjJ+fn5ceeWVHD9+HKUUzz//PG3btsXX15frrruOnJwcj2smJiZyzTXX8PPPPzNw4EB8fHxITk7mgw8+qLaMa9euRafTkZqayrJly9xNia7+IWVlZcyePZsOHTpgsViIj4/n0UcfpayszH0NnU5HUVER77//vvv8O+64o1afsetes2bNIjIyEn9/f2644QYyMzOr/Uxd5f/000954YUXaNu2LT4+PowePZqDBw9WeF7X5+vr68vAgQNZt26dV/10qnvGyvrUuL6PtWvXMmDAAHx9fenZsydr164F4IsvvqBnz574+PjQv39/tm7dWuGe+/bt46abbiIsLAwfHx8GDBjA119/XW05hbgYUlMjmpxvvvmG5ORkhg4detHXCggI4IYbbuDdd99lz549dO/e3X2stLSUrKwsj/yBgYFeVcHfe++9REZG8vTTT1NUVATAM888w7PPPsuYMWO45557SElJ4a233uK3337jf//7HyaTiREjRuBwOPj555+55pprAFi3bh16vZ5169a5r79161YKCwu59NJLPe67fPlyrrjiCoxG7Z/uqVOnGDhwILm5ucyYMYMuXbpw8uRJlixZQnFxMWazmfT0dIYOHUpxcTF/+tOfCA8P5/333+faa69lyZIl3HDDDRf24Vbio48+ory8nPvvv5+cnBxefvllbr75Zi6//HLWrl3LY489xsGDB3nzzTd55JFHWLBggcf5Bw8e5KabbuLOO+9k6tSpLFiwgDvuuIP+/ft7fHfn6tq1Kx9++CEPPfQQbdu2dTdDRkZG4nA4uPbaa/n555+ZMWMGXbt2ZefOnbz66qvs37/f3b/kww8/5K677mLgwIHMmDEDgPbt23v9Gbvcf//9hIaGMnv2bI4cOcJrr73GzJkz+eSTT2r87F566SX0ej2PPPIIeXl5vPzyy0yePNmjX9hbb73FzJkzGTFiBA899BBHjhzh+uuvJzQ01CO4rkx1z1iVgwcPctttt/HHP/6R3//+9/z9739nwoQJzJ8/nyeffJJ7770XgDlz5nDzzTeTkpKCXq/9X3n3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", + "image/png": "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", "text/plain": [ "
" ] @@ -166,7 +158,7 @@ "\n", " ax3.plot(x, y,label=key)\n", "\n", - "ax3.set_xlim([0,4000])\n", + "ax3.set_xlim([0,8000])\n", "ax3.legend()\n", "ax3.set_ylim([0,1])\n", "\n", @@ -185,27 +177,83 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 26, "id": "707322b0", - "metadata": { - "vscode": { - "languageId": "python" + "metadata": {}, + "outputs": [ + { + "ename": "KeyError", + "evalue": "'num_messages'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m~/.local/lib/python3.10/site-packages/pandas/core/indexes/base.py:3805\u001b[0m, in \u001b[0;36mIndex.get_loc\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 3804\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m-> 3805\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_engine\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcasted_key\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3806\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m err:\n", + "File \u001b[0;32mindex.pyx:167\u001b[0m, in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", + "File \u001b[0;32mindex.pyx:196\u001b[0m, in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", + "File \u001b[0;32mpandas/_libs/hashtable_class_helper.pxi:7081\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", + "File \u001b[0;32mpandas/_libs/hashtable_class_helper.pxi:7089\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", + "\u001b[0;31mKeyError\u001b[0m: 'num_messages'", + "\nThe above exception was the direct cause of the following exception:\n", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[26], line 7\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m key \u001b[38;5;129;01min\u001b[39;00m op_df:\n\u001b[1;32m 5\u001b[0m vsdf \u001b[38;5;241m=\u001b[39m op_df[key]\u001b[38;5;241m.\u001b[39mloc[(op_df[key][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtype\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mValidatorSamplingOperation\u001b[39m\u001b[38;5;124m'\u001b[39m)]\n\u001b[0;32m----> 7\u001b[0m x \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39msort(\u001b[43mvsdf\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mnum_messages\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m)\n\u001b[1;32m 8\u001b[0m N \u001b[38;5;241m=\u001b[39m vsdf[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnum_messages\u001b[39m\u001b[38;5;124m'\u001b[39m]\u001b[38;5;241m.\u001b[39mcount()\n\u001b[1;32m 9\u001b[0m \u001b[38;5;66;03m# get the cdf values of y\u001b[39;00m\n", + "File \u001b[0;32m~/.local/lib/python3.10/site-packages/pandas/core/frame.py:4102\u001b[0m, in \u001b[0;36mDataFrame.__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 4100\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcolumns\u001b[38;5;241m.\u001b[39mnlevels \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[1;32m 4101\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_getitem_multilevel(key)\n\u001b[0;32m-> 4102\u001b[0m indexer \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcolumns\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 4103\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m is_integer(indexer):\n\u001b[1;32m 4104\u001b[0m indexer \u001b[38;5;241m=\u001b[39m [indexer]\n", + "File \u001b[0;32m~/.local/lib/python3.10/site-packages/pandas/core/indexes/base.py:3812\u001b[0m, in \u001b[0;36mIndex.get_loc\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 3807\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(casted_key, \u001b[38;5;28mslice\u001b[39m) \u001b[38;5;129;01mor\u001b[39;00m (\n\u001b[1;32m 3808\u001b[0m \u001b[38;5;28misinstance\u001b[39m(casted_key, abc\u001b[38;5;241m.\u001b[39mIterable)\n\u001b[1;32m 3809\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28many\u001b[39m(\u001b[38;5;28misinstance\u001b[39m(x, \u001b[38;5;28mslice\u001b[39m) \u001b[38;5;28;01mfor\u001b[39;00m x \u001b[38;5;129;01min\u001b[39;00m casted_key)\n\u001b[1;32m 3810\u001b[0m ):\n\u001b[1;32m 3811\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m InvalidIndexError(key)\n\u001b[0;32m-> 3812\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(key) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01merr\u001b[39;00m\n\u001b[1;32m 3813\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m:\n\u001b[1;32m 3814\u001b[0m \u001b[38;5;66;03m# If we have a listlike key, _check_indexing_error will raise\u001b[39;00m\n\u001b[1;32m 3815\u001b[0m \u001b[38;5;66;03m# InvalidIndexError. Otherwise we fall through and re-raise\u001b[39;00m\n\u001b[1;32m 3816\u001b[0m \u001b[38;5;66;03m# the TypeError.\u001b[39;00m\n\u001b[1;32m 3817\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_check_indexing_error(key)\n", + "\u001b[0;31mKeyError\u001b[0m: 'num_messages'" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" } - }, + ], + "source": [ + "fig8, ax8 = plt.subplots()\n", + "\n", + "for key in op_df:\n", + "\n", + " vsdf = op_df[key].loc[(op_df[key]['type'] == 'ValidatorSamplingOperation')]\n", + "\n", + " x = np.sort(vsdf['num_messages'])\n", + " N = vsdf['num_messages'].count()\n", + " # get the cdf values of y\n", + " y = np.arange(N) / float(N)\n", + "\n", + " ax8.plot(x, y,label=key)\n", + "\n", + "ax8.legend()\n", + "#ax8.set_xlim([0,10])\n", + "ax8.set_ylim([0,1])\n", + "\n", + "ax8.set_title(\"CDF number of requests per row/column fetching process\")\n", + "ax8.set_xlabel(\"# Messages\")" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "95bea67e", + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Text(0.5, 0, '# Messages')" + "Text(0.5, 0, '#MBs')" ] }, - "execution_count": 4, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "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KSnJ8RwNGjSoxuusKdpVy8iPP/5Ily5dGDlyZJOP5efnxxVXXMH777/PgQMH6N27t+O68vJycnJyqpX39/fHYDDUedw777yToKAgnnjiCVJSUnj11VdZsGABS5cubXRd77zzTiIjI3nqqafYtGkT77zzDkajkQ0bNhAXF8ezzz7LsmXLeOGFF+jTp0+NLqaPP/6Y4uJi7rjjDsrLy/nvf//L+eefz969e4mIiABg//79jBo1ipiYGB566CF8fX354osvuPzyy/n666+54oorqh3zb3/7G2FhYTz++OOUlpY6rXtZWRnjx4/n2LFjLFiwgM6dO/Pll18yZ84cCgoKuPvuu+nVqxeffPIJ9957L506dXJ0q4WFhbl8XFavXs0XX3zBggULCA0NJSEhgczMTIYPH45KpWLBggWEhYXxyy+/cPPNN1NUVOQYFFtWVsbEiRM5deoUd911F9HR0XzyySesXr26oU+Pg81mY9q0afz555/Mnz+fXr16sXfvXl555RWOHDnCd99953isL7nkEvr168fChQsxGAwcO3aM9evXA9CrVy8WLlzI448/zvz58xkzZgwAI0eOxGw2M3nyZCoqKhyvi9TUVH766ScKCgoIDAx0Wcf8/HymTp3K9OnTue666/jiiy+4/fbb0ev13HTTTQ26H66eB1cOHz7Mddddx6233sq8efPo0aMHmZmZjBw5EpPJxF133UVISAgfffQR06ZN46uvvuKKK65ApVIxatQo/vjjD8ex9uzZQ2FhIWq1mvXr13PxxRcDsG7dOs477zz8/PwcZbdu3Up2djZTp0517Hvqqad48sknGTlyJAsXLkSv17N582ZWr17t6Mp58skneeqpp5g0aRK33347hw8f5q233mLr1q2sX78enU7n8v7Wl9Vq5aKLLmLs2LH85z//YcmSJSxYsABfX18effRRZs2axZVXXsmiRYu44YYbGDFiBJ07d652jMZ8/jz66KP06NGDd955h4ULF9K5c2cSExMB5bm96KKLGDRoEE888QRqtZoPP/yQ888/n3Xr1jF06FCuvPJKjhw5wv/93//xyiuvEBoaCvz1/q3PYwxw7Ngxrr76am6++WZuvPFGPvjgA+bMmcOgQYOqfT7XJj8/nylTpnDllVcyffp0vvrqK/7xj3/Qt29fLrroIkBpwT3//PNJT0/n7rvvJjIyks8+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h4czfvx43n777VoDouzs7Eafe+rUqWRkZFQbzV9ZWcnrr7+On58f48aNa/Sxz6XRaLjqqqv4+uuva30jn30/pk6dSlpaGl999ZVjn8lkqpYwzy4xMZFNmzZhNpsd+3766SdHk6rd9OnTSU1N5d13361xjLKyMseso7y8vBrX2z+oKyoqABzBwrlfZEVFRVRWVlbb17dvX9RqteO2rlRWVvL22287/jebzbz99tuEhYUxaNCgBt0Pd5o6dSpbtmxh48aNjn2lpaW88847JCQkVGvmHzNmDBUVFbz66quMHj3a8f4dM2YMn3zyCWlpadXGHlgsFlauXFmtiwaUsVRqtZqFCxfW6CKz/6KeNGkSer2e1157rdqv7Pfff5/CwsIaxzxbfHw8Go2mxnv9f//7X30fFo8aNGgQiYmJvPjii44u7bOd/X5y9nqtz2PcUiZPnkxqaio//PCDY195eXmtr3NX3nzzzWr/v/766wCOz1NnNBoNF154Id9//321Lp3MzEw+++wzRo8e7RiOcNVVV7F7926+/fbbGsexP27u/LzJzc2tdr1erycpKQkhBBaLxeX9qq921TKSmJjIZ599xowZM+jVq1e1DKwbNmxwTBk9W2pqKp9++imgtIYcOHCAL7/8koyMDP7+979XG8zXUm655RZuu+02rrrqKi644AJ2797NihUrHFPi3K1r166MHj2a22+/3fEhHhISwoMPPugo8+abbzJ69Gj69u3LvHnz6NKlC5mZmWzcuJEzZ86we/fuRp17/vz5vP3228yZM4ft27eTkJDAV199xfr163n11VfdOiAZ4N///jdr1qxh2LBhzJs3j6SkJPLy8tixYwe//fab4405b9483njjDW644Qa2b99OVFQUn3zyCT4+PjWOecstt/DVV18xZcoUpk+fTnJyMp9++qnjl6Pd7Nmz+eKLL7jttttYs2YNo0aNwmq1cujQIb744gtWrFjB4MGDWbhwIX/88QcXX3wx8fHxZGVl8b///Y9OnTo5xjkkJiZiNBpZtGgR/v7++Pr6MmzYMHbv3s2CBQu45ppr6N69O5WVlXzyySeOQKwu0dHRPP/886SkpNC9e3eWLl3Krl27eOeddxxTVOt7P9zpoYce4v/+7/+46KKLuOuuuwgODuajjz7ixIkTfP3119Va1UaMGIFWq+Xw4cPVBhyPHTuWt956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", "text/plain": [ "
" ] @@ -217,12 +265,12 @@ "source": [ "fig8, ax8 = plt.subplots()\n", "\n", - "for key in op_df:\n", + "for key in msg_df:\n", "\n", - " vsdf = op_df[key].loc[(op_df[key]['type'] == 'ValidatorSamplingOperation')]\n", + " vsdf = msg_df[key].loc[(msg_df[key]['nodeType'] == 'validator')]\n", "\n", - " x = np.sort(vsdf['num_messages'])\n", - " N = vsdf['num_messages'].count()\n", + " x = np.sort(vsdf['bytesIn'])/ 1024 / 1024\n", + " N = vsdf['bytesIn'].count()\n", " # get the cdf values of y\n", " y = np.arange(N) / float(N)\n", "\n", @@ -232,8 +280,163 @@ "#ax8.set_xlim([0,10])\n", "ax8.set_ylim([0,1])\n", "\n", - "ax8.set_title(\"CDF number of requests per row/column fetching process\")\n", - "ax8.set_xlabel(\"# Messages\")" + "ax8.set_title(\"CDF bytes received per sampling process validator\")\n", + "ax8.set_xlabel(\"#MBs\")" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "64a9d6f0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0, '#MBs')" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAHHCAYAAABtF1i4AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAAC3VklEQVR4nOzdd3hUZdrA4d/09N4LCRBaIIAEKQIC0kEsi4KKUlbBhnVdV/0su7rK6rrIrg17d0VRXBUFkSJSpUrvhEBIL5MySaad74+TGYhJIDMkOTOZ976uXGdy5sycJ5n2zFueVyVJkoQgCIIgCIJC1EoHIAiCIAiCbxPJiCAIgiAIihLJiCAIgiAIihLJiCAIgiAIihLJiCAIgiAIihLJiCAIgiAIihLJiCAIgiAIihLJiCAIgiAIihLJiCAIgiAIihLJiId6//33UalUbNu2TelQ2iWVSsVf//rXNj+v43HNyspq83P7it8/tuJ/LjTHX//6V1QqldJhtKisrCxUKhXvv/++0qFckEhGgGPHjnH77bfTqVMn/Pz8CAkJYciQIfz73/+murraeVxqaioqlQqVSoVarSYsLIyMjAzmzp3Lli1bGr1vx/G//4mLi2urP8/pueee4+uvv27z8wqCIAjC+WiVDkBpy5Yt4/rrr8dgMDBjxgx69eqF2Wxm/fr1/PnPf2bfvn28+eabzuP79u3Ln/70JwAqKio4cOAAX3zxBW+99RYPPPAACxYsaHCOMWPGMGPGjHr7/P39W/cPa8Rzzz3HddddxzXXXNPm5/Y01dXVaLU+//T3Cbfccgs33HADBoNB6VAEQWiCT78bnzhxghtuuIGUlBRWr15NfHy887q7776bo0ePsmzZsnq3SUxM5Oabb6637/nnn+emm27ipZdeokuXLtx55531ru/atWuD2/i6mpoa9Ho9arUyjXN+fn6KnNeTSJJETU2NIolxW9JoNGg0GqXDcJnVasVut6PX65UOpdVVVVURGBiodBgtxldeWy3Jp7tpXnjhBSorK3nnnXfqJSIOaWlp3HfffRe8H39/fz766CMiIiJ49tlnacmFkE0mE7fffjuRkZGEhIQwY8YMSktLndfPnDmTqKgoLBZLg9uOHTuWbt26AXJ3UVVVFR988IGzq2jWrFnOY3NycvjjH/9IbGwsBoOBnj178u677za4z5dffpmePXsSEBBAeHg4/fv359NPPz3v37B27VpUKhWfffYZjz/+OImJiQQEBFBeXg7Ali1bGD9+PKGhoQQEBDB8+HA2bNjQ4H5ycnK49dZbSUhIwGAw0LFjR+68807MZrPzmLKyMu6//36Sk5MxGAykpaXx/PPPY7fb693XueMKlixZgkql4ueff25wzjfeeAOVSsXevXud+w4ePMh1111HREQEfn5+9O/fn2+++abBbfft28cVV1yBv78/SUlJ/P3vf28QR1NmzZpFUFAQx48fZ9y4cQQGBpKQkMDTTz/d4Pllt9tZuHAhPXv2xM/Pj9jYWG6//fZ6zxOQuxmvvPJKVqxYQf/+/fH39+eNN95oMoYjR44wZcoU4uLi8PPzIykpiRtuuAGj0eg85r333uOKK64gJiYGg8FAeno6r7/+eoP7cpx77dq1znNnZGSwdu1aAL766isyMjLw8/MjMzOTnTt3uv3/+L3Gxow44lm/fj0DBgzAz8+PTp068eGHHza4/e7duxk+fHi9x/G9995r1jiU5sbt6Nt/8cUXWbhwIZ07d8ZgMLB//34AVq9ezbBhwwgMDCQsLIyrr76aAwcONDhfS75GPvvsMzIzMwkODiYkJISMjAz+/e9/O6+3WCz87W9/o0uXLvj5+REZGcnQoUNZuXJlsx6Pn3/+mbvuuouYmBiSkpKc1//www/OvzU4OJhJkyaxb9++BvfzxRdfkJ6ejp+fH7169WLp0qXMmjWL1NRU5zGO9x7H8+z3/+8LjaVw9fnd3NfWiBEj6NWrF/v372fkyJEEBASQmJjICy+80ODYgoICbr31VmJjY/Hz86NPnz588MEHDY4rKytj1qxZhIaGEhYWxsyZMykrK2v0/M19D2tLPt0y8u2339KpUycuu+yyi76voKAgrr32Wt555x32799Pz549ndfV1NRQVFRU7/jg4OBmNRvPmzePsLAw/vrXv3Lo0CFef/11Tp486XyR3XLLLXz44YesWLGCK6+80nm7vLw8Vq9ezVNPPQXARx99xG233caAAQOYO3cuAJ07dwYgPz+fQYMGoVKpmDdvHtHR0fzwww/ceuutlJeXc//99wPw1ltvce+993Lddddx3333UVNTw+7du9myZQs33XTTBf+WZ555Br1ez0MPPURtbS16vZ7Vq1czYcIEMjMzeeqpp1Cr1c43gF9++YUBAwYAcObM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Vv71r38xa9Ys/ve///Hjjz9y7733Mn/+fDZv3kxSUhLHjh1j1KhRdO/enQULFpCcnIxer+f777/npZdeajAgsqkZLU3tl1pwILgnnfd8Wnv2RXNfIzExMezatYsVK1bwww8/8MMPP/Dee+8xY8YM5+DJyy+/nGPHjjmfH2+//TYvvfQSixYt4rbbbrtgLE29H3z00UeN1mFyZyp+U0XMbDbbBW/r6vPb1cdOieefJ76HOfhsMgJw5ZVX8uabb7Jp06ZGv/24orKykqVLl5KcnOzMWlvCkSNHGDlyZL3z5ObmMnHixHrHzZgxgwcffJDc3Fw+/fRTJk2aRHh4eL1jGnthRkdHExwcjM1ma1brTWBgINOmTWPatGmYzWb+8Ic/8Oyzz/Loo4+6PF3WMYA2JCTkvOeOjo4mJCTkgolj586dqaysdLsVatq0aXzwwQesWrWKAwcOIEmSs4sGcH671el0FzxHSkpKo83Xhw4danY8drud48eP10uiDh8+DOAcyNe5c2d++uknhgwZ0iofZBkZGWRkZPD444+zceNGhgwZwqJFi/j73//Ot99+S21tLd988029Vobfdw21lOb8P1paSkoKR48ebbC/sX1NuZi4U1JSgMafNwcPHiQqKorAwED8/f1b/DWi1+uZPHkykydPxm63c9ddd/HGG2/wxBNPOD+wIiIimD17NrNnz6ayspLLL7+cv/71r81KRhqLDeRE6HzxOf4nzXlcHO+Bv59V4mhROJ+2fn43JiUlhd27d2O32+u1jhw8eNB5vWO7atUqKisr67WO/P5548p7WFvz2TEjAA8//DCBgYHcdttt5OfnN7j+2LFj9aayNaW6uppbbrmFkpIS/u///q9FSwq/+eab9abtvv7661itVudoa4cbb7wRlUrFfffdx/HjxxutaxIYGNjgRanRaJgyZQpffvllo29khYWFzsvFxcX1rtPr9aSnpyNJUqNTiy8kMzOTzp078+KLLzq7uBo7t1qt5pprruHbb79ttDy+45vE1KlT2bRpEytWrGhwTFlZGVar9bzxjB49moiICBYvXszixYsZMGBAvabXmJgYRowYwRtvvEFubm6T8QJMnDiRzZs38+uvv9a7vqkWjKa88sorzsuSJPHKK6+g0+mcXUlTp07FZrPxzDPPNLit1WptcmrfhZSXlzf4f2VkZKBWq6mtrQXO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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig8, ax8 = plt.subplots()\n", + "\n", + "for key in msg_df:\n", + "\n", + " vsdf = msg_df[key].loc[(msg_df[key]['nodeType'] == 'regular')]\n", + "\n", + " x = np.sort(vsdf['bytesIn'])/ 1024 / 1024\n", + " N = vsdf['bytesIn'].count()\n", + " # get the cdf values of y\n", + " y = np.arange(N) / float(N)\n", + "\n", + " ax8.plot(x, y,label=key)\n", + "\n", + "ax8.legend()\n", + "#ax8.set_xlim([0,10])\n", + "ax8.set_ylim([0,1])\n", + "\n", + "ax8.set_title(\"CDF bytes received per sampling process regular node\")\n", + "ax8.set_xlabel(\"#MBs\")" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "0792c905", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "No artists with labels found to put in legend. Note that artists whose label start with an underscore are ignored when legend() is called with no argument.\n" + ] + }, + { + "data": { + "text/plain": [ + "Text(0.5, 0, '% Malicious')" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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lYBhhIhKNc7fEr5HxwFH5a6k4nzx8HkQ0ZOJYYSISrU6vgCDZm6AbxUcSEnnXFISVi8cghfkLoSIisUwQkSlSr8nkOfgDdRrLXcpFZaXrkX6PSF3GURUgqp7EpiIiIiqBYYRIiIikhXDCBEREcmKYYSIiIhkxTBCREREsmIYISIiIlkxjBAREZGsGEaIiIhIVgwjREREJCuGESIiIpIVwwgRERHJimGEiIiIZMUwQkRERLJiGCEiIiJZMYwQERGRrBhGiIiISFYMI0RERCQrhhEiIiKSFcMIERERyYphhIiIiGTFMEJERESyYhghIiIiWTGMEBERkawYRoiIiEhWDCNEREQkK4YRIiIikhXDCBEREcmKYYSIiIhkxTBCREREsmIYISIiIlkxjBAREZGsGEaIiIhIVgwjREREJKsKhZHly5fDw8MDVlZW6NChA06cOFFi2y+++AKBgYGoXbs2ateujaCgoFLbExERkXkxOIx88803iIiIwKxZs3Dq1Cm0atUKvXv3RmZmZrHtY2JiMHjwYBw5cgRxcXFwd3fHs88+i2vXrv3r4omIiKjqMziMLFq0CGPHjsXIkSPRrFkzrFq1CjY2Nli3bl2x7Tdv3ozx48ejdevW8PHxwZdffgmtVovDhw//6+KJiIio6jMojBQUFCA+Ph5BQUH/W4FSiaCgIMTFxZVrHbm5uSgsLESdOnVKbJOfn4+srCy9HyIiIqqeDAojN2/ehEajgYuLi950FxcXpKenl2sd7777LurVq6cXaB4XGRkJe3t76cfd3d2QMomIiKgKMenVNB9//DG2bduGb7/9FlZWViW2mzZtGu7evSv9/P333yaskoiIiEzJwpDGjo6OUKlUyMjI0JuekZEBV1fXUpddsGABPv74Y/z4449o2bJlqW3VajXUarUhpREREVEVZdCREUtLS/j7++t1PtV1Ru3UqVOJy3366af48MMPsX//frRr167i1RIREVG1Y9CREQCIiIhAeHg42rVrh/bt22Px4sXIycnByJEjAQBhYWGoX78+IiMjAQCffPIJZs6ciS1btsDDw0PqW2JrawtbW9tKfCpERERUFRkcRgYNGoQbN25g5syZSE9PR+vWrbF//36pU+vVq1ehVP7vgMvKlStRUFCAAQMG6K1n1qxZ+OCDD/5d9URERFTlGRxGAGDixImYOHFisfNiYmL0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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig18, ax18 = plt.subplots()\n", + "\n", + "data = []\n", + "for key in msg_df:\n", + "\n", + " vsdf = msg_df[key].loc[(msg_df[key]['nodeType'] == 'validator')]\n", + " x = np.sort(vsdf['bytesIn']) \n", + " data.append(x)\n", + "\n", + "ax18.boxplot(data)\n", + "\n", + "ax18.legend()\n", + "#ax18.set_xlim([0,2])\n", + "#ax18.set_ylim([0,1])\n", + "ax18.set_xticklabels([0,20,40,60,80])\n", + "ax18.set_title(\"Bytes received per row/column fetching process\")\n", + "ax18.set_xlabel(\"% Malicious\")" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "ddc5328e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0, '# MBs')" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAHHCAYAAABtF1i4AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAACrbklEQVR4nOzdd3xUVdrA8d+0zKQX0mmh9yIgCIiAgCBYV0EFaQqWFRvruoprX/W1IRYUe4UVG+pKE1EUFVFBRKT3mt77lPP+cTMTYhKYSZs78Hz55DPJnTtzT4bJvc+c85znGJRSCiGEEEIIPzH6uwFCCCGEOL1JMCKEEEIIv5JgRAghhBB+JcGIEEIIIfxKghEhhBBC+JUEI0IIIYTwKwlGhBBCCOFXEowIIYQQwq8kGBFCCCGEX0kwIrzy1ltvYTAY2L9/v7+bIoTHAw88gMFg8Hcz6uyXX35h0KBBhIaGYjAY2LRpU5Mde9iwYXTv3v2k++3fvx+DwcBbb73V+I0Spy0JRvxoz549XH/99bRt2xabzUZERASDBw/m2WefpaSkxLNfSkoKBoMBg8GA0WgkKiqKHj16cN1117F+/foan9u9/1+/EhMTm+rX81i0aBHz5s1r8uM2hq1bt/LAAw9IUOYDl8tFXFwcTzzxhL+boit2u53x48eTnZ3NM888w7vvvkvr1q29fry8F8WpxOzvBpyuli5dyvjx47FarUyZMoXu3btTXl7O999/zz//+U/+/PNPXnnlFc/+vXv35h//+AcABQUFbNu2jQ8//JBXX32V22+/nblz51Y7xqhRo5gyZUqVbcHBwY37i9Vg0aJFbNmyhdtuu63Jj93Qtm7dyoMPPsiwYcNISUnxd3MCws8//0xmZibjxo3zd1N0Zc+ePRw4cIBXX32VGTNm+Pz4pnovtm7dmpKSEiwWS6MdQwgJRvxg3759XHnllbRu3Zqvv/6apKQkz3033XQTu3fvZunSpVUe07x5c66++uoq2x5//HEmTpzIM888Q4cOHbjxxhur3N+xY8dqjxGnHqUUpaWlPgWaxcXFhISENGKrKi1btozWrVvTrVu3JjleoEhPTwcgKirKvw05CYPBgM1m83czfFaXvwvhPzJM4wdPPPEEhYWFvP7661UCEbf27dtz6623nvR5goODeffdd4mJieGRRx6hoRZg/vPPPzn33HMJDg6mRYsW/Oc//8HlclXb77PPPmPcuHEkJydjtVpp164dDz/8ME6n07PPsGHDWLp0KQcOHPAMFbk/xZWXl3PffffRt29fIiMjCQ0NZciQIXzzzTdetfPXX39l9OjRxMbGEhwcTJs2bbjmmmuq7ONyuZg3bx7dunXDZrORkJDA9ddfT05OTpX9UlJSuOCCC/j+++/p378/NpuNtm3b8s4773j2eeuttxg/fjwAw4cP9/w+a9asqbWN06ZNIywsjL179zJ69GhCQ0NJTk7moYceqvb/5WtbV65cSb9+/QgODubll1+utQ3u3IANGzZwzjnnEBISwpw5cwDtgnjttdeSkJCAzWajV69evP3221Ue36dPH/72t79V2dajRw8MBgObN2/2bFu8eDEGg4Ft27ZV2Xfp0qXVekWWL1/O0KFDCQ8PJyIigjPPPJNFixZV2efDDz+kb9++BAcHExsby9VXX82RI0dq/T3hxPkNBoOBBx54wPOzO99k586dXH311URGRhIXF8e9996LUopDhw5x8cUXExERQWJiIk8//XSV51uzZg0Gg4EPPviARx55hBYtWmCz2RgxYgS7d+8+YTunTZvG0KFDARg/fjwGg4Fhw4Z57t++fTuXX345MTEx2Gw2+vXrx+eff+6535v3ojevMWg9LMOHDyckJITmzZtXG06r6TV1v6+PHDnCJZdcQlhYGHFxcdxxxx1V/v4BsrKymDx5MhEREURFRTF16lR+//13r/JQ3Llq3333Hddffz3NmjUjIiKCKVOm+PR3sXfvXsaPH09MTAwhISGcddZZ1T7wAZSWlvLAAw/QsWNHbDYbSUlJ/O1vf2PPnj2efbz9O/Xm/PT+++/Tt29fz/9Rjx49ePbZZ0/4mpyylGhyzZs3V23btvV6/9atW6tx48bVev+1116rALVlyxbPNkBde+21KiMjo8pXaWnpCY917NgxFRcXp6Kjo9UDDzygnnzySdWhQwfVs2dPBah9+/Z59r3kkkvUhAkT1JNPPqleeuklNX78eAWoO+64w7PPl19+qXr37q1iY2PVu+++q9599121ZMkSpZRSGRkZKikpSc2ePVu99NJL6oknnlCdOnVSFotF/fbbbydsZ1pamoqOjlYdO3ZUTz75pHr11VfVPffco7p06VJlvxkzZiiz2axmzpypFixYoP71r3+p0NBQdeaZZ6ry8vIqr3GnTp1UQkKCmjNnjnrhhRdUnz59lMFg8Lyue/bsUbfccosC1Jw5czy/T2pqaq3tnDp1qrLZbKpDhw5q8uTJ6oUXXlAXXHCBAtS9995b57a2b99eRUdHq7vuukstWLBAffPNN7W2YejQoSoxMVHFxcWpm2++Wb388svq008/VcXFxapLly7KYrGo22+/XT333HNqyJAhClDz5s3zPP6WW25RcXFxnp+zsrKUwWBQRqNRvfDCC57tN910U5X9lNLeTwaDQX3xxReebW+++aYyGAyqe/fu6pFHHlHz589XM2bMUJMnT66yD6DOPPNM9cwzz6i77rpLBQcHq5SUFJWTk+PZ7/7771fHn8b27dunAPXmm29Wex0Adf/991d7bO/evdVVV12lXnzxRTVu3DgFqLlz56pOnTqpG2+8Ub344otq8ODBClDffvut5/HffPONAtQZZ5yh+vbtq5555hn1wAMPqJCQENW/f/9a/z+UUurHH39Uc+bMUYC65ZZb1Lvvvqu+/PJLpZRSW7ZsUZGRkapr167q8ccfVy+88II655xzlMFgUJ988olS6uTvRW9e46FDh6rk5GTVsmVLdeutt6oXX3xRnXvuuQpQy5YtO+Fr6n5fd+vWTV1zzTXqpZdeUpdddpkC1IsvvujZz+l0qoEDByqTyaRmzZqlXnjhBTVq1CjVq1evWv+fjud+H/To0UMNGTJEPffcc+qmm25SRqNRnXPOOcrlcnn2re3vIjU1VSUkJKjw8HB1zz33qLlz56pevXopo9HoeT2VUsrhcKgRI0YoQF155ZXqhRdeUI899pg699xz1aeffurZz5u/U2/OT19++aUC1IgRI9T8+fPV/Pnz1axZs9T48eNP+JqcqiQYaWJ5eXkKUBdffLHXjzlZMPLMM88oQH322WeebUCNXyf747/tttsUoNavX+/Zlp6eriIjI6sFI8XFxdUef/3116uQkJAqQc+4ceNU69atq+3rcDhUWVlZlW05OTkqISFBXXPNNSds55IlSxSgfvnll1r3Wbt2rQLUwoULq2xfsWJFte2tW7dWgPruu+8829LT05XValX/+Mc/PNs+/PBDBZzw4n+8qVOnKkDdfPPNnm0ul0uNGzdOBQUFqYyMjDq3dcWKFV61YejQoQpQCxYsqLJ93rx5ClDvvfeeZ1t5ebkaOHCgCgsLU/n5+VV+561btyqllPr888+V1WpVF110kbriiis8j+3Zs6e69NJLqxzj9ddfV8HBwZ73Sm5urgoPD1cDBgxQJSUlVfZ1X1jKy8tVfHy86t69e5V9vvjiCwWo++67z7OtIYKR6667zrPN4XCoFi1aKIPBoP7v//7Psz0nJ0cFBwerqVOnera5g5EuXbpUeR8/++yzClB//PFHtTYcz/34Dz/8sMr2ESNGqB49elT5G3K5XGrQoEGqQ4cOnm21vRe9eY2VqnxfvPPOO55tZWVlKjExUV122WWebbUFI4B66KGHqjy/OzBz+/jjj6sFt06n0xP0eBuM9O3bt0pA/sQTT1Q759X2d+E+p61du9azraCgQLVp00alpKQop9OplFLqjTfe8ASif+V+3bz9O/Xm/HTrrbeqiIgI5XA4TvganC5kmKaJ5efnAxAeHt5gzxkWFgZoia3Hu/jii1m1alWVr9GjR5/wuZYtW8ZZZ51F//79Pdvi4uKYNGlStX2PH4stKCggMzOTIUOGUFxczPbt20/abpPJRFBQEKB1fWZnZ+NwOOjXrx8bN2484WPd4+xffPEFdru9xn0+/PBDIiMjGTVqFJmZmZ6vvn37EhYWVm04qGvXrgwZMqTK792pUyf27t170t/lZGbNmuX53mAwMGvWLMrLy/nqq6/q1NY2bdqc9P/yeFarlenTp1fZtmzZMhITE7nqqqs82ywWC7fccguFhYV8++23AJ7X5LvvvgNg7dq1nHnmmYwaNYq1a9cCkJuby5YtW6q8fu5jDB8+3PNeWbVqFQUFBdx1113V8hDcU3R//fVX0tPT+fvf/15ln3HjxtG5c+cau9fr4/jkUZPJRL9+/VBKce2113q2R0VF1fpemD59uud9DJWvV13eN9nZ2Xz99ddMmDDB8zeVmZlJVlYWo0ePZteuXScdqvLmNXYLCwurklcWFBRE//79vW77DTfcUOXnIUOGVHnsihUrsFgszJw507PNaDRy0003efX8btddd12VBNobb7wRs9nMsmXLquxX09/FsmXL6N+/P2effbZnW1hYGNdddx379+9n69atAHz88cfExsZy8803Vzu++3Xz9u/Um/NTVFQURUVFrFq1yqfX4lQlwUgTi4iIAKoHDvVRWFgIVA9wWrRowciRI6t81ZSjcrwDBw7QoUOHats7depUbduff/7JpZdeSmRkJBEREcTFxXlObHl5eV61/e2336Znz57YbDaaNWtGXFwcS5cuPenjhw4dymWXXcaDDz5IbGwsF198MW+++SZlZWWefXbt2kVeXh7x8fHExcVV+SosLPQkELq1atWq2nGio6OrjQX7ymg00rZt2yrbOnbsCOCZlulrW9u0aeNTG5o3b17lggmV/9dGY9XTQJcuXTz3AyQkJNChQwdP4LF27VqGDBnCOeecw9GjR9m7dy8//PADLperSjBit9tZtWpVlXwR99j7iepbuI9b03uuc+fOnvsbyl//3yMjI7HZbMTGxlbbXtN74a+Pj46OBqjT+2b37t0opbj33nurvQ/uv/9+gGrvhb/y5jV2a9GiRbUAxdv3vM1mIy4u7oSPPXDgAElJSdWSpdu3b3/S5z/eX89JYWFhJCUlVZvWXNPfxYEDB2p8L/31fb5nzx46deqE2Vz7vA5v/069OT/9/e9/p2PHjpx//vm0aNGCa665hhUrVnj3gpyCZDZNE4uIiCA5OZktW7Y02HO6n8vXP/D6yM3NZejQoURERPDQQw/Rrl07bDYbGzdu5F//+leNCa9/9d577zFt2jQuueQS/vnPfxIfH4/JZOKxxx6rkjBWE4PBwEcffcRPP/3E//73P1auXMk111zD008/zU8//URYWBgul4v4+HgWLlxY43P89URqMplq3E81UGLwifjaVl9nCNR3RsHZZ5/N6tWrKSkpYcOGDdx33310796dqKgo1q5dy7Zt2wgLC+OMM87wPOb7778nPz+fsWPH1uvYvqitANpfkyqPV9P/uy/vhYZ837j/bu64445ae74a8u+8Pm2v7bH+1NgzZ7z9O/Xm/BQfH8+mTZtYuXIly5cvZ/ny5bz55ptMmTKlWhL56UCCET+44IILeOWVV1i3bh0DBw6s13MVFhayZMkSWrZs6Yn066N169bs2rWr2vYdO3ZU+XnNmjVkZWXxySefcM4553i279u3r9pja7tAfPTRR7Rt25ZPPvmkyj7uT4DeOOusszjrrLN45JFHWLRoEZMmTeL9999nxowZtGvXjq+++orBgwc32EmqLtU+XS4Xe/fu9fSGAOzcuRPAM7OoMdp6Mq1bt2bz5s24XK4qvSPuIbbjC3ANGTKEN998k/fffx+n08mgQYMwGo2cffbZnmBk0KBBVS5QS5cupWvXrlVqYLRr1w7QAujaLqru4+7YsYNzzz23yn07duw4YWEwd69Ebm5ule0N3ZvSWNw9aBaLhZEjR55w39rei968xk2ldevWfPPNN9Wmkp9sttFf7dq1i+HDh3t+Liws5NixY14Fuq1bt652/oLq7/N27dqxfv167HZ7rTVVfP07PdH5CbRhsQsvvJALL7wQl8vF3//+d15++WXuvfdev//fNTUZpvGDO++8k9DQUGbMmEFaWlq1+/fs2ePV9K6SkhImT55MdnY299xzT4OUxR47diw//fQTP//8s2dbRkZGtU8C7ovO8Z+gysvLefHFF6s9Z2hoaI3DLjU9x/r161m3bt1J25mTk1Pt01vv3r0BPF2hEyZMwOl08vDDD1d7vMPhqHbB8kZoaChQ/WJ3Mi+88ILne6UUL7zwAhaLhREjRjRaW09m7NixpKamsnjx4irHev755wkLC/NMPYXKPIjHH3+cnj17EhkZ6dm+evVqfv311xrzRf46pfe8884jPDycxx57jNLS0ir3uf8/+/XrR3x8PAsWLKjSrb18+XK2bdt2wuJpERERxMbGevJb3Gp6X+pRfHw8w4YN4+WXX+bYsWPV7s/IyPB8X9t70ZvXuKmMHj0au93Oq6++6tnmcrmYP3++T8/zyiuvVMm9eOmll3A4HJx//vknfezYsWP5+eefq5xXioqKeOWVV0hJSaFr164AXHbZZWRmZlb5W3Vzv27e/p16c37Kysqqcr/RaKRnz55V9jmdSM+IH7Rr145FixZxxRVX0KVLlyoVWH/88Uc+/PBDpk2bVuUxR44c4b333gO0TwVbt27lww8/JDU1lX/84x9cf/31DdK2O++8k3fffZcxY8Zw6623EhoayiuvvOL5FO02aNAgoqOjmTp1KrfccgsGg4F33323xpNd3759Wbx4MbNnz+bMM88kLCyMCy+8kAsuuIBPPvmESy+9lHHjxrFv3z4WLFhA165dPXkwtXn77bd58cUXufTSS2nXrh0FBQW8+uqrREREeD4tDR06lOuvv57HHnuMTZs2cd5552GxWNi1axcffvghzz77LJdffrlPr0/v3r0xmUw8/vjj5OXlYbVaOffcc4mPj6/1MTabjRUrVjB16lQGDBjA8uXLWbp0KXPmzPF06zZGW0/muuuu4+WXX2batGls2LCBlJQUPvroI3744QfmzZtXJQepffv2JCYmsmPHjioJfueccw7/+te/AKoEI/v27WPbtm289NJLVY4ZERHBM888w4wZMzjzzDOZOHEi0dHR/P777xQXF/P2229jsVh4/PHHmT59OkOHDuWqq64iLS2NZ599lpSUFG6//fYT/l4zZszg//7v/5gxYwb9+vXju+++8/REBYL58+dz9tln06NHD2bOnEnbtm1JS0tj3bp1HD58mN9//x048XvxZK9xU7nkkkvo378///jHP9i9ezedO3fm888/Jzs7G/C+p7G8vJwRI0YwYcIEduzYwYsvvsjZZ5/NRRdddNLH3nXXXfz3v//l/PPP55ZbbiEmJoa3336bffv28fHHH3t6BadMmcI777zD7Nmz+fnnnxkyZAhFRUV89dVX/P3vf+fiiy/2+u/Um/PTjBkzyM7O5txzz6VFixYcOHCA559/nt69ezdIL3fA8cMMHlFh586daubMmSolJUUFBQWp8PBwNXjwYPX8889XmdbnnrIGKIPBoCIiIlS3bt3UzJkzq0zBPR6gbrrppjq1a/PmzWro0KHKZrOp5s2bq4cffli9/vrr1ab2/vDDD+qss85SwcHBKjk5Wd15551q5cqV1aYbFhYWqokTJ6qoqCgFeKb5ulwu9eijj6rWrVsrq9WqzjjjDPXFF1+oqVOn1jgV+HgbN25UV111lWrVqpWyWq0qPj5eXXDBBerXX3+ttu8rr7yi+vbtq4KDg1V4eLjq0aOHuvPOO9XRo0c9+9Q2fXro0KFq6NChVba9+uqrqm3btspkMp10mu/UqVNVaGio2rNnjzrvvPNUSEiISkhIUPfff79nSmFDtbU2Q4cOVd26davxvrS0NDV9+nQVGxurgoKCVI8ePWqdbumuI7N48WLPtvLychUSEqKCgoKqTCN94YUXVGRkpLLb7TU+1+eff64GDRqkgoODVUREhOrfv7/673//W2WfxYsXqzPOOENZrVYVExOjJk2apA4fPlxln79O7VVKm3J+7bXXqsjISBUeHq4mTJig0tPTa53a655e7eb+P/urv76OtU3NPdH04uPV9niltDoiU6ZMUYmJicpisajmzZurCy64QH300UdV9jvRe/Fkr3Ft74u//v3VNrW3pteopv+PjIwMNXHiRBUeHq4iIyPVtGnT1A8//KAA9f7775/wNXJP7f3222/Vddddp6Kjo1VYWJiaNGmSysrKqrLvif4u9uzZoy6//HIV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O8aqVauw2+1Mnz6d66677oTr1axbt44xY8Zw99138/zzz2M2m/n9999rHMVoSD4HI1dccQUZGRncd999pKam0rt3b1asWOFJaj148GCVRv/73//GYDDw73//myNHjhAXF8eFF17II4880nC/RRPzBCNm/dWM0JUD62DdC7D9C+3n3lfD2CchqOnWMtmWtY1F27U/vGu7X0uwuWkL1dlLteRcW1jDBK5p+aX8tDeLr7enk1FQxtHcEk8yKkBksIV7xnXhsj4tJPgQQmesVmuNKQ0TJ07E6XSyePFizza73U5SUhJz585lypQp1YZpTmbbtm2sWLGCX375hX79+gHw/PPPM3bsWJ566imSk2uewn/77bdzyy23VCnV0alTJx9+y7qp0yD2rFmzmDVrVo33/XVlQbPZzP3338/9999fl0PpknK4gxGppl+rH5+HL/9d+XNMOzj//5o0EAFYfVAbUuwd15tL2l/SpMcGKK8IRizWuvUCulyKjzce5vvdmfx+KLdK4HG8qBAL1w5uwzVntyHUKu9LcfpQSnmW6GhKhuDgBkv+njRpEuPHj6ewsJCwMK1K88qVKykuLubSSy+t03OuW7eOqKgoTyACMHLkSIxGI+vXr6/xedPT01m/fj2TJk1i0KBB7Nmzh86dO/PII49w9tln1+2X85KcterA0zNikZ6RGhWkwjePat93vgAG36rNmDE17dvNpVys2L8CgEvaX+KXWSP2Ui1xNMjmfTDyx+E8nl29i72ZhezNKKp2f6uYEKJDLJzbOYGz2sbQulkoCRFWmRUjTkuqpIQdffo2+XE7bdyAIcS3D1dffPGFJ9hwmzNnDnfeeSehoaEsWbLEU4Nr0aJFXHTRRYSH121xzdTU1GpV0c1mMzExMaSmptb4mL17taU3HnjgAZ566il69+7NO++8w4gRI9iyZQsdOnSoU1u8IcFIXdi1C4zBIi9fjTa+A/ZirXz7Fe+Bny6SG9M2ciD/AKGWUM5vc75f2lBeVtEzYqv+XsksLGPr0XxS80spLnNQbHdyMKuY9385VGU/s9FAclQwc8Z2oX+bGGJCJVdJiEA0fPhwXnrppSrbYmJiMJvNTJgwgYULFzJ58mSKior47LPPeP/997163htuuIH33nvP87M3Sao1cbm0IojXX3+9Jw/0jDPOYPXq1bzxxhueXNDGIFfTOpAE1hMo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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig18, ax18 = plt.subplots()\n", + "\n", + "for key in msg_df:\n", + "\n", + " vsdf = msg_df[key].loc[(msg_df[key]['nodeType'] == 'regular')]\n", + "\n", + " vsdf = vsdf['bytesOut'] / 1024 / 1024\n", + " vsdf = vsdf[~np.isnan(vsdf)]\n", + "\n", + " x = np.sort(vsdf) \n", + " N = vsdf.count()\n", + " # get the cdf values of y\n", + " y = np.arange(N) / float(N)\n", + "\n", + " ax18.plot(x, y,label=key)\n", + "\n", + "ax18.legend()\n", + "#ax18.set_xlim([0,2])\n", + "ax18.set_ylim([0,1])\n", + "\n", + "ax18.set_title(\"CDF data sent per row/column fetching process\")\n", + "ax18.set_xlabel(\"# MBs\")" ] }, { @@ -251,13 +454,9 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 29, "id": "a511ead6", - "metadata": { - "vscode": { - "languageId": "python" - } - }, + "metadata": {}, "outputs": [ { "data": { @@ -265,13 +464,13 @@ "Text(0.5, 0, 'Operation complete time (ms)')" ] }, - "execution_count": 5, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjkAAAHHCAYAAABdm0mZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAACXBklEQVR4nOzdd3xT9frA8U9W03TvQSmUJUOWgiCIExSuE3+KCMhS8aKiIq6LCjiu4kQUEUQFREFQL7hQFBGciMoGkV3K6t4z6/z+OE1o6KAtTdKmz/v16uukJ2c8SUr78B3PV6MoioIQQgghhI/RejsAIYQQQgh3kCRHCCGEED5JkhwhhBBC+CRJcoQQQgjhkyTJEUIIIYRPkiRHCCGEED5JkhwhhBBC+CRJcoQQQgjhkyTJEUIIIYRPkiRHiGbkqaeeQqPReDuMJm/cuHEkJSW57NNoNDz11FNeiac6VcUpRHMiSY5o8g4ePMi///1v2rZti7+/PyEhIVx00UW8/vrrlJSUOI9LSkpCo9Gg0WjQarWEhYXRrVs37rrrLjZt2lTltR3Hn/4VFxdXY0wbNmxwOV6n0xETE8PNN9/Mnj17GvT1i+btxIkTPPXUU2zbts3boQjR6Oi9HYAQZ2P16tUMGzYMo9HImDFj6Nq1K2azmV9++YVHHnmE3bt3s2DBAufxPXv25KGHHgKgoKCAPXv28Mknn/DOO+/w4IMPMmvWrEr3uPLKKxkzZozLPpPJVKv47r//fi644AIsFgs7duxg/vz5bNiwgV27dp0xURJNS0lJCXq953+lnjhxgqeffpqkpCR69uzp8tw777yD3W73eExCNBaS5Igm6/Dhw9x66620bt2aH374gfj4eOdz9957LwcOHGD16tUu5yQkJHDbbbe57HvxxRcZOXIkr732Gh06dODuu+92ef6cc86pdE5tXXzxxdx8883O7zt27Mjdd9/NkiVLePTRR+t1TdE4+fv7ezuESgwGg7dDEMKrpLtKNFkvvfQShYWFvPfeey4JjkP79u154IEHzngdk8nEBx98QEREBM899xyKorgjXEBNekDtYqvolVdeoX///kRGRmIymejVqxeffvpppfM1Gg2TJk3is88+o2vXrhiNRs4991zWrFlT6dhffvmFCy64AH9/f9q1a8fbb79dZUxWq5Vnn32Wdu3aYTQaSUpK4vHHH6esrMzluKSkJK699lo2bNhA7969MZlMdOvWjQ0bNgCwcuVKunXrhr+/P7169WLr1q1nfD8sFgtPP/00HTp0wN/fn8jISAYMGMDatWudx+zYsYNx48Y5uyPj4uK4/fbbycrKcrmWY7zRvn37uO222wgNDSU6Oppp06ahKApHjx7lhhtuICQkhLi4OF599VWX8x1djCtWrODxxx8nLi6OwMBArr/+eo4ePXrG13L6mBxHPAcOHGDcuHGEhYURGhrK+PHjKS4udjm3pKSE+++/n6ioKIKDg7n++us5fvz4Gcf5bNiwgQsuuACA8ePHO7tHFy9eDFQek5OcnIxGo+GVV15h7ty5tG3bloCAAK666iqOHj2Koig8++yztGzZEpPJxA033EB2dnal+37zzTdcfPHFBAYGEhwczDXXXMPu3bvP+B4J4WnSkiOarC+//JK2bdvSv3//s75WUFAQN954I++99x5///035557rvO50tJSMjMzXY4PDg7GaDTW+T7JyckAhIeHu+x//fXXuf766xk1ahRms5nly5czbNgwvvrqK6655hqXY3/55RdWrlzJPffcQ3BwMG+88QY33XQTKSkpREZGArBz506uuuoqoqOjeeqpp7BarcyYMYPY2NhKMd155528//773HzzzTz00ENs2rSJmTNnsmfPHlatWuVy7IEDBxg5ciT//ve/ue2223jllVe47rrrmD9/Po8//jj33HMPADNnzuSWW25h7969aLXV/1/qqaeeYubMmdx555306dOH/Px8/vrrL7Zs2cKVV14JwNq1azl06BDjx48nLi7O2QW5e/dufv/990oDqYcPH07nzp154YUXWL16Nf/973+JiIjg7bff5oorruDFF19k6dKlPPzww1xwwQVccsklLuc/99xzaDQaHnvsMdLT05k9ezaDBg1i27Ztte6mrOiWW26hTZs2zJw5ky1btvDuu+8SExPDiy++6Dxm3LhxfPzxx4wePZoLL7yQH3/8sdLnXpXOnTvzzDPPMH36dO666y5nEn2mfxNLly7FbDZz3333kZ2dzUsvvcQtt9zCFVdcwYYNG3jsscc4cOAAc+bM4eGHH2bhwoXOcz/44APGjh3L4MGDefHFFykuLmbevHkMGDCArVu3ykBn0bgoQjRBeXl5CqDccMMNtT6ndevWyjXXXFPt86+99poCKJ9//rlzH1Dl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HYcPH3ZbTBEREQwYMIDx48eTlpbG7Nmzad++PRMmTHDL/Xr16sVNN93E7NmzycrKck4h37dvH3Dmlpp27doRFhbG/PnzCQ4OJjAwkL59+1Ya49MQQkJCmDdvHqNHj+b888/n1ltvJTo6mpSUFFavXs1FF13Em2++2eD3FaK+JMkRTdr111/Pjh07ePnll/n888+ZN28eRqOR7t278+qrr1b6w7Rt2zZGjx6NRqMhODiYxMRErrvuOmedFk/o3bs3l112GfPmzWPq1KlcccUVvPfee7zwwgtMnjyZNm3a8OKLL5KcnFzvJKd79+58++23TJkyhenTp9OyZUuefvppTp48Wema7777Lm3btmXx4sWsWrWKuLg4pk6dyowZMxri5dbo/vvv54svvuC7776jrKyM1q1b89///pdHHnnEecyyZcu47777mDt3LoqicNVVV/HNN9/QokULt8T0+OOPs2PHDmbOnElBQQEDBw7krbfeIiAgwC33A7X1KC4ujo8++ohVq1YxaNAgVqxYQceOHc9YSdlgMPD+++8zdepUJk6ciNVqZdGiRW5JcgBGjhxJixYteOGFF3j55ZcpKysjISGBiy++mPHjx7vlnkLUl0bx5ug3IYRoJDZs2MDll1/OJ5984rIUh7ds27aN8847jw8//JBRo0Z5OxwhmiQZkyOEEF5WUlJSad/s2bPRarWVKjILIWpPuquEEMLLXnrpJTZv3szll1+OXq/nm2++4ZtvvuGuu+6qVLtGCFF7kuQIIYSX9e/fn7Vr1/Lss89SWFhIq1ateOqpp3jiiSe8HZoQTVqdx+T89NNPvPzyy2zevJmTJ0+yatUqhg4dWuM5GzZsYMqUKezevZvExESefPLJSrNehBBCCCEaUp3H5BQVFdGjRw/mzp1bq+MPHz7MNddcw+WXX862bduYPHkyd955Z6V6HUIIIYQQDemsZldpNJoztuQ89thjrF692qX8/q233kpubq5zYTohhBBCiIbm9jE5GzdurFT+e/DgwUyePLnac8rKylwWKbTb7WRnZxMZGenREuZCCCGEqD9FUSgoKKBFixZVLk7sbm5PclJTU4mNjXXZFxsbS35+PiUlJZhMpkrnzJw5k6efftrdoQkhhBDCA44ePUrLli09ft9GObtq6tSpTJkyxfl9Xl4erVq14ujRo4SEhHgxMuEpiqLw68Es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", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjkAAAHHCAYAAABdm0mZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAACmEUlEQVR4nOzdd3xUZfb48c+0zEw66QkEQu9FQRAERUVh7f4UC4iKiroruyrrqrgqllXs4roKa0XXhg31KwrLori6IioISO+dJIT0TDL1/v64MwORljLJvXfmvF+vvO5kMjP3TNqceZ7zPMekKIqCEEIIIUSUMWsdgBBCCCFES5AkRwghhBBRSZIcIYQQQkQlSXKEEEIIEZUkyRFCCCFEVJIkRwghhBBRSZIcIYQQQkQlSXKEEEIIEZUkyRFCCCFEVJIkR4gY8sADD2AymbQOw/CuvfZaCgoK6l1nMpl44IEHNInnaI4UpxCxRJIcYXhbtmzhpptuolOnTjgcDpKTkznllFN47rnnqK2tDd+uoKAAk8mEyWTCbDaTmppK3759ufHGG1m6dOkRHzt0+99+5OTkHDOmxYsX17u9xWIhKyuLSy+9lHXr1kX0+YvYtnfvXh544AFWrFihdShC6I5V6wCEaI558+YxduxY7HY7V199NX369MHj8fDdd9/xl7/8hTVr1vDSSy+Fbz9gwAD+/Oc/A1BVVcW6dev44IMPePnll7n99tt55plnDjvHWWedxdVXX13vOqfT2aD4/vSnP3HSSSfh9XpZtWoVs2bNYvHixaxevfq4iZIwltraWqzW1v+XunfvXh588EEKCgoYMGBAva+9/PLLBAKBVo9JCL2QJEcY1rZt27jiiivo0KEDX331Fbm5ueGv3XLLLWzevJl58+bVu0/btm256qqr6l33+OOPM27cOJ599lm6du3K73//+3pf79at22H3aagRI0Zw6aWXhj/v3r07v//973nzzTe58847m/SYQp8cDofWIRzGZrNpHYIQmpLpKmFYTzzxBNXV1bz66qv1EpyQLl26cOuttx73cZxOJ//6179IS0vjkUceQVGUlggXUJMeUKfYDvXUU08xbNgw0tPTcTqdDBw4kA8//PCw+5tMJiZPnswnn3xCnz59sNvt9O7dm/nz5x922++++46TTjoJh8NB586d+ec//3nEmHw+Hw8//DCdO3fGbrdTUFDAPffcg9vtrne7goICzjvvPBYvXsygQYNwOp307duXxYsXA/Dxxx/Tt29fHA4HAwcO5Jdffjnu98Pr9fLggw/StWtXHA4H6enpDB8+nIULF4Zvs2rVKq699trwdGROTg7XXXcdBw4cqPdYoXqjjRs3ctVVV5GSkkJmZib33XcfiqKwa9cuLrzwQpKTk8nJyeHpp5+ud//QFOOcOXO45557yMnJISEhgQsuuIBdu3Yd97n8tiYnFM/mzZu59tprSU1NJSUlhYkTJ+Jyuerdt7a2lj/96U9kZGSQlJTEBRdcwJ49e45b57N48WJOOukkACZOnBieHp09ezZweE3O9u3bMZlMPPXUU7zwwgt06tSJ+Ph4zj77bHbt2oWiKDz88MO0a9cOp9PJhRdeSGlp6WHn/fLLLxkxYgQJCQkkJSVx7rnnsmbNmuN+j4RobTKSIwzr//7v/+jUqRPDhg1r9mMlJiZy8cUX8+qrr7J27Vp69+4d/lpdXR0lJSX1bp+UlITdbm/0ebZv3w5AmzZt6l3/3HPPccEFFzB+/Hg8Hg/vvfceY8eO5fPPP+fcc8+td9vvvvuOjz/+mD/84Q8kJSXx97//nUsuuYSdO3eSnp4OwK+//srZZ59NZmYmDzzwAD6fj2nTppGdnX1YTDfccANvvPEGl156KX/+859ZunQp06dPZ926dcydO7febTdv3sy4ceO46aabuOqqq3jqqac4//zzmTVrFvfccw9/+MMfAJg+fTqXXXYZGzZswGw++nupBx54gOnTp3PDDTcwePBgKisr+fnnn1m+fDlnnXUWAAsXLmTr1q1MnDiRnJyc8BTkmjVr+OGHHw4rpL788svp2bMnjz32GPPmzeNvf/sbaWlp/POf/+SMM87g8ccf5+233+aOO+7gpJNO4tRTT613/0ceeQSTycRdd91FcXExM2bMYNSoUaxYsaLB05SHuuyyy+jYsSPTp09n+fLlvPLKK2RlZfH444+Hb3Pttdfy/vvvM2HCBE4++WS++eabw37uR9KzZ08eeugh7r//fm688cZwEn28v4m3334bj8fDH//4R0pLS3niiSe47LLLOOOMM1i8eDF33XUXmzdv5vnnn+eOO+7gtddeC9/3X//6F9dccw2jR4/m8ccfx+VyMXPmTIYPH84vv/wihc5CXxQhDKiiokIBlAsvvLDB9+nQoYNy7rnnHvXrzz77rAIon376afg64Igfr7/++jHP9fXXXyuA8tprryn79+9X9u7dq8yfP1/p0qWLYjKZlB9//LHe7V0uV73PPR6P0qdPH+WMM86odz2gxMXFKZs3bw5ft3LlSgVQnn/++fB1F110keJwOJQdO3aEr1u7dq1isViUQ//sV6xYoQDKDTfcUO88d9xxhwIoX331Vfi6Dh06KIDy/fffh69bsGCBAihOp7Peuf75z38qgPL1118f8/vUv3//Y/5MFOXw742iKMq7776rAMp///vf8HXTpk1TAOXGG28MX+fz+ZR27dopJpNJeeyxx8LXl5WVKU6nU7nmmmvC14V+Zm3btlUqKyvD17///vsKoDz33HPh66655hqlQ4cO9WIClGnTph0Wz3XXXVfvdhdffLGSnp4e/nzZsmUKoNx22231bnfttdce9phH8tNPPx31d/K3cW7btk0BlMzMTKW8vDx8/dSpUxVA6d+/v+L1esPXX3nllUpcXJxSV1enKIqiVFVVKampqcqkSZPqnaewsFBJSUk57HohtCbTVcKQKisrAXVEJVISExMBtSD5UBdeeCELFy6s9zF69OgGPeZ1111HZmYmeXl5jBkzhoqKCv71r3+FpxhCDh0hKCsro6KighEjRrB8+fLDHnPUqFF07tw5/Hm/fv1ITk5m69atAPj9fhYsWMBFF11E+/btw7fr2bPnYXF/8cUXAEyZMqXe9aHi7N/WNPXq1YuhQ4eGPx8yZAgAZ5xxRr1zha4PxXQ0qamprFmzhk2bNh31Nod+b0KjaieffDLAEb8/N9xwQ/iyxWJh0KBBKIrC9ddfX++83bt3P2J8V199db3fq0svvZTc3Nzw96qxbr755nqfjxgxggMHDoR/h0NTjaFRsJA//vGPTTpfQ4wdO5aUlJTw56Gf11VXXVWveHrIkCF4PB727NkDqKNq5eXlXHnllZSUlIQ/LBYLQ4YM4euvv26xmIVoCpmuEoaUnJwMHJ6QNEd1dTVweOLUrl07Ro0a1aTHvP/++xkxYgTV1dXMnTuX995774jTN59//jl/+9vfWLFiRb1amCPtaXNoMhHSpk0bysrKANi/fz+1tbV07dr1sNt179693ov1jh07MJvNdOnSpd7tcnJySE1NZceOHcc8d+iFMj8//4jXh2I6moceeogLL7yQbt260adPH8aM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zo7vDyY4Xc6Ck26A9ifL6qkIqfKoOx2nORo/z61H7q3bAIiTnlWGs3t9GQD5PaPjd1Ec3emnn87MmTPrXZeWlobVauWyyy7j7bffZsKECdTU1PDpp5/y3nvvNehxb775Zt56663w58crLj6W++67j/Lycv7zn/+QkZHBJ598wmWXXca3335L377GexMVO0lOeCTHIFnOgU3qsf0wuOpDbWOJQpWeSgDirfEaRxIZ7i3qHjlxHQu0DUQ0Sk2Fm13BkZycztJVvCmscWZufO40Tc7bWAkJCUcdERk/fjynnXYaxcXFLFy4EKfT2eCVVw899BB33HFHvetycnIoLi6ud53P56O0tJScnJwjPs6WLVv4xz/+werVq+kd3DW9f//+fPvtt7zwwgvMmjWrQfHoScwkOWCw3lUH1OXAZMly4JawqUxNIqOhHgfAvUHd88feWUZyjMLvC/DZcysASEiJIzNfpqqawmQyRUU/r2HDhpGfn8+cOXP48ssvGTt2LDabrUH3zcrKOmxqaujQoZSXl7Ns2TIGDlRrN7/66isCgQBDhgw54uO4XC4AzOb6CZzFYiEQaP26p0iImSTHcDU5pWpTPjK6aRtHlKpwVwBqSwej85WU4AvOsdtlI0DD2LayhNK9NVisZkbf2FeWjMcAt9t9WD2M1WolIyMDgHHjxjFr1iw2btzI119/3axz9ezZkzFjxjBp0iRmzZqF1+tl8uTJXHHFFeQFFyfs2bOHM888kzfffJPBgwfTo0cPunTpwk033cRTTz1Feno6n3zyCQsXLuTzzz9vVjxaiZm/KsPV5LjUjepIio6N6vQmtEdOG0cbjSNpvpoflgJqgmNtY/znEyvWfrcHgL6ntyNXpqpiwvz588nNza33MXz48PDXx48fz9q1a2nbti2nnHJKs8/39ttv06NHD84880zOOecchg8fzksvvRT+utfrZcOGDeERHJvNxhdffEFmZibnn38+/fr148033+SNN97gnHPOaXY8WoihkZzgdJVRxnJqy9WjXYawW8K6UrU3UJdUY64YOFTtqpUAOE8YoG0gosHKCmvYtU4tOO45TN7IxILZs2cze/bsY96mZ8+e4deq31q8eHG9z7cH98U6lrS0tGNu/FdQUHDY+bp27WroHY5/K+ZGcoyS41AR3BMn1fgb1emN2+8Oj+R0SumkcTTNV/fragAc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S3x8PFlZWfzlL3/B56vfuXvx4sWceOKJ2O12unTpwuzZs1v66RnaY489hslkqrdxpvwsWteePXu46qqrSE9Px+l00rdvX37++efw1xVF4f777yc3Nxen08moUaPYtGlTvccoLS1l/PjxJCcnk5qayvXXX091dXW926xatYoRI0bgcDjIz8/niSeeaJXnZxR+v5/77ruPjh074nQ66dy5Mw8//HC9/kfys2gZ//3vfzn//PPJy8vDZDId1ky7Nb/vH3zwAT169MDhcNC3b1+++OKLxj8hRcfee+89JS4uTnnttdeUNWvWKJMmTVJSU1OVoqIirUMzrNGjRyuvv/66snr1amXFihXKOeeco7Rv316prq4O3+bmm29W8vPzlUWLFik///yzcvLJJyvDhg0Lf93n8yl9+vRRRo0apfzyyy/KF198oWRkZChTp04N32br1q1KfHy8MmXKFGXt2rXK888/r1gsFmX+/Pmt+nyN4scff1QKCgqUfv36Kbfeemv4evlZtJ7S0lKlQ4cOyrXXXqssXbpU2bp1q7JgwQJl8+bN4ds89thjSkpKivLJJ58oK1euVC644AKlY8eOSm1tbfg2Y8aMUfr376/88MMPyrfffqt06dJFufLKK8Nfr6ioULKzs5Xx48crq1evVt59913F6XQq//znP1v1+erZI488oqSnpyuff/65sm3bNuWDDz5QEhMTleeeey58G/lZtIwvvvhC+etf/6p8/PHHCqDMnTu33tdb6/v+v//9T7FYLMoTTzyhrF27Vrn33nsVm82m/Prrr416PrpOcgYPHqzccsst4c/9fr+Sl5enTJ8+XcOooktxcbECKN98842iKIpSXl6u2Gw25YMPPgjfZt26dQqgLFmyRFEU9Y/AbDYrhYWF4dvMnDlTSU5OVtxut6IoinLnnXcqvXv3rneuyy+/XBk9enRLPyXDqaqqUrp27aosXLhQOe2008JJjvwsWtddd92lDB8+/KhfDwQCSk5OjvLkk0+GrysvL1fsdrvy7rvvKoqiKGvXrlUA5aeffgrf5ssvv1RMJpOyZ88eRVEU5cUXX1TatGkT/vmEzt29e/dIPyXDOvfcc5Xrrruu3nX/7//9P2X8+PGKosjPorX8Nslpze/7ZZddppx77rn14hkyZIhy0003Neo56Ha6yuPxsGzZMkaNGhW+zmw2M2rUKJYs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", "text/plain": [ "
" ] @@ -313,27 +512,34 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 30, "id": "666028c4", - "metadata": { - "vscode": { - "languageId": "python" - } - }, + "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "Text(0.5, 0, '# Messages')" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" + "ename": "KeyError", + "evalue": "'num_messages'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m~/.local/lib/python3.10/site-packages/pandas/core/indexes/base.py:3805\u001b[0m, in \u001b[0;36mIndex.get_loc\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 3804\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m-> 3805\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_engine\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcasted_key\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3806\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m err:\n", + "File \u001b[0;32mindex.pyx:167\u001b[0m, in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", + "File \u001b[0;32mindex.pyx:196\u001b[0m, in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", + "File \u001b[0;32mpandas/_libs/hashtable_class_helper.pxi:7081\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", + "File \u001b[0;32mpandas/_libs/hashtable_class_helper.pxi:7089\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", + "\u001b[0;31mKeyError\u001b[0m: 'num_messages'", + "\nThe above exception was the direct cause of the following exception:\n", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[30], line 7\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m key \u001b[38;5;129;01min\u001b[39;00m op_df:\n\u001b[1;32m 5\u001b[0m rsdf \u001b[38;5;241m=\u001b[39m op_df[key]\u001b[38;5;241m.\u001b[39mloc[(op_df[key][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtype\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mRandomSamplingOperation\u001b[39m\u001b[38;5;124m'\u001b[39m)]\n\u001b[0;32m----> 7\u001b[0m x \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39msort(\u001b[43mrsdf\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mnum_messages\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m)\n\u001b[1;32m 8\u001b[0m N \u001b[38;5;241m=\u001b[39m rsdf[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnum_messages\u001b[39m\u001b[38;5;124m'\u001b[39m]\u001b[38;5;241m.\u001b[39mcount()\n\u001b[1;32m 9\u001b[0m \u001b[38;5;66;03m# get the cdf values of y\u001b[39;00m\n", + "File \u001b[0;32m~/.local/lib/python3.10/site-packages/pandas/core/frame.py:4102\u001b[0m, in \u001b[0;36mDataFrame.__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 4100\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcolumns\u001b[38;5;241m.\u001b[39mnlevels \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[1;32m 4101\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_getitem_multilevel(key)\n\u001b[0;32m-> 4102\u001b[0m indexer \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcolumns\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 4103\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m is_integer(indexer):\n\u001b[1;32m 4104\u001b[0m indexer \u001b[38;5;241m=\u001b[39m [indexer]\n", + "File \u001b[0;32m~/.local/lib/python3.10/site-packages/pandas/core/indexes/base.py:3812\u001b[0m, in \u001b[0;36mIndex.get_loc\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 3807\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(casted_key, \u001b[38;5;28mslice\u001b[39m) \u001b[38;5;129;01mor\u001b[39;00m (\n\u001b[1;32m 3808\u001b[0m \u001b[38;5;28misinstance\u001b[39m(casted_key, abc\u001b[38;5;241m.\u001b[39mIterable)\n\u001b[1;32m 3809\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28many\u001b[39m(\u001b[38;5;28misinstance\u001b[39m(x, \u001b[38;5;28mslice\u001b[39m) \u001b[38;5;28;01mfor\u001b[39;00m x \u001b[38;5;129;01min\u001b[39;00m casted_key)\n\u001b[1;32m 3810\u001b[0m ):\n\u001b[1;32m 3811\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m InvalidIndexError(key)\n\u001b[0;32m-> 3812\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(key) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01merr\u001b[39;00m\n\u001b[1;32m 3813\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m:\n\u001b[1;32m 3814\u001b[0m \u001b[38;5;66;03m# If we have a listlike key, _check_indexing_error will raise\u001b[39;00m\n\u001b[1;32m 3815\u001b[0m \u001b[38;5;66;03m# InvalidIndexError. Otherwise we fall through and re-raise\u001b[39;00m\n\u001b[1;32m 3816\u001b[0m \u001b[38;5;66;03m# the TypeError.\u001b[39;00m\n\u001b[1;32m 3817\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_check_indexing_error(key)\n", + "\u001b[0;31mKeyError\u001b[0m: 'num_messages'" + ] }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -368,11 +574,7 @@ "cell_type": "code", "execution_count": null, "id": "1da370f8", - "metadata": { - "vscode": { - "languageId": "python" - } - }, + "metadata": {}, "outputs": [], "source": [] } diff --git a/simulator/python/analysis_vs_evil_final.ipynb b/simulator/python/analysis_vs_evil_final.ipynb new file mode 100644 index 00000000..27011113 --- /dev/null +++ b/simulator/python/analysis_vs_evil_final.ipynb @@ -0,0 +1,688 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f2905ced", + "metadata": {}, + "source": [ + "# DAS protocol\n", + "\n", + "* The network is formed of a single builder that is generating the block with all samples and `N` nodes distributed between validators and regular nodes.\n", + "* Builder knows all the validators\n", + "* All nodes have a unique 256 bits identifier, following the Kademlia procotol used in DEVP2P.\n", + "* We assume DAS protocol works on top of Kademlia DHT. We reuse identifiers and we can use the DHT to discover peers. \n", + "However it is not necessary to use DEVP2P or Kademlia as long as we have nodes with random uniformly distributed identifiers and a way to discover nodes and resolve nodes identifiers to connection parameters.\n", + "* Builder divides the hash space into 512*512 sample-specific regions, according to the block matrix.\n", + "* Builder transforms the 2D block matrix into a two 1D line of samples (1 line row-wise, and 1 line column-wise, i.e, 1 line row-wise means that after all samples in the first row we continue by the first sample of the second row. 1 line column-wise we mean we first start with all the samples of the first column and then we continue with the samples of the second column)\n", + "* We assign each sample with a 256 identifier in the hash space with the double 1D aligment. Every sample is defined by a double id in the hash space, one following row-wise and another column-wise order. This way when fetching rows we can find colocated samples, but also when fetching columns.\n", + "* Builder chooses the redundancy factor `redundancy` - the higher `redundancy` the higher overhead but the more resistant the scheme becomes to malicious validators.\n", + "* The region of samples is defined as all the validators such that `dict(c, v) <= ((2^256 -1) * redundancy * 2) / N_validators `\n", + "* The validator pushes each sample to all the validators within the sample's region (Note that it's done in batches - i.e., the builder connects to each validator and gives them all the samples they should hold).\n", + "\n", + "* When a new block is released, nodes got the samples from builder, according to the redundancy parameter and their identifier. \n", + "After getting the assigned samples, they start the sampling process.\n", + "* There are two types of sampling processes: validator rows/columns fetching and random sampling.\n", + "* Validator row/column consists in getting 2 rows and 2 columns of the block matrix, selected randomly.\n", + "* Validators perform rows/columns fetching and regular nodes random sampling only.\n", + "* The rows/columns fetching and random sampling follows the same process with the only difference of the selection of the samples to obtain. \n", + "We call sampling nodes, the nodes requesting samples, and serving nodes the nodes replying with samples:\n", + " - Sampling nodes select a subset of replying nodes from a list of known nodes that are within the redundancy range following the id space for the samples requesting (how all nodes of the network are discovered is not included in this initial report, but will be in the following reports. Validators are supposed to know all other validators by default).\n", + " - Sampling nodes send samples requests to the replying nodes selected. Samples requests include the wanted samples (all samples pending to be received are included in the requests).\n", + " - Replying nodes reply with the samples requested they have, and also with known nodes to the same distance, from their nodes discovery table. This way nodes can easily discover kew nodes in the network.\n", + " - Once a response is received from all replying nodes, or a configurable time out happened, the process is restarted selecting a new subset of replying nodes, in case there are still samples to be received. The number of replying nodes selected is increasing each round, defined by an algorithm increasing an aggressiveness parameter each round.\n", + " - Once all nodes known nodes are queried, extra nodes are added to the list and the process is repeated.\n", + " - This extra nodes added consists of:\n", + " - In case of row/column, validators in the range of the column id for each missing sample, in case of row fetching, or each row id in case of column sampling.\n", + " - In case of random samplings, validators that requested in the range of the column or row id, even though not the specific sample.\n", + " - For every increase of the aggressiveness params, validators increase the number of samples obtained from the builder, to protect from sybil attacks.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "ca444432", + "metadata": {}, + "source": [ + "## Malicious protocol (ignoring requests / sybil attack)\n", + "\n", + "* Some of both validator and regular nodes might be malicious. \n", + "* Malicious behaviour is just ignoring samples requests without sending any response.\n", + "\n", + "\n", + "## Simulation parameters\n", + "\n", + "* Number of nodes: 15000\n", + "* Number of attackers: Range from 0% to 90%\n", + "* Number of validators: 50% nodes are validators\n", + "* Redundancy parameter: 2\n", + "* Latency between nodes: 5ms - 125ms\n", + "* Number of samples per block : 512x512\n", + "* Sample size: 512 bytes\n", + "* Blocks: 1 blocks simulation.\n", + "* Number of random samples fetch: 75. " + ] + }, + { + "cell_type": "markdown", + "id": "edd080e7", + "metadata": {}, + "source": [ + "The following cell is just loading traces files into a dataframe" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "2983fa0b", + "metadata": {}, + "outputs": [], + "source": [ + "from matplotlib import pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "ops_path = {'DAS': '../logsDasEvil0/operation.csv', \n", + " 'Evil-0.25': '../logsDasEvil0.25/operation.csv',\n", + " 'Evil-0.5': '../logsDasEvil0.5/operation.csv',\n", + " 'Evil-0.75': '../logsDasEvil0.75/operation.csv',\n", + " 'Evil-0.9': '../logsDasEvil0.9/operation.csv'\n", + " }\n", + "msgs_path = {'DAS': '../logsDasEvil0/messages.csv', \n", + " 'Evil-0.25': '../logsDasEvil0.25/messages.csv',\n", + " 'Evil-0.5': '../logsDasEvil0.5/messages.csv',\n", + " 'Evil-0.75': '../logsDasEvil0.75/messages.csv',\n", + " 'Evil-0.9': '../logsDasEvil0.9/messages.csv'\n", + " }\n", + "\n", + "\n", + "builder_address = '83814183170291850251680823880522715558189094423550585243365458794131648333116'\n", + "\n", + "op_df={}\n", + "msg_df={}\n", + "for key in ops_path:\n", + " op_df[key] = pd.read_csv(ops_path[key],index_col=False,low_memory=False)\n", + "for key in msgs_path:\n", + " msg_df[key] = pd.read_csv(msgs_path[key],index_col=False,low_memory=False)\n" + ] + }, + { + "cell_type": "markdown", + "id": "c6cc3d58", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "0c418d95", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0, '% Malicious nodes')" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAh8AAAHHCAYAAAAf2DoOAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAABMlUlEQVR4nO3deXhM598G8HsSMiaLCbEkISTEEsSWkkYapFRKkTS2KBV7VRS1/JTW3oq11L60tdOiEa3aCQ0NIiiKSEhQjSiRhUTC5Hn/cGVeY7KbOZNk7s91zcU855nzfGfOLHfOKhNCCBARERFJxMTQBRAREZFxYfggIiIiSTF8EBERkaQYPoiIiEhSDB9EREQkKYYPIiIikhTDBxEREUmK4YOIiIgkxfBBREREkmL4KIPi4+Mhk8mwYcMGdduMGTMgk8kK9XiZTIYZM2bopzgqtA0bNkAmkyE+Pt7QpRRLTEwMOnXqBKVSCZlMhtDQUMnGHjhwICwtLQvVtyS+3wcOHAhHR0dDl6Flx44dqFy5Mp48eWLoUvTu+PHjkMlkOH78eKEf8/z5czg4OGDlypX6K6yMYPgwsO7du8Pc3BxpaWl59unXrx/MzMzw6NEjCSsruqtXr2LGjBml9seyuNzc3DBy5EhDl1HiBAYG4vLly/jmm2+wefNmvPXWW4V+7L///osZM2bg4sWL+ivQwErbc1SpVJg+fTo+++yzQgc7Y1O+fHmMGzcO33zzDZ49e2bocko0hg8D69evHzIyMrB79+5cp6enp2PPnj14//33YWNjU+xxvvrqK2RkZBT78YVx9epVzJw506jCR0JCAi5cuIAPPvjA0KWUKBkZGYiIiMCQIUMwatQo9O/fHzVr1iz04//991/MnDlTkh/mjIwMfPXVV3of53X5Pcd169YhOjpa8pry89tvvyE6OhrDhw83dCkl2qBBg/Dw4UNs27bN0KWUaAwfBta9e3dYWVnl+Ubds2cPnj59in79+r3ROOXKlUOFChXeaB6Gkp6eXqT+T58+1VMl2vbv348KFSrg3XfflWzM0uC///4DAFhbWxu2kEKoUKECypUrZ+gyNJQvXx5yudzQZWhYv349PD09UaNGDUOXUqJZW1ujU6dOGpu9SRvDh4EpFAr4+/vj6NGjePDggdb0bdu2wcrKCt27d0dSUhImTJgAV1dXWFpaomLFiujcuTP++uuvAsfJbZ+PzMxMfP7556hatap6jH/++Ufrsbdv38bIkSPRoEEDKBQK2NjYoFevXhprODZs2IBevXoBALy9vSGTybS2l65cuRKNGzeGXC6Hvb09goKCkJycrDFW+/bt0aRJE0RFRaFt27YwNzfHlClT8nxeOdv2b968iS5dusDKykod1J4+fYrx48fDwcEBcrkcDRo0wMKFC/HqhZz9/f3RsmVLjXl269YNMpkMv/76q7rtzJkzkMlk2L9/v0bf33//Hd7e3lAoFBp9u3TpgkqVKsHCwgJNmzbFd999p/G4Y8eOwcvLCxYWFrC2toavry+uXbuW5/PMkdf+CY6Ojhg4cKD6fs7+IidPnsTo0aNRtWpVWFtb45NPPkFWVhaSk5MxYMAAVKpUCZUqVcL//vc/jdclZ7+hhQsXYu3atahbty7kcjlatWqFyMjIfGucMWMGateuDQCYOHEiZDKZxv4L9+7dw+DBg1G9enXI5XI0btwYP/74o3r68ePH0apVKwAv/4rMeS+9+mVemNc4Zyw/Pz9YWlqiatWqmDBhAlQqVb6vac5nJTY2FgMHDoS1tTWUSiUGDRqkFYQzMjIwevRoVKlSRf0ZunfvXoH7kRT0HF/f5+PV5bFixQrUqVMH5ubm6NSpE+7evQshBGbPno2aNWtCoVDA19cXSUlJWuPu379f/b6zsrLCBx98gL///jvPOnM8e/YMBw4cQMeOHbWmHT58GO+88w6sra1haWmJBg0aaH1mMzMzMX36dDg7O0Mul8PBwQH/+9//kJmZqTW/LVu2oHXr1jA3N0elSpXQtm1bHDp0SKNPUb5Lrl69Cm9vb5ibm6NGjRqYP3++1pj//PMP/Pz8YGFhgWrVquHzzz/PtbaYmBj06NEDtra2qFChAmrWrImAgACkpKRo9Hvvvfdw8uTJXJcBvVSy4r6R6tevHzZu3IgdO3Zg1KhR6vakpCQcPHgQffv2hUKhwN9//43Q0FD06tULTk5OSExMxJo1a9CuXTtcvXoV9vb2RRp36NCh2LJlCz766CO0adMGx44dy3XzQWRkJP78808EBASgZs2aiI+Px6pVq9C+fXtcvXoV5ubmaNu2LUaPHo2lS5diypQpcHFxAQD1vzNmzMDMmTPRsWNHfPrpp4iOjsaqVasQGRmJU6dOoXz58urxHj16hM6dOyMgIAD9+/dH9erV830eL168gI+PD9555x0sXLgQ5ubmEEKge/fuCAsLw5AhQ9C8eXMcPHgQEydOxL1797B48WIAgJeXF/bs2YPU1FRUrFgRQgicOnUKJiYmCA8PR/fu3QEA4eHhMDExgaenp3rc58+f48iRI5gzZ4667fDhw+jatSvs7OwwZswY2Nra4tq1a9i7dy/GjBkDADhy5Ag6d+6MOnXqYMaMGcjIyMCyZcvg6emJ8+fP63RHw88++wy2traYOXMmTp8+jbVr18La2hp//vknatWqhTlz5mDfvn1YsGABmjRpggEDBmg8ftu2bUhLS8Mnn3wCmUyG+fPnw9/fH7du3dJYZq/y9/eHtbU1Pv/8c/Tt2xddunRR7yOQmJiIt99+GzKZDKNGjULVqlWxf/9+DBkyBKmpqRg7dixcXFwwa9YsTJs2DcOHD4eXlxcAoE2bNoV+jYGX+yj4+PjA3d0dCxcuxJEjR7Bo0SLUrVsXn376aYGvXe/eveHk5ITg4GCcP38e33//PapVq4Z58+ap+wwcOBA7duzAxx9/jLfffhsnTpwo1Ca4gp5jXrZu3YqsrCx89tlnSEpKwvz589G7d2+8++67OH78OCZNmoTY2FgsW7YMEyZM0Ah1mzdvRmBgIHx8fDBv3jykp6dj1apVeOedd3DhwoV833dRUVHIysrSCup///03unbtiqZNm2LWrFmQy+WIjY3FqVOn1H2ys7PRvXt3nDx5EsOHD4eLiwsuX76MxYsX48aNGxo7Is+cORMzZsxAmzZtMGvWLJiZmeHMmTM4duwYOnXqBKBo3yWPHz/G+++/D39/f/Tu3Ru7du3CpEmT4Orqis6dOwN4GSA7dOiAO3fuYPTo0bC3t8fmzZtx7NgxjeealZUFHx8fZGZmqj9X9+7dw969e5GcnAylUqnu6+bmBiEE/vzzT3Tt2jXfZWq0BBncixcvhJ2dnfDw8NBoX716tQAgDh48KIQQ4tmzZ0KlUmn0iYuLE3K5XMyaNUujDYBYv369um369Oni1cV98eJFAUCMHDlSY34fffSRACCmT5+ubktPT9eqOSIiQgAQmzZtUrft3LlTABBhYWEafR88eCDMzMxEp06dNOpfvny5ACB+/PFHdVu7du0EALF69WqtMXMTGBgoAIgvvvhCoz00NFQAEF9//bVGe8+ePYVMJhOxsbFCCCEiIyMFALFv3z4hhBCXLl0SAESvXr2Eu7u7+nHdu3cXLVq00JjX0aNHBQARFxcnhHi5HJ2cnETt2rXF48ePNfpmZ2er/9+8eXNRrVo18ejRI3XbX3/9JUxMTMSAAQPUbevXr9eYvxBCa9nkqF27tggMDNR6rI+Pj8bYHh4eQiaTiREjRqjbXrx4IWrWrCnatWunbst5D9nY2IikpCR1+549ewQA8dtvv2nV8Kqcxy9YsECjfciQIcLOzk48fPhQoz0gIEAolUr1ey1nubz6Hs6ptTCvcc774tXPhRBCtGjRQri5uWm0vf6a5nxWBg8erNHvww8/FDY2Nur7UVFRAoAYO3asRr+BAwfmuZxelddzzKm/du3a6vs5r2fVqlVFcnKyun3y5MkCgGjWrJl4/vy5ur1v377CzMxMPHv2TAghRFpamrC2thbDhg3TGOf+/ftCqVRqtb/u+++/FwDE5cuXNdoXL14sAIj//vsvz8du3rxZmJiYiPDwcI32nO+3U6dOCSGEiImJESYmJuLDDz/U+p7LWbbF+S559TsqMzNT2Nraih49eqjblixZIgCIHTt2qNuePn0qnJ2dNb7PLly4IACInTt35vtaCSHEv//+KwCIefPmFdjXWHGzSwlgamqKgIAAREREaGzK2LZtG6pXr44OHToAAORyOUxMXi4ylUqFR48eqVdznj9/vkhj7tu3DwAwevRojfaxY8dq9X11k8Lz58/x6NEjODs7w9raulDjHjlyBFlZWRg7dqy6fgAYNmwYKlasiN9//12jv1wux6BBg4rydLT+kt23bx9MTU21nt/48eMhhFBvPmnRogUsLS3xxx9/AHi5hqNmzZoYMGAAzp8/j/T0dAghcPLkSfVfp6+O0ahRI/VfjBcuXEBcXBzGjh2rta9DziavhIQEXLx4EQMHDkTlypXV05s2bYr33ntPvVx0ZciQIRqb29zd3SGEwJAhQ9RtpqameOutt3Dr1i2tx/fp0weVKlVS3895DXLrWxAhBH755Rd069YNQgg8fPhQffPx8UFKSkqB76fCvMavGjFihMZ9Ly+vQtee22MfPXqE1NRUAMCBAwcAQOtIp88++6xQ8y+OXr16afyF7e7uDgDo37+/xn4r7u7uyMrKwr179wC8XFuUnJyMvn37arzupqamcHd3R1hYWL7j5hxp9+p7Afj/fXr27NmD7OzsXB+7c+dOuLi4oGHDhhpj5+wnlTN2aGgosrOzMW3aNI3vCeD/l21Rv0ssLS3Rv39/9X0zMzO0bt1a4z2wb98+2NnZoWfPnuo2c3NzrR1rc173gwcPFrgfWs7r9PDhw3z7GTOGjxIiZz+FnB1P//nnH4SHhyMgIACmpqYAXq6+XLx4MerVqwe5XI4qVaqgatWquHTpktY2x4Lcvn0bJiYmqFu3rkZ7gwYNtPpmZGRg2rRp6n0ncsZNTk4u1Li3b9/Odd5mZmaoU6eOenqOGjVqwMzMrNDPpVy5clpHUty+fRv29vawsrLSaM/ZDJQzpqmpKTw8PBAeHg7gZfjw8vLCO++8A5VKhdOnT+Pq1atISkrSCh+///67xir2mzdvAgCaNGmSZ615vRY5tT18+FCnO8zWqlVL437OF6iDg4NW++PHjwt8fM6Xam59C/Lff/8hOTkZa9euRdWqVTVuOWEzt/2eXlWY1zhHhQoVULVqVa36C1t7Qc895zPk5OSk0c/Z2blQ8y+OoixP4P9rjYmJAQC8++67Wq/9oUOHCnzdc4hX9gsCXoZTT09PDB06FNWrV0dAQAB27NihEURiYmLw999/a41bv359AP+/zG/evAkTExM0atQoz/GL+l1Ss2ZNrVD6+nvg9u3bcHZ21ur3+hhOTk4YN24cvv/+e1SpUgU+Pj5YsWJFrt+BOa9TYc+tZIy4z0cJ4ebmhoYNG2L79u2YMmUKtm/fDiGExlEuc+bMwdSpUzF48GDMnj0blStXhomJCcaOHZvnXx268Nlnn2H9+vUYO3YsPDw81CeNCggI0Mu4r65pKYxX1wgVxzvvvKM+Lj88PBxffvklrK2t0aRJE4SHh6v3OXk1fMTFxeH69etYtWpVscfVpdd3osyRE1wL0/76D0t+j8+tb0Fy3iv9+/dHYGBgrn2aNm1a5PnmJa/a3/TxxXnuulKU5Qn8f605r/3mzZtha2ur1a+go31yDvN//PixRtBXKBT4448/EBYWht9//x0HDhzAzz//jHfffReHDh2CqakpsrOz4erqim+//TbXeb8enHRJ18tw0aJFGDhwIPbs2YNDhw5h9OjRCA4OxunTpzVel5xwU6VKlWKNYwwYPkqQfv36YerUqbh06RK2bduGevXqqfeIB4Bdu3bB29sbP/zwg8bjkpOTi/wmr127NrKzs3Hz5k2NhJ/buQV27dqFwMBALFq0SN327Nkzrb3L80r5OUc+REdHo06dOur2rKwsxMXF5boH/ZuqXbs2jhw5grS0NI21H9evX9eoCXgZKrKysrB9+3bcu3dPHTLatm2rDh/169fX2PH1999/h1KpxDvvvKNuy1mLdOXKlTyf06uvxeuuX7+OKlWqwMLCIs/nValSJa3XPSsrCwkJCXk+pqTIOapKpVIVuMzzei8V5jWWSs5nKC4uDvXq1VO3x8bGFurxUv5VnPO6VatWrVivW8OGDQG8DN2urq4a00xMTNChQwd06NAB3377LebMmYMvv/wSYWFh6NixI+rWrYu//voLHTp0yPc5161bF9nZ2bh69SqaN2+eax99fJfUrl0bV65cgRBCo768zrPi6uoKV1dXfPXVV/jzzz/h6emJ1atX4+uvv1b3iYuLA/D/a1pJGze7lCA5azmmTZuGixcvap3bw9TUVCux79y5U71dtyhy9vReunSpRvuSJUu0+uY27rJly7T+2s750Xz9x7Fjx44wMzPD0qVLNebzww8/ICUlRS8n6OrSpQtUKhWWL1+u0b548WLIZDL18wdebh8vX7485s2bh8qVK6Nx48YAXoaS06dP48SJE7nu79GpUyeNvxhbtmwJJycnLFmyROs1yHnednZ2aN68OTZu3KjR58qVKzh06BC6dOmS7/OqW7euev+UHGvXrs1zzUdJYmpqih49euCXX37BlStXtKbnnBsEyPu9VJjXWCo+Pj4AoHUq7WXLlhXq8Xk9R33w8fFBxYoVMWfOHDx//lxr+quvfW7c3NxgZmaGc+fOabTndihpTnDIOVS1d+/euHfvHtatW6fVNyMjQ72Z0c/PDyYmJpg1a5bWGtWcZauP75IuXbrg33//xa5du9Rt6enpWLt2rUa/1NRUvHjxQqPN1dUVJiYmWoflRkVFQSaTwcPDo8j1GAuu+ShBnJyc0KZNG+zZswcAtMJH165dMWvWLAwaNAht2rTB5cuXsXXrVo2/AAqrefPm6Nu3L1auXImUlBS0adMGR48ezfWvtq5du2Lz5s1QKpVo1KgRIiIicOTIEa0zrjZv3hympqaYN28eUlJSIJfL8e6776JatWqYPHkyZs6ciffffx/du3dHdHQ0Vq5ciVatWmnsEKYr3bp1g7e3N7788kvEx8ejWbNmOHToEPbs2YOxY8dq7Otibm4ONzc3nD59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Rnv16tXV016XmZmJzMxM9f3U1FRdlkREREQljMGPdgkODoZSqVTfHBwcDF0SERER6ZFOw4etrS0AIDExUaM9MTFRPe11kydPRkpKivp29+5dXZZEREREJYxOw4eTkxNsbW1x9OhRdVtqairOnDkDDw+PXB8jl8tRsWJFjRsRERGVXUXe5+PJkyeIjY1V34+Li8PFixdRuXJl1KpVC2PHjsXXX3+NevXqwcnJCVOnToW9vT38/Px0WTcRERGVUkUOH+fOnYO3t7f6/rhx4wAAgYGB2LBhA/73v//h6dOnGD58OJKTk/HOO+/gwIEDqFChgu6qJiIiolKryOGjffv2EELkOV0mk2HWrFmYNWvWGxVGREREZZPBj3YhIiIi48LwQURERJJi+CAiIiJJMXwQERGRpBg+iIiISFIMH0RERCQphg8iIiKSFMMHERERSYrhg4iIiCTF8EFERESSYvggIiIiSTF8EBERkaQYPoiIiEhSDB9EREQkKYYPIiIikhTDBxEREUmK4YOIiIgkxfBBREREkmL4ICIiIkkxfBAREZGkGD6IiIhIUgwfREREJCmGDyIiIpIUwwcRERFJiuGDiIiIJMXwQURERJJi+CAiIiJJMXwQERGRpBg+iIiISFIMH0RERCQphg8iIiKSFMMHERERSYrhg4iIiCTF8EFERESSYvggIiIiSTF8EBERkaQYPoiIiEhSDB9EREQkKYYPIiIikhTDBxEREUmK4YOIiIgkxfBBREREkmL4ICIiIkkxfBAREZGkGD6IiIhIUgwfREREJCmGDyIiIpIUwwcRERFJiuGDiIiIJMXwQURERJJi+CAiIiJJ6Tx8qFQqTJ06FU5OTlAoFKhbty5mz54NIYSuhyIiIqJSqJyuZzhv3jysWrUKGzduROPGjXHu3DkMGjQISqUSo0eP1vVwREREVMroPHz8+eef8PX1xQcffAAAcHR0xPbt23H27FldD0VERESlkM43u7Rp0wZHjx7FjRs3AAB//fUXTp48ic6dO+faPzMzE6mpqRo3IiIiKrt0vubjiy++QGpqKho2bAhTU1OoVCp888036NevX679g4ODMXPmTF2XQURERCWUztd87NixA1u3bsW2bdtw/vx5bNy4EQsXLsTGjRtz7T958mSkpKSob3fv3tV1SURERFSC6HzNx8SJE/HFF18gICAAAODq6orb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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "\n", + "fig3, ax3 = plt.subplots()\n", + "\n", + "data = []\n", + "for key in op_df:\n", + "\n", + " vsdf = op_df[key].loc[(op_df[key]['type'] == 'ValidatorSamplingOperation')]\n", + " data.append(vsdf['completion_time']/1000)\n", + "\n", + "ax3.boxplot(data)\n", + "\n", + "#ax3.legend()\n", + "#ax18.set_xlim([0,2])\n", + "ax3.set_ylim([0,12])\n", + "ax3.set_xticklabels([0,25,50,75,90])\n", + "ax3.set_title(\"Validator row/column fetching time (seconds)\")\n", + "ax3.set_xlabel(\"% Malicious nodes\")" + ] + }, + { + "cell_type": "markdown", + "id": "2af47752", + "metadata": {}, + "source": [ + "In this graph we observe the time required to complete the row/column fetching process in validators. All validators are able to complete the row/colum fetching in our simulations. We observe the time increaseas, as the number of sybil in the network increases, but without preventing validators to complete the process. In all cases the process is completed within the 4 seconds requirements, but in the case of 90% sybils, where 75% of processes are completed within 5 seconds. " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "95bea67e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0, '% Malicious nodes')" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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7du30axZM2zevBk3b97E5s2b0axZM9y+fRuzZs1i4UFERDUer/OhR8uWLQMArF69GlOmTJHaa9Wqhblz50rriYiIajKedjGAgoICbNy4EVeuXIG7uzumTp3KHg8iIjJpFfn/m8UHERERPTOO+SAiIqIqi8UHERERyYrFBxEREcmKxQcRERHJisUHERERyYrFBxEREcmKxQcRERHJisUHERERyYrFBxEREcmKxQcRERHJisUHERERyYrFBxEREcmKxQcRERHJisUHERERyYrFBxEREcmKxQcRERHJisUHERERyYrFBxEREcmKxQcRERHJisUHERERyYrFBxEREcmKxQcRERHJisUHERERyYrFBxEREcmKxQcRERHJymDFx4YNG+Dq6oo6deqgS5cuOHPmjKF2RURERNWIQYqP77//HrNnz8Z7772HuLg4tGvXDn379kV6erohdkdERETViEGKj1WrVmHSpEkYP348Wrdujc8//xyWlpb46quvDLE7IiIiqkb0XnwUFBQgNjYWffr0+d9OzMzQp08fxMTE6Ht3REREVM3U0vcG7969C7VajcaNG+u0N27cGImJicXi8/PzkZ+fLy1nZGQAADIzM/WdGhERERmI9v9tIcRTY/VefFRUaGgolixZUqzdycnJCNkQERHRs8jKyoKdnV2ZMXovPho0aABzc3Pcvn1bp/327dto0qRJsfiFCxdi9uzZ0rJGo8H9+/dhb28PhUKh7/Rkk5mZCScnJ1y/fh22trbGTqdG43tRdfC9qFr4flQdpvBeCCGQlZUFR0fHp8bqvfiwsLCAj48Pfv/9dwQFBQH4p6D4/fffMX369GLxSqUSSqVSp61u3br6TstobG1tq+0HydTwvag6+F5ULXw/qo7q/l48rcdDyyCnXWbPno2xY8eiY8eO6Ny5M9asWYOcnByMHz/eELsjIiKiasQgxcfw4cNx584dvPvuu7h16xbat2+PX3/9tdggVCIiIqp5DDbgdPr06SWeZqkplEol3nvvvWKnlEh+fC+qDr4XVQvfj6qjpr0XClGeOTFEREREesIbyxEREZGsWHwQERGRrFh8EBERkaxYfBAREZGsWHwYwIYNG+Dq6oo6deqgS5cuOHPmjLFTMnmhoaHo1KkTbGxs0KhRIwQFBeHSpUs6Mf7+/lAoFDo/r7/+upEyNm2LFy8u9lp7enpK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szNCQkJgZmaGP//8E/Hx8fjwww8RFhYGtVqNLl26wNLSEtu3b4dKpYKLi0ul8iYyNez5IDISIQQmT56MVatWwcrKCsA/35bDwsLw/vvv47XXXsP69evLfb2OWrVqoUGDBqhVq+TvFFOmTEFwcDCGDx+OLl264N69e5g6dWqFcv7ss88QEhKCqVOnwtPTE5MmTUJOTk6JsR06dMCuXbuwc+dOeHt7491338X777+PcePGSTErV66Ek5MT/Pz8MHLkSLz99tuwtLSU1tvY2GDZsmXo2LEjOnXqhNTUVPz8889S70JlbN26FT4+PhgwYAC6desGIQR+/vlnqejp2rUrtmzZgk8//RTt2rXDwYMH8X//93862+jbty8iIyNx8OBBdOrUCV27dsXq1aul4qJu3brYsmULunfvjueeew6//fYbfvzxR9jb21c6byJTohBPnnAlIiIiMiD2fBAREZGsWHwQERGRrFh8EBERkaxYfBAREZGsWHwQERGRrFh8EBERkaxYfBAREZGsWHwQERGRrFh8EBERkaxYfBAREZGsWHwQERGRrFh8EBERkaz+HwX/k+z4sKixAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "fig3, ax3 = plt.subplots()\n", + "\n", + "data = []\n", + "for key in op_df:\n", + "\n", + " vsdf = op_df[key].loc[(op_df[key]['type'] == 'RandomSamplingOperation')]\n", + " data.append(vsdf['completion_time']/1000)\n", + "\n", + "ax3.boxplot(data)\n", + "\n", + "\n", + "ax3.set_ylim([0,15])\n", + "ax3.set_xticklabels([0,25,50,75,90])\n", + "ax3.set_title(\"Random sampling time regular nodes (seconds)\")\n", + "ax3.set_xlabel(\"% Malicious nodes\")" + ] + }, + { + "cell_type": "markdown", + "id": "92fe1b66", + "metadata": {}, + "source": [ + "In this graph we observe the time required for the random sampling to complete when increasing the number of sybils. We can observe that only in case of 90% sybils, a small number of nodes are slighly delayed and cannot complete within the 12 seconds block time" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "64a9d6f0", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/sergi/seal/tmpo/ipykernel_2730530/1455769239.py:11: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator.\n", + " ax3.set_xticklabels([0,0,25,50,75,90])\n" + ] + }, + { + "data": { + "text/plain": [ + "Text(0.5, 0, '% Malicious nodes')" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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REVFFftMguHDhxf72O/iHDx4sMjDggAAQMWwf//+Yr8tupBbwWLjxo0u35W/fft2de3aVbfddlup11H4ddH79+9XQECAO5sHAADlJCcnR+Hh4ed9XITkZrA499HIkydPVoMGDdz6zoDCyx8BAQEECwAAKpgL3cZw0fdY5OXlae7cuRozZsx5N5Kbm+vyBLicnJyL3SQAAPiDu+hPhSxdulTHjx/XoEGDztsvOTlZgYGBzhf3VwAAUHld9Bdkde/eXd7e3nr33XfP26+4Mxbh4eHKzs7mUggAABVETk6OAgMDL/j/90VdCtm7d69Wr16txYsXX7Cvw+GQw+G4mM0AAIAK5qIuhaSmpio4OFg9e/a0XQ8AAKjA3A4WBQUFSk1NVWJiory8eIYZAAD4H7eDxerVq7Vv3z4NGTKkLOoBAAAVmNunHLp16yYeiAoAAIrDQ8gAAIA1BAsAAGANwQIAAFhDsAAAANYQLAAAgDUECwAAYA3BAgAAWFOpvjozaux75V1ChbFnMl/HDgCwjzMWAADAGoIFAACwhmABAACsIVgAAABrCBYAAMAaggUAALCGYAEAAKwhWAAAAGsIFgAAwBqCBQAAsIZgAQAArCFYAAAAawgWAADAGoIFAACwhmABAACsIVgAAABrCBYAAMAaggUAALCGYAEAAKwhWAAAAGsIFgAAwBqCBQAAsIZgAQAArCFYAAAAawgWAADAGoIFAACwhmABAACsIVgAAABrCBYAAMAaggUAALCGYAEAAKwhWAAAAGsIFgAAwBq3g8WBAwd01113qVatWvL19VXz5s21adOmsqgNAABUMF7udD527Jg6dOig66+/Xu+//76CgoKUmZmpmjVrllV9AACgAnErWEyZMkXh4eFKTU11ttWrV896UQAAoGJy61LIO++8o6uuukq33XabgoOD1bp1a82ePbusagMAABWMW8Hiu+++04wZM9SwYUOtWLFC999/v0aOHKlXX321xGVyc3OVk5Pj8gIAAJWTW5dCCgoKdNVVV+mpp56SJLVu3Vrbt2/XzJkzlZiYWOwyycnJmjhx4qVXCgAA/vDcOmMRGhqqmJgYl7amTZtq3759JS4zbtw4ZWdnO1/79++/uEoBAMAfnltnLDp06KCMjAyXtm+++UaRkZElLuNwOORwOC6uOgAAUKG4dcbigQce0IYNG/TUU09p165d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izxosE6dOjp8+HD5FFwJLV26VMePH9egQYOcbezrZcPf31/t27fXpEmT1LRpU9WpU0dvvPGG1q9fr+joaOd+Xdzx/nLd5wkWqBSSkpK0fft2l2v9knTPPfc4/928eXOFhoaqc+fO+vbbb9WgQYPfu8xKoUePHs5/t2jRQvHx8YqMjNTChQvl6+tbjpVdPubMmaMePXq4PL6afb3svP766xoyZIiuvPJKeXp6qk2bNhowYIA2b95c3qX9IXEppAzUrl1bnp6eRe6EP3LkiEJCQsqpqsprxIgRWrZsmdasWaO6deuet298fLwkadeuXb9HaZeFGjVqqFGjRtq1a5dCQkKUl5en48ePu/Rh37dn7969Wr16te6+++7z9mNft6dBgwZat26dTp48qf379+uzzz7TL7/8ovr16zv3a473/0OwKAPe3t6Ki4vTBx984GwrKCjQBx98oPbt25djZZWLMUYjRozQkiVL9J///Ef16tW74DJbt26VJIWGhpZxdZePkydP6ttvv1VoaKji4uJUtWpVl30/IyND+/btY9+3JDU1VcHBwerZs+d5+7Gv21etWjWFhobq2LFjWrFihXr37q169eopJCTEZZ/PycnRp59+evnu8+V992hl9eabbxqHw2HS0tLMjh07zD333GNq1KhhDh8+XN6lVRr333+/CQwMNGvXrjWHDh1yvk6fPm2MMWbXrl3miSeeMJs2bTK7d+82b7/9tqlfv77p2LFjOVdesT344INm7dq1Zvfu3eaTTz4xXbp0MbVr1zZZWVnGGGPuu+8+ExERYf7zn/+YTZs2mfbt25v27duXc9WVQ35+vomIiDCPPPKISzv7etlavny5ef/99813331nVq5caVq2bGni4+NNXl6eMcaYyZMnmxo1api3337bfPnll6Z3796mXr165syZM+VcefkgWJShf/7znyYiIsJ4e3ubdu3amQ0bNpR3SZWKpGJfqampxhhj9u3bZzp27GiuuOIK43A4THR0tHnooYdMdnZ2+RZewfXv39+EhoYab29vc+WVV5r+/fubXbt2OeefOXPGDB8+3NSsWdP4+fmZvn37mkOHDpVjxZXHihUrjCSTkZHh0s6+XrYWLFhg6tevb7y9vU1ISIhJSkoyx48fd84vKCgwf//7302dOnWMw+EwnTt3LvIzupzw2HQAAGAN91gAAABrCBYAAMAaggUAALCGYAEAAKwhWAAAAGsIFgAAwBqCBQAAsIZgAVxGBg0apD59+jinO3XqpNGjR5dq2bVr18rDw6PIc0Aqg7S0tCJPZAVwcQgWQBmYN2+ewsPDVbNmTY0ZM8Zl3p49e9SoUSPl5OScdx179uyRh4eHPD09deDAAZd5hw4dkpeXlzw8PLRnz56LrnPx4sWaNGlSqfpec801OnTokAIDAy96ewAqP4IFYNmPP/6ou+++W88++6xWrlypuXPnatmyZc75w4cP1+TJkxUQEFCq9V155ZV67bXXXNpeffVVXXnllZdc6xVXXCF/f/9S9fX29lZISIg8PDwuebsAKi+CBWDZd999p8DAQPXv319t27bV9ddfr507d0qS3njjDVWtWlV//vOfS72+xMREpaamurSlpqYqMTHRpS0/P19Dhw5VvXr15Ovrq8aNG+vFF18877rPvRSSm5urRx55ROHh4XI4HIqOjtacOXMkFX8pZNGiRWrWrJkcDoeioqL03HPPuazfw8NDS5cudWmrUaOG0tLSJEl5eXkaMWKEQkND5ePjo8jISCUnJ5dYb+GlnGeffVahoaGqVauWkpKS9Msvvzj7HDt2TAMHDlTNmjXl5+enHj16KDMz02U9aWlpioiIkJ+fn/r27auffvqpyLbefvtttWnTRj4+Pqpfv74mTpyos2fPSvr1yboTJkxQRESEHA6HwsLCNHLkyBLrBi4nBAvAsoYNG+r06dP6/PPPdfToUW3cuFEtWrTQsWPH9Pe//13Tpk1za31/+tOfdOzYMX388ceSpI8//ljHjh1Tr169XPoVFBSobt26Sk9P144dO/T444/r0Ucf1cKFC0u9rYEDB+qNN97QSy+9pJ07dyolJUXVq1cvtu/mzZvVr18/3X777dq2bZsmTJigv//9787QUBovvfSS3nnnHS1cuFAZGRmaN2+eoqKizrvMmjVr9O2332rNmjV69dVXlZaW5rLNQYMGadOmTXrnnXe0fv16GWN00003OcPHp59+qqFDh2rEiBHaunWrrr/+ev3jH/9w2cZHH32kgQMHatSoUdqxY4dSUlKUlpamJ598UtKvger5559XSkqKMjMztXTpUjVv3rzU7xuo1Mr3GWhA5bR48WITGxtrGjRoYMaPH2+MMWbIkCHm+eefN+vWrTOtWrUyzZo1M+np6SWuY/fu3UaS+fzzz83o0aPN4MGDjTHGDB482DzwwAPm888/N5LM7t27S1xHUlKSueWWW5zTiYmJpnfv3s7phIQEM2rUKGOMMRkZGUaSWbVqVbHrWrNmjZFkjh07Zowx5o477jBdu3Z16fPQQw+ZmJgY57Qks2TJEpc+gYGBzifQ/vWvfzU33HCDKSgoKPE9/FZiYqKJjIw0Z8+edbbddtttpn///sYYY7755hsjyXzyySfO+T/++KPx9fU1CxcuNMYYM2DAAHPTTTe5rLd///4mMDDQOd25c2fz1FNPufR5/fXXTWhoqDHGmOeee840atTI+dhsAP/DGQugDPTt21fbtm3Trl27NGHCBK1bt05ffvml7rnnHt1+++164YUXtGjRIg0dOlRZWVkXXN+QIUOUnp6uw4cPKz09XUOGDCm238svv6y4uDgFBQWpevXqmjVrlvbt21eqmrdu3SpPT08lJCSUqv/OnTvVoUMHl7YOHTooMzNT+fn5pVrHoEGDtHXrVjVu3FgjR47UypUrL7hMs2bN5Onp6ZwODQ11juHOnTvl5eWl+Ph45/xatWqpcePGzstRO3fudJkvSe3bt3eZ/uKLL/TEE0+oevXqztewYcN06NAhnT59WrfddpvOnDmj+vXra9iwYVqyZInzMglwuSNYAGUsNzdXw4cPV0pKinbt2qWzZ88qISFBjRs3VqNGjfTpp59ecB3NmzdXkyZNNGDAADVt2lSxsbFF+rz55pv6v//7Pw0dOlQrV67U1q1bNXjwYOXl5ZWqTl9fX7ff24V4eHjIGOPS9tv7Idq0aaPdu3dr0qRJOnPmjPr166dbb731vOusWrVqkW0UFBTYK1rSyZMnNXHiRG3dutX52rZtmzIzM+Xj46Pw8HBlZGRo+vTp8vX11fDhw9WxY0eX9wZcrggWQBn7xz/+oRtvvFFt2rRRfn6+y1+2v/zyS6n/uh8yZIjWrl1b4tmKTz75RNdcc42GDx+u1q1bKzo6Wt9++22p62zevLkKCgq0bt26UvVv2rSpPvnkkyI1NGrUyHlGISgoSIcOHXLOz8zM1OnTp12WCQgIUP/+/TV79mwtWLBAixYt0tGjR0td97k1nT171iWs/fTTT8rIyFBMTIyzz7lhbsOGDS7Tbdq0UUZGhqKjo4u8qlT59bDp6+urXr166aWXXtLatWu1fv16bdu27aLqBioTr/IuAKjMduzYoQULFujzzz+XJDVp0kRVqlTRnDlzFBISoq+//lpt27Yt1bqGDRum2267rcQvcmrYsKFee+01rVixQvXq1dPrr7+ujRs3ql69eqVaf1RUlBITEzVkyBC99NJLatmypfbu3ausrCz169evSP8HH3xQbdu21aRJk9S/f3+tX79e06ZN0/Tp0519brjhBk2bNk3t27dXfn6+HnnkEZczDlOnTlVoaKhat26tKlWqKD09XSEhIRf9ZVUNGzZU7969NWzYMKWkpMjf319jx47VlVdeqd69e0uSRo4cqQ4dOujZZ59V7969tWLFCi1fvtxlPY8//rhuvvlmRURE6NZbb1WVKlX0xRdfaPv27frHP/6htLQ05efnKz4+Xn5+fpo7d658fX0VGRl5UXUDlUp53+QBVFYFBQWmQ4cO5t1333Vpf/fdd01ERISpU6eOmT17donL//bmzeKce/Pmzz//bAYNGmQCAwNNjRo1zP3332/Gjh1rWrZs6VzmfDdvGmPMmTNnzAMPPGBCQ0ONt7e3iY6ONq+88ooxpujNm8YY89Zbb5mYmBhTtWpVExERYZ555hmXGg8cOGC6detmqlWrZho2bGj+/e9/u9y8OWvWLNOqVStTrVo1ExAQYDp37my2bNlS4picW78xxowaNcokJCQ4p48ePWr+8pe/mMDAQOPr62u6d+9uvvnmG5dl5syZY+rWrWt8fX1Nr169zLPPPuty86Yxxixfvtxcc801xtfX1wQEBJh27dqZWbNmGWOMWbJkiYmPjzcBAQGmWrVq5uqrrzarV68usW7gcuJhzDkXQAEAAC4S91gAAABrCBYAAMAaggUAALCGYAEAAKwhWAAAAGsIFgAAwBqCBQAAsIZgAQAArCFYAAAAawgWAADAGoIFAACwhmABAACs+X+zUAcTXqCduQAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "fig3, ax3 = plt.subplots()\n", + "\n", + "data = []\n", + "for key in msg_df:\n", + "\n", + " vsdf = msg_df[key].loc[(msg_df[key]['nodeType'] == 'builder')]\n", + " data.append(vsdf['bytesOut'].values[0]/1024/1024/1024)\n", + "\n", + "ax3.bar([1,2,3,4,5],data)\n", + "\n", + "ax3.set_xticklabels([0,0,25,50,75,90])\n", + "ax3.set_title(\"GBs sent by the builder per sampling process\")\n", + "ax3.set_xlabel(\"% Malicious nodes\")" + ] + }, + { + "cell_type": "markdown", + "id": "9d56ea3a", + "metadata": {}, + "source": [ + "In this graph we observe the amount of data sent by the builder per block in GBs. We observe this amount is reduced with the increasing number of sybils, since there are less validators requesting samples from the builder." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "0726c136", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0, '% Malicious nodes')" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig3, ax3 = plt.subplots()\n", + "\n", + "data = []\n", + "for key in msg_df:\n", + "\n", + " vsdf = msg_df[key].loc[(msg_df[key]['nodeType'] == 'validator')]\n", + " data.append(vsdf['bytesOut']/1024/1024)\n", + "\n", + "ax3.boxplot(data)\n", + "\n", + "\n", + "ax3.set_xticklabels([0,25,50,75,90])\n", + "ax3.set_title(\"MBs sent per validator\")\n", + "ax3.set_xlabel(\"% Malicious nodes\")" + ] + }, + { + "cell_type": "markdown", + "id": "685667c3", + "metadata": {}, + "source": [ + "In this case we observe the amount of data sent by validators. We observe this is not incremented in our simulations, although the cause is that the number of validators requesting is also reduced for the presence of sybils. In any case, we observe the number of data sent is not reduced in the same range, meaning honest validators need to do more work in case of sybils." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "40b59007", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0, '% Malicious nodes')" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig3, ax3 = plt.subplots()\n", + "\n", + "data = []\n", + "for key in msg_df:\n", + "\n", + " vsdf = msg_df[key].loc[(msg_df[key]['nodeType'] == 'regular')]\n", + " data.append(vsdf['bytesOut']/1024/1024)\n", + "\n", + "ax3.boxplot(data)\n", + "\n", + "ax3.set_xticklabels([0,25,50,75,90])\n", + "ax3.set_title(\"MBs sent per slot regular node\")\n", + "ax3.set_xlabel(\"% Malicious nodes\")" + ] + }, + { + "cell_type": "markdown", + "id": "f94b650c", + "metadata": {}, + "source": [ + "This is the data sent by regular nodes in MB. This amount of data is smaller compared to validators, since nodes validators tend to prioritize nodes withe more samples when fetching. Also, regular nodes have less capacity, and therefore samples sent by them may arrive later on, limiting their participation." + ] + }, + { + "cell_type": "markdown", + "id": "8cf282f0", + "metadata": {}, + "source": [ + "\n", + "## Malicious builder (withhold attack)\n", + "\n", + "* Builder withholds some specific samples from the matrix, without sending them to validators.\n", + "\n", + "\n", + "## Simulation parameters\n", + "\n", + "* Number of nodes: 5000\n", + "* Number of validators: 50% nodes are validators\n", + "* Redundancy parameter: 2\n", + "* Latency between nodes: 5ms - 125ms\n", + "* Number of samples per block : 512x512\n", + "* Sample size: 512 bytes\n", + "* Blocks: 1 blocks simulation.\n", + "* Number of random samples fetch: 75. \n", + "* 75% samples withheld by builder." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "ddd499e5", + "metadata": {}, + "outputs": [], + "source": [ + "from matplotlib import pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "ops_path = {'DAS': '../logsDasEvil0.5000/operation.csv', \n", + " 'Evil': '../logsDasBuilderEvil5000/operation.csv'\n", + " }\n", + "msgs_path = {'DAS': '../logsDasEvil0.5000/messages.csv', \n", + " 'Evil': '../logsDasBuilderEvil5000/messages.csv'\n", + " }\n", + "\n", + "\n", + "builder_address = '83814183170291850251680823880522715558189094423550585243365458794131648333116'\n", + "\n", + "op_df={}\n", + "msg_df={}\n", + "for key in ops_path:\n", + " op_df[key] = pd.read_csv(ops_path[key],index_col=False,low_memory=False)\n", + "for key in msgs_path:\n", + " msg_df[key] = pd.read_csv(msgs_path[key],index_col=False,low_memory=False)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "e1f09c13", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0, '% Withhold')" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAh8AAAHHCAYAAAAf2DoOAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA490lEQVR4nO3deXyM5/7/8fckJBKy2CUVpGqJvYJ8UUtKpZaqw6F6qFhKW1RTp5vWGq2lddr8ilJd6KF6qj3KOVVLaWy1NIJutlBUFa0tQSIhuX9/eGSOMUkkTK4JXs/HI492rvu67+tz3zMZ79z3dc/YLMuyBAAAYIiHuwsAAAB3FsIHAAAwivABAACMInwAAACjCB8AAMAowgcAADCK8AEAAIwifAAAAKMIHwAAwCjCx23o0KFDstlsmjdvnr1t/Pjxstls+VrfZrNp/PjxhVMc8m3evHmy2Ww6dOiQu0u5IUlJSerQoYMCAgJks9m0ZMkSY2P3799fpUqVylffovh679+/v6pVq+buMpwsWrRIZcqU0fnz591dSqFbu3atbDab1q5dm+91Ll26pJCQEL3zzjuFV9htgvDhZl27dpWvr6/OnTuXa58+ffrIy8tLp06dMlhZwe3atUvjx4+/Zf+xvFHh4eEaOnSou8socqKjo/Xjjz/qtdde0/z589WkSZN8r/v7779r/Pjx2rlzZ+EV6Ga32j5mZmZq3Lhxevrpp/Md7O40xYsX18iRI/Xaa6/p4sWL7i6nSCN8uFmfPn2UlpamL774IsflqampWrp0qR588EGVLVv2hscZPXq00tLSbnj9/Ni1a5cmTJhwR4WPY8eOaceOHercubO7SylS0tLStHnzZg0aNEjDhw9X3759Vbly5Xyv//vvv2vChAlG/mFOS0vT6NGjC32ca+W1j++995727t1rvKa8/Pe//9XevXs1ZMgQd5dSpA0YMEAnT57UwoUL3V1KkUb4cLOuXbvKz88v1xfq0qVLdeHCBfXp0+emxilWrJhKlChxU9twl9TU1AL1v3DhQiFV4mz58uUqUaKE7r//fmNj3gr+/PNPSVJgYKB7C8mHEiVKqFixYu4uw0Hx4sXl7e3t7jIczJ07Vy1bttRdd93l7lKKtMDAQHXo0MHhsjecET7czMfHR927d9eaNWv0xx9/OC1fuHCh/Pz81LVrV50+fVrPPfec6tevr1KlSsnf318dO3bU999/f91xcprzkZ6ermeffVbly5e3j/Hbb785rXv48GENHTpUtWrVko+Pj8qWLauePXs6nOGYN2+eevbsKUmKjIyUzWZzul76zjvvqG7duvL29lZwcLCGDRums2fPOozVtm1b1atXT4mJiWrdurV8fX318ssv57pf2df2Dxw4oE6dOsnPz88e1C5cuKC///3vCgkJkbe3t2rVqqVp06bp6i9y7t69uxo3buywzYceekg2m03/+c9/7G1bt26VzWbT8uXLHfouW7ZMkZGR8vHxcejbqVMnlS5dWiVLllSDBg30//7f/3NY75tvvlGrVq1UsmRJBQYG6uGHH9bu3btz3c9suc1PqFatmvr3729/nD1fZOPGjRoxYoTKly+vwMBAPfHEE8rIyNDZs2fVr18/lS5dWqVLl9YLL7zgcFyy5w1NmzZNc+bMUfXq1eXt7a2mTZsqISEhzxrHjx+vqlWrSpKef/552Ww2h/kLR48e1cCBA1WxYkV5e3urbt26+vDDD+3L165dq6ZNm0q68ldk9mvp6jfz/Bzj7LG6deumUqVKqXz58nruueeUmZmZ5zHN/l3Zv3+/+vfvr8DAQAUEBGjAgAFOQTgtLU0jRoxQuXLl7L9DR48eve48kuvt47VzPq5+PmbOnKm7775bvr6+6tChg44cOSLLsjRx4kRVrlxZPj4+evjhh3X69GmncZcvX25/3fn5+alz5876+eefc60z28WLF7VixQq1b9/eadnXX3+t++67T4GBgSpVqpRq1arl9Dubnp6ucePG6Z577pG3t7dCQkL0wgsvKD093Wl7CxYsULNmzeTr66vSpUurdevWWrVqlUOfgryX7Nq1S5GRkfL19dVdd92l119/3WnM3377Td26dVPJkiVVoUIFPfvssznWlpSUpB49eqhSpUoqUaKEKleurN69eys5Odmh3wMPPKCNGzfm+BzgiqIV9+9Qffr00UcffaRFixZp+PDh9vbTp09r5cqVevTRR+Xj46Off/5ZS5YsUc+ePRUaGqoTJ07o3XffVZs2bbRr1y4FBwcXaNzHH39cCxYs0N/+9je1aNFC33zzTY6XDxISErRp0yb17t1blStX1qFDhzRr1iy1bdtWu3btkq+vr1q3bq0RI0bo7bff1ssvv6ywsDBJsv93/PjxmjBhgtq3b6+nnnpKe/fu1axZs5SQkKBvv/1WxYsXt4936tQpdezYUb1791bfvn1VsWLFPPfj8uXLioqK0n333adp06bJ19dXlmWpa9euio+P16BBg9SoUSOtXLlSzz//vI4ePaq33npLktSqVSstXbpUKSkp8vf3l2VZ+vbbb+Xh4aENGzaoa9eukqQNGzbIw8NDLVu2tI976dIlrV69WpMmTbK3ff311+rSpYuCgoL0zDPPqFKlStq9e7e+/PJLPfPMM5Kk1atXq2PHjrr77rs1fvx4paWlafr06WrZsqW2b9/u0omGTz/9tCpVqqQJEyZoy5YtmjNnjgIDA7Vp0yZVqVJFkyZN0ldffaU33nhD9erVU79+/RzWX7hwoc6dO6cnnnhCNptNr7/+urp3765ffvnF4Tm7Wvfu3RUYGKhnn31Wjz76qDp16mSfI3DixAn93//9n2w2m4YPH67y5ctr+fLlGjRokFJSUhQTE6OwsDDFxsZq7NixGjJkiFq1aiVJatGiRb6PsXRljkJUVJQiIiI0bdo0rV69Wv/4xz9UvXp1PfXUU9c9dr169VJoaKgmT56s7du36/3331eFChU0depUe5/+/ftr0aJFeuyxx/R///d/WrduXb4uwV1vH3Pz8ccfKyMjQ08//bROnz6t119/Xb169dL999+vtWvX6sUXX9T+/fs1ffp0Pffccw6hbv78+YqOjlZUVJSmTp2q1NRUzZo1S/fdd5927NiR5+suMTFRGRkZTkH9559/VpcuXdSgQQPFxsbK29tb+/fv17fffmvvk5WVpa5du2rjxo0aMmSIwsLC9OOPP+qtt97Svn37HCYiT5gwQePHj1eLFi0UGxsrLy8vbd26Vd988406dOggqWDvJWfOnNGDDz6o7t27q1evXvr888/14osvqn79+urYsaOkKwGyXbt2+vXXXzVixAgFBwdr/vz5+uabbxz2NSMjQ1FRUUpPT7f/Xh09elRffvmlzp49q4CAAHvf8PBwWZalTZs2qUuXLnk+p3csC253+fJlKygoyGrevLlD++zZsy1J1sqVKy3LsqyLFy9amZmZDn0OHjxoeXt7W7GxsQ5tkqy5c+fa28aNG2dd/XTv3LnTkmQNHTrUYXt/+9vfLEnWuHHj7G2pqalONW/evNmSZP3zn/+0t3322WeWJCs+Pt6h7x9//GF5eXlZHTp0cKh/xowZliTrww8/tLe1adPGkmTNnj3bacycREdHW5Ksl156yaF9yZIlliTr1VdfdWj/61//atlsNmv//v2WZVlWQkKCJcn66quvLMuyrB9++MGSZPXs2dOKiIiwr9e1a1fr3nvvddjWmjVrLEnWwYMHLcu68jyGhoZaVatWtc6cOePQNysry/7/jRo1sipUqGCdOnXK3vb9999bHh4eVr9+/extc+fOddi+ZVlOz022qlWrWtHR0U7rRkVFOYzdvHlzy2azWU8++aS97fLly1blypWtNm3a2NuyX0Nly5a1Tp8+bW9funSpJcn673//61TD1bLXf+ONNxzaBw0aZAUFBVknT550aO/du7cVEBBgf61lPy9Xv4aza83PMc5+XVz9e2FZlnXvvfda4eHhDm3XHtPs35WBAwc69PvLX/5ilS1b1v44MTHRkmTFxMQ49Ovfv3+uz9PVctvH7PqrVq1qf5x9PMuXL2+dPXvW3j5q1ChLktWwYUPr0qVL9vZHH33U8vLysi5evGhZlmWdO3fOCgwMtAYPHuwwzvHjx62AgACn9mu9//77liTrxx9/dGh/6623LEnWn3/+meu68+fPtzw8PKwNGzY4tGe/v3377beWZVlWUlKS5eHhYf3lL39xep/Lfm5v5L3k6veo9PR0q1KlSlaPHj3sbXFxcZYka9GiRfa2CxcuWPfcc4/D+9mOHTssSdZnn32W57GyLMv6/fffLUnW1KlTr9v3TsVllyLA09NTvXv31ubNmx0uZSxcuFAVK1ZUu3btJEne3t7y8LjylGVmZurUqVP205zbt28v0JhfffWVJGnEiBEO7TExMU59r76kcOnSJZ06dUr33HOPAgMD8zXu6tWrlZGRoZiYGHv9kjR48GD5+/tr2bJlDv29vb01YMCAguyO01+yX331lTw9PZ327+9//7ssy7JfPrn33ntVqlQprV+/XtKVMxyVK1dWv379tH37dqWmpsqyLG3cuNH+1+nVY9SpU8f+F+OOHTt08OBBxcTEOM11yL7kdezYMe3cuVP9+/dXmTJl7MsbNGigBx54wP68uMqgQYMcLrdFRETIsiwNGjTI3ubp6akmTZrol19+cVr/kUceUenSpe2Ps49BTn2vx7Is/fvf/9ZDDz0ky7J08uRJ+09UVJSSk5Ov+3rKzzG+2pNPPunwuFWrVvmuPad1T506pZSUFEnSihUrJMnpTqenn346X9u/ET179nT4CzsiIkKS1LdvX4d5KxEREcrIyNDRo0clXTlbdPbsWT366KMOx93T01MRERGKj4/Pc9zsO+2ufi1I/5vTs3TpUmVlZeW47meffaawsDDVrl3bYezseVLZYy9ZskRZWVkaO3asw/uE9L/ntqDvJaVKlVLfvn3tj728vNSsWTOH18BXX32loKAg/fWvf7W3+fr6Ok2szT7uK1euvO48tOzjdPLkyTz73ckIH0VE9jyF7Imnv/32mzZs2KDevXvL09NT0pXTl2+99ZZq1Kghb29vlStXTuXLl9cPP/zgdM3xeg4fPiwPDw9Vr17dob1WrVpOfdPS0jR27Fj73Inscc+ePZuvcQ8fPpzjtr28vHT33Xfbl2e766675OXlle99KVasmNOdFIcPH1ZwcLD8/Pwc2rMvA2WP6enpqebNm2vDhg2SroSPVq1a6b777lNmZqa2bNmiXbt26fTp007hY9myZQ6n2A8cOCBJqlevXq615nYssms7efKkSyfMVqlSxeFx9htoSEiIU/uZM2euu372m2pOfa/nzz//1NmzZzVnzhyVL1/e4Sc7bOY07+lq+TnG2UqUKKHy5cs71Z/f2q+379m/Q6GhoQ797rnnnnxt/0YU5PmU/ldrUlKSJOn+++93OvarVq267nHPZl01L0i6Ek5btmypxx9/XBUrVlTv3r21aNEihyCSlJSkn3/+2WncmjVrSvrfc37gwAF5eHioTp06uY5f0PeSypUrO4XSa18Dhw8f1j333OPU79oxQkNDNXLkSL3//vsqV66coqKiNHPmzBzfA7OPU34/W+lOxJyPIiI8PFy1a9fWJ598opdfflmffPKJLMtyuMtl0qRJGjNmjAYOHKiJEyeqTJky8vDwUExMTK5/dbjC008/rblz5yomJkbNmze3f2hU7969C2Xcq8+05MfVZ4RuxH333We/L3/Dhg165ZVXFBgYqHr16mnDhg32OSdXh4+DBw9qz549mjVr1g2P60rXTqLMlh1c89N+7T8sea2fU9/ryX6t9O3bV9HR0Tn2adCgQYG3m5vcar/Z9W9k312lIM+n9L9as4/9/PnzValSJad+17vbJ/s2/zNnzjgEfR8fH61fv17x8fFatmyZVqxYoU8//VT333+/Vq1aJU9PT2VlZal+/fp68803c9z2tcHJlVz9HP7jH/9Q//79tXTpUq1atUojRozQ5MmTtWXLFofjkh1uypUrd0Pj3AkIH0VInz59NGbMGP3www9auHChatSoYZ8RL0mff/65IiMj9cEHHzisd/bs2QK/yKtWraqsrCwdOHDAIeHn9NkCn3/+uaKjo/WPf/zD3nbx4kWn2eW5pfzsOx/27t2ru+++296ekZGhgwcP5jiD/mZVrVpVq1ev1rlz5xzOfuzZs8ehJulKqMjIyNAnn3yio0eP2kNG69at7eGjZs2aDhNfly1bpoCAAN133332tuyzSD/99FOu+3T1sbjWnj17VK5cOZUsWTLX/SpdurTTcc/IyNCxY8dyXaeoyL6rKjMz87rPeW6vpfwcY1Oyf4cOHjyoGjVq2Nv379+fr/VN/lWcfdwqVKhwQ8etdu3akq6E7vr16zss8/DwULt27dSuXTu9+eabmjRpkl555RXFx8erffv2ql69ur7//nu1a9cuz32uXr26srKytGvXLjVq1CjHPoXxXlK1alX99NNPsizLob7cPmelfv36ql+/vkaPHq1NmzapZcuWmj17tl599VV7n4MHD0r635lWOOOySxGSfZZj7Nix2rlzp9Nne3h6ejol9s8++8x+Xbcgsmd6v/322w7tcXFxTn1zGnf69OlOf21n/6N57T+O7du3l5eXl95++22H7XzwwQdKTk4ulA/o6tSpkzIzMzVjxgyH9rfeeks2m82+/9KV6+PFixfX1KlTVaZMGdWtW1fSlVCyZcsWrVu3Lsf5Hh06dHD4i7Fx48YKDQ1VXFyc0zHI3u+goCA1atRIH330kUOfn376SatWrVKnTp3y3K/q1avb56dkmzNnTq5nPooST09P9ejRQ//+97/1008/OS3P/mwQKffXUn6OsSlRUVGS5PRR2tOnT8/X+rntY2GIioqSv7+/Jk2apEuXLjktv/rY5yQ8PFxeXl7atm2bQ3tOt5JmB4fsW1V79eqlo0eP6r333nPqm5aWZr/M2K1bN3l4eCg2NtbpjGr2c1sY7yWdOnXS77//rs8//9zelpqaqjlz5jj0S0lJ0eXLlx3a6tevLw8PD6fbchMTE2Wz2dS8efMC13On4MxHERIaGqoWLVpo6dKlkuQUPrp06aLY2FgNGDBALVq00I8//qiPP/7Y4S+A/GrUqJEeffRRvfPOO0pOTlaLFi20Zs2aHP9q69Kli+bPn6+AgADVqVNHmzdv1urVq50+cbVRo0by9PTU1KlTlZycLG9vb91///2qUKGCRo0apQkTJujBBx9U165dtXfvXr3zzjtq2rSpw4QwV3nooYcUGRmpV155RYcOHVLDhg21atUqLV26VDExMQ5zXXx9fRUeHq4tW7bYP+NDunLm48KFC7pw4YJD+EhLS1N8fLxmz57tMKaHh4dmzZqlhx56SI0aNdKAAQMUFBSkPXv26Oeff9bKlSslSW+88YY6duyo5s2ba9CgQfZbbQMCAq77HSOPP/64nnzySfXo0UMPPPCAvv/+e61cufKWOb07ZcoUxcfHKyIiQoMHD1adOnV0+vRpbd++XatXr7b/Y1a9enUFBgZq9uzZ8vPzU8mSJRUREaHQ0NB8HWMTwsPD1aNHD8XFxenUqVP2W2337dsn6fpnNvLaR1fz9/fXrFmz9Nhjj6lx48bq3bu3ypcvr19//VXLli1Ty5YtnYL61UqUKKEOHTpo9erVio2NtbfHxsZq/fr16ty5s6pWrao//vhD77zzjipXrmw/K/jYY49p0aJFevLJJxUfH6+WLVsqMzNTe/bs0aJFi7Ry5Uo1adJE99xzj1555RVNnDhRrVq1Uvfu3eXt7a2EhAQFBwdr8uTJKl++vMvfSwYPHqwZM2aoX79+SkxMVFBQkObPny9fX1+Hft98842GDx+unj17qmbNmrp8+bLmz59vD9VX+/rrr9WyZcub+lTq257Re2twXTNnzrQkWc2aNXNadvHiRevvf/+7FRQUZPn4+FgtW7a0Nm/ebLVp0ybH2yTzutXWsiwrLS3NGjFihFW2bFmrZMmS1kMPPWQdOXLE6TbBM2fOWAMGDLDKlStnlSpVyoqKirL27NnjdHunZVnWe++9Z919992Wp6en0223M2bMsGrXrm0VL17cqlixovXUU0853S7Zpk0bq27duvk+XtHR0VbJkiVzXHbu3Dnr2WeftYKDg63ixYtbNWrUsN544w2HWzKzPf/88zneGpd9u92BAwfsbV9++aVls9msEydO5Djuxo0brQceeMDy8/OzSpYsaTVo0MCaPn26Q5/Vq1dbLVu2tHx8fCx/f3/roYcesnbt2uXQJ6dbbTMzM60XX3zRKleunOXr62tFRUVZ+/fvz/VW24SEBIdtZr8Orr018trjmNutspaV++2+V8tr/RMnTljDhg2zQkJCrOLFi1uVKlWy2rVrZ82ZM8eh39KlS606depYxYoVc3o9X+8Y5/a6yOn34Nr9ye0Y5fR8XLhwwRo2bJhVpkwZq1SpUla3bt2svXv3WpKsKVOm5HmM8trH3G61vfZ4xsfH53j7Z27Pf3x8vBUVFWUFBARYJUqUsKpXr27179/f2rZt23VrXbx4sWWz2axff/3V3rZmzRrr4YcftoKDgy0vLy8rODjYevTRR619+/Y5rJuRkWFNnTrVqlu3ruXt7W2VLl3aCg8PtyZMmGAlJyc79P3www+te++9196vTZs21tdff+3Q52beS649tpZlWYcPH7a6du1q+fr6WuXKlbOeeeYZa8WKFQ7vYb/88os1cOBAq3r16laJEiWsMmXKWJGRkdbq1asdtnX27FnLy8vLev/99697TO9kNsty4+wp4BY0dOhQbdu2Td999527S0ERtHPnTt17771asGDBTX8tQlGSmZmpOnXqqFevXpo4caK7yymy4uLi9Prrr+vAgQMFnjx/J2HOB1BAjRo10oQJE9xdBoqAnL6sMS4uTh4eHmrdurUbKio8np6eio2N1cyZM3X+/Hl3l1MkXbp0SW+++aZGjx5N8LgOznwAwA2aMGGCEhMTFRkZqWLFimn58uVavny5hgwZonfffdfd5QFFFuEDAG7Q119/rQkTJmjXrl06f/68qlSposcee0yvvPJKkfumXKAoKXD4WL9+vd544w0lJibq2LFj+uKLL9StWzdJV045jR49Wl999ZV++eUXBQQEqH379poyZUqBv/QMAADcngo85+PChQtq2LChZs6c6bQsNTVV27dv15gxY7R9+3YtXrxYe/futX8zKAAAwE1ddrHZbA5nPnKSkJCgZs2a6fDhw07fSwAAAO48hX5RMjk5WTabzekbKLOlp6c7fDpcVlaWTp8+rbJly/KlPAAA3CIsy9K5c+cUHBx83e/bKtTwcfHiRb344ot69NFH5e/vn2OfyZMnc9siAAC3iSNHjjh90/i1Cu2yy6VLl9SjRw/99ttvWrt2ba7h49ozH8nJyapSpYqOHDmS6zoAAKBoSUlJUUhIiM6ePauAgIA8+xbKmY9Lly6pV69eOnz4sL755ps8Q4S3t7e8vb2d2v39/QkfAADcYvIzZcLl4SM7eCQlJSk+Pp4v1gEAAA4KHD7Onz/v8M2nBw8e1M6dO1WmTBkFBQXpr3/9q7Zv364vv/xSmZmZOn78uCSpTJky8vLycl3lAADgllTgOR9r165VZGSkU3t0dLTGjx+f69dBx8fHq23bttfdfkpKigICApScnMxlFwAAbhEF+fe7wGc+2rZtq7zyCp/WDgAA8sK32gIAAKMIHwAAwCjCBwAAMIrwAQAAjCJ8AAAAowgfAADAKMIHAAAwivABAACMInwAAACjCB8AAMAowgcAADCK8AEAAIwifAAAAKMIHwAAwCjCBwAAMIrwAQAAjCJ8AAAAowgfAADAKMIHAAAwivABAACMInwAAACjCB8AAMAowgcAADCK8AEAAIwifAAAAKMIHwAAwCjCBwAAMIrwAQAAjCJ8AAAAowgfAADAKMIHAAAwivABAACMInwAAACjCB8AAMAowgcAADCK8AEAAIwifAAAAKMIHwAAwCjCBwAAMIrwAQAAjCJ8AAAAowgfAADAKMIHAAAwivABAACMInwAAACjCB8AAMAowgcAADCqmLsLAADcelJTU7Vnz548+6SlpenQoUOqVq2afHx8rrvN2rVry9fX11UloggjfAAACmzPnj0KDw936TYTExPVuHFjl24TRRPhAwBQYLVr11ZiYmKefXbv3q2+fftqwYIFCgsLy9c2cWcocPhYv3693njjDSUmJurYsWP64osv1K1bN/tyy7I0btw4vffeezp79qxatmypWbNmqUaNGq6sGwDgRr6+vvk+SxEWFsYZDTgo8ITTCxcuqGHDhpo5c2aOy19//XW9/fbbmj17trZu3aqSJUsqKipKFy9evOliAQDAra/AZz46duyojh075rjMsizFxcVp9OjRevjhhyVJ//znP1WxYkUtWbJEvXv3vrlqAQDALc+lt9oePHhQx48fV/v27e1tAQEBioiI0ObNm105FAAAuEW5dMLp8ePHJUkVK1Z0aK9YsaJ92bXS09OVnp5uf5ySkuLKkgAAQBHj9g8Zmzx5sgICAuw/ISEh7i4JAAAUIpeGj0qVKkmSTpw44dB+4sQJ+7JrjRo1SsnJyfafI0eOuLIkAABQxLg0fISGhqpSpUpas2aNvS0lJUVbt25V8+bNc1zH29tb/v7+Dj8AAOD2VeA5H+fPn9f+/fvtjw8ePKidO3eqTJkyqlKlimJiYvTqq6+qRo0aCg0N1ZgxYxQcHOzwWSAAAODOVeDwsW3bNkVGRtof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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "\n", + "fig3, ax3 = plt.subplots()\n", + "\n", + "data = []\n", + "for key in op_df:\n", + "\n", + " vsdf = op_df[key].loc[(op_df[key]['type'] == 'ValidatorSamplingOperation')]\n", + " data.append(vsdf['completion_time']/1000)\n", + "\n", + "ax3.boxplot(data)\n", + "\n", + "\n", + "ax3.set_ylim([0,12])\n", + "ax3.set_xticklabels([0,75])\n", + "ax3.set_title(\"Validator row/column fetching time (seconds)\")\n", + "ax3.set_xlabel(\"% Withhold\")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "84859565", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0, '% Withhold')" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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ej37b7N48WK7embOnGlT+x133GGEhIRYry9fvtyQZMybN8/alpmZabRv395uzJx88cUXhiRj06ZNdrddW+emTZsMSUbjxo1t7mPfvn0Ni8VihIeH2yzfunVrm+dLYmKi4eLiYrz44os2/X799VejdOnSdu3XmjZtmiHJ6Nu3r017fsdNT083vL29jTvvvNO4evWqtV9UVJQhyea+Zv89r30OZj8G/3y8Bg0aZHM/DcP+eXflyhWjcePGRvv27W3aJRmlSpUyfvvttzzvezZ/f39DkrFlyxZr26lTpwxXV1djwoQJ1raxY8cakoytW7da21JTU43AwEAjICDAyMzMNAzDMObNm2dIMj7//HNrv7S0NKNOnTo29zMrK8uoW7eu0alTJyMrK8vmfgYGBhr33XeftS0/r8uc/Pvf/zYkGampqTbtTz/9tOHp6WlkZGTkuuwLL7xguLu7GwcPHrRpnzx5suHi4mIcOXLEMAzD2LhxoyHJGDNmjN0Y2fdr7969hiRj+PDhNrc/88wzhiRj48aN1raC/j127Nhh08/Ly8vmebZixQpDkrFr165c72u2H3/80ZBkfPbZZ9ftW5Kw28UEHTt2VNWqVeXn56devXrJ3d1dq1atsvmG5uLiYt0vn5WVpbNnzyojI0MtWrTIcTPnww8/bLPlJHtXzh9//CFJOn78uPbu3atBgwbJy8vL2u++++5Tw4YNbcb6+uuv5eLiojFjxti0T5gwQYZhaM2aNTbtHTp0sPlW16pVK0nSQw89JA8PD7v27JpyU7FiRe3YsUN//vlnrn3++c0iLS1Nf/31l9q0aSPDMPTTTz/Z9R8+fLjN+PXr15e7u7v69Oljba9fv74qVqyYY30jR460mTj6xBNPqHTp0jd8WNzjjz9uc71t27Y26/3mm29UpkwZjRgxwtpWqlQp69alwjBw4ECb+9iqVSsZhmG3abhVq1Y6evSoMjIyJEkxMTHKyspSnz599Ndff1kvNWrUUN26de12Febm2sckv+Pu3r1bZ86c0YgRI1S69P823vbv39/mNeEI/3zenTt3TsnJyWrbtm2Or8l27drZvbby0rBhQ+vrVpKqVq2q+vXr2zwvvv76a7Vs2dJmt1SFChU0cuRIJSYm6vfff7f28/HxUa9evaz9ypcvr5EjR9qsc+/evYqPj1e/fv105swZ62OclpamDh06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D8PLy8sYPHiw8cMPPxiSbA4Rzs17771n1K5d23BxcbE5vDK3Q22v/bvk9nzNrvX06dM27cuXLzfuuecew93d3XB3dzeCg4ONUaNGGQcOHMizztzGK+i4b775pvX10rJlS+OHH34wQkJCjM6dO9v0O3z4sNGxY0fD1dXVqF69uvHcc88Z69aty9ehth988IFRt25dw9XV1QgODjYWL16c498up9dFXq593mW79m+VXX+vXr2MihUrGuXKlTNatmxprF692m7ZpKQko0ePHkb58uWNKlWqGE8//bTxzTff5HgI9k8//WT07NnT8Pb2NlxdXQ1/f3+jT58+xoYNGwzDyP/rMjevvfaaUaFCBZtDlZctW2bcf//9RrVq1YyyZcsatWrVMh577DHj+PHjNsumpqYaU6ZMMerUqWOULVvWqFKlitGmTRtj7ty5NoeGZ2RkGK+88ooRHBxslC1b1qhataoRHh5uxMbGWvtcvXrVmDFjhhEYGGiUKVPG8PPzM6ZMmWJcvnzZZp0F+Xv88ssvRrt27Yxy5coZNWvWNF544QXjgw8+sDnUds+ePUbfvn2NWrVqGa6urka1atWMbt26Gbt377YZa//+/dbTMdxqLIZxi51WDchDVFSUhgwZol27dlknCTvTypUr9eCDD+r777/X3Xff7exyirSsrCxVrVpVPXv2tNl9BfMlJyerdu3amjNnjoYNG+bscoqssWPHasuWLYqNjb3ltnww5wMoIq49VXxmZqbmz58vT0/PPM8oeSu6fPmy3T71//znPzp79qzN6dXhHF5eXnr22Wf1yiuv5Hjqcfw9B+b999/XrFmzbrngITHnAygynnrqKV26dEmtW7dWenq6YmJi9OOPP+qll14q8GGcJd327ds1btw49e7dW97e3tqzZ48++OADNW7c2Po7N3CuSZMmadKkSc4uo8jy9va+4fl8JQHhAygi2rdvr1dffVWrV6/W5cuXVadOHc2fP1+jR492dmlFTkBAgPz8/PTmm29aJ5IOHDhQL7/8cpH/BV8AEnM+AACAqZjzAQAATEX4AAAApipycz6ysrL0559/ysPD45acAQwAQHFkGIZSU1Pl6+trPQFebopc+Pjzzz/tflUTAAAUD0ePHtVtt92WZ58iFz6yf9js6NGj8vT0dHI1AAAgP1JSUuTn52fzA6W5KXLhI3tXi6enJ+EDAIBiJj9TJphwCgAATEX4AAAApiJ8AAAAUxE+AACAqQgfAADAVIQPAABgKsIHAAAwFeEDAACYivABAABMRfgAAACmInwAAABTET4AAICpCB8AAMBUhA8AAGAqwgcAADAV4QMAAJiK8AEAAExV4PCxZcsWde/eXb6+vrJYLFq5cmWufR9//HFZLBbNmzfvJkoEAAAlSYHDR1pampo2baoFCxbk2W/FihXavn27fH19b7g4AABQ8pQu6ALh4eEKDw/Ps8+xY8f01FNPae3ateratesNFwcAAEoeh8/5yMrK0qOPPqqJEyeqUaNGjh4eAAAUcwXe8nE9s2fPVunSpTVmzJh89U9PT1d6err1ekpKiqNLAgAARYhDt3zExsbqjTfeUFRUlCwWS76WiYyMlJeXl/Xi5+fnyJIAAEAR49DwsXXrVp06dUq1atVS6dKlVbp0aSUlJWnChAkKCAjIcZkpU6YoOTnZejl69KgjSwIAAEWMQ3e7PProo+rYsaNNW6dOnfToo49qyJAhOS7j6uoqV1dXR5YBAACKsAKHjwsXLujQoUPW6wkJCdq7d68qV66sWrVqydvb26Z/mTJlVKNGDdWvX//mqwUAAMVegcPH7t27FRYWZr0+fvx4SdKgQYMUFRXlsMIAAEDJVODwERoaKsMw8t0/MTGxoKsAAAAlGL/tAgAATEX4AAAApiJ8AAAAUxE+AACAqQgfAADAVIQPAABgKsIHAAAwFeEDAACYivABAABMRfgAAACmInwAAABTET4AAICpCB8AAMBUhA8AAGAqwgcAADAV4QMAAJiK8AEAAExF+AAAAKYifAAAAFMRPgAAgKkIHwAAwFSEDwAAYCrCBwAAMBXhAwAAmIrwAQAATEX4AAAApiJ8AAAAUxE+AACAqQgfAADAVIQPAABgKsIHAAAwFeEDAACYivABAABMRfgAAACmInwAAABTET4AAICpCB8AAMBUhA8AAGAqwgcAADBVgcPHli1b1L17d/n6+spisWjlypXW265evapJkyapSZMmcnd3l6+vrwYOHKg///zTkTUDAIBirMDhIy0tTU2bNtWCBQvsbrt48aL27NmjqVOnas+ePYqJidGBAwfUo0cPhxQLAACKP4thGMYNL2yxaMWKFYqIiMi1z65du9SyZUslJSWpVq1a1x0zJSVFXl5eSk5Olqen542WBgAATFSQ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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig3, ax3 = plt.subplots()\n", + "\n", + "data = []\n", + "for key in op_df:\n", + "\n", + " vsdf = op_df[key].loc[(op_df[key]['type'] == 'RandomSamplingOperation')]\n", + " #vsdf = op_df[key].loc[(op_df[key]['validator'] == 'no')]\n", + " data.append(vsdf['completion_time']/1000)\n", + "\n", + "ax3.boxplot(data)\n", + "\n", + "#ax3.legend()\n", + "#ax18.set_xlim([0,2])\n", + "ax3.set_ylim([0,15])\n", + "ax3.set_xticklabels([0,75])\n", + "ax3.set_title(\"Random sampling time regular nodes (seconds)\")\n", + "ax3.set_xlabel(\"% Withhold\")" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "e8193010", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0, '% Withhold')" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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s3PnTrcaioqKXD9XdP9VkX1hYGCgGTx48Cm3AU7gNM05pviwY/Xq1UtMS0xMVN26dV2PSZMmlegzf/58LV++XMuWLdOMGTPUtGlT9e7dW59++qmrT82aNfXTTz9p7dq1HtV2qnHGGM2fP189evSQMUYHDx50Pbp06aKcnJwShyj79+/vdp3CVVddJUn68ccfPartZPHx8YqLi3M9r1+/vnr27KmlS5eqsLBQkpSSkqL8/Hy3w+Zz587V8ePHdccdd5zR8qOiolzrIkl169ZVs2bN3NZr3rx5uuqqq1SrVi23bZWUlKTCwkK300plCQsL0w033OB6HhAQoJSUFG3YsEFZWVlntA6l2bdvnzZu3Ki+ffsqMDDQ1X7ttdcqKirKre+8efMUGBioa6+91m394uLiVL16da1cudKtf8OGDdWlS5cK11KlShXdfffdruc+Pj66++67tX//fn3xxReuGlq0aKHmzZu71XD11VdLUokaEhISSqxHaWrWrCnpxIXmv//+e5n9/njNy6FDh5STk6Orrrqq1EP111xzjdspyI4dO0qSevfurRo1apRoP/k9UpHt4YmkpCQ1btzY9bx169YKCAhwLbewsFArVqxQr169FBYW5uoXGRmpbt26VXg5ntTdt29ft226bt067d+/X/fdd5/btT3Jyclq3ry5Fi9eLEk6cOCAVq9erQEDBqh+/fpu8yw+neTJ/qsi+9CaNWvqs88+0969eyu8LS5mhJFzTPFO5+jRoyWmTZ06VcuXL9esWbPKHN+pUyclJSXp2muvVb9+/ZSRkaEaNWro73//u6vPI488ourVq6tDhw5q0qSJBg8erE8++eSUtZ1q3IEDB3T48GFNmzbNLTTVrVtX/fv3lyTt37/fbZ4n7xhq1aolSSWuKfBUkyZNSrQ1bdpUv/76qw4cOCBJat68udq3b6/Zs2e7+syePVuXXXaZIiMjz2j5J6+XdGLd/rheW7du1ZIlS0psq6SkJEklt1VpIiMjS5ybb9q0qSSdlduOd+7cKan07dusWTO351u3blVOTo6CgoJKrOPRo0dLrF/Dhg09qiUsLEzVqlVzazt53bdu3apvvvmmxPKL+51uDQkJCerdu7eefPJJ1alTRz179tSMGTNKXIeyaNEiXXbZZfL19dUll1yiunXrasqUKcrJySkxz5NfM8Vh7+Rrw4rbT36PVGR7eOJUr+H9+/fr2LFjpb5XPHn/eFL3yb+f4tfjya896cT7u3h6cYCKjo4usw5P9l8V2Yc+88wz2rRpk8LDw9WhQweNGjXqjP/IupCdf5dQX+ACAwMVGhqqTZs2lZhW/BeRJzuW6tWrq2PHjnr33XeVl5enatWqqUWLFtqyZYsWLVqkJUuWaP78+Zo8ebKeeOIJPfnkk2XO61Tjii+6vOOOO9S3b99S59G6dWu3597e3qX2M8ZUeB3PREpKih544AH99NNPys/P15o1azRx4sQznm9F1quoqEjXXnuthg0bVmrf4h3ymSrrQsLiI0RnS1FRkYKCgtzC3h/VrVvX7fnZuHOmqKhIrVq10vjx40udfvIHfUVrcDgcevvtt7VmzRr93//9n5YuXaoBAwZo3LhxWrNmjapXr66PPvpIf/nLX9SpUydNnjxZoaGhqlq1qmbMmFHqxeJlvWZsvUdsvzdLczbvrvJk/1WRfejNN9+sq666Su+8846WLVumZ599VmPHjtWCBQs8OnJ0sSCMnIOSk5P18ssv6/PPP1eHDh3OeH7Hjx+XdOJoS/FfINWqVVOfPn3Up08fFRQU6K9//auefvppjRgxotxbGcsbV7duXdWoUUOFhYWuv+4rw+l8O+TWrVtLtH3//ffy9/d3+xC85ZZblJqaqjfeeEPHjh1T1apV1adPn7NS08kaN26so0ePntG22rZtm4wxbvV8//33kuQ65F98tOnw4cOu0wvS//6q9ETx99qUtn23bNni9rxx48ZasWKFrrjiirPyIbJ3715XwC528ro3btxYX375pa655pqz8i2jl112mS677DI9/fTTmjNnjm6//Xa9+eabuvPOOzV//nz5+vpq6dKlcjqdrjEzZsyo9Dqkim2PyhQUFCRfX1+3u9+KldZWljOpu/j1uGXLFtept2JbtmxxTW/UqJEklfpHXjFP918V2YeGhobqvvvu03333af9+/erbdu2evrppwkjpeA0zTlo2LBh8vf314ABA5SdnV1iuid/mfzyyy/69NNPFRISoqCgIEnSzz//7NbHx8dHUVFRMsaUe/77VOO8vb3Vu3dvzZ8/v9Q3ffHpEU9Vq1at1MPa5cnMzHQ7L7979269++67uu6669z+4qtTp466deumWbNmafbs2eratavb97SUV5N04gP+dN18883KzMzU0qVLS0w7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AADAecnjMNKnTx8dOHBATzzxhLKyshQbG6slS5a4LmrdtWuXvLz+d8Dl0KFDGjRokLKyslSrVi3FxcXp008/VVRUVOWtBQAAOG85jDHGdhGnkpubq8DAQOXk5CggIKBS5x0xfHGlzg+40OwYk2y7hErBex0o29l6n1f085v/TQMAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACw6rTCyKRJkxQRESFfX1917NhRn3/+ebn9582bp+bNm8vX11etWrXS+++/f1rFAgCAC4/HYWTu3LlKTU3VyJEjtX79esXExKhLly7av39/qf0//fRT3XrrrRo4cKA2bNigXr16qVevXtq0adMZFw8AAM5/HoeR8ePHa9CgQerfv7+ioqKUnp4uf39/TZ8+vdT+L7zwgrp27aqHH35YLVq00FNPPaW2bdtq4sSJZ1w8AAA4/3kURgoKCvTFF18oKSnpfzPw8lJSUpIyMzNLHZOZmenWX5K6dOlSZn8AAHBxqeJJ54MHD6qwsFDBwcFu7cHBwdq8eXOpY7Kyskrtn5WVVeZy8vPzlZ+f73qek5MjScrNzfWk3Aopyv+10ucJXEjOxvvOBt7rQNnO1vu8eL7GmHL7eRRG/ixpaWl68sknS7SHh4dbqAa4uAVOsF0BgLPtbL/Pjxw5osDAwDKnexRG6tSpI29vb2VnZ7u1Z2dnKyQkpNQxISEhHvWXpBEjRig1NdX1vKioSL/88otq164th8PhSck4j+Tm5io8PFy7d+9WQECA7XIAnCW81y8exhgdOXJEYWFh5fbzKIz4+PgoLi5OGRkZ6tWrl6QTQSEjI0NDhgwpdUx8fLwyMjI0dOhQV9vy5csVHx9f5nKcTqecTqdbW82aNT0pFeexgIAAdlDARYD3+sWhvCMixTw+TZOamqq+ffuqXbt26tChgyZMmKC8vDz1799fkpSSkqJLL71UaWlpkqQHHnhACQkJGjdunJKTk/Xmm29q3bp1mjZtmqeLBgAAFyCPw0ifPn104MABPfHEE8rKylJsbKyWLFniukh1165d8vL63006l19+uebMmaPHH39cjz76qJo0aaKFCxcqOjq68tYCAACctxzmVJe4An+S/Px8paWlacSIESVO0wG4cPBex8kIIwAAwCr+UR4AALCKMAIAAKwijAAAAKsIIwAAwCrCCM4ZkyZNUkREhHx9fdWxY0d9/vnntksCcJoiIiLkcDhKPAYPHixJSkxMLDHtnnvusVw1bCGM4Jwwd+5cpaamauTIkVq/fr1iYmLUpUsX7d+/33ZpAE7D2rVrtW/fPtdj+fLlkqSbbrrJ1WfQoEFufZ555hlb5cIybu3FOaFjx45q3769Jk6cKOnEvxkIDw/X3//+dw0fPtxydQDO1NChQ7Vo0SJt3bpVDodDiYmJio2N1YQJE2yXhnMAR0ZgXUFBgb744gslJSW52ry8vJSUlKTMzEyLlQGoDAUFBZo1a5YGDBjg9s9OZ8+erTp16ig6OlojRozQr7/+arFK2OTx18EDle3gwYMqLCx0/UuBYsHBwdq8ebOlqgBUloULF+rw4cPq16+fq+22225TgwYNFBYWpq+++kqPPPKItmzZogULFtgrFNYQRgAAZ9Urr7yibt26uf0b+bvuusv1c6tWrRQaGqprrrlGP/zwgxo3bmyjTFjEaRpYV6dOHXl7eys7O9utPTs7WyEhIZaqAlAZdu7cqRUrVujOO+8st1/Hjh0lSdu2bfszysI5hjAC63x8fBQXF6eMjAxXW1FRkTIyMhQfH2+xMgBnasaMGQoKClJycnK5/TZu3ChJCg0N/ROqwrmG0zQ4J6Smpqpv375q166dOnTooAkTJigvL0/9+/e3XRqA01RUVKQZM2aob9++qlLlfx83P/zwg+bMmaPrr79etWvX1ldffaUHH3xQnTp1UuvWrS1WDFsIIzgn9OnTRwcOHNATTzyhrKwsxcbGasmSJSUuagVw/lixYoV27dqlAQMGuLX7+PhoxYoVrj86wsPD1bt3bz3++OOWKoVtfM8IAACwimtGAACAVYQRAABgFWEEAABYRRgBAABWEUYAAIBVhBEAAGAVYQQAAFhFGAFw1iUmJmro0KHl9pk5c6Zq1qxZbp9+/fqpV69eZ1RLRZYzatQoxcbGntFyAFQcYQS4SMyePVvh4eGqVauWUlNT3abt2LFDTZs2VW5ubrnzCA0N1ZgxY9zahg8fLofDoVWrVrm1JyYm6m9/+5skacGCBXrqqadc0yIiIjRhwoTTXxkAFxTCCHAROHjwoO68804999xzWrZsmWbNmqVFixa5pt93330aM2aMAgICyp1PYmJiidCxcuVKhYeHu7X/9ttvWrNmja6++mpJ0iWXXKIaNWpU2voAuLAQRoCLwI8//qjAwED16dNH7du3V+fOnfXdd99Jkt544w1VrVpVf/3rX085n86dO+uTTz7R8ePHJUlHjhzRhg0b9Mgjj7iFkczMTOXn56tz586S3E/TJCYmaufOnXrwwQflcDjkcDjclrF06VK1aNFC1atXV9euXbVv374SdTz33HMKDQ1V7dq1NXjwYP3++++uaYcOHVJKSopq1aolf39/devWTVu3bi13vcaMGaPg4GDVqFFDAwcO1G+//XbKbQGg8hBGgItAkyZN9Ouvv2rDhg365ZdftHbtWrVu3VqHDh3SP//5T02cOLFC8+ncubOOHj2qtWvXSpI++ugjNW3aVL1799Znn33m+hBfuXKlIiIiFBERUWIeCxYsUL169TR69Gjt27fPLWz8+uuveu655/T6669r9erV2rVrl/7xj3+4jV+5cqV++OEHrVy5Uq+++qpmzpypmTNnuqb369dP69at03vvvafMzEwZY3T99de7BZY/euuttzRq1Cj9+9//1rp16xQaGqrJkydXaHsAqByEEeAiUKtWLb366qtKSUlRhw4dlJKSoi5duugf//iHhgwZou3bt6tNmzaKjo7W22+/XeZ8mjRpoksvvdR1FGTVqlVKSEhQSEiI6tevr8zMTFd78VGRk11yySXy9vZWjRo1FBISopCQENe033//Xenp6WrXrp3atm2rIUOGKCMjo8S6TJw4Uc2bN1f37t2VnJzs6rN161a99957evnll3XVVVcpJiZGs2fP1p49e7Rw4cJS65kwYYIGDhyogQMHqlmzZvrXv/6lqKioim5aAJWAMAJcJG644QZ9/fXX2rZtm0aNGqUPP/xQX331le666y7dcsstmjBhgubPn6+BAwdq//79Zc7nj9eNrFq1SomJiZKkhIQErVq1SseOHdNnn31WZhgpj7+/vxo3bux6HhoaWqKWli1bytvbu9Q+3333napUqaKOHTu6pteuXVvNmjVznZY62XfffefWX5Li4+M9rh3A6SOMABeh/Px83XfffZo6daq2bdum48ePKyEhQc2aNVPTpk312WeflTm2+LqRn3/+WRs2bFBCQoKkE2Fk5cqV+vTTT1VQUOC6eNUTVatWdXvucDhkjDlln6KiIo+XBeDcQRgBLkL/+te/1LVrV7Vt21aFhYWuC1KlE6dKCgsLyxzbuXNn5eXlafz48WrSpImCgoIkSZ06ddLnn3+uDz74wHU6pyw+Pj7lLuN0tWjRQsePH3cLUz///LO2bNlS5qmXFi1alAhfa9asqfTaAJSNMAJcZL799lvNnTtXo0ePliQ1b95cXl5eeuWVV7R48WJt3rxZ7du3L3N8o0aNVL9+fb344ouuoyKSFB4errCwME2bNu2Up2giIiK0evVq7dmzRwcPHqycFdOJa1p69uypQYMG6eOPP9aXX36pO+64Q5deeql69uxZ6pgHHnhA06dP14wZM/T9999r5MiR+uabbyqtJgCnRhgBLiLGGN11110aP368qlWrJkny8/PTzJkzNXr0aA0cOFATJ04s96iGdOLoyJEjR1zXixRLSEjQkSNHThlGRo8erR07dqhx48aqW7fuGa3TyWbMmKG4uDh1795d8fHxMsbo/fffL3F6p1ifPn30z3/+U8OGDVNcXJx27type++9t1JrAlA+hzn5hCwAAMCfiCMjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAq/4fEeYldgsA9CQAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "fig3, ax3 = plt.subplots()\n", + "\n", + "data = []\n", + "for key in msg_df:\n", + "\n", + " vsdf = msg_df[key].loc[(msg_df[key]['nodeType'] == 'builder')]\n", + " data.append(vsdf['bytesOut'].values[0]/1024/1024/1024)\n", + "\n", + "ax3.bar([1,2],data)\n", + "\n", + "ax3.set_xticks([1,2])\n", + "ax3.set_xticklabels([0,75])\n", + "ax3.set_title(\"GBs sent by the builder per sampling process\")\n", + "ax3.set_xlabel(\"% Withhold\")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "36b2f17e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0, '% Withhold')" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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AJjN5U+7JCYmKj8/377k5OS4uiSYxGq1qlOnTpKkTp06ETwA4Abh1PARFBQkSTp27JhD+7Fjx+zbLubp6amAgACHBQAAuC+nho/w8HAFBQVp3bp19raCggJ988036tatmzNPBQAAaqkqj/k4c+aMDhw4YF/PysrSjh07VL9+fbVo0UITJkzQ9OnT1bp1a/ujtsHBwYqLi3Nm3QAAoJaqcvhIT09XTEyMfT0hIUGSNHz4cM2dO1cvvviizp49qzFjxuj06dO66667tHr1aub4AAAAkq4hfERHR1eYmbI8i8WiadOmadq0addVGAAAcE8uf9oFAADcWAgfAADAVIQPAABgKsIHAAAwFeEDAACYivABAABMRfgAAACmInwAAABTET4AAICpCB8AAMBUhA8AAGAqwgcAADAV4QMAAJiK8AEAAExF+AAAAKYifAAAAFMRPgAAgKkIHwAAwFSEDwAAYCrCBwAAMBXhAwAAmIrwAQAATEX4AAAApiJ8AAAAUxE+AACAqQgfAADAVIQPAABgKsIHAAAwFeEDAACYivABAABMRfgAAACmInwAAABTET4AAICpCB8AAMBUhA8AAGAqp4cPm82mSZMmKTw8XN7e3mrZsqVeffVVGYbh7FMBAIBaqI6zD/jmm29q1qxZmjdvnm677Talp6dr5MiRCgwM1DPPPOPs0wEAgFrG6eFj48aN6tevn/r06SNJCgsL06JFi7RlyxZnnwoAANRCTr/t0r17d61bt0779++XJH377bf66quvFBsb6+xTAQCAWsjpVz5eeuklFRQUKCIiQlarVTabTa+99poeeeSRSvuXlJSopKTEvl5QUODskgAAQA3i9CsfH3/8sT766CMtXLhQ27Zt07x58zRjxgzNmzev0v5JSUkKDAy0LyEhIc4uCQAA1CBODx8vvPCCXnrpJQ0ZMkRRUVF69NFH9dxzzykpKanS/omJicrPz7cvOTk5zi4JAADUIE6/7VJUVCQPD8dMY7VaVVpaWml/T09PeXp6OrsMAABQQzk9fDz44IN67bXX1KJFC912223avn273n77bT3++OPOPhUAAKiFnB4+3n33XU2aNElPPfWU8vLyFBwcrLFjx+qVV15x9qkAAEAt5PTw4e/vr+TkZCUnJzv70AAAwA3wbhcAAGAqwgcAADAV4QMAAJiK8AEAAExF+AAAAKYifAAA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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig3, ax3 = plt.subplots()\n", + "\n", + "data = []\n", + "for key in msg_df:\n", + "\n", + " vsdf = msg_df[key].loc[(msg_df[key]['nodeType'] == 'validator')]\n", + " data.append(vsdf['bytesOut']/1024/1024)\n", + "\n", + "ax3.boxplot(data)\n", + "\n", + "ax3.set_xticklabels([0,75])\n", + "ax3.set_title(\"MBs sent per validator\")\n", + "ax3.set_xlabel(\"% Withhold\")" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "874a8373", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0, '% Withhold')" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhYAAAHHCAYAAADjzRHEAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA/DklEQVR4nO3dfVhUdf7/8ReMciugqQgqCYEGCmViWRqJm623JaGZmXlTaaVWppbaby01U7Msv6up1W5ma9qNoRXetFZSVNQamjflDZqYq3ibCgpCzJzfH17MOoI6yIGR4fm4Lq6Yc97nzHtgbF58zjmf42EYhiEAAAATeLq6AQAA4D4IFgAAwDQECwAAYBqCBQAAMA3BAgAAmIZgAQAATEOwAAAApiFYAAAA0xAsAACAaQgWACokMTFRiYmJrm7DZSZNmiQPDw9Xt2Gq7OxseXh46J133nF1K6iGCBaoFO+88448PDzk4eGhb7/9ttR6wzAUFhYmDw8P9ezZ02FdyXYlX/7+/mrZsqWmTp2q/Pz8qnoJpjtw4IAmTZqkn3/+2dWtXBHy8/M1adIkpaWluboVACaq5eoG4N58fHy0ZMkS3XrrrQ7Lv/76a/33v/+Vt7d3mdvdcccdGjhwoCTp1KlTSk9P18SJE7Vp0yZ99NFHld53ZThw4IAmT56s8PBwtW7d2tXtuFx+fr4mT54sSTV6xANwNwQLVKru3bvro48+0t///nfVqvW/t9uSJUsUHx+vo0ePlrldixYtNGDAAPvjRx99VEVFRUpJSdGZM2fk4+NT6b3XFPn5+fLz83N1G5fl9OnT8vf3d3UbpjEMQ2fOnJGvr6+rWwEuG4dCUKnuu+8+HTt2TGvXrrUvKyoq0rJly9S/f/9y7SskJEQeHh4OASUrK0u9e/dWSEiIfHx81LRpU/Xr108nT5686L6c3W7x4sWKj4+Xr6+vrrrqKvXr10/79u1zqElMTFRsbKx+/fVXderUSX5+fmrSpIlmzpxpr0lLS9ONN94oSRoyZIj9MM/FjmGXHLvfvn27+vbtq8DAQNWvX19PPvmkzpw5U6q+PL1mZmbqtttuk5+fn5599tkL9nDw4EENGTJETZs2lbe3t0JDQ9WrVy9lZ2dfcBtJOnz4sB566CE1atRIPj4+uv7667Vo0SL7+uzsbDVs2FCSNHnyZPvPY9KkSRfcZ8nhta+//lrDhw9XcHCwmjZtal+/evVqJSQkyN/fXwEBAerRo4d++eWXUvv56KOP1LJlS/n4+Cg2NlbLly/X4MGDFR4ebq9JS0uTh4dHqcM0zp57sHDhQv3lL39RcHCwvL291bJlS82fP79UXXh4uHr27KnPP/9cbdu2la+vr954440L7teZ91qJS/0OSpw4cUKDBw9WUFCQ6tatq0GDBunEiRNlPv/27dvVp08fXXXVVfLx8VHbtm316aefXvRngZqHEQtUqvDwcN1yyy1aunSpunXrJunsB8DJkyfVr18//f3vfy9zuzNnzthHM06fPq3vvvtOixYtUv/+/e3BoqioSF26dFFhYaEef/xxhYSEaP/+/UpNTdWJEycUFBRU5r6d3e7FF1/UxIkT1bdvXz388MM6cuSI5syZo9tuu00bN25U3bp17fs8fvy4unbtquTkZPXt21fLli3TuHHjFBcXp27duikmJkZTpkzRc889p2HDhikhIUGS1L59+0v+DPv27avw8HBNnz5dP/zwg/7+97/r+PHjevfdd+015en12LFj6tatm/r166cBAwaoUaNGF3zu3r1765dfftHjjz+u8PBwHT58WGvXrtXvv//u8EF8roKCAiUmJmrXrl0aOXKkIiIi9NFHH2nw4ME6ceKEnnzySTVs2FDz58/XY489prvvvlvJycmSpOuuu+6SP4/hw4erYcOGeu6553T69GlJ0r/+9S8NGjRIXbp00UsvvaT8/HzNnz9ft956qzZu3GjvdeXKlbr33nsVFxen6dOn6/jx43rooYfUpEmTSz5vecyfP1+tWrXSXXfdpVq1aumzzz7T8OHDZbPZNGLECIfaHTt26L777tMjjzyioUOH6tprr73ovi/1XpOc+x1IZ0dIevXqpW+//VaPPvqoYmJitHz5cg0aNKjU8/7yyy/q0KGDmjRpovHjx8vf318ffvihkpKS9PHHH+vuu+826aeHas8AKsHChQsNScb69euNuXPnGgEBAUZ+fr5hGIZxzz33GJ06dTIMwzCaNWtm9OjRw2FbSWV+JSUlGWfOnLHXbdy40ZBkfPTRR+XqzZntsrOzDYvFYrz44osOy7ds2WLUqlXLYXnHjh0NSca7775rX1ZYWGiEhIQYvXv3ti9bv369IclYuHChU30+//zzhiTjrrvuclg+fPhwQ5KxadOmy+51wYIFl3z+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GYah7t27O4SPc3344YeaNGmSpk2bpp9++kmhoaGaN2+eUz8PAOYgWADVTL169bRo0SINHDhQN910kwYOHKguXbpo7NixGjlypPbs2aMbbrhBsbGxWrZs2QX307x5czVp0sQ+OpGWlqaOHTsqJCREV199tTIyMuzLS0YrznfVVVfJYrEoICBAISEhCgkJsa/7888/tWDBArVt21Zt2rTRyJEj9eWXX5Z6LXPnzlV0dLR69uypHj162GuysrL06aef6h//+IcSEhJ0/fXX67333tP+/fu1YsWKMvuZPXu2HnroIT300EO69tprNXXqVLVs2dLZHy0AExAsgGro7rvv1pYtW7Rr1y5NmjRJX3/9tTZv3qxhw4apX79+mj17tj7++GM99NBDOnz48AX3c+55FmlpaUpMTJQkdezYUWlpaSooKNCPP/54wWBxMX5+foqMjLQ/Dg0NLdVLq1atZLFYyqzZtm2batWqpXbt2tnX169fX9dee6390M/5tm3b5lAvSbfccku5ewdw+QgWQDVXWFio4cOH64033tCuXbtUXFysjh076tprr1WLFi30448/XnDbkvMsjh07po0bN6pjx46SzgaLdevW6fvvv1dRUZH9xM3yqF27tsNjDw8PGYZxyRqbzVbu5wJw5SBYANXc1KlT1bVrV7Vp00ZWq9V+MqZ09nCE1Wq94LadOnXS6dOn9eqrr6p58+YKDg6WJN122236z3/+o9WrV9sPmVyIl5fXRZ/jcsXExKi4uNghGB07dkw7duy44OGNmJiYUkHqhx9+ML03ABdGsACqsV9//VUffPCBpkyZIkmKjo6Wp6en/vnPf2rlypXavn27brzxxgtuf8011+jqq6/WnDlz7KMVkhQWFqbGjRvrzTffvORhkPDwcH3zzTfav3+/jh49as4L09lzQHr16qWhQ4fq22+/1aZNmzRgwAA1adJEvXr1KnObJ598Um+//bYWLlyonTt36vnnn9cvv/xiWk8ALo1gAVRThmFo2LBhevXVV+Xv7y9J8vX11TvvvKMpU6booYce0ty5cy862iCdHbXIy8uzn19RomPHjsrLy7tksJgyZYqys7MVGRmphg0bVug1nW/hwoWKj49Xz549dcstt8gwDK1atarUIZQS9957ryZOnKhnnnlG8fHx2rt3rx577DFTewJwcR7G+Qc9AQAALhMjFgAAwDQECwAAYBqCBQAAMA3BAgAAmIZgAQAATEOwAAAApiFYAAAA0xAsAACAaQgWAADANAQLAABgGoIFAAAwDcECAACY5v8DJab7xkMFdtkAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig3, ax3 = plt.subplots()\n", + "\n", + "data = []\n", + "for key in msg_df:\n", + "\n", + " vsdf = msg_df[key].loc[(msg_df[key]['nodeType'] == 'regular')]\n", + " data.append(vsdf['bytesOut']/1024/1024)\n", + "\n", + "ax3.boxplot(data)\n", + "\n", + "\n", + "ax3.set_xticklabels([0,75])\n", + "ax3.set_title(\"MBs sent per slot regular node\")\n", + "ax3.set_xlabel(\"% Withhold\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/simulator/python/analysis_withhold.ipynb b/simulator/python/analysis_withhold.ipynb new file mode 100644 index 00000000..594575ad --- /dev/null +++ b/simulator/python/analysis_withhold.ipynb @@ -0,0 +1,352 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f2905ced", + "metadata": {}, + "source": [ + "# DAS evaluation builder withholding attack\n", + "\n", + "## DAS protocol\n", + "\n", + "* The network is formed of a single builder that is generating the block with all samples and `N` nodes distributed between validators and regular nodes.\n", + "* Builder knows all the validators\n", + "* All nodes have a unique 256 bits identifier, following the Kademlia procotol used in DEVP2P.\n", + "* We assume DAS protocol works on top of Kademlia DHT. We reuse identifiers and we can use the DHT to discover peers. \n", + "However it is not necessary to use DEVP2P or Kademlia as long as we have nodes with random uniformly distributed identifiers and a way to discover nodes and resolve nodes identifiers to connection parameters.\n", + "* Builder divides the hash space into 512*512 sample-specific regions, according to the block matrix.\n", + "* Builder transforms the 2D block matrix into a two 1D line of samples (1 line row-wise, and 1 line column-wise, i.e, 1 line row-wise means that after all samples in the first row we continue by the first sample of the second row. 1 line column-wise we mean we first start with all the samples of the first column and then we continue with the samples of the second column)\n", + "* We assign each sample with a 256 identifier in the hash space with the double 1D aligment. Every sample is defined by a double id in the hash space, one following row-wise and another column-wise order. This way when fetching rows we can find colocated samples, but also when fetching columns.\n", + "* Builder chooses the redundancy factor `redundancy` - the higher `redundancy` the higher overhead but the more resistant the scheme becomes to malicious validators.\n", + "* The region of samples is defined as all the validators such that `dict(c, v) <= ((2^256 -1) * redundancy * 2) / N_validators `\n", + "* The validator pushes each sample to all the validators within the sample's region (Note that it's done in batches - i.e., the builder connects to each validator and gives them all the samples they should hold).\n", + "\n", + "* When a new block is released, nodes got the samples from builder, according to the redundancy parameter and their identifier. \n", + "After getting the assigned samples, they start the sampling process.\n", + "* There are two types of sampling processes: validator sampling and random sampling.\n", + "* Validator sampling consists in getting 2 rows and 2 columns of the block matrix.\n", + "* Random sampling consists in gettting 75 random samples from any row or column.\n", + "* One of the rows and one of the columns to download is choosen by selecting the row or column that the node is already in possession of the highest number of samples from the builder.\n", + "* The second row and column to download is selected randomly.\n", + "* Validators perform validator sampling and random sampling. \n", + "* Non-validator (regular) nodes they just perform random sampling.\n", + "* The validator sampling and random sampling follows the same process with the only difference of the selection of the samples to obtain. \n", + "We call sampling nodes, the nodes requesting samples, and serving nodes the nodes replying with samples:\n", + " - Sampling nodes select a set of replying nodes from a list of known nodes that are within the redundancy range following the id space for the samples requesting (how all nodes of the network are discovered is not included in this initial report, but will be in the following reports. Validators are supposed to know all other validators by default).\n", + " - Sampling nodes send samples requests to the replying nodes selected. Samples requests include the wanted samples (all samples pending to be received are included in the requests).\n", + " - Replying nodes reply with the samples requested they have, and also with known nodes to the same distance, from their Kademlia routing table. This way nodes can easily discover kew nodes in the network.\n", + " - Only Alpha requests can be sent at the same time. After sending initially Alpha requests, a response must be received after sending the next request. Alpha is a configurable parameter.\n", + " - For validator sampling the process is stopped after getting half of the row or column. We consider is not necessary to obtain the rest of the samples, since can be obtained reconstructing.\n", + " - Random sampling process stops when all samples are obtained.\n", + "\n", + "## Malicious builder\n", + "\n", + "* Builder withholds some specific samples from the matrix, without sending them to validators.\n", + "\n", + "\n", + "## Simulation parameters\n", + "\n", + "* Number of nodes: 15000\n", + "* Number of attackers: Range from 0% to 90%\n", + "* Number of validators: 50% nodes are validators\n", + "* Redundancy parameter: 2\n", + "* Latency between nodes: 5ms - 125ms\n", + "* Number of samples per block : 512x512\n", + "* Sample size: 512 bytes\n", + "* Blocks: 1 blocks simulation.\n", + "* Number of random samples fetch: 75. \n" + ] + }, + { + "cell_type": "markdown", + "id": "edd080e7", + "metadata": {}, + "source": [ + "The following cell is just loading traces files into a dataframe" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "id": "2983fa0b", + "metadata": {}, + "outputs": [], + "source": [ + "from matplotlib import pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "ops_path = {'DAS': '../logsDasEvil0.5000/operation.csv', \n", + " 'Evil-0.25': '../logsDasBuilderEvil5000/operation.csv'\n", + " }\n", + "msgs_path = {'DAS': '../logsDasEvil0.5000/messages.csv', \n", + " 'Evil-0.25': '../logsDasBuilderEvil5000/messages.csv'\n", + " }\n", + "\n", + "\n", + "builder_address = '83814183170291850251680823880522715558189094423550585243365458794131648333116'\n", + "\n", + "op_df={}\n", + "msg_df={}\n", + "for key in ops_path:\n", + " op_df[key] = pd.read_csv(ops_path[key],index_col=False,low_memory=False)\n", + "for key in msgs_path:\n", + " msg_df[key] = pd.read_csv(msgs_path[key],index_col=False,low_memory=False)\n" + ] + }, + { + "cell_type": "markdown", + "id": "c6cc3d58", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "0c418d95", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0, '% Withhold')" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAh8AAAHHCAYAAAAf2DoOAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA490lEQVR4nO3deXyM5/7/8fckJBKy2CUVpGqJvYJ8UUtKpZaqw6F6qFhKW1RTp5vWGq2lddr8ilJd6KF6qj3KOVVLaWy1NIJutlBUFa0tQSIhuX9/eGSOMUkkTK4JXs/HI492rvu67+tz3zMZ79z3dc/YLMuyBAAAYIiHuwsAAAB3FsIHAAAwivABAACMInwAAACjCB8AAMAowgcAADCK8AEAAIwifAAAAKMIHwAAwCjCx23o0KFDstlsmjdvnr1t/Pjxstls+VrfZrNp/PjxhVMc8m3evHmy2Ww6dOiQu0u5IUlJSerQoYMCAgJks9m0ZMkSY2P3799fpUqVylffovh679+/v6pVq+buMpwsWrRIZcqU0fnz591dSqFbu3atbDab1q5dm+91Ll26pJCQEL3zzjuFV9htgvDhZl27dpWvr6/OnTuXa58+ffrIy8tLp06dMlhZwe3atUvjx4+/Zf+xvFHh4eEaOnSou8socqKjo/Xjjz/qtdde0/z589WkSZN8r/v7779r/Pjx2rlzZ+EV6Ga32j5mZmZq3Lhxevrpp/Md7O40xYsX18iRI/Xaa6/p4sWL7i6nSCN8uFmfPn2UlpamL774IsflqampWrp0qR588EGVLVv2hscZPXq00tLSbnj9/Ni1a5cmTJhwR4WPY8eOaceOHercubO7SylS0tLStHnzZg0aNEjDhw9X3759Vbly5Xyv//vvv2vChAlG/mFOS0vT6NGjC32ca+W1j++995727t1rvKa8/Pe//9XevXs1ZMgQd5dSpA0YMEAnT57UwoUL3V1KkUb4cLOuXbvKz88v1xfq0qVLdeHCBfXp0+emxilWrJhKlChxU9twl9TU1AL1v3DhQiFV4mz58uUqUaKE7r//fmNj3gr+/PNPSVJgYKB7C8mHEiVKqFixYu4uw0Hx4sXl7e3t7jIczJ07Vy1bttRdd93l7lKKtMDAQHXo0MHhsjecET7czMfHR927d9eaNWv0xx9/OC1fuHCh/Pz81LVrV50+fVrPPfec6tevr1KlSsnf318dO3bU999/f91xcprzkZ6ermeffVbly5e3j/Hbb785rXv48GENHTpUtWrVko+Pj8qWLauePXs6nOGYN2+eevbsKUmKjIyUzWZzul76zjvvqG7duvL29lZwcLCGDRums2fPOozVtm1b1atXT4mJiWrdurV8fX318ssv57pf2df2Dxw4oE6dOsnPz88e1C5cuKC///3vCgkJkbe3t2rVqqVp06bp6i9y7t69uxo3buywzYceekg2m03/+c9/7G1bt26VzWbT8uXLHfouW7ZMkZGR8vHxcejbqVMnlS5dWiVLllSDBg30//7f/3NY75tvvlGrVq1UsmRJBQYG6uGHH9bu3btz3c9suc1PqFatmvr3729/nD1fZOPGjRoxYoTKly+vwMBAPfHEE8rIyNDZs2fVr18/lS5dWqVLl9YLL7zgcFyy5w1NmzZNc+bMUfXq1eXt7a2mTZsqISEhzxrHjx+vqlWrSpKef/552Ww2h/kLR48e1cCBA1WxYkV5e3urbt26+vDDD+3L165dq6ZNm0q68ldk9mvp6jfz/Bzj7LG6deumUqVKqXz58nruueeUmZmZ5zHN/l3Zv3+/+vfvr8DAQAUEBGjAgAFOQTgtLU0jRoxQuXLl7L9DR48eve48kuvt47VzPq5+PmbOnKm7775bvr6+6tChg44cOSLLsjRx4kRVrlxZPj4+evjhh3X69GmncZcvX25/3fn5+alz5876+eefc60z28WLF7VixQq1b9/eadnXX3+t++67T4GBgSpVqpRq1arl9Dubnp6ucePG6Z577pG3t7dCQkL0wgsvKD093Wl7CxYsULNmzeTr66vSpUurdevWWrVqlUOfgryX7Nq1S5GRkfL19dVdd92l119/3WnM3377Td26dVPJkiVVoUIFPfvssznWlpSUpB49eqhSpUoqUaKEKleurN69eys5Odmh3wMPPKCNGzfm+BzgiqIV9+9Qffr00UcffaRFixZp+PDh9vbTp09r5cqVevTRR+Xj46Off/5ZS5YsUc+ePRUaGqoTJ07o3XffVZs2bbRr1y4FBwcXaNzHH39cCxYs0N/+9je1aNFC33zzTY6XDxISErRp0yb17t1blStX1qFDhzRr1iy1bdtWu3btkq+vr1q3bq0RI0bo7bff1ssvv6ywsDBJsv93/PjxmjBhgtq3b6+nnnpKe/fu1axZs5SQkKBvv/1WxYsXt4936tQpdezYUb1791bfvn1VsWLFPPfj8uXLioqK0n333adp06bJ19dXlmWpa9euio+P16BBg9SoUSOtXLlSzz//vI4ePaq33npLktSqVSstXbpUKSkp8vf3l2VZ+vbbb+Xh4aENGzaoa9eukqQNGzbIw8NDLVu2tI976dIlrV69WpMmTbK3ff311+rSpYuCgoL0zDPPqFKlStq9e7e+/PJLPfPMM5Kk1atXq2PHjrr77rs1fvx4paWlafr06WrZsqW2b9/u0omGTz/9tCpVqqQJEyZoy5YtmjNnjgIDA7Vp0yZVqVJFkyZN0ldffaU33nhD9erVU79+/RzWX7hwoc6dO6cnnnhCNptNr7/+urp3765ffvnF4Tm7Wvfu3RUYGKhnn31Wjz76qDp16mSfI3DixAn93//9n2w2m4YPH67y5ctr+fLlGjRokFJSUhQTE6OwsDDFxsZq7NixGjJkiFq1aiVJatGiRb6PsXRljkJUVJQiIiI0bdo0rV69Wv/4xz9UvXp1PfXUU9c9dr169VJoaKgmT56s7du36/3331eFChU0depUe5/+/ftr0aJFeuyxx/R///d/WrduXb4uwV1vH3Pz8ccfKyMjQ08//bROnz6t119/Xb169dL999+vtWvX6sUXX9T+/fs1ffp0Pffccw6hbv78+YqOjlZUVJSmTp2q1NRUzZo1S/fdd5927NiR5+suMTFRGRkZTkH9559/VpcuXdSgQQPFxsbK29tb+/fv17fffmvvk5WVpa5du2rjxo0aMmSIwsLC9OOPP+qtt97Svn37HCYiT5gwQePHj1eLFi0UGxsrLy8vbd26Vd988406dOggqWDvJWfOnNGDDz6o7t27q1evXvr888/14osvqn79+urYsaOkKwGyXbt2+vXXXzVixAgFBwdr/vz5+uabbxz2NSMjQ1FRUUpPT7f/Xh09elRffvmlzp49q4CAAHvf8PBwWZalTZs2qUuXLnk+p3csC253+fJlKygoyGrevLlD++zZsy1J1sqVKy3LsqyLFy9amZmZDn0OHjxoeXt7W7GxsQ5tkqy5c+fa28aNG2dd/XTv3LnTkmQNHTrUYXt/+9vfLEnWuHHj7G2pqalONW/evNmSZP3zn/+0t3322WeWJCs+Pt6h7x9//GF5eXlZHTp0cKh/xowZliTrww8/tLe1adPGkmTNnj3bacycREdHW5Ksl156yaF9yZIlliTr1VdfdWj/61//atlsNmv//v2WZVlWQkKCJcn66quvLMuyrB9++MGSZPXs2dOKiIiwr9e1a1fr3nvvddjWmjVrLEnWwYMHLcu68jyGhoZaVatWtc6cOePQNysry/7/jRo1sipUqGCdOnXK3vb9999bHh4eVr9+/extc+fOddi+ZVlOz022qlWrWtHR0U7rRkVFOYzdvHlzy2azWU8++aS97fLly1blypWtNm3a2NuyX0Nly5a1Tp8+bW9funSpJcn673//61TD1bLXf+ONNxzaBw0aZAUFBVknT550aO/du7cVEBBgf61lPy9Xv4aza83PMc5+XVz9e2FZlnXvvfda4eHhDm3XHtPs35WBAwc69PvLX/5ilS1b1v44MTHRkmTFxMQ49Ovfv3+uz9PVctvH7PqrVq1qf5x9PMuXL2+dPXvW3j5q1ChLktWwYUPr0qVL9vZHH33U8vLysi5evGhZlmWdO3fOCgwMtAYPHuwwzvHjx62AgACn9mu9//77liTrxx9/dGh/6623LEnWn3/+meu68+fPtzw8PKwNGzY4tGe/v3377beWZVlWUlKS5eHhYf3lL39xep/Lfm5v5L3k6veo9PR0q1KlSlaPHj3sbXFxcZYka9GiRfa2CxcuWPfcc4/D+9mOHTssSdZnn32W57GyLMv6/fffLUnW1KlTr9v3TsVllyLA09NTvXv31ubNmx0uZSxcuFAVK1ZUu3btJEne3t7y8LjylGVmZurUqVP205zbt28v0JhfffWVJGnEiBEO7TExMU59r76kcOnSJZ06dUr33HOPAgMD8zXu6tWrlZGRoZiYGHv9kjR48GD5+/tr2bJlDv29vb01YMCAguyO01+yX331lTw9PZ327+9//7ssy7JfPrn33ntVqlQprV+/XtKVMxyVK1dWv379tH37dqWmpsqyLG3cuNH+1+nVY9SpU8f+F+OOHTt08OBBxcTEOM11yL7kdezYMe3cuVP9+/dXmTJl7MsbNGigBx54wP68uMqgQYMcLrdFRETIsiwNGjTI3ubp6akmTZrol19+cVr/kUceUenSpe2Ps49BTn2vx7Is/fvf/9ZDDz0ky7J08uRJ+09UVJSSk5Ov+3rKzzG+2pNPPunwuFWrVvmuPad1T506pZSUFEnSihUrJMnpTqenn346X9u/ET179nT4CzsiIkKS1LdvX4d5KxEREcrIyNDRo0clXTlbdPbsWT366KMOx93T01MRERGKj4/Pc9zsO+2ufi1I/5vTs3TpUmVlZeW47meffaawsDDVrl3bYezseVLZYy9ZskRZWVkaO3asw/uE9L/ntqDvJaVKlVLfvn3tj728vNSsWTOH18BXX32loKAg/fWvf7W3+fr6Ok2szT7uK1euvO48tOzjdPLkyTz73ckIH0VE9jyF7Imnv/32mzZs2KDevXvL09NT0pXTl2+99ZZq1Kghb29vlStXTuXLl9cPP/zgdM3xeg4fPiwPDw9Vr17dob1WrVpOfdPS0jR27Fj73Inscc+ePZuvcQ8fPpzjtr28vHT33Xfbl2e766675OXlle99KVasmNOdFIcPH1ZwcLD8/Pwc2rMvA2WP6enpqebNm2vDhg2SroSPVq1a6b777lNmZqa2bNmiXbt26fTp007hY9myZQ6n2A8cOCBJqlevXq615nYssms7efKkSyfMVqlSxeFx9htoSEiIU/uZM2euu372m2pOfa/nzz//1NmzZzVnzhyVL1/e4Sc7bOY07+lq+TnG2UqUKKHy5cs71Z/f2q+379m/Q6GhoQ797rnnnnxt/0YU5PmU/ldrUlKSJOn+++93OvarVq267nHPZl01L0i6Ek5btmypxx9/XBUrVlTv3r21aNEihyCSlJSkn3/+2WncmjVrSvrfc37gwAF5eHioTp06uY5f0PeSypUrO4XSa18Dhw8f1j333OPU79oxQkNDNXLkSL3//vsqV66coqKiNHPmzBzfA7OPU34/W+lOxJyPIiI8PFy1a9fWJ598opdfflmffPKJLMtyuMtl0qRJGjNmjAYOHKiJEyeqTJky8vDwUExMTK5/dbjC008/rblz5yomJkbNmze3f2hU7969C2Xcq8+05MfVZ4RuxH333We/L3/Dhg165ZVXFBgYqHr16mnDhg32OSdXh4+DBw9qz549mjVr1g2P60rXTqLMlh1c89N+7T8sea2fU9/ryX6t9O3bV9HR0Tn2adCgQYG3m5vcar/Z9W9k312lIM+n9L9as4/9/PnzValSJad+17vbJ/s2/zNnzjgEfR8fH61fv17x8fFatmyZVqxYoU8//VT333+/Vq1aJU9PT2VlZal+/fp68803c9z2tcHJlVz9HP7jH/9Q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BQXpr3/9q7Zv364vv/xSmZmZOn78uCSpTJky8vLycl3lAADgllTgOR9r165VZGSkU3t0dLTGjx+f69dBx8fHq23bttfdfkpKigICApScnMxlFwAAbhEF+fe7wGc+2rZtq7zyCp/WDgAA8sK32gIAAKMIHwAAwCjCBwAAMIrwAQAAjCJ8AAAAowgfAADAKMIHAAAwivABAACMInwAAACjCB8AAMAowgcAADCK8AEAAIwifAAAAKMIHwAAwCjCBwAAMIrwAQAAjCJ8AAAAowgfAADAKMIHAAAwivABAACMInwAAACjCB8AAMAowgcAADCK8AEAAIwifAAAAKMIHwAAwCjCBwAAMIrwAQAAjCJ8AAAAowgfAADAKMIHAAAwivABAACMInwAAACjCB8AAMAowgcAADCK8AEAAIwifAAAAKMIHwAAwCjCBwAAMIrwAQAAjCJ8AAAAowgfAADAKMIHAAAwivABAACMInwAAACjCB8AAMAowgcAADCqmLsLAADcelJTU7Vnz548+6SlpenQoUOqVq2afHx8rrvN2rVry9fX11UloggjfAAACmzPnj0KDw936TYTExPVuHFjl24TRRPhAwBQYLVr11ZiYmKefXbv3q2+fftqwYIFCgsLy9c2cWcocPhYv3693njjDSUmJurYsWP64osv1K1bN/tyy7I0btw4vffeezp79qxatmypWbNmqUaNGq6sGwDgRr6+vvk+SxEWFsYZDTgo8ITTCxcuqGHDhpo5c2aOy19//XW9/fbbmj17trZu3aqSJUsqKipKFy9evOliAQDAra/AZz46duyojh075rjMsizFxcVp9OjRevjhhyVJ//znP1WxYkUtWbJEvXv3vrlqAQDALc+lt9oePHhQx48fV/v27e1tAQEBioiI0ObNm105FAAAuEW5dMLp8ePHJUkVK1Z0aK9YsaJ92bXS09OVnp5uf5ySkuLKkgAAQBHj9g8Zmzx5sgICAuw/ISEh7i4JAAAUIpeGj0qVKkmSTpw44dB+4sQJ+7JrjRo1SsnJyfafI0eOuLIkAABQxLg0fISGhqpSpUpas2aNvS0lJUVbt25V8+bNc1zH29tb/v7+Dj8AAOD2VeA5H+fPn9f+/fvtjw8ePKidO3eqTJkyqlKlimJiYvTqq6+qRo0aCg0N1ZgxYxQcHOzwWSAAAODOVeDwsW3bNkVGRtof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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "\n", + "fig3, ax3 = plt.subplots()\n", + "\n", + "data = []\n", + "for key in op_df:\n", + "\n", + " vsdf = op_df[key].loc[(op_df[key]['type'] == 'ValidatorSamplingOperation')]\n", + " data.append(vsdf['completion_time']/1000)\n", + "\n", + "ax3.boxplot(data)\n", + "\n", + "\n", + "ax3.set_ylim([0,12])\n", + "ax3.set_xticklabels([0,75])\n", + "ax3.set_title(\"Validator row/column fetching time (seconds)\")\n", + "ax3.set_xlabel(\"% Withhold\")" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "id": "95bea67e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0, '% Withhold')" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAh8AAAHHCAYAAAAf2DoOAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAABCEUlEQVR4nO3df3zN9f//8fsxzMw2jLEx22yYX5GJKNlQzK8k9A75kR8Vkh8Jvd9CKZFKflRUzLv0k5GUlF9R+Tnph4zRNj7y+8c2w9j2+v7Rd+ftONtsnL3ONrfr5XIunOfreZ6vxzk7P+7n9Xq+XsdiGIYhAAAAk5RwdgEAAOD2QvgAAACmInwAAABTET4AAICpCB8AAMBUhA8AAGAqwgcAADAV4QMAAJiK8AEAAExF+LgNDRgwQIGBgc4uo8gLDw9XeHi49XpCQoIsFouioqKcVlN2rq8T2SuOr4tNmzbJYrFo06ZNpq975syZCg0NVWZmpunrNltUVJQsFosSEhLyfJszZ87I3d1d33zzTcEVVogRPgpQ1hMy61KyZElVq1ZNAwYM0NGjR51dHoqRP//8U1OmTMnXmx9QUJKTkzVjxgyNHz9eJUrwMZMdb29vDR48WJMmTXJ2KU5R0tkF3A5efPFFBQUF6fLly9q2bZuioqL0448/6o8//lCZMmWcXR4cJCAgQJcuXVKpUqVMX/eff/6pqVOnKjw83O7b+3fffWd6Pbi9LVq0SOnp6Xr00UedXUqh9uSTT2rOnDnasGGD2rRp4+xyTEUkNUFkZKT69u2rwYMH6/3339ezzz6rQ4cOadWqVc4uDQ5ksVhUpkwZubi4OLsUG6VLl1bp0qWdXUauUlNTnV2CQ2VmZury5cvOLsNpFi9erK5du/Ll6gbq1q2rBg0aFLpdtWYgfDhBq1atJEmHDh2ytl25ckUvvPCCwsLC5OXlJXd3d7Vq1UobN260uW3WvIJZs2Zp4cKFCg4Olqurq+666y7t3LnTbl0rV65UgwYNVKZMGTVo0EArVqzItqbU1FSNHTtW/v7+cnV1VZ06dTRr1ixd/6PHFotFI0aM0BdffKF69erJzc1NLVq00O+//y5JWrBggUJCQlSmTBmFh4fnaTdASkqKRo0apcDAQLm6usrHx0f333+/du/ebe2zZcsW9ezZUzVq1JCrq6v8/f01evRoXbp0yWasAQMGqFy5cjp8+LA6d+6scuXKqVq1apo/f74k6ffff1ebNm3k7u6ugIAAffzxxza3z9pVtnnzZj3xxBPy9vaWp6en+vXrp3PnzuV6P7Kb85FVz9GjR9WtWzeVK1dOlStX1rPPPquMjAyb2585c0aPPfaYPD09Vb58efXv31+//vrrDeeRREVFqWfPnpKkiIgI626+rP3818/5yJoH8Pnnn2vq1KmqVq2aPDw81KNHDyUlJSktLU2jRo2Sj4+PypUrp4EDByotLc1uvR999JHCwsLk5uamihUr6l//+peOHDmS62MkSVOmTJHFYtGff/6p3r17q0KFCrr33nvzPe78+fNVs2ZNubm5qVmzZtqyZYvdfc1pX3xe50LMmjVLLVu2lLe3t9zc3BQWFqZly5bZ9ct6XSxdulT169eXq6urvv322xzHDQwMVOfOnfXjjz+qWbNmKlOmjGrWrKn//ve/dn3/+usv9ezZUxUrVlTZsmV199136+uvv7br93//93/q1q2b3N3d5ePjo9GjR2f7d5Ok7du3q0OHDvLy8lLZsmXVunVr/fTTTzZ98vK6zE58fLx+++03tWvXzm7Zp59+qrCwMHl4eMjT01MNGzbUW2+9ZdPn/PnzGjVqlPW9KCQkRDNmzLCbO5KZmam33npLDRs2VJkyZVS5cmV16NBBu3btsvZJT0/XSy+9ZH2fDAwM1PPPP2/3uOTn77F37161adNGbm5uql69uqZNm5btvJZdu3apffv2qlSpktzc3BQUFKTHH3/crt/999+vr776yu69trhjt4sTZL0RVqhQwdqWnJys999/X48++qiGDBmilJQUffDBB2rfvr127Nihxo0b24zx8ccfKyUlRU888YQsFotmzpyp7t2766+//rJu9v/uu+/08MMPq169epo+fbrOnDmjgQMHqnr16jZjGYahrl27auPGjRo0aJAaN26stWvXaty4cTp69KjefPNNm/5btmzRqlWrNHz4cEnS9OnT1blzZz333HN6++23NWzYMJ07d04zZ87U448/rg0bNuT6eDz55JNatmyZRowYoXr16unMmTP68ccftW/fPjVp0kSS9MUXX+jixYt66qmn5O3trR07dmju3Ln6v//7P33xxRc242VkZCgyMlL33XefZs6cqaVLl2rEiBFyd3fXv//9b/Xp00fdu3fXu+++q379+qlFixYK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pqpt27bavHmzdRdCXl6X2Tlz5oxKliypcuXK2bSXL19eqamp+v7773O87RdffKFWrVqpQoUKNs+Bdu3aKSMjQ5s3b5YkLV++XBaLRZMnT7YbI2vLZNZrdcyYMTbLx44dK0l2u67y+ve4++67rVuHsvr16dPH7r5K0urVq3X16tUc76/0vy3gp0+fzrVfccNuFxPMnz9ftWvXVlJSkhYtWqTNmzfL1dXVrt+SJUv0+uuvKzY21uYJe/0uAUmqUaOGzfWsJ3DWvITExERJUq1atexuW6dOHZs3z8TERPn5+dkEB+l/m+2zxspp3Vnhxt/fP9v2G82VmDlzpvr37y9/f3+FhYWpY8eO6tevn2rWrGntc/jwYb3wwgtatWqV3XhJSUk217P2/15fS/Xq1e12mXh5eWVb3/WPW7ly5eTr63tTh7JmV0+FChVs1puYmChfX1+VLVvWpl9ISEi+15dX+fk7ZmZmKikpSd7e3oqLi5NhGNk+tyTl+Wif65/XeR036/l4/WNTsmRJh5+nY/Xq1Zo2bZr27NljM08gu11v2b1Oc3P94y9l/7zICvHXuva12aBBAyUmJiokJMSurjp16thcj4uLk6Rcd+clJSWpQoUKeXpd5sewYcP0+eefKzIyUtWqVdMDDzygXr16qUOHDjb1/fbbb3avlywnT56U9M98OT8/P1WsWDHH9SUmJqpEiRJ2z5OqVauqfPnyN3xfk/L+97j+cW7durUefvhhTZ06VW+++abCw8PVrVs39e7d2+693/j/uxzzuzu3qCN8mKBZs2bWfZDdunXTvffeq969e2v//v3WbwcfffSRBgwYoG7dumncuHHy8fGRi4uLpk+fbjMxNUtOR1QYJkxaymndN1tTr1691KpVK61YsULfffedXnvtNc2YMUPR0dGKjIxURkaG7r//fp09e1bjx49XaGio3N3ddfToUQ0YMMBuspej67tVhe3olyw3+zhlZmbKYrFozZo12fa9/htvTq7fT+6oca+V0xv69ZN9s7NlyxZ17dpV9913n95++235+vqqVKlSWrx4sd1EZcn+/tyIM56PWa+V1157zW4eWZasx/lGr8uceHt7Kz09XSkpKTZfaHx8fLRnzx6tXbtWa9as0Zo1a7R48WL169dPS5YssdZ3//3367nnnst27Nq1a+f7Puf1Q92Rfw+LxaJly5Zp27Zt+uqrr7R27Vo9/vjjev3117Vt2zab53JWuKlUqVK+11OUET5MlhUoIiIiNG/ePE2YMEGStGzZMtWsWVPR0dE2L5bsNivmRUBAgKT/fdO51v79++36rlu3zu7NIjY21masguTr66thw4Zp2LBhOnnypJo0aaKXX35ZkZGR+v3333XgwAEtWbJE/fr1s94mt823tyouLk4RERHW6xcuXNCxY8fUsWPHAllfQECANm7cqIsXL9ps/Th48GCebm/mt6bg4GAZhqGgoKCb+jC41XGzno8HDx60+Rulp6crISFBd9xxh7Uta4vg+fPnbca4/ltvdpYvX64yZcpo7dq1Nt9WFy9enKf74wgBAQF2r1fJ/rUZEBCgP/74Q4Zh2DwXrr9tcHCwJMnT0zPbo1Gul9vrMiehoaGS/jnq5dq/hfTPYd9dunRRly5dlJmZqWHDhmnBggWaNGmSQkJCFBwcrAsXLtywtuDgYK1du1Znz57NcetHQECAMjMzFRcXZzP5+sSJEzp//vxNva8FBATk6T01y9133627775bL7/8sj7++GP16dNHn376qc1u4fj4eEk3niBe3DDnwwnCw8PVrFkzzZ4923ougKzUfW3K3r59u7Zu3XpT6/D19VXjxo21ZMkSm90S33//vXU/cZaOHTsqIyND8+bNs2l/8803ZbFYcn2juVUZGRl2u018fHzk5+dn3cyd3WNjGIbdIXqOtHDhQptdX++8847S09ML7LFo3769rl69qvfee8/alpmZaT1E+Ebc3d0l2X/IFoTu3bvLxcVFU6dOtftWaBiGzpw5U6DjNm3aVN7e3nrvvfes81AkaenSpXa70LI+bLPmCkj/POcWLlx4w3pcXFxksVhstpIkJCRo5cqV+b5vN6tjx47asWOHzftAamqqFi5cqMDAQOsck44dO+rvv/+2OQz44sWLdvczLCxMwcHBmjVrli5cuGC3vlOnTknK2+syJy1atJAkm0NeJdk9L0qUKGENJ1lj9urVS1u3btXatWvtxj1//rz17/3www/LMAxNnTrVrl/Wcyfri8K1R8hI0htvvCFJdkcr5UXHjh21bds27dixw9p26tQpLV261KbfuXPn7J7DWVuarn/8YmJi5OXlZT2i5nbBlg8nGTdunHr27KmoqCg9+eST6ty5s6Kjo/XQQw+pU6dOio+P17vvvqt69epl+yaRF9OnT1enTp1077336vHHH9fZs2c1d+5c1a9f32bMLl26KCIiQv/+97+VkJCgRo0a6bvvvtOXX36pUaNGWd/AC0JKSoqqV6+uHj16qFGjRipXrpzWrVunnTt36vXXX5f0zzep4OBgPfvsszp69Kg8PT21fPnyG84luRVXrlxR27Zt1atXL+3fv19vv/227r33XnXt2rVA1tetWzc1a9ZMY8eO1cGDBxUaGqpVq1bp7Nmzkm68ZaNx48ZycXHRjBkzlJSUJFdXV7Vp00Y+Pj4OrzU4OFjTpk3TxIkTrYe4enh4KD4+XitWrNDQoUP17LPPFti4pUuX1pQpU/T000+rTZs26tWrlxISEhQVFaXg4GCbx6p+/fq6++67NXHiROu35E8//dQmtOSkU6dOeuONN9ShQwf17t1bJ0+e1Pz58xUSEqLffvst3/fvZkyYMEGffPKJIiMjNXLkSFWsWFFLlixRfHy8li9fbj11+ZAhQzRv3jz169dPMTEx8vX11Ycffmg3h6hEiRJ6//33FRkZqfr162vgwIGqVq2ajh49qo0bN8rT01NfffVVnl6XOalZs6YaNGigdevW2UxeHjx4sM6ePas2bdqoevXqSkxM1Ny5c9W4cWPrt/5x48Zp1apV6ty5s/Uw19TUVP3+++9atmyZEhISVKlSJUVEROixxx7TnDlzFBcXpw4dOigzM1NbtmxRRESERowYoUaNGql///5auHChzp8/r9atW2vHjh1asmSJunXrZrPVLK+ee+45ffjhh+rQoYOeeeYZ66G2AQEBNs+JJUuW6O2339ZDDz2k4OBgpaSk6L333pOnp6fd1tPvv/9eXbp0ue3mfHCobQHKOswvu8OtMjIyjODgYCM4ONhIT083MjMzjVdeecUICAgwXF1djTvvvNNYvXq13eF/WYdzvvbaa3Zj6rrDRg3jn0M469ata7i6uhr16tUzoqOjsz2kMCUlxRg9erTh5+dnlCpVyqhVq5bx2muv2RyOl7WO6w+/y6mmrMMZv/jiixwfo7S0NGPcuHFGo0aNDA8PD8Pd3d1o1KiR8fbbb9v0+/PPP4127doZ5cqVMypVqmQMGTLE+PXXX7M9tNXd3d1uPa1btzbq169v1x4QEGB06tTJej3rb/bDDz8YQ4cONSpUqGCUK1fO6NOnj3HmzBm7MfNyqG129WQdbnqtU6dOGb179zY8PDwMLy8vY8CAAcZPP/1kSLI5RDgn7733nlGzZk3DxcXF5vDKnA61vf7vktPzNavWU6dO2bQvX77cuPfeew13d3fD3d3dCA0NNYYPH27s378/1zpzGi+/486ZM8f6emnWrJnx008/GWFhYUaHDh1s+h06dMho166d4erqalSpUsV4/vnnje+//z5Ph9p+8MEHRq1atQxXV1cjNDTUWLx4cbZ/u+xeF7m5/nmX5fq/VVb9PXr0MMqXL2+UKVPGaNasmbF69Wq72yYmJhpdu3Y1ypYta1SqVMl45plnjG+//TbbQ7B/+eUXo3v37oa3t7fh6upqBAQEGL169TLWr19vGEbeX5c5eeONN4xy5crZHKq8bNky44EHHjB8fHyM0qVLGzVq1DCeeOIJ49ixYza3TUlJMSZOnGiEhIQYpUuXNipVqmS0bNnSmDVrls2h4enp6cZrr71mhIaGGqVLlzYqV65sREZGGjExMdY+V69eNaZOnWoEBQUZpUqVMvz9/Y2JEycaly9ftllnfv4ev/32m9G6dWujTJkyRrVq1YyXXnrJ+OCDD2wOtd29e7fx6KOPGjVq1DBcXV0NHx8fo3PnzsauXbtsxtq3b5/1dAy3G4th3GanVQNyERUVpYEDB2rnzp3WScLOtHLlSj300EP68ccfdc899zi7nEItMzNTlStXVvfu3W12X8F8SUlJqlmzpmbOnKlBgwY5u5xCa9SoUdq8ebNiYmJuuy0fzPkAConrTxWfkZGhuXPnytPTM9czSt6OLl++bLdP/b///a/Onj1rc3p1OIeXl5eee+45vfbaa9meehz/zIF5//33NW3atNsueEjM+QAKjaefflqXLl1SixYtlJaWpujoaP3888965ZVX8n0YZ3G3bds2jR49Wj179pS3t7d2796tDz74QA0aNLD+zg2ca/z48Ro/fryzyyi0vL29b3o+X3FA+AAKiTZt2uj111/X6tWrdfnyZYWEhGju3LkaMWKEs0srdAIDA+Xv7685c+ZYJ5L269dPr776aqH/BV8AEnM+AACAqZjzAQAATEX4AAAApip0cz4yMzP1999/y8PD47acAQwAQFFkGIZSUlLk5+dnPQFeTgpd+Pj777/tflUTAAAUDUeOHFH16tVz7VPowkfWD5sdOXJEnp6eTq4GAADkRXJysvz9/W1+oDQnhS58ZO1q8fT0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ZsyYMerfv7+aNm2qZs2aafbs2UpNTdXAgQOdXRqAfMrMzNTixYvVv39/lSz5v4+WQ4cO6eOPP1bHjh3l7e2t3377TaNHj9Z9992nO+64w4kVw5kIH3CaRx55RKdOndILL7yg48ePq3Hjxvr222/tJqECKPzWrVunw4cP6/HHH7dpL126tNatW2f9cuHv76+HH35Y//nPf5xUKQoDzvMBAABMxZwPAABgKsIHAAAwFeEDAACYivABAABMRfgAAACmInwAAABTET4AAICpCB8AHC48PFyjRo3KtU9UVJTKly+fa58BAwaoW7dut1RLXtYzZcoUNW7c+JbWAyDvCB9AMbV06VL5+/urQoUKGjNmjM2yhIQE1a5dW8nJybmO4evrq1dffdWmbcKECbJYLNq0aZNNe3h4uB577DFJUnR0tF566SXrssDAQM2ePfvm7wyAYoXwARRDp0+f1uDBgzVr1ix99913+uijj7R69Wrr8mHDhunVV1+Vp6dnruOEh4fbhYyNGzfK39/fpv3y5cvatm2b2rRpI0mqWLGiPDw8HHZ/ABQvhA+gGPrrr7/k5eWlRx55RHfddZciIiK0b98+SdInn3yiUqVKqXv37jccJyIiQj/99JPS09MlSSkpKfrll180fvx4m/CxdetWpaWlKSIiQpLtbpfw8HAlJiZq9OjRslgsslgsNutYu3at6tatq3LlyqlDhw46duyYXR2zZs2Sr6+vvL29NXz4cF29etW67Ny5c+rXr58qVKigsmXLKjIyUnFxcbner1dffVVVqlSRh4eHBg0apMuXL9/wsQDgOIQPoBiqVauWLl68qF9++UVnz57Vzp07dccdd+jcuXOaNGmS5s2bl6dxIiIidOHCBe3cuVOStGXLFtWuXVsPP/ywtm/fbv3Q3rhxowIDAxUYGGg3RnR0tKpXr64XX3xRx44dswkXFy9e1KxZs/Thhx9q8+bNOnz4sJ599lmb22/cuFGHDh3Sxo0btWTJEkVFRSkqKsq6fMCAAdq1a5dWrVqlrVu3yjAMdezY0SagXOvzzz/XlClT9Morr2jXrl3y9fXV22+/nafHA4BjED6AYqhChQpasmSJ+vXrp2bNmqlfv35q3769nn32WY0YMULx8fG688471aBBAy1btizHcWrVqqVq1apZt3Js2rRJrVu3VtWqVVWjRg1t3brV2p611eN6FStWlIuLizw8PFS1alVVrVrVuuzq1at699131bRpUzVp0kQjRozQ+vXr7e7LvHnzFBoaqs6dO6tTp07WPnFxcVq1apXef/99tWrVSo0aNdLSpUt19OhRrVy5Mtt6Zs+erUGDBmnQoEGqU6eOpk2bpnr16uX1oQXgAIQPoJh66KGH9Pvvv+vgwYOaMmWKfvjhB/32228aOnSo/vWvf2n27Nlavny5Bg0apJMnT+Y4zrXzPjZt2qTw8HBJUuvWrbVp0yZdunRJ27dvzzF85KZs2bIKDg62Xvf19bWrpX79+nJxccm2z759+1SyZEk1b97cutzb21t16tSx7ma63r59+2z6S1KLFi3yXTuAm0f4AG4DaWlpGjZsmBYsWKCDBw8qPT1drVu3Vp06dVS7dm1t3749x9tmzfs4c+aMfvnlF7Vu3VrSP+Fj48aN+vnnn3XlyhXrZNP8KFWqlM11i8UiwzBu2CczMzPf6wJQeBA+gNvAtGnT1KFDBzVp0kQZGRnWCaTSP7s+MjIycrxtRESEUlNT9cYbb6hWrVry8fGRJN13333asWOH1qxZY909k5PSpUvnuo6bVbduXaWnp9uEpzNnzmj//v057kqpW7euXdjatm2bw2sDkDPCB1DM/fnnn/rss8/04osvSpJCQ0NVokQJffDBB/r6668VGxuru+66K8fb16xZUzVq1NDcuXOtWz0kyd/fX35+flq4cOENd7kEBgZq8+bNOnr0qE6fPu2YO6Z/5qQ8+OCDGjJkiH788Uf9+uuv6tu3r6pVq6YHH3ww29s888wzWrRokRYvXqwDBw5o8uTJ2rt3r8NqAnBjhA+gGDMMQ0OHDtUbb7whd3d3SZKbm5uioqL04osvatCgQZo3b16uWy2kf7Z+pKSkWOd7ZGndurVSUlJuGD5efPFFJSQkKDg4WJUrV76l+3S9xYsXKywsTJ07d1aLFi1kGIa++eYbu901WR555BFNmjRJzz33nMLCwpSYmKinnnrKoTUByJ3FuH4HKwAAQAFiywcAADAV4QMAAJiK8AEAAExF+AAAAKYifAAAAFMRPgAAgKkIHwAAwFSEDwAAYCrCBwAAMBXhAwAAmIrwAQAATEX4AAAApvp/eKma7EVbgVsAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "fig3, ax3 = plt.subplots()\n", + "\n", + "data = []\n", + "for key in op_df:\n", + "\n", + " vsdf = op_df[key].loc[(op_df[key]['type'] == 'RandomSamplingOperation')]\n", + " #vsdf = op_df[key].loc[(op_df[key]['validator'] == 'no')]\n", + " data.append(vsdf['completion_time']/1000)\n", + "\n", + "ax3.boxplot(data)\n", + "\n", + "#ax3.legend()\n", + "#ax18.set_xlim([0,2])\n", + "ax3.set_ylim([0,15])\n", + "ax3.set_xticklabels([0,75])\n", + "ax3.set_title(\"Random sampling time regular nodes (seconds)\")\n", + "ax3.set_xlabel(\"% Withhold\")" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "id": "64a9d6f0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0, '% Withhold')" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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s3PnTrcaioqKXD9XdP9VkX1hYGCgGTx48Cm3AU7gNM05pviwY/Xq1UtMS0xMVN26dV2PSZMmlegzf/58LV++XMuWLdOMGTPUtGlT9e7dW59++qmrT82aNfXTTz9p7dq1HtV2qnHGGM2fP189evSQMUYHDx50Pbp06aKcnJwShyj79+/vdp3CVVddJUn68ccfPartZPHx8YqLi3M9r1+/vnr27KmlS5eqsLBQkpSSkqL8/Hy3w+Zz587V8ePHdccdd5zR8qOiolzrIkl169ZVs2bN3NZr3rx5uuqqq1SrVi23bZWUlKTCwkK300plCQsL0w033OB6HhAQoJSUFG3YsEFZWVlntA6l2bdvnzZu3Ki+ffsqMDDQ1X7ttdcqKirKre+8efMUGBioa6+91m394uLiVL16da1cudKtf8OGDdWlS5cK11KlShXdfffdruc+Pj66++67tX//fn3xxReuGlq0aKHmzZu71XD11VdLUokaEhISSqxHaWrWrCnpxIXmv//+e5n9/njNy6FDh5STk6Orrrqq1EP111xzjdspyI4dO0qSevfurRo1apRoP/k9UpHt4YmkpCQ1btzY9bx169YKCAhwLbewsFArVqxQr169FBYW5uoXGRmpbt26VXg5ntTdt29ft226bt067d+/X/fdd5/btT3Jyclq3ry5Fi9eLEk6cOCAVq9erQEDBqh+/fpu8yw+neTJ/qsi+9CaNWvqs88+0969eyu8LS5mhJFzTPFO5+jRoyWmTZ06VcuXL9esWbPKHN+pUyclJSXp2muvVb9+/ZSRkaEaNWro73//u6vPI488ourVq6tDhw5q0qSJBg8erE8++eSUtZ1q3IEDB3T48GFNmzbNLTTVrVtX/fv3lyTt37/fbZ4n7xhq1aolSSWuKfBUkyZNSrQ1bdpUv/76qw4cOCBJat68udq3b6/Zs2e7+syePVuXXXaZIiMjz2j5J6+XdGLd/rheW7du1ZIlS0psq6SkJEklt1VpIiMjS5ybb9q0qSSdlduOd+7cKan07dusWTO351u3blVOTo6CgoJKrOPRo0dLrF/Dhg09qiUsLEzVqlVzazt53bdu3apvvvmmxPKL+51uDQkJCerdu7eefPJJ1alTRz179tSMGTNKXIeyaNEiXXbZZfL19dUll1yiunXrasqUKcrJySkxz5NfM8Vh7+Rrw4rbT36PVGR7eOJUr+H9+/fr2LFjpb5XPHn/eFL3yb+f4tfjya896cT7u3h6cYCKjo4usw5P9l8V2Yc+88wz2rRpk8LDw9WhQweNGjXqjP/IupCdf5dQX+ACAwMVGhqqTZs2lZhW/BeRJzuW6tWrq2PHjnr33XeVl5enatWqqUWLFtqyZYsWLVqkJUuWaP78+Zo8ebKeeOIJPfnkk2XO61Tjii+6vOOOO9S3b99S59G6dWu3597e3qX2M8ZUeB3PREpKih544AH99NNPys/P15o1azRx4sQznm9F1quoqEjXXnuthg0bVmrf4h3ymSrrQsLiI0RnS1FRkYKCgtzC3h/VrVvX7fnZuHOmqKhIrVq10vjx40udfvIHfUVrcDgcevvtt7VmzRr93//9n5YuXaoBAwZo3LhxWrNmjapXr66PPvpIf/nLX9SpUydNnjxZoaGhqlq1qmbMmFHqxeJlvWZsvUdsvzdLczbvrvJk/1WRfejNN9+sq666Su+8846WLVumZ599VmPHjtWCBQs8OnJ0sSCMnIOSk5P18ssv6/PPP1eHDh3OeH7Hjx+XdOJoS/FfINWqVVOfPn3Up08fFRQU6K9//auefvppjRgxotxbGcsbV7duXdWoUUOFhYWuv+4rw+l8O+TWrVtLtH3//ffy9/d3+xC85ZZblJqaqjfeeEPHjh1T1apV1adPn7NS08kaN26so0ePntG22rZtm4wxbvV8//33kuQ65F98tOnw4cOu0wvS//6q9ETx99qUtn23bNni9rxx48ZasWKFrrjiirPyIbJ3715XwC528ro3btxYX375pa655pqz8i2jl112mS677DI9/fTTmjNnjm6//Xa9+eabuvPOOzV//nz5+vpq6dKlcjqdrjEzZsyo9Dqkim2PyhQUFCRfX1+3u9+KldZWljOpu/j1uGXLFtept2JbtmxxTW/UqJEklfpHXjFP918V2YeGhobqvvvu03333af9+/erbdu2evrppwkjpeA0zTlo2LBh8vf314ABA5SdnV1iuid/mfzyyy/69NNPFRISoqCgIEnSzz//7NbHx8dHUVFRMsaUe/77VOO8vb3Vu3dvzZ8/v9Q3ffHpEU9Vq1at1MPa5cnMzHQ7L7979269++67uu6669z+4qtTp466deumWbNmafbs2eratavb97SUV5N04gP+dN18883KzMzU0qVLS0w7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AADAecnjMNKnTx8dOHBATzzxhLKyshQbG6slS5a4LmrdtWuXvLz+d8Dl0KFDGjRokLKyslSrVi3FxcXp008/VVRUVOWtBQAAOG85jDHGdhGnkpubq8DAQOXk5CggIKBS5x0xfHGlzg+40OwYk2y7hErBex0o29l6n1f085v/TQMAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAqwgjAADAKsIIAACw6rTCyKRJkxQRESFfX1917NhRn3/+ebn9582bp+bNm8vX11etWrXS+++/f1rFAgCAC4/HYWTu3LlKTU3VyJEjtX79esXExKhLly7av39/qf0//fRT3XrrrRo4cKA2bNigXr16qVevXtq0adMZFw8AAM5/HoeR8ePHa9CgQerfv7+ioqKUnp4uf39/TZ8+vdT+L7zwgrp27aqHH35YLVq00FNPPaW2bdtq4sSJZ1w8AAA4/3kURgoKCvTFF18oKSnpfzPw8lJSUpIyMzNLHZOZmenWX5K6dOlSZn8AAHBxqeJJ54MHD6qwsFDBwcFu7cHBwdq8eXOpY7Kyskrtn5WVVeZy8vPzlZ+f73qek5MjScrNzfWk3Aopyv+10ucJXEjOxvvOBt7rQNnO1vu8eL7GmHL7eRRG/ixpaWl68sknS7SHh4dbqAa4uAVOsF0BgLPtbL/Pjxw5osDAwDKnexRG6tSpI29vb2VnZ7u1Z2dnKyQkpNQxISEhHvWXpBEjRig1NdX1vKioSL/88otq164th8PhSck4j+Tm5io8PFy7d+9WQECA7XIAnCW81y8exhgdOXJEYWFh5fbzKIz4+PgoLi5OGRkZ6tWrl6QTQSEjI0NDhgwpdUx8fLwyMjI0dOhQV9vy5csVHx9f5nKcTqecTqdbW82aNT0pFeexgIAAdlDARYD3+sWhvCMixTw+TZOamqq+ffuqXbt26tChgyZMmKC8vDz1799fkpSSkqJLL71UaWlpkqQHHnhACQkJGjdunJKTk/Xmm29q3bp1mjZtmqeLBgAAFyCPw0ifPn104MABPfHEE8rKylJsbKyWLFniukh1165d8vL63006l19+uebMmaPHH39cjz76qJo0aaKFCxcqOjq68tYCAACctxzmVJe4An+S/Px8paWlacSIESVO0wG4cPBex8kIIwAAwCr+UR4AALCKMAIAAKwijAAAAKsIIwAAwCrCCM4ZkyZNUkREhHx9fdWxY0d9/vnntksCcJoiIiLkcDhKPAYPHixJSkxMLDHtnnvusVw1bCGM4Jwwd+5cpaamauTIkVq/fr1iYmLUpUsX7d+/33ZpAE7D2rVrtW/fPtdj+fLlkqSbbrrJ1WfQoEFufZ555hlb5cIybu3FOaFjx45q3769Jk6cKOnEvxkIDw/X3//+dw0fPtxydQDO1NChQ7Vo0SJt3bpVDodDiYmJio2N1YQJE2yXhnMAR0ZgXUFBgb744gslJSW52ry8vJSUlKTMzEyLlQGoDAUFBZo1a5YGDBjg9s9OZ8+erTp16ig6OlojRozQr7/+arFK2OTx18EDle3gwYMqLCx0/UuBYsHBwdq8ebOlqgBUloULF+rw4cPq16+fq+22225TgwYNFBYWpq+++kqPPPKItmzZogULFtgrFNYQRgAAZ9Urr7yibt26uf0b+bvuusv1c6tWrRQaGqprrrlGP/zwgxo3bmyjTFjEaRpYV6dOHXl7eys7O9utPTs7WyEhIZaqAlAZdu7cqRUrVujOO+8st1/Hjh0lSdu2bfszysI5hjAC63x8fBQXF6eMjAxXW1FRkTIyMhQfH2+xMgBnasaMGQoKClJycnK5/TZu3ChJCg0N/ROqwrmG0zQ4J6Smpqpv375q166dOnTooAkTJigvL0/9+/e3XRqA01RUVKQZM2aob9++qlLlfx83P/zwg+bMmaPrr79etWvX1ldffaUHH3xQnTp1UuvWrS1WDFsIIzgn9OnTRwcOHNATTzyhrKwsxcbGasmSJSUuagVw/lixYoV27dqlAQMGuLX7+PhoxYoVrj86wsPD1bt3bz3++OOWKoVtfM8IAACwimtGAACAVYQRAABgFWEEAABYRRgBAABWEUYAAIBVhBEAAGAVYQQAAFhFGAFw1iUmJmro0KHl9pk5c6Zq1qxZbp9+/fqpV69eZ1RLRZYzatQoxcbGntFyAFQcYQS4SMyePVvh4eGqVauWUlNT3abt2LFDTZs2VW5ubrnzCA0N1ZgxY9zahg8fLofDoVWrVrm1JyYm6m9/+5skacGCBXrqqadc0yIiIjRhwoTTXxkAFxTCCHAROHjwoO68804999xzWrZsmWbNmqVFixa5pt93330aM2aMAgICyp1PYmJiidCxcuVKhYeHu7X/9ttvWrNmja6++mpJ0iWXXKIaNWpU2voAuLAQRoCLwI8//qjAwED16dNH7du3V+fOnfXdd99Jkt544w1VrVpVf/3rX085n86dO+uTTz7R8ePHJUlHjhzRhg0b9Mgjj7iFkczMTOXn56tz586S3E/TJCYmaufOnXrwwQflcDjkcDjclrF06VK1aNFC1atXV9euXbVv374SdTz33HMKDQ1V7dq1NXjwYP3++++uaYcOHVJKSopq1aolf39/devWTVu3bi13vcaMGaPg4GDVqFFDAwcO1G+//XbKbQGg8hBGgItAkyZN9Ouvv2rDhg365ZdftHbtWrVu3VqHDh3SP//5T02cOLFC8+ncubOOHj2qtWvXSpI++ugjNW3aVL1799Znn33m+hBfuXKlIiIiFBERUWIeCxYsUL169TR69Gjt27fPLWz8+uuveu655/T6669r9erV2rVrl/7xj3+4jV+5cqV++OEHrVy5Uq+++qpmzpypmTNnuqb369dP69at03vvvafMzEwZY3T99de7BZY/euuttzRq1Cj9+9//1rp16xQaGqrJkydXaHsAqByEEeAiUKtWLb366qtKSUlRhw4dlJKSoi5duugf//iHhgwZou3bt6tNmzaKjo7W22+/XeZ8mjRpoksvvdR1FGTVqlVKSEhQSEiI6tevr8zMTFd78VGRk11yySXy9vZWjRo1FBISopCQENe033//Xenp6WrXrp3atm2rIUOGKCMjo8S6TJw4Uc2bN1f37t2VnJzs6rN161a99957evnll3XVVVcpJiZGs2fP1p49e7Rw4cJS65kwYYIGDhyogQMHqlmzZvrXv/6lqKioim5aAJWAMAJcJG644QZ9/fXX2rZtm0aNGqUPP/xQX331le666y7dcsstmjBhgubPn6+BAwdq//79Zc7nj9eNrFq1SomJiZKkhIQErVq1SseOHdNnn31WZhgpj7+/vxo3bux6HhoaWqKWli1bytvbu9Q+3333napUqaKOHTu6pteuXVvNmjVznZY62XfffefWX5Li4+M9rh3A6SOMABeh/Px83XfffZo6daq2bdum48ePKyEhQc2aNVPTpk312WeflTm2+LqRn3/+WRs2bFBCQoKkE2Fk5cqV+vTTT1VQUOC6eNUTVatWdXvucDhkjDlln6KiIo+XBeDcQRgBLkL/+te/1LVrV7Vt21aFhYWuC1KlE6dKCgsLyxzbuXNn5eXlafz48WrSpImCgoIkSZ06ddLnn3+uDz74wHU6pyw+Pj7lLuN0tWjRQsePH3cLUz///LO2bNlS5qmXFi1alAhfa9asqfTaAJSNMAJcZL799lvNnTtXo0ePliQ1b95cXl5eeuWVV7R48WJt3rxZ7du3L3N8o0aNVL9+fb344ouuoyKSFB4errCwME2bNu2Up2giIiK0evVq7dmzRwcPHqycFdOJa1p69uypQYMG6eOPP9aXX36pO+64Q5deeql69uxZ6pgHHnhA06dP14wZM/T9999r5MiR+uabbyqtJgCnRhgBLiLGGN11110aP368qlWrJkny8/PTzJkzNXr0aA0cOFATJ04s96iGdOLoyJEjR1zXixRLSEjQkSNHThlGRo8erR07dqhx48aqW7fuGa3TyWbMmKG4uDh1795d8fHxMsbo/fffL3F6p1ifPn30z3/+U8OGDVNcXJx27type++9t1JrAlA+hzn5hCwAAMCfiCMjAADAKsIIAACwijACAACsIowAAACrCCMAAMAqwggAALCKMAIAAKwijAAAAKsIIwAAwCrCCAAAsIowAgAArCKMAAAAq/4fEeYldgsA9CQAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "fig3, ax3 = plt.subplots()\n", + "\n", + "data = []\n", + "for key in msg_df:\n", + "\n", + " vsdf = msg_df[key].loc[(msg_df[key]['nodeType'] == 'builder')]\n", + " data.append(vsdf['bytesOut'].values[0]/1024/1024/1024)\n", + "\n", + "ax3.bar([1,2],data)\n", + "\n", + "ax3.set_xticks([1,2])\n", + "ax3.set_xticklabels([0,75])\n", + "ax3.set_title(\"GBs sent by the builder per sampling process\")\n", + "ax3.set_xlabel(\"% Withhold\")" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "id": "0726c136", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0, '% Withhold')" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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AJjN5U+7JCYmKj8/377k5OS4uiSYxGq1qlOnTpKkTp06ETwA4Abh1PARFBQkSTp27JhD+7Fjx+zbLubp6amAgACHBQAAuC+nho/w8HAFBQVp3bp19raCggJ988036tatmzNPBQAAaqkqj/k4c+aMDhw4YF/PysrSjh07VL9+fbVo0UITJkzQ9OnT1bp1a/ujtsHBwYqLi3Nm3QAAoJaqcvhIT09XTEyMfT0hIUGSNHz4cM2dO1cvvviizp49qzFjxuj06dO66667tHr1aub4AAAAkq4hfERHR1eYmbI8i8WiadOmadq0addVGAAAcE8uf9oFAADcWAgfAADAVIQPAABgKsIHAAAwFeEDAACYivABAABMRfgAAACmInwAAABTET4AAICpCB8AAMBUhA8AAGAqwgcAADAV4QMAAJiK8AEAAExF+AAAAKYifAAAAFMRPgAAgKkIHwAAwFSEDwAAYCrCBwAAMBXhAwAAmIrwAQAATEX4AAAApiJ8AAAAUxE+AACAqQgfAADAVIQPAABgKsIHAAAwFeEDAACYivABAABMRfgAAACmInwAAABTET4AAICpCB8AAMBUhA8AAGAqp4cPm82mSZMmKTw8XN7e3mrZsqVeffVVGYbh7FMBAIBaqI6zD/jmm29q1qxZmjdvnm677Talp6dr5MiRCgwM1DPPPOPs0wEAgFrG6eFj48aN6tevn/r06SNJCgsL06JFi7RlyxZnnwoAANRCTr/t0r17d61bt0779++XJH377bf66quvFBsb6+xTAQCAWsjpVz5eeuklFRQUKCIiQlarVTabTa+99poeeeSRSvuXlJSopKTEvl5QUODskgAAQA3i9CsfH3/8sT766CMtXLhQ27Zt07x58zRjxgzNmzev0v5JSUkKDAy0LyEhIc4uCQAA1CBODx8vvPCCXnrpJQ0ZMkRRUVF69NFH9dxzzykpKanS/omJicrPz7cvOTk5zi4JAADUIE6/7VJUVCQPD8dMY7VaVVpaWml/T09PeXp6OrsMAABQQzk9fDz44IN67bXX1KJFC912223avn273n77bT3++OPOPhUAAKiFnB4+3n33XU2aNElPPfWU8vLyFBwcrLFjx+qVV15x9qkAAEAt5PTw4e/vr+TkZCUnJzv70AAAwA3wbhcAAGAqwgcAADAV4QMAAJiK8AEAAExF+AAAAKYifAAAAFMRPgAAgKkIHwAAwFSEDwAAYCrCBwAAMBXhAwAAmIrwAQAATEX4AAAApiJ8AAAAUxE+AACAqQgfAADAVIQPAABgqjquLgAAUPNkZmaqsLDwuo6xZ88eh/9eL39/f7Vu3dopx4JrET4AAA4yMzPVpk0bpx1v2LBhTjvW/v37CSBugPABAHBQdsVjwYIFioyMvObjFBcXKzs7W2FhYfL29r6umvbs2aNhw4Zd99UY1AyEDwBApSIjI9WhQ4frOsadd97ppGrgTggfuGbcEwYAXAvCB64J94QBANeK8IFrwj1hAMC1InzgunBPGABQVUwyBgAATEX4AAAApiJ8AAAAUxE+AACAqQgfAADAVIQPAABgKsIHAAAwFeEDAACYivABAABMRfgAAACmInwAAABTVUv4OHz4sIYNG6YGDRrI29tbUVFRSk9Pr45TAQCAWsbpL5Y7deqU7rzzTsXExGjVqlVq1KiRMjMzVa9ePWefCgAA1EJODx9vvvmmQkJCNGfOHHtbeHi4s08DAABqKaffdvnss8/UqVMnDRw4UI0bN9avfvUr/fWvf71k/5KSEhUUFDgsAADAfTk9fPzwww+aNWuWWrdurTVr1ujJJ5/UM888o3nz5lXaPykpSYGBgfYlJCTE2SUBAIAaxOnho7S0VB06dNDrr7+uX/3qVxozZoxGjx6t2bNnV9o/MTFR+fn59iUnJ8fZJQEAgBrE6eGjadOmuvXWWx3aIiMjdejQoUr7e3p6KiAgwGEBAADuy+nh484779S+ffsc2vbv36/Q0FBnnwoAANRCTn/a5bnnnlP37t31+uuva9CgQdqyZYs++OADffDBB84+FVwsyM8i79P7pSM1Y64679P7FeRncXUZAIArcHr46Ny5sz799FMlJiZq2rRpCg8PV3Jysh555BFnnwouNrZjXUWuHyutd3Ulv4jULzUBAGo2p4cPSerbt6/69u1bHYdGDfJ+xnkNfmWuIiMiXF2KJGnP3r16/49D9ZCrCwEAXFa1hA/cGHLPGCq+uY0U3N7VpUiSinNLlXvGcHUZAIArqBk36wEAwA2D8AEAAExF+AAAAKYifAAAAFMRPgAAgKkIHwAAwFSEDwAAYCrCBwAAMBXhAwAAmIrwAQAATEX4AAAApiJ8AAAAUxE+AACAqQgfAADAVIQPAABgKsIHAAAwFeEDAACYivABAABMRfgAAACmInwAAABTET4AAICpCB8AAMBUhA8AAGAqwgcAADAV4QMAAJiK8AEAAExF+AAAAKaq4+oCUDsVFRVJkrZt23ZdxykuLlZ2drbCwsLk7e19Xcfas2fPde0PADAH4QPXZO/evZKk0aNHu7iSivz9/V1dAgDgMggfuCZxcXGSpIiICPn4+Fzzcfbs2aNhw4ZpwYIFioyMvO66/P391bp16+s+DgCg+hA+cE0aNmyoJ554wmnHi4yMVIcOHZx2PABAzcWAUwAAYCrCBwAAMBXhAwAAmKraw8cbb7whi8WiCRMmVPepAABALVCt4WPr1q16//33dfvtt1fnaQAAQC1SbeHjzJkzeuSRR/TXv/5V9erVq67TAACAWqbaHrUdN26c+vTpo169emn69OmX7FdSUqKSkhL7ekFBQXWVBAC4SkF+Fnmf3i8dqRlDA71P71eQn8XVZcBJqiV8/POf/9S2bdu0devWK/ZNSkrS1KlTq6MMAMA1GtuxriLXj5XWu7qSX0Tql5rgHpwePnJycvTss89q7dq18vLyumL/xMREJSQk2NcLCgoUEhLi7LIAAFXwfsZ5DX5lriIjIlxdiiRpz969ev+PQ/WQqwuBUzg9fGRkZCgvL89htkqbzab169dr5syZKikpkdVqtW/z9PSUp6ens8sAAFyH3DOGim9uIwW3d3UpkqTi3FLlnjFcXQacxOnh495779V3333n0DZy5EhFRERo4sSJDsEDAADceJwePvz9/dW2bVuHNl9fXzVo0KBCOwAAuPHUjGHMAADghmHKW23T0tLMOA0AAKgFuPIBAABMRfgAAACmInwAAABTET4AAICpCB8AAMBUhA8AAGAqwgcAADAV4QMAAJiK8AEAAExF+AAAAKYifAAAAFMRPgAAgKkIHwAAwFSEDwAAYCrCBwAAMBXhAwAAmIrwAQAATEX4AAAApiJ8AAAAUxE+AACAqQgfAADAVIQPAABgKsIHAAAwFeEDAACYivABAABMRfgAAACmInwAAABTET4AAICpCB8AAMBUhA8AAGAqwgcAADAV4QMAAJiK8AEAAExF+AAAAKYifAAAAFM5PXwkJSWpc+fO8vf3V+PGjRUXF6d9+/Y5+zQAAKCWcnr4+PLLLzVu3Dht3rxZa9eu1c8//6xf//rXOnv2rLNPBQAAaqE6zj7g6tWrHdbnzp2rxo0bKyMjQ3fffbezTwcAAGqZah/zkZ+fL0mqX79+dZ8KAADUAk6/8lFeaWmpJkyYoDvvvFNt27attE9JSYlKSkrs6wUFBdVZEgAAcLFqvfIxbtw47dq1S//85z8v2ScpKUmBgYH2JSQkpDpLAgAALlZt4WP8+PFasWKFUlNT1bx580v2S0xMVH5+vn3JycmprpIAAEAN4PTbLoZh6Omnn9ann36qtLQ0hYeHX7a/p6enPD09nV0GAACooZwePsaNG6eFCxdq+fLl8vf3V25uriQpMDBQ3t7ezj4dAACoZZx+22XWrFnKz89XdHS0mjZtal8WL17s7FMBAIBaqFpuuwAAAFwK73YBAACmqtZ5PgAAtU9RUZEkadu2bdd1nOLiYmVnZyssLOy6x/zt2bPnuvZHzUL4AAA42Lt3ryRp9OjRLq6kIn9/f1eXACcgfAAAHMTFxUmSIiIi5OPjc83H2bNnj4YNG6YFCxYoMjLyuuvy9/dX69atr/s4cD3CBwDAQcOGDfXEE0847XiRkZHq0KGD046H2o8BpwAAwFSEDwAAYCrCBwAAMBXhAwAAmIrwAQAATEX4AAAApiJ8wGVsNpvS09MlSenp6bLZbC6uCABgBsIHXCIlJUV+fn4aO3asJGns2LHy8/NTSkqKiysDAFQ3wgdMl5KSov79++vcuXMO7efOnVP//v0JIADg5ggfMJXNZlP//v0v26d///7cggEAN8b06qg2RUVF9hdUlUlOTr6qfUeOHKkJEyZUaL/ed00AAFyP8IFqs3fvXnXs2PGa9p0/f77mz59foT0jI4N3RABALUf4QLWJiIhQRkaGQ1tVwsjF+5YdEwBQuxE+UG18fHyu6yoFVzgAwD0x4BQAAJiK8AEAAExF+AAAAKYifAAAAFMRPgAAgKkIHwAAwFSED5jKYrE4tR8AoPYhfMBUfn5+Tu0HAKh9mGQMpvL19VVhYeFV9QNQc1X27qaL7dmzx+G/V8K7m24chA8AQJVV5d1Nw4YNu6p+vLvpxkH4gKmCg4OVm5t7Vf0A1FyVvbvpYsXFxcrOzlZYWJi8vb2v6pi4MVgMwzBcXUR5BQUFCgwMVH5+vgICAlxdDpxs5cqV6tOnzxX7ff7553rggQdMqAgA4AxV+f3NgFOYqnfv3qpbt+5l+9StW1e9e/c2qSIAgNkIHzCV1WrVokWLLttn0aJFslqtJlUEADAb4QOmi4+P1yeffKIWLVo4tIeGhuqTTz5RfHy8iyoDAJiBMR9wGZvNpg0bNujo0aNq2rSpevTowRUPAKilqvL7m6dd4DJWq1XR0dGuLgMAYLJqu+3y3nvvKSwsTF5eXuratau2bNlSXacCAAC1SLWEj8WLFyshIUGTJ0/Wtm3b1K5dO/Xu3Vt5eXnVcToAAFCLVEv4ePvttzV69GiNHDlSt956q2bPni0fHx/9/e9/r47TAQCAWsTp4eP8+fPKyMhQr169/nsSDw/16tVLmzZtqtC/pKREBQUFDgsAAHBfTg8fJ06ckM1mU5MmTRzamzRpUum02klJSQoMDLQvISEhzi4JAADUIC6f5yMxMVH5+fn2JScnx9UlAQCAauT0R20bNmwoq9WqY8eOObQfO3ZMQUFBFfp7enrK09PT2WUAAIAayulXPurWrauOHTtq3bp19rbS0lKtW7dO3bp1c/bpAABALVMtk4wlJCRo+PDh6tSpk7p06aLk5GSdPXtWI0eOrI7TAQCAWqRawsfgwYN1/PhxvfLKK8rNzVX79u21evXqCoNQK1M22ztPvQAAUHuU/d6+mre21Lh3u/z444888QIAQC2Vk5Oj5s2bX7ZPjQsfpaWlOnLkiPz9/WWxWFxdDqpZQUGBQkJClJOTw4sEATfD3+8bi2EYKiwsVHBwsDw8Lj+ktMa9WM7Dw+OKiQnuJyAggP85AW6Kv983jsDAwKvq5/J5PgAAwI2F8AEAAExF+IBLeXp6avLkyUw0B7gh/n7jUmrcgFMAAODeuPIBAABMRfgAAACmInwAAABTET4AAICpCB9wqffee09hYWHy8vJS165dtWXLFleXBKCKwsLCZLFYKizjxo2TJEVHR1fY9tvf/tbFVcOVCB9wmcWLFyshIUGTJ0/Wtm3b1K5dO/Xu3Vt5eXmuLg1AFWzdulVHjx61L2vXrpUkDRw40N5n9OjRDn3eeustV5WLGoBHbeEyXbt2VefOnTVz5kxJv7zXJyQkRE8//bReeuklF1cH4FpNmDBBK1asUGZmpiwWi6Kjo9W+fXslJye7ujTUEFz5gEucP39eGRkZ6tWrl73Nw8NDvXr10qZNm1xYGYDrcf78eS1YsECPP/64w8tBP/roIzVs2FBt27ZVYmKiioqKXFglXK3GvVgON4YTJ07IZrOpSZMmDu1NmjTR3r17XVQVgOu1bNkynT59WiNGjLC3DR06VKGhoQoODtbOnTs1ceJE7du3TykpKa4rFC5F+AAAOM2HH36o2NhYBQcH29vGjBlj/zoqKkpNmzbVvffeq++//14tW7Z0RZlwMW67wCUaNmwoq9WqY8eOObQfO3ZMQUFBLqoKwPU4ePCgvvjiCz3xxBOX7de1a1dJ0oEDB8woCzUQ4QMuUbduXXXs2FHr1q2zt5WWlmrdunXq1q2bCysDcK3mzJmjxo0bq0+fPpftt2PHDklS06ZNTagKNRG3XeAyCQkJGj58uDp16qQuXbooOTlZZ8+e1ciRI11dGoAqKi0t1Zw5czR8+HDVqfPfXy3ff/+9Fi5cqAceeEANGjTQzp079dxzz+nuu+/W7bff7sKK4UqED7jM4MGDdfz4cb3yyivKzc1V+/bttXr16gqDUAHUfF988YUOHTqkxx9/3KG9bt26+uKLL+z/uAgJCVH//v31+9//3kWVoiZgng8AAGAqxnwAAABTET4AAICpCB8AAMBUhA8AAGAqwgcAADAV4QMAAJiK8AEAAExF+ADgdNHR0ZowYcJl+8ydO1c333zzZfuMGDFCcXFx11XL1ZxnypQpat++/XWdB8DVI3wAbuqjjz5SSEiI6tWrp4SEBIdt2dnZatOmjQoKCi57jKZNm+qNN95waHvppZdksViUlpbm0B4dHa1HH31UkpSSkqJXX33Vvi0sLEzJycnX/mEAuBXCB+CGTpw4oSeeeEIzZszQv/71Ly1YsEArVqywb3/qqaf0xhtvKCAg4LLHiY6OrhAyUlNTFRIS4tB+7tw5bd68Wffcc48kqX79+vL393fa5wHgXggfgBv64YcfFBgYqMGDB6tz586KiYnRnj17JEmLFi3STTfdpPj4+CseJyYmRl9//bUuXLggSSosLNT27ds1ceJEh/CxadMmlZSUKCYmRpLjbZfo6GgdPHhQzz33nCwWiywWi8M51qxZo8jISPn5+en+++/X0aNHK9QxY8YMNW3aVA0aNNC4ceP0888/27edOnVKjz32mOrVqycfHx/FxsYqMzPzsp/rjTfeUJMmTeTv769Ro0bp3LlzV/xeAHAewgfghlq3bq2ioiJt375dP/30k7Zu3arbb79dp06d0qRJkzRz5syrOk5MTIzOnDmjrVu3SpI2bNigNm3aqH///vrmm2/sv7RTU1MVFhamsLCwCsdISUlR8+bNNW3aNB09etQhXBQVFWnGjBmaP3++1q9fr0OHDun555932D81NVXff/+9UlNTNW/ePM2dO1dz5861bx8xYoTS09P12WefadOmTTIMQw888IBDQCnv448/1pQpU/T6668rPT1dTZs21V/+8per+n4AcA7CB+CG6tWrp3nz5umxxx5Tly5d9Nhjj6l37956/vnnNX78eGVlZelXv/qV2rZtq6VLl17yOK1bt1azZs3sVznS0tLUs2dPBQUFqUWLFtq0aZO9veyqx8Xq168vq9Uqf39/BQUFKSgoyL7t559/1uzZs9WpUyd16NBB48eP17p16yp8lpkzZyoiIkJ9+/ZVnz597H0yMzP12Wef6W9/+5t69Oihdu3a6aOPPtLhw4e1bNmySutJTk7WqFGjNGrUKN1yyy2aPn26br311qv91gJwAsIH4KZ+85vf6LvvvtOBAwc0ZcoUffnll9q5c6fGjBmjIUOGKDk5WZ988olGjRqlvLy8Sx6n/LiPtLQ0RUdHS5J69uyptLQ0FRcX65tvvrlk+LgcHx8ftWzZ0r7etGnTCrXcdtttslqtlfbZs2eP6tSpo65du9q3N2jQQLfccov9NtPF9uzZ49Bfkrp161bl2gFcO8IHcAMoKSnRU089pffff18HDhzQhQsX1LNnT91yyy1q06aNvvnmm0vuWzbu4+TJk9q+fbt69uwp6ZfwkZqaqo0bN+r8+fP2waZVcdNNNzmsWywWGYZxxT6lpaVVPheAmoPwAdwApk+frvvvv18dOnSQzWazDyCVfrn1YbPZLrlvTEyMzp49q7ffflutW7dW48aNJUl33323tmzZolWrVtlvz1xK3bp1L3uOaxUZGakLFy44hKeTJ09q3759l7yVEhkZWSFsbd682em1Abg0wgfg5nbv3q3Fixdr2rRpkqSIiAh5eHjoww8/1Oeff669e/eqc+fOl9z/f/7nf9SiRQu9++679qsekhQSEqLg4GB98MEHV7zlEhYWpvXr1+vw4cM6ceKEcz6YfhmT0q9fP40ePVpfffWVvv32Ww0bNkzNmjVTv379Kt3n2Wef1d///nfNmTNH+/fv1+TJk/Wf//zHaTUBuDLCB+DGDMPQmDFj9Pbbb8vX11eS5O3trblz52ratGkaNWqUZs6cedmrFtIvVz8KCwvt4z3K9OzZU4WFhVcMH9OmTVN2drZatmypRo0aXddnuticOXPUsWNH9e3bV926dZNhGFq5cmWF2zVlBg8erEmTJunFF19Ux44ddfDgQT355JNOrQnA5VmMi2+wAgAAVCOufAAAAFMRPgAAgKkIHwAAwFSEDwAAYCrCBwAAMBXhAwAAmIrwAQAATEX4AAAApiJ8AAAAUxE+AACAqQgfAADAVIQPAABgqv8HIO4OSQUFUNsAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig3, ax3 = plt.subplots()\n", + "\n", + "data = []\n", + "for key in msg_df:\n", + "\n", + " vsdf = msg_df[key].loc[(msg_df[key]['nodeType'] == 'validator')]\n", + " data.append(vsdf['bytesOut']/1024/1024)\n", + "\n", + "ax3.boxplot(data)\n", + "\n", + "ax3.set_xticklabels([0,75])\n", + "ax3.set_title(\"MBs sent per validator\")\n", + "ax3.set_xlabel(\"% Withhold\")" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "id": "40b59007", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0, '% Withhold')" + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhYAAAHHCAYAAADjzRHEAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA/DklEQVR4nO3dfVhUdf7/8ReMciugqQgqCYEGCmViWRqJm623JaGZmXlTaaVWppbaby01U7Msv6up1W5ma9qNoRXetFZSVNQamjflDZqYq3ibCgpCzJzfH17MOoI6yIGR4fm4Lq6Yc97nzHtgbF58zjmf42EYhiEAAAATeLq6AQAA4D4IFgAAwDQECwAAYBqCBQAAMA3BAgAAmIZgAQAATEOwAAAApiFYAAAA0xAsAACAaQgWACokMTFRiYmJrm7DZSZNmiQPDw9Xt2Gq7OxseXh46J133nF1K6iGCBaoFO+88448PDzk4eGhb7/9ttR6wzAUFhYmDw8P9ezZ02FdyXYlX/7+/mrZsqWmTp2q/Pz8qnoJpjtw4IAmTZqkn3/+2dWtXBHy8/M1adIkpaWluboVACaq5eoG4N58fHy0ZMkS3XrrrQ7Lv/76a/33v/+Vt7d3mdvdcccdGjhwoCTp1KlTSk9P18SJE7Vp0yZ99NFHld53ZThw4IAmT56s8PBwtW7d2tXtuFx+fr4mT54sSTV6xANwNwQLVKru3bvro48+0t///nfVqvW/t9uSJUsUHx+vo0ePlrldixYtNGDAAPvjRx99VEVFRUpJSdGZM2fk4+NT6b3XFPn5+fLz83N1G5fl9OnT8vf3d3UbpjEMQ2fOnJGvr6+rWwEuG4dCUKnuu+8+HTt2TGvXrrUvKyoq0rJly9S/f/9y7SskJEQeHh4OASUrK0u9e/dWSEiIfHx81LRpU/Xr108nT5686L6c3W7x4sWKj4+Xr6+vrrrqKvXr10/79u1zqElMTFRsbKx+/fVXderUSX5+fmrSpIlmzpxpr0lLS9ONN94oSRoyZIj9MM/FjmGXHLvfvn27+vbtq8DAQNWvX19PPvmkzpw5U6q+PL1mZmbqtttuk5+fn5599tkL9nDw4EENGTJETZs2lbe3t0JDQ9WrVy9lZ2dfcBtJOnz4sB566CE1atRIPj4+uv7667Vo0SL7+uzsbDVs2FCSNHnyZPvPY9KkSRfcZ8nhta+//lrDhw9XcHCwmjZtal+/evVqJSQkyN/fXwEBAerRo4d++eWXUvv56KOP1LJlS/n4+Cg2NlbLly/X4MGDFR4ebq9JS0uTh4dHqcM0zp57sHDhQv3lL39RcHCwvL291bJlS82fP79UXXh4uHr27KnPP/9cbdu2la+vr954440L7teZ91qJS/0OSpw4cUKDBw9WUFCQ6tatq0GDBunEiRNlPv/27dvVp08fXXXVVfLx8VHbtm316aefXvRngZqHEQtUqvDwcN1yyy1aunSpunXrJunsB8DJkyfVr18//f3vfy9zuzNnzthHM06fPq3vvvtOixYtUv/+/e3BoqioSF26dFFhYaEef/xxhYSEaP/+/UpNTdWJEycUFBRU5r6d3e7FF1/UxIkT1bdvXz388MM6cuSI5syZo9tuu00bN25U3bp17fs8fvy4unbtquTkZPXt21fLli3TuHHjFBcXp27duikmJkZTpkzRc889p2HDhikhIUGS1L59+0v+DPv27avw8HBNnz5dP/zwg/7+97/r+PHjevfdd+015en12LFj6tatm/r166cBAwaoUaNGF3zu3r1765dfftHjjz+u8PBwHT58WGvXrtXvv//u8EF8roKCAiUmJmrXrl0aOXKkIiIi9NFHH2nw4ME6ceKEnnzySTVs2FDz58/XY489prvvvlvJycmSpOuuu+6SP4/hw4erYcOGeu6553T69GlJ0r/+9S8NGjRIXbp00UsvvaT8/HzNnz9ft956qzZu3GjvdeXKlbr33nsVFxen6dOn6/jx43rooYfUpEmTSz5vecyfP1+tWrXSXXfdpVq1aumzzz7T8OHDZbPZNGLECIfaHTt26L777tMjjzyioUOH6tprr73ovi/1XpOc+x1IZ0dIevXqpW+//VaPPvqoYmJitHz5cg0aNKjU8/7yyy/q0KGDmjRpovHjx8vf318ffvihkpKS9PHHH+vuu+826aeHas8AKsHChQsNScb69euNuXPnGgEBAUZ+fr5hGIZxzz33GJ06dTIMwzCaNWtm9OjRw2FbSWV+JSUlGWfOnLHXbdy40ZBkfPTRR+XqzZntsrOzDYvFYrz44osOy7ds2WLUqlXLYXnHjh0NSca7775rX1ZYWGiEhIQYvXv3ti9bv369IclYuHChU30+//zzhiTjrrvuclg+fPhwQ5KxadOmy+51wYIFl3z+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GYah7t27O4SPc3344YeaNGmSpk2bpp9++kmhoaGaN2+eUz8PAOYgWADVTL169bRo0SINHDhQN910kwYOHKguXbpo7NixGjlypPbs2aMbbrhBsbGxWrZs2QX307x5czVp0sQ+OpGWlqaOHTsqJCREV199tTIyMuzLS0YrznfVVVfJYrEoICBAISEhCgkJsa/7888/tWDBArVt21Zt2rTRyJEj9eWXX5Z6LXPnzlV0dLR69uypHj162GuysrL06aef6h//+IcSEhJ0/fXX67333tP+/fu1YsWKMvuZPXu2HnroIT300EO69tprNXXqVLVs2dLZHy0AExAsgGro7rvv1pYtW7Rr1y5NmjRJX3/9tTZv3qxhw4apX79+mj17tj7++GM99NBDOnz48AX3c+55FmlpaUpMTJQkdezYUWlpaSooKNCPP/54wWBxMX5+foqMjLQ/Dg0NLdVLq1atZLFYyqzZtm2batWqpXbt2tnX169fX9dee6390M/5tm3b5lAvSbfccku5ewdw+QgWQDVXWFio4cOH64033tCuXbtUXFysjh076tprr1WLFi30448/XnDbkvMsjh07po0bN6pjx46SzgaLdevW6fvvv1dRUZH9xM3yqF27tsNjDw8PGYZxyRqbzVbu5wJw5SBYANXc1KlT1bVrV7Vp00ZWq9V+MqZ09nCE1Wq94LadOnXS6dOn9eqrr6p58+YKDg6WJN122236z3/+o9WrV9sPmVyIl5fXRZ/jcsXExKi4uNghGB07dkw7duy44OGNmJiYUkHqhx9+ML03ABdGsACqsV9//VUffPCBpkyZIkmKjo6Wp6en/vnPf2rlypXavn27brzxxgtuf8011+jqq6/WnDlz7KMVkhQWFqbGjRvrzTffvORhkPDwcH3zzTfav3+/jh49as4L09lzQHr16qWhQ4fq22+/1aZNmzRgwAA1adJEvXr1KnObJ598Um+//bYWLlyonTt36vnnn9cvv/xiWk8ALo1gAVRThmFo2LBhevXVV+Xv7y9J8vX11TvvvKMpU6booYce0ty5cy862iCdHbXIy8uzn19RomPHjsrLy7tksJgyZYqys7MVGRmphg0bVug1nW/hwoWKj49Xz549dcstt8gwDK1atarUIZQS9957ryZOnKhnnnlG8fHx2rt3rx577DFTewJwcR7G+Qc9AQAALhMjFgAAwDQECwAAYBqCBQAAMA3BAgAAmIZgAQAATEOwAAAApiFYAAAA0xAsAACAaQgWAADANAQLAABgGoIFAAAwDcECAACY5v8DJab7xkMFdtkAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig3, ax3 = plt.subplots()\n", + "\n", + "data = []\n", + "for key in msg_df:\n", + "\n", + " vsdf = msg_df[key].loc[(msg_df[key]['nodeType'] == 'regular')]\n", + " data.append(vsdf['bytesOut']/1024/1024)\n", + "\n", + "ax3.boxplot(data)\n", + "\n", + "\n", + "ax3.set_xticklabels([0,75])\n", + "ax3.set_title(\"MBs sent per slot regular node\")\n", + "ax3.set_xlabel(\"% Withhold\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From f9fa308d63f7eb869b9a7ec118350182e7b06020 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sun, 3 Nov 2024 17:25:01 +0100 Subject: [PATCH 92/98] config --- .../config/malicious/dasprotocolevil0.cfg | 4 +- .../kademlia/das/CustomDistributionDas.java | 53 +-- .../peersim/kademlia/das/DASProtocol.java | 2 +- .../kademlia/das/DASProtocolBuilder.java | 127 ++----- .../kademlia/das/DASProtocolValidator.java | 53 ++- .../peersim/kademlia/das/SearchTable.java | 319 ++++++------------ 6 files changed, 166 insertions(+), 392 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg index 7ba1a3a3..5a79fa49 100644 --- a/simulator/config/malicious/dasprotocolevil0.cfg +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 1000 +SIZE 10000 # Random seed K 5 @@ -94,7 +94,7 @@ init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol init.1uniqueNodeID.protocolEvildas 8evildasprotocol -init.1uniqueNodeID.validator_rate 0.5 +init.1uniqueNodeID.validator_rate 1.0 init.1uniqueNodeID.evilNodeRatioValidator 0.0 init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 diff --git a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java index 95be590f..c285572a 100644 --- a/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java +++ b/simulator/src/main/java/peersim/kademlia/das/CustomDistributionDas.java @@ -65,12 +65,6 @@ public CustomDistributionDas(String prefix) { validatorRate = Configuration.getDouble(prefix + "." + PAR_VALIDATOR_RATE, 1.0); } - /** - * Scan over the nodes in the network and assign a randomly generated NodeId in the space - * 0..2^BITS, where BITS is a parameter from the kademlia protocol (usually 160) - * - * @return boolean always false - */ public boolean execute() { int numValidators = (int) (Network.size() * validatorRate); @@ -88,6 +82,8 @@ public boolean execute() { List validators = new ArrayList<>(); List evilIds = new ArrayList<>(); numValidators = numValidators - numEvilValidatorNodes; + SearchTable searchTable = new SearchTable(); + for (int i = 0; i < Network.size(); ++i) { Node generalNode = Network.get(i); BigInteger id; @@ -103,7 +99,6 @@ public boolean execute() { kadProt.setNode(node); if (i == 0) { - dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolDasBuilderID))); builderAddress = node.getId(); validators.add(generalNode); @@ -125,14 +120,11 @@ public boolean execute() { } else { dasProt = ((DASProtocol) (Network.get(i).getProtocol(protocolDasNonValidatorID))); nonValidatorsIds.add(kadProt.getKademliaNode().getId()); - // node.setServer(false); } dasProt.setKademliaProtocol(kadProt); kadProt.setEventsCallback(dasProt); - // dasProt.setBuilderAddress(builderAddress); - if (dasProt instanceof DASProtocolBuilder) System.out.println("DASProtocol Builder " + i); generalNode.setProtocol(protocolKadID, kadProt); generalNode.setKademliaProtocol(kadProt); @@ -144,56 +136,23 @@ public boolean execute() { generalNode.setProtocol(protocolEvilValDasID, null); generalNode.setProtocol(protocolDasValidatorID, null); generalNode.setProtocol(protocolDasNonValidatorID, null); + + generalNode.getDASProtocol().setSearchTable(searchTable); + generalNode.getDASProtocol().setBuilderAddress(builderAddress); } System.out.println("Validators " + validatorsIds.size()); System.out.println("Non-Validators " + nonValidatorsIds.size()); - SearchTable searchTable = new SearchTable(); searchTable.setBuilderAddress(builderAddress); searchTable.addNodes(nonValidatorsIds.toArray(new BigInteger[0])); searchTable.addValidatorNodes(validatorsIds.toArray(new BigInteger[0])); searchTable.setEvil(evilNodes); searchTable.setEvilIds(evilIds); - // for (DASProtocol validator : validators) { - for (int i = 0; i < Network.size(); i++) { - Node generalNode = Network.get(i); - // generalNode.getDASProtocol().setNonValidators(nonValidatorsIds); - // generalNode.getDASProtocol().addKnownValidator(validatorsIds.toArray(new BigInteger[0])); - generalNode.getDASProtocol().setSearchTable(searchTable); - generalNode.getDASProtocol().setBuilderAddress(builderAddress); - - /*if (generalNode.getDASProtocol().isEvil()) { - if (generalNode.getDASProtocol() instanceof DASProtocolEvilValidator) { - DASProtocolEvilValidator dasEvil = - (DASProtocolEvilValidator) generalNode.getDASProtocol(); - dasEvil.setEvilIds(evilNodes); - } else { - DASProtocolEvilNonValidator dasEvil = - (DASProtocolEvilNonValidator) generalNode.getDASProtocol(); - dasEvil.setEvilIds(evilNodes); - } - }*/ - /*int k = 0; - while (k < 100) { - // while (k= column.length / 2 diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index a0350829..a4d82724 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -1,32 +1,27 @@ package peersim.kademlia.das; import java.math.BigInteger; -import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import peersim.core.Network; import peersim.core.Node; -import peersim.edsim.EDSimulator; import peersim.kademlia.Message; import peersim.kademlia.Util; public class DASProtocolBuilder extends DASProtocol { protected static String prefix = null; - protected HashMap> samplesToRequest; public DASProtocolBuilder(String prefix) { super(prefix); DASProtocolBuilder.prefix = prefix; isBuilder = true; isValidator = false; - samplesToRequest = new HashMap<>(); } @Override protected void handleInitGetSample(Message m, int myPid) { logger.warning("Init block builder node - getting samples " + this); System.err.println("Wrong eventInit block builder node - getting samples "); + System.exit(-1); } @Override @@ -34,118 +29,36 @@ protected void handleInitNewBlock(Message m, int myPid) { super.handleInitNewBlock(m, myPid); logger.warning("Builder new block:" + currentBlock.getBlockId()); - int samplesWithinRegion = 0; // samples that are within at least one node's region - int samplesWithinRegionColumn = 0; // samples that are within at least one node's region - - int samplesValidators = 0; - int samplesNonValidators = 0; - samplesToRequest.clear(); - BigInteger radiusNonValidator = - currentBlock.computeRegionRadius(KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); + searchTable.assignSamples(currentBlock, KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); + currentBlock.initIterator(); while (currentBlock.hasNext()) { - boolean inRegion = false; Sample s = currentBlock.next(); - kv.add(s.getId()); - // kv.add(s.getId(), s); - // kv.add(s.getIdByColumn(), s); - BigInteger radiusValidator = - currentBlock.computeRegionRadius( - KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, - searchTable.getValidatorsIndexed().size()); - BigInteger radiusUsed = radiusValidator; - while (!inRegion) { - - List idsValidators = - searchTable.getValidatorNodesbySample(s.getIdByRow(), radiusUsed); - idsValidators.addAll(searchTable.getValidatorNodesbySample(s.getIdByColumn(), radiusUsed)); - for (BigInteger id : idsValidators) { - logger.info( - "Sending sample to validator " - + s.getIdByRow() - + " " - + s.getIdByColumn() - + " to " - + id); + List nodesByRow = searchTable.getNodesBySample(s.getId()); + if (nodesByRow != null) { + for (BigInteger id : nodesByRow) { + Message msg = new Message(Message.MSG_SEED_SAMPLE, new Sample[] {s}); + msg.operationId = -1; + msg.src = this.kadProtocol.getKademliaNode(); Node n = Util.nodeIdtoNode(id, kademliaId); - DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); - if (dasProt.isBuilder()) continue; - if (n.isUp()) { - - if (!samplesToRequest.containsKey(id)) { - List samples = new ArrayList<>(); - samples.add(s.getId()); - samplesToRequest.put(id, samples); - } else { - samplesToRequest.get(id).add(s.getId()); - } - samplesValidators++; - if (inRegion == false) { - samplesWithinRegion++; - inRegion = true; - } - } + msg.dst = n.getKademliaProtocol().getKademliaNode(); + sendMessage(msg, id, myPid); } - if (!inRegion) radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); } - List idsNonValidators = - searchTable.getNonValidatorNodesbySample(s.getIdByRow(), radiusNonValidator); - idsNonValidators.addAll( - searchTable.getNonValidatorNodesbySample(s.getIdByColumn(), radiusNonValidator)); - for (BigInteger id : idsNonValidators) { - logger.info( - "Sending sample to non-validator " - + s.getIdByRow() - + " " - + s.getIdByColumn() - + " to " - + id); - Node n = Util.nodeIdtoNode(id, kademliaId); - DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); - if (dasProt.isBuilder()) continue; - if (n.isUp()) { - samplesNonValidators++; - - if (!dasProt.isValidator()) { - - if (!samplesToRequest.containsKey(id)) { - List samples = new ArrayList<>(); - samples.add(s.getId()); - samplesToRequest.put(id, samples); - } else { - samplesToRequest.get(id).add(s.getId()); - } - } + List nodesByColumn = searchTable.getNodesBySample(s.getIdByColumn()); + if (nodesByColumn != null) { + for (BigInteger id : nodesByColumn) { + Message msg = new Message(Message.MSG_SEED_SAMPLE, new Sample[] {s}); + msg.operationId = -1; + msg.src = this.kadProtocol.getKademliaNode(); + Node n = Util.nodeIdtoNode(id, kademliaId); + msg.dst = n.getKademliaProtocol().getKademliaNode(); + sendMessage(msg, id, myPid); } } } - - for (int i = 0; i < Network.size(); i++) { - Node n = Network.get(i); - DASProtocol dasProt = n.getDASProtocol(); - BigInteger id = dasProt.getKademliaId(); - if (!dasProt.isBuilder && samplesToRequest.containsKey(id)) { - EDSimulator.add( - 1, - generateNewSampleMessage(samplesToRequest.get(id).toArray(new BigInteger[0])), - n, - dasProt.getDASProtocolID()); - } - } - - logger.warning( - samplesWithinRegion - + " " - + samplesWithinRegionColumn - + " samples out of " - + currentBlock.getNumSamples() - + " samples are within a node's region" - + " " - + samplesValidators - + " " - + samplesNonValidators); } @Override diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index f1502f6d..8952a080 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -1,7 +1,6 @@ package peersim.kademlia.das; import java.math.BigInteger; -import peersim.core.CommonState; import peersim.core.Node; import peersim.kademlia.Message; import peersim.kademlia.Util; @@ -10,12 +9,14 @@ public class DASProtocolValidator extends DASProtocol { protected static String prefix = null; + protected boolean started; public DASProtocolValidator(String prefix) { super(prefix); DASProtocolValidator.prefix = prefix; isValidator = true; isBuilder = false; + started = false; } @Override @@ -33,13 +34,40 @@ protected void handleInitGetSample(Message m, int myPid) { sendMessage(msg, builderAddress, myPid); } + @Override + protected void handleSeedSample(Message m, int myPid) { + Sample[] samples = (Sample[]) m.body; + for (Sample s : samples) { + logger.warning( + "Sample received " + + s.getId() + + " " + + s.getIdByColumn() + + " from " + + m.src.getId() + + " " + + m.id); + + kv.add((BigInteger) s.getIdByRow()); + // kv.add((BigInteger) s.getIdByRow(), s); + // kv.add((BigInteger) s.getIdByColumn(), s); + // count # of samples for each row and column and reconstruct if more than half received + reconstruct(s); + } + if (!started) { + started = true; + startRowsandColumnsSampling(); + } + } + @Override protected void handleInitNewBlock(Message m, int myPid) { super.handleInitNewBlock(m, myPid); - if (!isEvil) { + started = false; + /*if (!isEvil) { startRowsandColumnsSampling(); startRandomSampling(); - } + }*/ } /** @@ -77,14 +105,17 @@ protected void startRowsandColumnsSampling() { KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER, KademliaCommonConfigDas.validatorsSize)), time);*/ - createValidatorSamplingOperation( - CommonState.r.nextInt(KademliaCommonConfigDas.BLOCK_DIM_SIZE) + 1, 0, time); - createValidatorSamplingOperation( - 0, CommonState.r.nextInt(KademliaCommonConfigDas.BLOCK_DIM_SIZE) + 1, time); - createValidatorSamplingOperation( - CommonState.r.nextInt(KademliaCommonConfigDas.BLOCK_DIM_SIZE) + 1, 0, time); - createValidatorSamplingOperation( - 0, CommonState.r.nextInt(KademliaCommonConfigDas.BLOCK_DIM_SIZE) + 1, time); + // createValidatorSamplingOperation( + // CommonState.r.nextInt(KademliaCommonConfigDas.BLOCK_DIM_SIZE) + 1, 0, time); + // createValidatorSamplingOperation( + // 0, CommonState.r.nextInt(KademliaCommonConfigDas.BLOCK_DIM_SIZE) + 1, time); + // createValidatorSamplingOperation( + // CommonState.r.nextInt(KademliaCommonConfigDas.BLOCK_DIM_SIZE) + 1, 0, time); + // createValidatorSamplingOperation( + // 0, CommonState.r.nextInt(KademliaCommonConfigDas.BLOCK_DIM_SIZE) + 1, time); + + createValidatorSamplingOperation(searchTable.getValidatorRow(this.getKademliaId()), 0, time); + createValidatorSamplingOperation(0, searchTable.getValidatorColumn(this.getKademliaId()), time); } private void createValidatorSamplingOperation(int row, int column, long timestamp) { diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index 45dd2c15..4624d054 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -1,254 +1,125 @@ package peersim.kademlia.das; import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; -import peersim.core.Node; +import java.util.*; -public class SearchTable { +import peersim.core.CommonState; +import peersim.core.Network; - private HashMap neighbours; +public class SearchTable extends SearchTableV1 { - private TreeSet nodesIndexed; // , samplesIndexed; - - private static TreeSet validatorsIndexed = new TreeSet<>(); // , samplesIndexed; - - private TreeSet nonValidatorsIndexed; // , samplesIndexed; - - private HashSet blackList; // , samplesIndexed; - - private BigInteger builderAddress; - - private List evilNodes; - private List evilIds; + private HashMap> validatorsSamples; + private HashMap validatorsRow; + private HashMap validatorsColumn; + private HashMap> rowsValidator; + private HashMap> columnsValidator; public SearchTable() { - - this.nodesIndexed = new TreeSet<>(); - this.nonValidatorsIndexed = new TreeSet<>(); - - this.blackList = new HashSet<>(); - this.neighbours = new HashMap<>(); - } - - public void addNeighbour(Neighbour neigh) { - if (neigh.getId().compareTo(builderAddress) != 0) { - if (neighbours.get(neigh.getId()) == null) { - neighbours.put(neigh.getId(), neigh); - nodesIndexed.add(neigh.getId()); + validatorsSamples = new HashMap<>(); + validatorsRow = new HashMap<>(); + validatorsColumn = new HashMap<>(); + rowsValidator = new HashMap<>(); + columnsValidator = new HashMap<>(); + } + + public void assignSamples(Block b, int r) { + /* BigInteger radiusValidator = b.computeRegionRadius(r, this.getValidatorsIndexed().size()); + + while (b.hasNext()) { + BigInteger radiusUsed = radiusValidator; + boolean inRegion = false; + Sample s = b.next(); + while (!inRegion) { + + List idsValidators = this.getValidatorNodesbySample(s.getIdByRow(), radiusUsed); + if (idsValidators.size() > 0) { + inRegion = true; + validatorsSamples.put(s.getIdByRow(), idsValidators); + rowsValidator.put(s.getRow(), idsValidators); + for (BigInteger id : idsValidators) { + validatorsRow.put(id, s.getRow()); + } + } + idsValidators = this.getValidatorNodesbySample(s.getIdByColumn(), radiusUsed); + if (idsValidators.size() > 0) { + inRegion = true; + validatorsSamples.put(s.getIdByColumn(), idsValidators); + columnsValidator.put(s.getRow(), idsValidators); + for (BigInteger id : idsValidators) { + validatorsColumn.put(id, s.getColumn()); + } + } + if (!inRegion) radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); + } + }*/ + int nodesPerRow = + Network.size() / (b.getSize() * KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); + + int row = 1; + int counter = 0; + for (int i = 0; i < Network.size(); i++) { + counter++; + BigInteger id = Network.get(i).getDASProtocol().getKademliaId(); + if (rowsValidator.get(row) != null) { + rowsValidator.get(row).add(id); } else { - if (neighbours.get(neigh.getId()).getLastSeen() < neigh.getLastSeen()) - neighbours.get(neigh.getId()).updateLastSeen(neigh.getLastSeen()); + List list = new ArrayList<>(); + list.add(id); + rowsValidator.put(row, list); } - } - } - - public void addNodes(BigInteger[] nodes) { - - for (BigInteger id : nodes) { - if (id.compareTo(builderAddress) != 0) { - if (!blackList.contains(id) - && !validatorsIndexed.contains(id) - && !builderAddress.equals(id)) { - nonValidatorsIndexed.add(id); - } + validatorsRow.put(id, row); + if (counter == nodesPerRow) { + row++; + counter = 0; } + if (row > b.getSize()) break; } - } - public void addValidatorNodes(BigInteger[] nodes) { - for (BigInteger id : nodes) { - if (!blackList.contains(id) && id.compareTo(builderAddress) != 0) { - validatorsIndexed.add(id); + int column = 1; + counter = 0; + for (int i = 0; i < Network.size(); i++) { + counter++; + BigInteger id = Network.get(i).getDASProtocol().getKademliaId(); + if (columnsValidator.get(column) != null) { + columnsValidator.get(column).add(id); + } else { + List list = new ArrayList<>(); + list.add(id); + columnsValidator.put(column, list); } - } - } - - public void setBuilderAddress(BigInteger builderAddress) { - this.builderAddress = builderAddress; - } - - public void removeNode(BigInteger node) { - this.nodesIndexed.remove(node); - this.nonValidatorsIndexed.remove(node); - this.neighbours.remove(node); - validatorsIndexed.remove(node); - } - - public TreeSet nodesIndexed() { - return nodesIndexed; - } - - public TreeSet getValidatorsIndexed() { - return validatorsIndexed; - } - - public List getNodesbySample(BigInteger sampleId, BigInteger radius) { - - BigInteger bottom = sampleId.subtract(radius); - if (radius.compareTo(sampleId) == 1) bottom = BigInteger.ZERO; - - BigInteger top = sampleId.add(radius); - if (top.compareTo(Block.MAX_KEY) == 1) top = Block.MAX_KEY; - - Collection subSet = nodesIndexed.subSet(bottom, true, top, true); - return new ArrayList(subSet); - } - - public List getValidatorNodesbySample(BigInteger sampleId, BigInteger radius) { - - BigInteger bottom = sampleId.subtract(radius); - if (radius.compareTo(sampleId) == 1) bottom = BigInteger.ZERO; - - BigInteger top = sampleId.add(radius); - if (top.compareTo(Block.MAX_KEY) == 1) top = Block.MAX_KEY; - Collection subSet = validatorsIndexed.subSet(bottom, true, top, true); - return new ArrayList(subSet); - } - - public List getNonValidatorNodesbySample(BigInteger sampleId, BigInteger radius) { - - BigInteger bottom = sampleId.subtract(radius); - if (radius.compareTo(sampleId) == 1) bottom = BigInteger.ZERO; - - BigInteger top = sampleId.add(radius); - if (top.compareTo(Block.MAX_KEY) == 1) top = Block.MAX_KEY; - - Collection subSet = nonValidatorsIndexed.subSet(bottom, true, top, true); - return new ArrayList(subSet); - } - - public List getNodesbySample(Set samples, BigInteger radius) { - - List result = new ArrayList<>(); - - for (BigInteger sample : samples) { - result.addAll(getNodesbySample(sample, radius)); - } - return result; - } - - public List getAllNeighbours() { - - List result = new ArrayList<>(neighbours.keySet()); - return result; - } - - public Neighbour[] getNeighbours(int n) { - - List result = new ArrayList<>(); - List neighs = new ArrayList<>(); - for (Neighbour neigh : neighbours.values()) { - neighs.add(neigh); - } - Collections.shuffle(neighs); - - for (Neighbour neigh : neighs) { - if (result.size() < n) result.add(neigh); - else break; - } - return result.toArray(new Neighbour[0]); - } - - public void setEvil(List nodes) { - this.evilNodes = nodes; - } - - public boolean isEvil(BigInteger id) { - if (evilIds.contains(id)) return true; - else return false; - } + validatorsColumn.put(id, column); - public void setEvilIds(List ids) { - this.evilIds = ids; - } - - public Neighbour[] getEvilNeighbours(int n) { - - List result = new ArrayList<>(); - if (evilNodes != null) { - Collections.shuffle(evilNodes); - for (Node neigh : evilNodes) { - if (result.size() < n) - result.add(new Neighbour(neigh.getDASProtocol().getKademliaId(), neigh, true)); - else break; + if (counter == nodesPerRow) { + column++; + counter = 0; } + if (column > b.getSize()) break; } - return result.toArray(new Neighbour[0]); - } - - public Neighbour[] getNeighbours(BigInteger id, BigInteger radius) { - List nodes = getNodesbySample(id, radius); - List neighs = new ArrayList<>(); - List result = new ArrayList<>(); - for (BigInteger n : nodes) { - neighs.add(neighbours.get(n)); + for (int i : rowsValidator.keySet()) { + System.out.println("Row " + i + " nodes " + rowsValidator.get(i).size()); } - Collections.shuffle(neighs); - for (Neighbour neigh : neighs) { - if (result.size() < KademliaCommonConfigDas.MAX_NODES_RETURNED) result.add(neigh); - else break; + for (int i : columnsValidator.keySet()) { + System.out.println("Column " + i + " nodes " + columnsValidator.get(i).size()); } - return result.toArray(new Neighbour[0]); - } - - public int getAllNeighboursCount() { - return neighbours.size(); - } - - public int getValidatorsNeighboursCount() { - int count = 0; - for (Neighbour neigh : neighbours.values()) { - if (neigh.getNode().getDASProtocol().isValidator()) count++; + + for (int r=1;r<=b.getSize();r++) { + Sample s = b.getSample(row, column) + List vals = rowsValidator.get(s.getRow()); + validatorsSamples.put(s.getId(),vals.get(CommonState.r.nextInt(vals.size())) ) } - return count; } - public int getNonValidatorsNeighboursCount() { - int count = 0; - for (Neighbour neigh : neighbours.values()) { - if (!neigh.getNode().getDASProtocol().isValidator()) count++; - } - return count; + public List getNodesBySample(BigInteger sampleId) { + return validatorsSamples.get(sampleId); } - public int getAllAliveNeighboursCount() { - int count = 0; - for (Neighbour neigh : neighbours.values()) { - if (neigh.getNode().isUp()) count++; - } - return count; + public int getValidatorRow(BigInteger id) { + return validatorsRow.get(id); } - public int getMaliciousNeighboursCount() { - int count = 0; - for (Neighbour neigh : neighbours.values()) { - if (neigh.isEvil()) count++; - } - return count; - } - - public boolean isNeighbourKnown(Neighbour neighbour) { - return neighbours.containsKey(neighbour.getId()); - } - - public void refresh() { - - List toRemove = new ArrayList<>(); - for (Neighbour neigh : neighbours.values()) { - if (neigh.expired()) { - toRemove.add(neigh); - nodesIndexed.remove(neigh.getId()); - } - } - for (Neighbour n : toRemove) neighbours.remove(n.getId()); + public int getValidatorColumn(BigInteger id) { + return validatorsColumn.get(id); } } From 0d0f62b7190b11502b7cdda2bff998b48ab92b70 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sun, 1 Dec 2024 17:57:23 +0100 Subject: [PATCH 93/98] wip --- .../config/malicious/dasprotocolevil0.cfg | 2 +- .../peersim/kademlia/das/DASProtocol.java | 2 +- .../kademlia/das/DASProtocolBuilder.java | 6 +- .../kademlia/das/DASProtocolValidator.java | 13 +- .../peersim/kademlia/das/SearchTable.java | 205 ++++++++++++------ 5 files changed, 154 insertions(+), 74 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg index 5a79fa49..5c60be8d 100644 --- a/simulator/config/malicious/dasprotocolevil0.cfg +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 10000 +SIZE 1000 # Random seed K 5 diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index 8c8c8081..c8bceac0 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -801,7 +801,7 @@ protected void startRandomSampling() { protected boolean doSampling(SamplingOperation sop) { - logger.info("Doingsampling " + sop.getId() + " " + sop.getPending()); + logger.warning("Doingsampling " + sop.getId() + " " + sop.getPending()); if (sop.completed()) { samplingOp.remove(sop.getId()); KademliaObserver.reportOperation(sop); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index a4d82724..0c8ad6a2 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -29,7 +29,7 @@ protected void handleInitNewBlock(Message m, int myPid) { super.handleInitNewBlock(m, myPid); logger.warning("Builder new block:" + currentBlock.getBlockId()); - searchTable.assignSamples(currentBlock, KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); + searchTable.assignByRowColumn(currentBlock); currentBlock.initIterator(); while (currentBlock.hasNext()) { @@ -44,6 +44,8 @@ protected void handleInitNewBlock(Message m, int myPid) { Node n = Util.nodeIdtoNode(id, kademliaId); msg.dst = n.getKademliaProtocol().getKademliaNode(); sendMessage(msg, id, myPid); + System.out.println( + "Sending row " + s.getRow() + " column " + s.getColumn() + " to " + id); } } @@ -56,6 +58,8 @@ protected void handleInitNewBlock(Message m, int myPid) { Node n = Util.nodeIdtoNode(id, kademliaId); msg.dst = n.getKademliaProtocol().getKademliaNode(); sendMessage(msg, id, myPid); + System.out.println( + "Sending row " + s.getRow() + " column " + s.getColumn() + " to " + id); } } } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index 8952a080..7c6b5e3f 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -1,6 +1,7 @@ package peersim.kademlia.das; import java.math.BigInteger; +import peersim.core.CommonState; import peersim.core.Node; import peersim.kademlia.Message; import peersim.kademlia.Util; @@ -114,8 +115,16 @@ protected void startRowsandColumnsSampling() { // createValidatorSamplingOperation( // 0, CommonState.r.nextInt(KademliaCommonConfigDas.BLOCK_DIM_SIZE) + 1, time); - createValidatorSamplingOperation(searchTable.getValidatorRow(this.getKademliaId()), 0, time); - createValidatorSamplingOperation(0, searchTable.getValidatorColumn(this.getKademliaId()), time); + int row = searchTable.getValidatorRow(this.getKademliaId()); + if (row == 0) { + row = CommonState.r.nextInt(currentBlock.getSize()) + 1; + } + int column = searchTable.getValidatorColumn(this.getKademliaId()); + if (column == 0) { + column = CommonState.r.nextInt(currentBlock.getSize()) + 1; + } + createValidatorSamplingOperation(row, 0, time); + // createValidatorSamplingOperation(0, column, time); } private void createValidatorSamplingOperation(int row, int column, long timestamp) { diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index 4624d054..3e797f69 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -2,7 +2,6 @@ import java.math.BigInteger; import java.util.*; - import peersim.core.CommonState; import peersim.core.Network; @@ -22,95 +21,163 @@ public SearchTable() { columnsValidator = new HashMap<>(); } - public void assignSamples(Block b, int r) { - /* BigInteger radiusValidator = b.computeRegionRadius(r, this.getValidatorsIndexed().size()); + public void assignSamplesRandom(Block b, int r) { + for (int i = 0; i < Network.size(); i++) { + BigInteger id = Network.get(i).getDASProtocol().getKademliaId(); + validatorsRow.put(id, 0); + validatorsColumn.put(id, 0); + } + ArrayList list = new ArrayList<>(validatorsIndexed); + while (b.hasNext()) { + Sample s = b.next(); + validatorsSamples.put(s.getIdByRow(), new ArrayList<>()); + validatorsSamples.put(s.getIdByColumn(), new ArrayList<>()); + BigInteger randomNode = list.get(CommonState.r.nextInt(validatorsIndexed.size())); + validatorsRow.put(randomNode, s.getRow()); + validatorsRow.put(randomNode, s.getColumn()); + validatorsSamples.get(s.getIdByRow()).add(randomNode); + validatorsSamples.get(s.getIdByColumn()).add(randomNode); + } + } + public void assignSamplesRadius(Block b, int r) { + BigInteger radiusValidator = b.computeRegionRadius(r, this.getValidatorsIndexed().size()); while (b.hasNext()) { - BigInteger radiusUsed = radiusValidator; - boolean inRegion = false; - Sample s = b.next(); - while (!inRegion) { - - List idsValidators = this.getValidatorNodesbySample(s.getIdByRow(), radiusUsed); - if (idsValidators.size() > 0) { - inRegion = true; - validatorsSamples.put(s.getIdByRow(), idsValidators); - rowsValidator.put(s.getRow(), idsValidators); - for (BigInteger id : idsValidators) { - validatorsRow.put(id, s.getRow()); - } - } - idsValidators = this.getValidatorNodesbySample(s.getIdByColumn(), radiusUsed); - if (idsValidators.size() > 0) { - inRegion = true; - validatorsSamples.put(s.getIdByColumn(), idsValidators); - columnsValidator.put(s.getRow(), idsValidators); - for (BigInteger id : idsValidators) { - validatorsColumn.put(id, s.getColumn()); - } - } - if (!inRegion) radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); - } - }*/ - int nodesPerRow = - Network.size() / (b.getSize() * KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); - - int row = 1; - int counter = 0; - for (int i = 0; i < Network.size(); i++) { - counter++; + BigInteger radiusUsed = radiusValidator; + boolean inRegion = false; + Sample s = b.next(); + while (!inRegion) { + + List idsValidators = this.getValidatorNodesbySample(s.getIdByRow(), radiusUsed); + if (idsValidators.size() > 0) { + inRegion = true; + validatorsSamples.put(s.getIdByRow(), idsValidators); + rowsValidator.put(s.getRow(), idsValidators); + for (BigInteger id : idsValidators) { + validatorsRow.put(id, s.getRow()); + } + } + idsValidators = this.getValidatorNodesbySample(s.getIdByColumn(), radiusUsed); + if (idsValidators.size() > 0) { + inRegion = true; + validatorsSamples.put(s.getIdByColumn(), idsValidators); + columnsValidator.put(s.getRow(), idsValidators); + for (BigInteger id : idsValidators) { + validatorsColumn.put(id, s.getColumn()); + } + } + if (!inRegion) radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); + } + } + } + + public void assignByRowColumn(Block b) { + + int i = 0; + for (int row = 0; row < b.getSize(); row++) { BigInteger id = Network.get(i).getDASProtocol().getKademliaId(); - if (rowsValidator.get(row) != null) { - rowsValidator.get(row).add(id); - } else { - List list = new ArrayList<>(); - list.add(id); - rowsValidator.put(row, list); + if (id.compareTo(builderAddress) == 0) { + id = Network.get(i + 1).getDASProtocol().getKademliaId(); } validatorsRow.put(id, row); - if (counter == nodesPerRow) { - row++; - counter = 0; + + for (int column = 0; column < b.getSize(); column++) { + BigInteger sampleRow = b.getSample(row, column).getIdByRow(); + if (validatorsSamples.get(sampleRow) == null) { + validatorsSamples.put(sampleRow, new ArrayList<>()); + } + validatorsSamples.get(sampleRow).add(id); } - if (row > b.getSize()) break; + + i++; + if (i >= Network.size()) i = 0; } - int column = 1; - counter = 0; - for (int i = 0; i < Network.size(); i++) { - counter++; + for (int column = 0; column < b.getSize(); column++) { BigInteger id = Network.get(i).getDASProtocol().getKademliaId(); - if (columnsValidator.get(column) != null) { - columnsValidator.get(column).add(id); - } else { - List list = new ArrayList<>(); - list.add(id); - columnsValidator.put(column, list); + if (id.compareTo(builderAddress) == 0) { + id = Network.get(i + 1).getDASProtocol().getKademliaId(); } validatorsColumn.put(id, column); - if (counter == nodesPerRow) { - column++; - counter = 0; + for (int row = 0; row < b.getSize(); row++) { + BigInteger sampleColumn = b.getSample(row, column).getIdByColumn(); + if (validatorsSamples.get(sampleColumn) == null) { + validatorsSamples.put(sampleColumn, new ArrayList<>()); + } + validatorsSamples.get(sampleColumn).add(id); } - if (column > b.getSize()) break; + + i++; + if (i >= Network.size()) i = 0; } + } + + public List getValidatorNodesbySample(BigInteger sampleId, BigInteger radius) { + return validatorsSamples.get(sampleId); + } - for (int i : rowsValidator.keySet()) { - System.out.println("Row " + i + " nodes " + rowsValidator.get(i).size()); + public List getNonValidatorNodesbySample(BigInteger sampleId, BigInteger radius) { + return new ArrayList<>(); + } + /*int nodesPerRow = + Network.size() / (b.getSize() * KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); + + int row = 1; + int counter = 0; + for (int i = 0; i < Network.size(); i++) { + counter++; + BigInteger id = Network.get(i).getDASProtocol().getKademliaId(); + if (rowsValidator.get(row) != null) { + rowsValidator.get(row).add(id); + } else { + List list = new ArrayList<>(); + list.add(id); + rowsValidator.put(row, list); + } + validatorsRow.put(id, row); + if (counter == nodesPerRow) { + row++; + counter = 0; } + if (row > b.getSize()) break; + } - for (int i : columnsValidator.keySet()) { - System.out.println("Column " + i + " nodes " + columnsValidator.get(i).size()); + int column = 1; + counter = 0; + for (int i = 0; i < Network.size(); i++) { + counter++; + BigInteger id = Network.get(i).getDASProtocol().getKademliaId(); + if (columnsValidator.get(column) != null) { + columnsValidator.get(column).add(id); + } else { + List list = new ArrayList<>(); + list.add(id); + columnsValidator.put(column, list); } - - for (int r=1;r<=b.getSize();r++) { - Sample s = b.getSample(row, column) - List vals = rowsValidator.get(s.getRow()); - validatorsSamples.put(s.getId(),vals.get(CommonState.r.nextInt(vals.size())) ) + validatorsColumn.put(id, column); + + if (counter == nodesPerRow) { + column++; + counter = 0; } + if (column > b.getSize()) break; + } + + for (int i : rowsValidator.keySet()) { + System.out.println("Row " + i + " nodes " + rowsValidator.get(i).size()); } + for (int i : columnsValidator.keySet()) { + System.out.println("Column " + i + " nodes " + columnsValidator.get(i).size()); + } + + for (int r=1;r<=b.getSize();r++) { + Sample s = b.getSample(row, column) + List vals = rowsValidator.get(s.getRow()); + validatorsSamples.put(s.getId(),vals.get(CommonState.r.nextInt(vals.size())) ) + }*/ + public List getNodesBySample(BigInteger sampleId) { return validatorsSamples.get(sampleId); } From ccb9988a5acef30347a4ccf0cb391f81dbcbd7ce Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sun, 1 Dec 2024 18:48:16 +0100 Subject: [PATCH 94/98] file --- .../peersim/kademlia/das/SearchTableV1.java | 254 ++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 simulator/src/main/java/peersim/kademlia/das/SearchTableV1.java diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTableV1.java b/simulator/src/main/java/peersim/kademlia/das/SearchTableV1.java new file mode 100644 index 00000000..09255d4e --- /dev/null +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTableV1.java @@ -0,0 +1,254 @@ +package peersim.kademlia.das; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import peersim.core.Node; + +public class SearchTableV1 { + + private HashMap neighbours; + + private TreeSet nodesIndexed; // , samplesIndexed; + + protected TreeSet validatorsIndexed; // , samplesIndexed; + + private TreeSet nonValidatorsIndexed; // , samplesIndexed; + + private HashSet blackList; // , samplesIndexed; + + protected BigInteger builderAddress; + + private List evilNodes; + private List evilIds; + + public SearchTableV1() { + + this.nodesIndexed = new TreeSet<>(); + this.nonValidatorsIndexed = new TreeSet<>(); + this.validatorsIndexed = new TreeSet<>(); + this.blackList = new HashSet<>(); + this.neighbours = new HashMap<>(); + } + + public void addNeighbour(Neighbour neigh) { + if (neigh.getId().compareTo(builderAddress) != 0) { + if (neighbours.get(neigh.getId()) == null) { + neighbours.put(neigh.getId(), neigh); + nodesIndexed.add(neigh.getId()); + } else { + if (neighbours.get(neigh.getId()).getLastSeen() < neigh.getLastSeen()) + neighbours.get(neigh.getId()).updateLastSeen(neigh.getLastSeen()); + } + } + } + + public void addNodes(BigInteger[] nodes) { + + for (BigInteger id : nodes) { + if (id.compareTo(builderAddress) != 0) { + if (!blackList.contains(id) + && !validatorsIndexed.contains(id) + && !builderAddress.equals(id)) { + nonValidatorsIndexed.add(id); + } + } + } + } + + public void addValidatorNodes(BigInteger[] nodes) { + for (BigInteger id : nodes) { + if (!blackList.contains(id) && id.compareTo(builderAddress) != 0) { + validatorsIndexed.add(id); + } + } + } + + public void setBuilderAddress(BigInteger builderAddress) { + this.builderAddress = builderAddress; + } + + public void removeNode(BigInteger node) { + this.nodesIndexed.remove(node); + this.nonValidatorsIndexed.remove(node); + this.neighbours.remove(node); + validatorsIndexed.remove(node); + } + + public TreeSet nodesIndexed() { + return nodesIndexed; + } + + public TreeSet getValidatorsIndexed() { + return validatorsIndexed; + } + + public List getNodesbySample(BigInteger sampleId, BigInteger radius) { + + BigInteger bottom = sampleId.subtract(radius); + if (radius.compareTo(sampleId) == 1) bottom = BigInteger.ZERO; + + BigInteger top = sampleId.add(radius); + if (top.compareTo(Block.MAX_KEY) == 1) top = Block.MAX_KEY; + + Collection subSet = nodesIndexed.subSet(bottom, true, top, true); + return new ArrayList(subSet); + } + + public List getValidatorNodesbySample(BigInteger sampleId, BigInteger radius) { + + BigInteger bottom = sampleId.subtract(radius); + if (radius.compareTo(sampleId) == 1) bottom = BigInteger.ZERO; + + BigInteger top = sampleId.add(radius); + if (top.compareTo(Block.MAX_KEY) == 1) top = Block.MAX_KEY; + Collection subSet = validatorsIndexed.subSet(bottom, true, top, true); + return new ArrayList(subSet); + } + + public List getNonValidatorNodesbySample(BigInteger sampleId, BigInteger radius) { + + BigInteger bottom = sampleId.subtract(radius); + if (radius.compareTo(sampleId) == 1) bottom = BigInteger.ZERO; + + BigInteger top = sampleId.add(radius); + if (top.compareTo(Block.MAX_KEY) == 1) top = Block.MAX_KEY; + + Collection subSet = nonValidatorsIndexed.subSet(bottom, true, top, true); + return new ArrayList(subSet); + } + + public List getNodesbySample(Set samples, BigInteger radius) { + + List result = new ArrayList<>(); + + for (BigInteger sample : samples) { + result.addAll(getNodesbySample(sample, radius)); + } + return result; + } + + public List getAllNeighbours() { + + List result = new ArrayList<>(neighbours.keySet()); + return result; + } + + public Neighbour[] getNeighbours(int n) { + + List result = new ArrayList<>(); + List neighs = new ArrayList<>(); + for (Neighbour neigh : neighbours.values()) { + neighs.add(neigh); + } + Collections.shuffle(neighs); + + for (Neighbour neigh : neighs) { + if (result.size() < n) result.add(neigh); + else break; + } + return result.toArray(new Neighbour[0]); + } + + public void setEvil(List nodes) { + this.evilNodes = nodes; + } + + public boolean isEvil(BigInteger id) { + if (evilIds.contains(id)) return true; + else return false; + } + + public void setEvilIds(List ids) { + this.evilIds = ids; + } + + public Neighbour[] getEvilNeighbours(int n) { + + List result = new ArrayList<>(); + if (evilNodes != null) { + Collections.shuffle(evilNodes); + for (Node neigh : evilNodes) { + if (result.size() < n) + result.add(new Neighbour(neigh.getDASProtocol().getKademliaId(), neigh, true)); + else break; + } + } + return result.toArray(new Neighbour[0]); + } + + public Neighbour[] getNeighbours(BigInteger id, BigInteger radius) { + + List nodes = getNodesbySample(id, radius); + List neighs = new ArrayList<>(); + List result = new ArrayList<>(); + for (BigInteger n : nodes) { + neighs.add(neighbours.get(n)); + } + Collections.shuffle(neighs); + + for (Neighbour neigh : neighs) { + if (result.size() < KademliaCommonConfigDas.MAX_NODES_RETURNED) result.add(neigh); + else break; + } + return result.toArray(new Neighbour[0]); + } + + public int getAllNeighboursCount() { + return neighbours.size(); + } + + public int getValidatorsNeighboursCount() { + int count = 0; + for (Neighbour neigh : neighbours.values()) { + if (neigh.getNode().getDASProtocol().isValidator()) count++; + } + return count; + } + + public int getNonValidatorsNeighboursCount() { + int count = 0; + for (Neighbour neigh : neighbours.values()) { + if (!neigh.getNode().getDASProtocol().isValidator()) count++; + } + return count; + } + + public int getAllAliveNeighboursCount() { + int count = 0; + for (Neighbour neigh : neighbours.values()) { + if (neigh.getNode().isUp()) count++; + } + return count; + } + + public int getMaliciousNeighboursCount() { + int count = 0; + for (Neighbour neigh : neighbours.values()) { + if (neigh.isEvil()) count++; + } + return count; + } + + public boolean isNeighbourKnown(Neighbour neighbour) { + return neighbours.containsKey(neighbour.getId()); + } + + public void refresh() { + + List toRemove = new ArrayList<>(); + for (Neighbour neigh : neighbours.values()) { + if (neigh.expired()) { + toRemove.add(neigh); + nodesIndexed.remove(neigh.getId()); + } + } + for (Neighbour n : toRemove) neighbours.remove(n.getId()); + } +} From 16230e55b8f48543863a1459c7e866aa12a36927 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sat, 18 Jan 2025 19:08:15 +0100 Subject: [PATCH 95/98] seeding ok --- .../config/malicious/dasprotocolevil0.cfg | 7 +- .../peersim/kademlia/KademliaObserver.java | 19 + .../main/java/peersim/kademlia/Message.java | 8 + .../peersim/kademlia/das/DASProtocol.java | 29 +- .../kademlia/das/DASProtocolBuilder.java | 216 +++++++++-- .../kademlia/das/DASProtocolNonValidator.java | 2 +- .../kademlia/das/DASProtocolValidator.java | 15 +- .../peersim/kademlia/das/SearchTable.java | 356 ++++++++++-------- .../peersim/kademlia/das/SearchTableV1.java | 254 ------------- .../peersim/kademlia/das/SearchTableV2.java | 192 ++++++++++ .../kademlia/das/SeedingSampleBody.java | 29 ++ 11 files changed, 679 insertions(+), 448 deletions(-) delete mode 100644 simulator/src/main/java/peersim/kademlia/das/SearchTableV1.java create mode 100644 simulator/src/main/java/peersim/kademlia/das/SearchTableV2.java create mode 100644 simulator/src/main/java/peersim/kademlia/das/SeedingSampleBody.java diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg index 5c60be8d..3bab4834 100644 --- a/simulator/config/malicious/dasprotocolevil0.cfg +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -11,7 +11,7 @@ SIZE 1000 K 5 MINDELAY 5 -MAXDELAY 100 +MAXDELAY 200 #Simulation time in ms SIM_TIME 11999 @@ -64,26 +64,31 @@ protocol.4dasprotocol peersim.kademlia.das.DASProtocolBuilder protocol.4dasprotocol.transport 2unreltr protocol.4dasprotocol.kademlia 3kademlia protocol.4dasprotocol.reportDiscovery false +protocol.4dasprotocol.reportMsg true protocol.5dasprotocol peersim.kademlia.das.DASProtocolValidator protocol.5dasprotocol.transport 2unreltr protocol.5dasprotocol.kademlia 3kademlia protocol.5dasprotocol.reportDiscovery false +protocol.5dasprotocol.reportMsg true protocol.6dasprotocol peersim.kademlia.das.DASProtocolNonValidator protocol.6dasprotocol.transport 2unreltr protocol.6dasprotocol.kademlia 3kademlia protocol.6dasprotocol.reportDiscovery false +protocol.6dasprotocol.reportMsg true protocol.7evildasprotocol peersim.kademlia.das.DASProtocolEvilValidator protocol.7evildasprotocol.transport 2unreltr protocol.7evildasprotocol.kademlia 3kademlia protocol.7evildasprotocol.reportDiscovery false +protocol.7evildasprotocol.reportMsg true protocol.8evildasprotocol peersim.kademlia.das.DASProtocolEvilNonValidator protocol.8evildasprotocol.transport 2unreltr protocol.8evildasprotocol.kademlia 3kademlia protocol.8evildasprotocol.reportDiscovery false +protocol.8evildasprotocol.reportMsg true # ::::: INITIALIZERS ::::: #Class that initializes nodes with kademlia protocol and generates uniform ids diff --git a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java index e551df19..78ed900f 100755 --- a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java +++ b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java @@ -302,6 +302,25 @@ private static HashMap> writeMessages() { msgs.put(msgId, result); msgId++; } + for (BigInteger id : msgsOut.keySet()) { + if (msgsIn.keySet().contains(id)) { + continue; + } + Map result = new HashMap(); + result.put("id", id); + Node n = Util.nodeIdtoNode(id, kademliaid); + boolean builder = n.getDASProtocol().isBuilder(); + boolean validator = n.getDASProtocol().isValidator(); + result.put("msgsIn", msgsIn.get(id)); + result.put("msgsOut", msgsOut.get(id)); + result.put("bytesIn", bytesIn.get(id)); + result.put("bytesOut", bytesOut.get(id)); + if (builder) result.put("nodeType", "builder"); + else if (validator) result.put("nodeType", "validator"); + else result.put("nodeType", "regular"); + msgs.put(msgId, result); + msgId++; + } return msgs; } } diff --git a/simulator/src/main/java/peersim/kademlia/Message.java b/simulator/src/main/java/peersim/kademlia/Message.java index c498baef..a835e6c4 100755 --- a/simulator/src/main/java/peersim/kademlia/Message.java +++ b/simulator/src/main/java/peersim/kademlia/Message.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.Map; import peersim.kademlia.das.Sample; +import peersim.kademlia.das.SeedingSampleBody; /** * Message class provide all functionalities to magage the various messages, principally LOOKUP @@ -155,6 +156,13 @@ public Message(int messageType, Object body) { size += 15 * 32; // neighbours size += 64; // src dst id size += 4; // message type + } else if (body instanceof SeedingSampleBody) { + SeedingSampleBody ssb = (SeedingSampleBody) body; + Sample[] samples = (Sample[]) ssb.getsamplesList(); + size += 512 * samples.length; // samples + size += 15 * 32; // neighbours + size += 64; // src dst id + size += 4; // message type } } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java index c8bceac0..7dcc1f5a 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocol.java @@ -179,7 +179,8 @@ public void processEvent(Node myNode, int myPid, Object event) { // m.dst = this.kadProtocol.getKademliaNode(); if (msgReport && (m.getType() == Message.MSG_GET_SAMPLE - || m.getType() == Message.MSG_GET_SAMPLE_RESPONSE)) + || m.getType() == Message.MSG_GET_SAMPLE_RESPONSE + || m.getType() == Message.MSG_SEED_SAMPLE)) KademliaObserver.reportMsg(m, false, this.getKademliaId()); /*if (m.src != null) { Node n = Util.nodeIdtoNode(m.src.getId(), kademliaId); @@ -651,7 +652,8 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { transport = (UnreliableTransport) (Network.prototype).getProtocol(tid); if (msgReport && (m.getType() == Message.MSG_GET_SAMPLE - || m.getType() == Message.MSG_GET_SAMPLE_RESPONSE)) + || m.getType() == Message.MSG_GET_SAMPLE_RESPONSE + || m.getType() == Message.MSG_SEED_SAMPLE)) KademliaObserver.reportMsg(m, true, this.getKademliaId()); if (m.getType() != Message.MSG_GET_SAMPLE_RESPONSE && m.getType() != Message.MSG_SEED_SAMPLE) { @@ -660,7 +662,14 @@ protected void sendMessage(Message m, BigInteger destId, int myPid) { // Send message taking into account the transmission delay and the availability of upload // interface // Timeout t = new Timeout(destId, m.id, m.operationId); - Sample[] samples = (Sample[]) m.body; + Sample[] samples; + if (m.getType() == Message.MSG_SEED_SAMPLE) { + SeedingSampleBody body = (SeedingSampleBody) m.body; + samples = (Sample[]) body.getsamplesList(); + } else { + samples = (Sample[]) m.body; + } + // Sample[] samples = (Sample[]) m.body; // Neighbour[] nghbrs = (Neighbour[]) m.value; double samplesSize = 0.0; if (samples != null) samplesSize = samples.length * KademliaCommonConfigDas.SAMPLE_SIZE; @@ -914,20 +923,6 @@ public void missing(BigInteger sample, Operation op) { // missing = true; } - // ______________________________________________________________________________________________ - /** - * generates a GET message for a specific sample. - * - * @return Message - */ - protected Message generateSeedSampleMessage(Sample[] s) { - - Message m = new Message(Message.MSG_SEED_SAMPLE, s); - m.timestamp = CommonState.getTime(); - - return m; - } - // ______________________________________________________________________________________________ /** * generates a GET message for t1 key. diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index 0c8ad6a2..b6daf15b 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -1,7 +1,11 @@ package peersim.kademlia.das; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import peersim.core.CommonState; import peersim.core.Node; import peersim.kademlia.Message; import peersim.kademlia.Util; @@ -29,39 +33,207 @@ protected void handleInitNewBlock(Message m, int myPid) { super.handleInitNewBlock(m, myPid); logger.warning("Builder new block:" + currentBlock.getBlockId()); - searchTable.assignByRowColumn(currentBlock); + rowSeeding(); + columnSeeding(); + } + + // Generating specific messages to be sent + protected Message generateSeedSampleMessage( + Sample[] s, List validators, boolean isRow) { + SeedingSampleBody body = new SeedingSampleBody(s, validators, isRow); + Message m = new Message(Message.MSG_SEED_SAMPLE, body); + m.timestamp = CommonState.getTime(); + + return m; + } + + private void rowSeeding(){ + // =============== + // Row Seeding + // =============== + int actualRow = 1; + while (currentBlock.getSize() >= actualRow) { + + Sample[] sampleRow = currentBlock.getSamplesByRow(actualRow); // get all sample of the row + BigInteger radiusValidator = + currentBlock.computeRegionRadius(1, searchTable.getValidatorsIndexed().size()); + + // Get the id of all validators we need to send the message + List idsValidators = new ArrayList<>(); + for (Sample sample : sampleRow) { + List ids = + searchTable.getValidatorNodesbySample(sample.getIdByRow(), radiusValidator); + if (ids != null && ids.size() > 0) idsValidators.addAll(ids); + } + + if (idsValidators.size() == 0) { + actualRow++; + continue; + } + // remove duplicate + Set set = new HashSet<>(idsValidators); + idsValidators = new ArrayList<>(set); + + int numberValidatorRow = idsValidators.size(); // Get the number of validators + logger.warning( + "Block " + + currentBlock.getBlockId() + + " Number of Validator for row" + + actualRow + + " is: " + + numberValidatorRow + + " radius " + + radiusValidator + + " validators " + + searchTable.getValidatorsIndexed().size() + + " row " + + sampleRow.length); + + // Get size of Parcels to send + int sizeParcels = 0; + sizeParcels = (currentBlock.getSize() / numberValidatorRow); + int redundancyFactor = 1; + + int indexSampleList = 0; + + for (BigInteger id : idsValidators) { - currentBlock.initIterator(); - while (currentBlock.hasNext()) { - Sample s = currentBlock.next(); + // -------------------------- + // Create Row Parcels to send + // -------------------------- - List nodesByRow = searchTable.getNodesBySample(s.getId()); - if (nodesByRow != null) { - for (BigInteger id : nodesByRow) { - Message msg = new Message(Message.MSG_SEED_SAMPLE, new Sample[] {s}); + Sample[] validatorParcel = new Sample[sizeParcels * redundancyFactor]; + int k = 0; + while (k != sizeParcels * redundancyFactor) { + Sample s = sampleRow[indexSampleList % sampleRow.length]; + validatorParcel[k] = s; + indexSampleList++; + k++; + } + + // ---------------- + // Send Row Parcels + // ---------------- + + logger.warning( + "Sending row " + + actualRow + + " " + + "parcel to validator " + + id + + " samples " + + validatorParcel.length); + Node n = Util.nodeIdtoNode(id, kademliaId); + DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); + if (dasProt.isBuilder()) continue; + if (n.isUp()) { + Sample[] samples = validatorParcel; + Message msg = generateSeedSampleMessage(samples, idsValidators, true); msg.operationId = -1; - msg.src = this.kadProtocol.getKademliaNode(); - Node n = Util.nodeIdtoNode(id, kademliaId); + msg.src = this.getKademliaProtocol().getKademliaNode(); msg.dst = n.getKademliaProtocol().getKademliaNode(); - sendMessage(msg, id, myPid); - System.out.println( - "Sending row " + s.getRow() + " column " + s.getColumn() + " to " + id); + sendMessage(msg, id, dasProt.getDASProtocolID()); + //samplesValidators++; } } - List nodesByColumn = searchTable.getNodesBySample(s.getIdByColumn()); - if (nodesByColumn != null) { - for (BigInteger id : nodesByColumn) { - Message msg = new Message(Message.MSG_SEED_SAMPLE, new Sample[] {s}); + //samplesWithinRegion += sampleRow.length; + actualRow++; + } + } + + private void columnSeeding(){ + // =============== + // Column Seeding + // =============== + int actualColumn = 1; + while (currentBlock.getSize() >= actualColumn) { + + Sample[] sampleColumn= currentBlock.getSamplesByColumn(actualColumn); // get all sample of the column + BigInteger radiusValidator = + currentBlock.computeRegionRadius(1, searchTable.getValidatorsIndexed().size()); + + // Get the id of all validators we need to send the message + List idsValidators = new ArrayList<>(); + for (Sample sample : sampleColumn) { + List ids = + searchTable.getValidatorNodesbySample(sample.getIdByColumn(), radiusValidator); + if (ids != null && ids.size() > 0) idsValidators.addAll(ids); + } + + if (idsValidators.size() == 0) { + actualColumn++; + continue; + } + // remove duplicate + Set set = new HashSet<>(idsValidators); + idsValidators = new ArrayList<>(set); + + int numberValidatorColumn = idsValidators.size(); // Get the number of validators + logger.warning( + "Block " + + currentBlock.getBlockId() + + " Number of Validator for column" + + actualColumn + + " is: " + + numberValidatorColumn + + " radius " + + radiusValidator + + " validators " + + searchTable.getValidatorsIndexed().size() + + " column " + + sampleColumn.length); + + // Get size of Parcels to send + int sizeParcels = 0; + sizeParcels = (currentBlock.getSize() / numberValidatorColumn); + int redundancyFactor = 1; + + int indexSampleList = 0; + + for (BigInteger id : idsValidators) { + + // -------------------------- + // Create column Parcels to send + // -------------------------- + + Sample[] validatorParcel = new Sample[sizeParcels * redundancyFactor]; + int k = 0; + while (k != sizeParcels * redundancyFactor) { + Sample s = sampleColumn[indexSampleList % sampleColumn.length]; + validatorParcel[k] = s; + indexSampleList++; + k++; + } + + // ---------------- + // Send column Parcels + // ---------------- + + logger.warning( + "Sending column " + + actualColumn + + " " + + "parcel to validator " + + id + + " samples " + + validatorParcel.length); + Node n = Util.nodeIdtoNode(id, kademliaId); + DASProtocol dasProt = ((DASProtocol) (n.getDASProtocol())); + if (dasProt.isBuilder()) continue; + if (n.isUp()) { + Sample[] samples = validatorParcel; + Message msg = generateSeedSampleMessage(samples, idsValidators, true); msg.operationId = -1; - msg.src = this.kadProtocol.getKademliaNode(); - Node n = Util.nodeIdtoNode(id, kademliaId); + msg.src = this.getKademliaProtocol().getKademliaNode(); msg.dst = n.getKademliaProtocol().getKademliaNode(); - sendMessage(msg, id, myPid); - System.out.println( - "Sending row " + s.getRow() + " column " + s.getColumn() + " to " + id); + sendMessage(msg, id, dasProt.getDASProtocolID()); + //samplesValidators++; } } + + //samplesWithinRegion += sampleRow.length; + actualColumn++; } } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java index d9a72fa7..78a67dca 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java @@ -59,7 +59,7 @@ protected void handleInitNewBlock(Message m, int myPid) { validatorsContacted.clear(); super.handleInitNewBlock(m, myPid); if (!isEvil) { - startRandomSampling(); + // startRandomSampling(); } } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index 7c6b5e3f..02f4c31d 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -1,7 +1,6 @@ package peersim.kademlia.das; import java.math.BigInteger; -import peersim.core.CommonState; import peersim.core.Node; import peersim.kademlia.Message; import peersim.kademlia.Util; @@ -37,7 +36,10 @@ protected void handleInitGetSample(Message m, int myPid) { @Override protected void handleSeedSample(Message m, int myPid) { - Sample[] samples = (Sample[]) m.body; + + SeedingSampleBody body = (SeedingSampleBody) m.body; + Sample[] samples = (Sample[]) body.getsamplesList(); + logger.warning("Seed received " + samples.length + " samples."); for (Sample s : samples) { logger.warning( "Sample received " @@ -55,10 +57,10 @@ protected void handleSeedSample(Message m, int myPid) { // count # of samples for each row and column and reconstruct if more than half received reconstruct(s); } - if (!started) { + /*if (!started) { started = true; startRowsandColumnsSampling(); - } + }*/ } @Override @@ -115,7 +117,7 @@ protected void startRowsandColumnsSampling() { // createValidatorSamplingOperation( // 0, CommonState.r.nextInt(KademliaCommonConfigDas.BLOCK_DIM_SIZE) + 1, time); - int row = searchTable.getValidatorRow(this.getKademliaId()); + /*int row = searchTable.getValidatorRow(this.getKademliaId()); if (row == 0) { row = CommonState.r.nextInt(currentBlock.getSize()) + 1; } @@ -123,7 +125,8 @@ protected void startRowsandColumnsSampling() { if (column == 0) { column = CommonState.r.nextInt(currentBlock.getSize()) + 1; } - createValidatorSamplingOperation(row, 0, time); + + createValidatorSamplingOperation(row, 0, time);*/ // createValidatorSamplingOperation(0, column, time); } diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java index 3e797f69..bd022d99 100644 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTable.java +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTable.java @@ -1,192 +1,254 @@ package peersim.kademlia.das; import java.math.BigInteger; -import java.util.*; -import peersim.core.CommonState; -import peersim.core.Network; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import peersim.core.Node; -public class SearchTable extends SearchTableV1 { +public class SearchTable { - private HashMap> validatorsSamples; - private HashMap validatorsRow; - private HashMap validatorsColumn; - private HashMap> rowsValidator; - private HashMap> columnsValidator; + private HashMap neighbours; + + private TreeSet nodesIndexed; // , samplesIndexed; + + protected TreeSet validatorsIndexed; // , samplesIndexed; + + private TreeSet nonValidatorsIndexed; // , samplesIndexed; + + private HashSet blackList; // , samplesIndexed; + + protected BigInteger builderAddress; + + private List evilNodes; + private List evilIds; public SearchTable() { - validatorsSamples = new HashMap<>(); - validatorsRow = new HashMap<>(); - validatorsColumn = new HashMap<>(); - rowsValidator = new HashMap<>(); - columnsValidator = new HashMap<>(); - } - - public void assignSamplesRandom(Block b, int r) { - for (int i = 0; i < Network.size(); i++) { - BigInteger id = Network.get(i).getDASProtocol().getKademliaId(); - validatorsRow.put(id, 0); - validatorsColumn.put(id, 0); - } - ArrayList list = new ArrayList<>(validatorsIndexed); - while (b.hasNext()) { - Sample s = b.next(); - validatorsSamples.put(s.getIdByRow(), new ArrayList<>()); - validatorsSamples.put(s.getIdByColumn(), new ArrayList<>()); - BigInteger randomNode = list.get(CommonState.r.nextInt(validatorsIndexed.size())); - validatorsRow.put(randomNode, s.getRow()); - validatorsRow.put(randomNode, s.getColumn()); - validatorsSamples.get(s.getIdByRow()).add(randomNode); - validatorsSamples.get(s.getIdByColumn()).add(randomNode); - } + + this.nodesIndexed = new TreeSet<>(); + this.nonValidatorsIndexed = new TreeSet<>(); + this.validatorsIndexed = new TreeSet<>(); + this.blackList = new HashSet<>(); + this.neighbours = new HashMap<>(); } - public void assignSamplesRadius(Block b, int r) { - BigInteger radiusValidator = b.computeRegionRadius(r, this.getValidatorsIndexed().size()); - while (b.hasNext()) { - BigInteger radiusUsed = radiusValidator; - boolean inRegion = false; - Sample s = b.next(); - while (!inRegion) { - - List idsValidators = this.getValidatorNodesbySample(s.getIdByRow(), radiusUsed); - if (idsValidators.size() > 0) { - inRegion = true; - validatorsSamples.put(s.getIdByRow(), idsValidators); - rowsValidator.put(s.getRow(), idsValidators); - for (BigInteger id : idsValidators) { - validatorsRow.put(id, s.getRow()); - } - } - idsValidators = this.getValidatorNodesbySample(s.getIdByColumn(), radiusUsed); - if (idsValidators.size() > 0) { - inRegion = true; - validatorsSamples.put(s.getIdByColumn(), idsValidators); - columnsValidator.put(s.getRow(), idsValidators); - for (BigInteger id : idsValidators) { - validatorsColumn.put(id, s.getColumn()); - } - } - if (!inRegion) radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); + public void addNeighbour(Neighbour neigh) { + if (neigh.getId().compareTo(builderAddress) != 0) { + if (neighbours.get(neigh.getId()) == null) { + neighbours.put(neigh.getId(), neigh); + nodesIndexed.add(neigh.getId()); + } else { + if (neighbours.get(neigh.getId()).getLastSeen() < neigh.getLastSeen()) + neighbours.get(neigh.getId()).updateLastSeen(neigh.getLastSeen()); } } } - public void assignByRowColumn(Block b) { + public void addNodes(BigInteger[] nodes) { - int i = 0; - for (int row = 0; row < b.getSize(); row++) { - BigInteger id = Network.get(i).getDASProtocol().getKademliaId(); - if (id.compareTo(builderAddress) == 0) { - id = Network.get(i + 1).getDASProtocol().getKademliaId(); - } - validatorsRow.put(id, row); - - for (int column = 0; column < b.getSize(); column++) { - BigInteger sampleRow = b.getSample(row, column).getIdByRow(); - if (validatorsSamples.get(sampleRow) == null) { - validatorsSamples.put(sampleRow, new ArrayList<>()); + for (BigInteger id : nodes) { + if (id.compareTo(builderAddress) != 0) { + if (!blackList.contains(id) + && !validatorsIndexed.contains(id) + && !builderAddress.equals(id)) { + nonValidatorsIndexed.add(id); } - validatorsSamples.get(sampleRow).add(id); } - - i++; - if (i >= Network.size()) i = 0; } + } - for (int column = 0; column < b.getSize(); column++) { - BigInteger id = Network.get(i).getDASProtocol().getKademliaId(); - if (id.compareTo(builderAddress) == 0) { - id = Network.get(i + 1).getDASProtocol().getKademliaId(); + public void addValidatorNodes(BigInteger[] nodes) { + for (BigInteger id : nodes) { + if (!blackList.contains(id) && id.compareTo(builderAddress) != 0) { + validatorsIndexed.add(id); } - validatorsColumn.put(id, column); + } + } - for (int row = 0; row < b.getSize(); row++) { - BigInteger sampleColumn = b.getSample(row, column).getIdByColumn(); - if (validatorsSamples.get(sampleColumn) == null) { - validatorsSamples.put(sampleColumn, new ArrayList<>()); - } - validatorsSamples.get(sampleColumn).add(id); - } + public void setBuilderAddress(BigInteger builderAddress) { + this.builderAddress = builderAddress; + } - i++; - if (i >= Network.size()) i = 0; - } + public void removeNode(BigInteger node) { + this.nodesIndexed.remove(node); + this.nonValidatorsIndexed.remove(node); + this.neighbours.remove(node); + validatorsIndexed.remove(node); + } + + public TreeSet nodesIndexed() { + return nodesIndexed; + } + + public TreeSet getValidatorsIndexed() { + return validatorsIndexed; + } + + public List getNodesbySample(BigInteger sampleId, BigInteger radius) { + + BigInteger bottom = sampleId.subtract(radius); + if (radius.compareTo(sampleId) == 1) bottom = BigInteger.ZERO; + + BigInteger top = sampleId.add(radius); + if (top.compareTo(Block.MAX_KEY) == 1) top = Block.MAX_KEY; + + Collection subSet = nodesIndexed.subSet(bottom, true, top, true); + return new ArrayList(subSet); } public List getValidatorNodesbySample(BigInteger sampleId, BigInteger radius) { - return validatorsSamples.get(sampleId); + + BigInteger bottom = sampleId.subtract(radius); + if (radius.compareTo(sampleId) == 1) bottom = BigInteger.ZERO; + + BigInteger top = sampleId.add(radius); + if (top.compareTo(Block.MAX_KEY) == 1) top = Block.MAX_KEY; + Collection subSet = validatorsIndexed.subSet(bottom, true, top, true); + return new ArrayList(subSet); } public List getNonValidatorNodesbySample(BigInteger sampleId, BigInteger radius) { - return new ArrayList<>(); - } - /*int nodesPerRow = - Network.size() / (b.getSize() * KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); - - int row = 1; - int counter = 0; - for (int i = 0; i < Network.size(); i++) { - counter++; - BigInteger id = Network.get(i).getDASProtocol().getKademliaId(); - if (rowsValidator.get(row) != null) { - rowsValidator.get(row).add(id); - } else { - List list = new ArrayList<>(); - list.add(id); - rowsValidator.put(row, list); + + BigInteger bottom = sampleId.subtract(radius); + if (radius.compareTo(sampleId) == 1) bottom = BigInteger.ZERO; + + BigInteger top = sampleId.add(radius); + if (top.compareTo(Block.MAX_KEY) == 1) top = Block.MAX_KEY; + + Collection subSet = nonValidatorsIndexed.subSet(bottom, true, top, true); + return new ArrayList(subSet); + } + + public List getNodesbySample(Set samples, BigInteger radius) { + + List result = new ArrayList<>(); + + for (BigInteger sample : samples) { + result.addAll(getNodesbySample(sample, radius)); } - validatorsRow.put(id, row); - if (counter == nodesPerRow) { - row++; - counter = 0; + return result; + } + + public List getAllNeighbours() { + + List result = new ArrayList<>(neighbours.keySet()); + return result; + } + + public Neighbour[] getNeighbours(int n) { + + List result = new ArrayList<>(); + List neighs = new ArrayList<>(); + for (Neighbour neigh : neighbours.values()) { + neighs.add(neigh); } - if (row > b.getSize()) break; - } - - int column = 1; - counter = 0; - for (int i = 0; i < Network.size(); i++) { - counter++; - BigInteger id = Network.get(i).getDASProtocol().getKademliaId(); - if (columnsValidator.get(column) != null) { - columnsValidator.get(column).add(id); - } else { - List list = new ArrayList<>(); - list.add(id); - columnsValidator.put(column, list); + Collections.shuffle(neighs); + + for (Neighbour neigh : neighs) { + if (result.size() < n) result.add(neigh); + else break; } - validatorsColumn.put(id, column); + return result.toArray(new Neighbour[0]); + } + + public void setEvil(List nodes) { + this.evilNodes = nodes; + } + + public boolean isEvil(BigInteger id) { + if (evilIds.contains(id)) return true; + else return false; + } + + public void setEvilIds(List ids) { + this.evilIds = ids; + } + + public Neighbour[] getEvilNeighbours(int n) { - if (counter == nodesPerRow) { - column++; - counter = 0; + List result = new ArrayList<>(); + if (evilNodes != null) { + Collections.shuffle(evilNodes); + for (Node neigh : evilNodes) { + if (result.size() < n) + result.add(new Neighbour(neigh.getDASProtocol().getKademliaId(), neigh, true)); + else break; + } } - if (column > b.getSize()) break; + return result.toArray(new Neighbour[0]); } - for (int i : rowsValidator.keySet()) { - System.out.println("Row " + i + " nodes " + rowsValidator.get(i).size()); + public Neighbour[] getNeighbours(BigInteger id, BigInteger radius) { + + List nodes = getNodesbySample(id, radius); + List neighs = new ArrayList<>(); + List result = new ArrayList<>(); + for (BigInteger n : nodes) { + neighs.add(neighbours.get(n)); + } + Collections.shuffle(neighs); + + for (Neighbour neigh : neighs) { + if (result.size() < KademliaCommonConfigDas.MAX_NODES_RETURNED) result.add(neigh); + else break; + } + return result.toArray(new Neighbour[0]); } - for (int i : columnsValidator.keySet()) { - System.out.println("Column " + i + " nodes " + columnsValidator.get(i).size()); + public int getAllNeighboursCount() { + return neighbours.size(); } - for (int r=1;r<=b.getSize();r++) { - Sample s = b.getSample(row, column) - List vals = rowsValidator.get(s.getRow()); - validatorsSamples.put(s.getId(),vals.get(CommonState.r.nextInt(vals.size())) ) - }*/ + public int getValidatorsNeighboursCount() { + int count = 0; + for (Neighbour neigh : neighbours.values()) { + if (neigh.getNode().getDASProtocol().isValidator()) count++; + } + return count; + } - public List getNodesBySample(BigInteger sampleId) { - return validatorsSamples.get(sampleId); + public int getNonValidatorsNeighboursCount() { + int count = 0; + for (Neighbour neigh : neighbours.values()) { + if (!neigh.getNode().getDASProtocol().isValidator()) count++; + } + return count; } - public int getValidatorRow(BigInteger id) { - return validatorsRow.get(id); + public int getAllAliveNeighboursCount() { + int count = 0; + for (Neighbour neigh : neighbours.values()) { + if (neigh.getNode().isUp()) count++; + } + return count; } - public int getValidatorColumn(BigInteger id) { - return validatorsColumn.get(id); + public int getMaliciousNeighboursCount() { + int count = 0; + for (Neighbour neigh : neighbours.values()) { + if (neigh.isEvil()) count++; + } + return count; + } + + public boolean isNeighbourKnown(Neighbour neighbour) { + return neighbours.containsKey(neighbour.getId()); + } + + public void refresh() { + + List toRemove = new ArrayList<>(); + for (Neighbour neigh : neighbours.values()) { + if (neigh.expired()) { + toRemove.add(neigh); + nodesIndexed.remove(neigh.getId()); + } + } + for (Neighbour n : toRemove) neighbours.remove(n.getId()); } } diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTableV1.java b/simulator/src/main/java/peersim/kademlia/das/SearchTableV1.java deleted file mode 100644 index 09255d4e..00000000 --- a/simulator/src/main/java/peersim/kademlia/das/SearchTableV1.java +++ /dev/null @@ -1,254 +0,0 @@ -package peersim.kademlia.das; - -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; -import peersim.core.Node; - -public class SearchTableV1 { - - private HashMap neighbours; - - private TreeSet nodesIndexed; // , samplesIndexed; - - protected TreeSet validatorsIndexed; // , samplesIndexed; - - private TreeSet nonValidatorsIndexed; // , samplesIndexed; - - private HashSet blackList; // , samplesIndexed; - - protected BigInteger builderAddress; - - private List evilNodes; - private List evilIds; - - public SearchTableV1() { - - this.nodesIndexed = new TreeSet<>(); - this.nonValidatorsIndexed = new TreeSet<>(); - this.validatorsIndexed = new TreeSet<>(); - this.blackList = new HashSet<>(); - this.neighbours = new HashMap<>(); - } - - public void addNeighbour(Neighbour neigh) { - if (neigh.getId().compareTo(builderAddress) != 0) { - if (neighbours.get(neigh.getId()) == null) { - neighbours.put(neigh.getId(), neigh); - nodesIndexed.add(neigh.getId()); - } else { - if (neighbours.get(neigh.getId()).getLastSeen() < neigh.getLastSeen()) - neighbours.get(neigh.getId()).updateLastSeen(neigh.getLastSeen()); - } - } - } - - public void addNodes(BigInteger[] nodes) { - - for (BigInteger id : nodes) { - if (id.compareTo(builderAddress) != 0) { - if (!blackList.contains(id) - && !validatorsIndexed.contains(id) - && !builderAddress.equals(id)) { - nonValidatorsIndexed.add(id); - } - } - } - } - - public void addValidatorNodes(BigInteger[] nodes) { - for (BigInteger id : nodes) { - if (!blackList.contains(id) && id.compareTo(builderAddress) != 0) { - validatorsIndexed.add(id); - } - } - } - - public void setBuilderAddress(BigInteger builderAddress) { - this.builderAddress = builderAddress; - } - - public void removeNode(BigInteger node) { - this.nodesIndexed.remove(node); - this.nonValidatorsIndexed.remove(node); - this.neighbours.remove(node); - validatorsIndexed.remove(node); - } - - public TreeSet nodesIndexed() { - return nodesIndexed; - } - - public TreeSet getValidatorsIndexed() { - return validatorsIndexed; - } - - public List getNodesbySample(BigInteger sampleId, BigInteger radius) { - - BigInteger bottom = sampleId.subtract(radius); - if (radius.compareTo(sampleId) == 1) bottom = BigInteger.ZERO; - - BigInteger top = sampleId.add(radius); - if (top.compareTo(Block.MAX_KEY) == 1) top = Block.MAX_KEY; - - Collection subSet = nodesIndexed.subSet(bottom, true, top, true); - return new ArrayList(subSet); - } - - public List getValidatorNodesbySample(BigInteger sampleId, BigInteger radius) { - - BigInteger bottom = sampleId.subtract(radius); - if (radius.compareTo(sampleId) == 1) bottom = BigInteger.ZERO; - - BigInteger top = sampleId.add(radius); - if (top.compareTo(Block.MAX_KEY) == 1) top = Block.MAX_KEY; - Collection subSet = validatorsIndexed.subSet(bottom, true, top, true); - return new ArrayList(subSet); - } - - public List getNonValidatorNodesbySample(BigInteger sampleId, BigInteger radius) { - - BigInteger bottom = sampleId.subtract(radius); - if (radius.compareTo(sampleId) == 1) bottom = BigInteger.ZERO; - - BigInteger top = sampleId.add(radius); - if (top.compareTo(Block.MAX_KEY) == 1) top = Block.MAX_KEY; - - Collection subSet = nonValidatorsIndexed.subSet(bottom, true, top, true); - return new ArrayList(subSet); - } - - public List getNodesbySample(Set samples, BigInteger radius) { - - List result = new ArrayList<>(); - - for (BigInteger sample : samples) { - result.addAll(getNodesbySample(sample, radius)); - } - return result; - } - - public List getAllNeighbours() { - - List result = new ArrayList<>(neighbours.keySet()); - return result; - } - - public Neighbour[] getNeighbours(int n) { - - List result = new ArrayList<>(); - List neighs = new ArrayList<>(); - for (Neighbour neigh : neighbours.values()) { - neighs.add(neigh); - } - Collections.shuffle(neighs); - - for (Neighbour neigh : neighs) { - if (result.size() < n) result.add(neigh); - else break; - } - return result.toArray(new Neighbour[0]); - } - - public void setEvil(List nodes) { - this.evilNodes = nodes; - } - - public boolean isEvil(BigInteger id) { - if (evilIds.contains(id)) return true; - else return false; - } - - public void setEvilIds(List ids) { - this.evilIds = ids; - } - - public Neighbour[] getEvilNeighbours(int n) { - - List result = new ArrayList<>(); - if (evilNodes != null) { - Collections.shuffle(evilNodes); - for (Node neigh : evilNodes) { - if (result.size() < n) - result.add(new Neighbour(neigh.getDASProtocol().getKademliaId(), neigh, true)); - else break; - } - } - return result.toArray(new Neighbour[0]); - } - - public Neighbour[] getNeighbours(BigInteger id, BigInteger radius) { - - List nodes = getNodesbySample(id, radius); - List neighs = new ArrayList<>(); - List result = new ArrayList<>(); - for (BigInteger n : nodes) { - neighs.add(neighbours.get(n)); - } - Collections.shuffle(neighs); - - for (Neighbour neigh : neighs) { - if (result.size() < KademliaCommonConfigDas.MAX_NODES_RETURNED) result.add(neigh); - else break; - } - return result.toArray(new Neighbour[0]); - } - - public int getAllNeighboursCount() { - return neighbours.size(); - } - - public int getValidatorsNeighboursCount() { - int count = 0; - for (Neighbour neigh : neighbours.values()) { - if (neigh.getNode().getDASProtocol().isValidator()) count++; - } - return count; - } - - public int getNonValidatorsNeighboursCount() { - int count = 0; - for (Neighbour neigh : neighbours.values()) { - if (!neigh.getNode().getDASProtocol().isValidator()) count++; - } - return count; - } - - public int getAllAliveNeighboursCount() { - int count = 0; - for (Neighbour neigh : neighbours.values()) { - if (neigh.getNode().isUp()) count++; - } - return count; - } - - public int getMaliciousNeighboursCount() { - int count = 0; - for (Neighbour neigh : neighbours.values()) { - if (neigh.isEvil()) count++; - } - return count; - } - - public boolean isNeighbourKnown(Neighbour neighbour) { - return neighbours.containsKey(neighbour.getId()); - } - - public void refresh() { - - List toRemove = new ArrayList<>(); - for (Neighbour neigh : neighbours.values()) { - if (neigh.expired()) { - toRemove.add(neigh); - nodesIndexed.remove(neigh.getId()); - } - } - for (Neighbour n : toRemove) neighbours.remove(n.getId()); - } -} diff --git a/simulator/src/main/java/peersim/kademlia/das/SearchTableV2.java b/simulator/src/main/java/peersim/kademlia/das/SearchTableV2.java new file mode 100644 index 00000000..afea2128 --- /dev/null +++ b/simulator/src/main/java/peersim/kademlia/das/SearchTableV2.java @@ -0,0 +1,192 @@ +package peersim.kademlia.das; + +import java.math.BigInteger; +import java.util.*; +import peersim.core.CommonState; +import peersim.core.Network; + +public class SearchTableV2 extends SearchTable { + + private HashMap> validatorsSamples; + private HashMap validatorsRow; + private HashMap validatorsColumn; + private HashMap> rowsValidator; + private HashMap> columnsValidator; + + public SearchTableV2() { + validatorsSamples = new HashMap<>(); + validatorsRow = new HashMap<>(); + validatorsColumn = new HashMap<>(); + rowsValidator = new HashMap<>(); + columnsValidator = new HashMap<>(); + } + + public void assignSamplesRandom(Block b, int r) { + for (int i = 0; i < Network.size(); i++) { + BigInteger id = Network.get(i).getDASProtocol().getKademliaId(); + validatorsRow.put(id, 0); + validatorsColumn.put(id, 0); + } + ArrayList list = new ArrayList<>(validatorsIndexed); + while (b.hasNext()) { + Sample s = b.next(); + validatorsSamples.put(s.getIdByRow(), new ArrayList<>()); + validatorsSamples.put(s.getIdByColumn(), new ArrayList<>()); + BigInteger randomNode = list.get(CommonState.r.nextInt(validatorsIndexed.size())); + validatorsRow.put(randomNode, s.getRow()); + validatorsRow.put(randomNode, s.getColumn()); + validatorsSamples.get(s.getIdByRow()).add(randomNode); + validatorsSamples.get(s.getIdByColumn()).add(randomNode); + } + } + + public void assignSamplesRadius(Block b, int r) { + BigInteger radiusValidator = b.computeRegionRadius(r, this.getValidatorsIndexed().size()); + while (b.hasNext()) { + BigInteger radiusUsed = radiusValidator; + boolean inRegion = false; + Sample s = b.next(); + while (!inRegion) { + + List idsValidators = this.getValidatorNodesbySample(s.getIdByRow(), radiusUsed); + if (idsValidators.size() > 0) { + inRegion = true; + validatorsSamples.put(s.getIdByRow(), idsValidators); + rowsValidator.put(s.getRow(), idsValidators); + for (BigInteger id : idsValidators) { + validatorsRow.put(id, s.getRow()); + } + } + idsValidators = this.getValidatorNodesbySample(s.getIdByColumn(), radiusUsed); + if (idsValidators.size() > 0) { + inRegion = true; + validatorsSamples.put(s.getIdByColumn(), idsValidators); + columnsValidator.put(s.getRow(), idsValidators); + for (BigInteger id : idsValidators) { + validatorsColumn.put(id, s.getColumn()); + } + } + if (!inRegion) radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); + } + } + } + + public void assignByRowColumn(Block b) { + + int i = 0; + for (int row = 0; row < b.getSize(); row++) { + BigInteger id = Network.get(i).getDASProtocol().getKademliaId(); + if (id.compareTo(builderAddress) == 0) { + id = Network.get(i + 1).getDASProtocol().getKademliaId(); + } + validatorsRow.put(id, row); + + for (int column = 0; column < b.getSize(); column++) { + BigInteger sampleRow = b.getSample(row, column).getIdByRow(); + if (validatorsSamples.get(sampleRow) == null) { + validatorsSamples.put(sampleRow, new ArrayList<>()); + } + validatorsSamples.get(sampleRow).add(id); + } + + i++; + if (i >= Network.size()) i = 0; + } + + for (int column = 0; column < b.getSize(); column++) { + BigInteger id = Network.get(i).getDASProtocol().getKademliaId(); + if (id.compareTo(builderAddress) == 0) { + id = Network.get(i + 1).getDASProtocol().getKademliaId(); + } + validatorsColumn.put(id, column); + + for (int row = 0; row < b.getSize(); row++) { + BigInteger sampleColumn = b.getSample(row, column).getIdByColumn(); + if (validatorsSamples.get(sampleColumn) == null) { + validatorsSamples.put(sampleColumn, new ArrayList<>()); + } + validatorsSamples.get(sampleColumn).add(id); + } + + i++; + if (i >= Network.size()) i = 0; + } + } + + public List getValidatorNodesbySample(BigInteger sampleId, BigInteger radius) { + return validatorsSamples.get(sampleId); + } + + public List getNonValidatorNodesbySample(BigInteger sampleId, BigInteger radius) { + return new ArrayList<>(); + } + /*int nodesPerRow = + Network.size() / (b.getSize() * KademliaCommonConfigDas.NUM_SAMPLE_COPIES_PER_PEER); + + int row = 1; + int counter = 0; + for (int i = 0; i < Network.size(); i++) { + counter++; + BigInteger id = Network.get(i).getDASProtocol().getKademliaId(); + if (rowsValidator.get(row) != null) { + rowsValidator.get(row).add(id); + } else { + List list = new ArrayList<>(); + list.add(id); + rowsValidator.put(row, list); + } + validatorsRow.put(id, row); + if (counter == nodesPerRow) { + row++; + counter = 0; + } + if (row > b.getSize()) break; + } + + int column = 1; + counter = 0; + for (int i = 0; i < Network.size(); i++) { + counter++; + BigInteger id = Network.get(i).getDASProtocol().getKademliaId(); + if (columnsValidator.get(column) != null) { + columnsValidator.get(column).add(id); + } else { + List list = new ArrayList<>(); + list.add(id); + columnsValidator.put(column, list); + } + validatorsColumn.put(id, column); + + if (counter == nodesPerRow) { + column++; + counter = 0; + } + if (column > b.getSize()) break; + } + + for (int i : rowsValidator.keySet()) { + System.out.println("Row " + i + " nodes " + rowsValidator.get(i).size()); + } + + for (int i : columnsValidator.keySet()) { + System.out.println("Column " + i + " nodes " + columnsValidator.get(i).size()); + } + + for (int r=1;r<=b.getSize();r++) { + Sample s = b.getSample(row, column) + List vals = rowsValidator.get(s.getRow()); + validatorsSamples.put(s.getId(),vals.get(CommonState.r.nextInt(vals.size())) ) + }*/ + + public List getNodesBySample(BigInteger sampleId) { + return validatorsSamples.get(sampleId); + } + + public int getValidatorRow(BigInteger id) { + return validatorsRow.get(id); + } + + public int getValidatorColumn(BigInteger id) { + return validatorsColumn.get(id); + } +} diff --git a/simulator/src/main/java/peersim/kademlia/das/SeedingSampleBody.java b/simulator/src/main/java/peersim/kademlia/das/SeedingSampleBody.java new file mode 100644 index 00000000..862f2cce --- /dev/null +++ b/simulator/src/main/java/peersim/kademlia/das/SeedingSampleBody.java @@ -0,0 +1,29 @@ +package peersim.kademlia.das; + +import java.math.BigInteger; +import java.util.List; + +public class SeedingSampleBody { + public List + validatorList; // Assuming sample is an array of integers, you can change the type as needed + public Sample[] samplesList; + public boolean isRow; // true if it's a row + + public SeedingSampleBody(Sample[] samples, List validators, boolean isRow) { + this.samplesList = samples; + this.validatorList = validators; + this.isRow = isRow; + } + + public List getValidators() { + return this.validatorList; + } + + public Sample[] getsamplesList() { + return this.samplesList; + } + + public boolean getIsRow() { + return this.isRow; + } +} From bffe919dd8a8505655db66cc623c065405d4673e Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sat, 18 Jan 2025 23:27:00 +0100 Subject: [PATCH 96/98] validator sampling --- .../config/malicious/dasprotocolevil0.cfg | 2 +- .../kademlia/das/DASDHTProtocolValidator.java | 1 + .../kademlia/das/DASProtocolBuilder.java | 19 ++++++------ .../kademlia/das/DASProtocolValidator.java | 30 ++++++++++++++++++- .../ValidatorSamplingOperation.java | 10 +++++-- .../ValidatorSamplingOperationDHT.java | 12 +++++++- 6 files changed, 59 insertions(+), 15 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg index 3bab4834..bbab57db 100644 --- a/simulator/config/malicious/dasprotocolevil0.cfg +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 1000 +SIZE 10000 # Random seed K 5 diff --git a/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolValidator.java index 8cffb592..a8ceeff4 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASDHTProtocolValidator.java @@ -74,6 +74,7 @@ private void createValidatorSamplingOperation(int row, int column, long timestam column, this.isValidator, KademliaCommonConfigDas.validatorsSize, + null, this); // op.elaborateResponse(this.kadProtocol.kv.getAll().toArray(new Sample[0])); diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java index b6daf15b..f9153b75 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolBuilder.java @@ -47,8 +47,8 @@ protected Message generateSeedSampleMessage( return m; } - private void rowSeeding(){ - // =============== + private void rowSeeding() { + // =============== // Row Seeding // =============== int actualRow = 1; @@ -133,23 +133,24 @@ private void rowSeeding(){ msg.src = this.getKademliaProtocol().getKademliaNode(); msg.dst = n.getKademliaProtocol().getKademliaNode(); sendMessage(msg, id, dasProt.getDASProtocolID()); - //samplesValidators++; + // samplesValidators++; } } - //samplesWithinRegion += sampleRow.length; + // samplesWithinRegion += sampleRow.length; actualRow++; } } - private void columnSeeding(){ + private void columnSeeding() { // =============== // Column Seeding // =============== int actualColumn = 1; while (currentBlock.getSize() >= actualColumn) { - Sample[] sampleColumn= currentBlock.getSamplesByColumn(actualColumn); // get all sample of the column + Sample[] sampleColumn = + currentBlock.getSamplesByColumn(actualColumn); // get all sample of the column BigInteger radiusValidator = currentBlock.computeRegionRadius(1, searchTable.getValidatorsIndexed().size()); @@ -223,16 +224,16 @@ private void columnSeeding(){ if (dasProt.isBuilder()) continue; if (n.isUp()) { Sample[] samples = validatorParcel; - Message msg = generateSeedSampleMessage(samples, idsValidators, true); + Message msg = generateSeedSampleMessage(samples, idsValidators, false); msg.operationId = -1; msg.src = this.getKademliaProtocol().getKademliaNode(); msg.dst = n.getKademliaProtocol().getKademliaNode(); sendMessage(msg, id, dasProt.getDASProtocolID()); - //samplesValidators++; + // samplesValidators++; } } - //samplesWithinRegion += sampleRow.length; + // samplesWithinRegion += sampleRow.length; actualColumn++; } } diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index 02f4c31d..7db2066b 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -1,6 +1,8 @@ package peersim.kademlia.das; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; import peersim.core.Node; import peersim.kademlia.Message; import peersim.kademlia.Util; @@ -57,6 +59,13 @@ protected void handleSeedSample(Message m, int myPid) { // count # of samples for each row and column and reconstruct if more than half received reconstruct(s); } + List validatorList = body.getValidators(); + boolean isRow = body.getIsRow(); + if (isRow) { + createValidatorSamplingOperation(samples[0].getRow(), 0, time, validatorList); + } else { + createValidatorSamplingOperation(0, samples[0].getColumn(), time, validatorList); + } /*if (!started) { started = true; startRowsandColumnsSampling(); @@ -130,7 +139,8 @@ protected void startRowsandColumnsSampling() { // createValidatorSamplingOperation(0, column, time); } - private void createValidatorSamplingOperation(int row, int column, long timestamp) { + private void createValidatorSamplingOperation( + int row, int column, long timestamp, List validatorList) { ValidatorSamplingOperation op = new ValidatorSamplingOperation( this.getKademliaId(), @@ -141,10 +151,28 @@ private void createValidatorSamplingOperation(int row, int column, long timestam column, this.isValidator, KademliaCommonConfigDas.validatorsSize, + validatorList, this); samplingOp.put(op.getId(), op); logger.warning("Sampling operation started validator " + op.getId()); + List samplesFound = new ArrayList<>(); + if (row > 0) { + Sample[] samples = currentBlock.getSamplesByRow(row); + for (Sample s : samples) { + if (kv.contains(s.getIdByRow())) { + samplesFound.add(s); + } + } + } else { + Sample[] samples = currentBlock.getSamplesByColumn(column); + for (Sample s : samples) { + if (kv.contains(s.getIdByColumn())) { + samplesFound.add(s); + } + } + } + op.elaborateResponse(samplesFound.toArray(new Sample[0])); // op.elaborateResponse(kv.getAll().toArray(new Sample[0])); doSampling(op); } diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java index c97e8393..76027863 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperation.java @@ -24,6 +24,7 @@ public class ValidatorSamplingOperation extends SamplingOperation { // private RoutingTable rou; protected int row, column; protected HashMap extras; + protected List validatorList; /** * default constructor * @@ -40,6 +41,7 @@ public ValidatorSamplingOperation( int column, boolean isValidator, int numValidators, + List validatorList, MissingNode callback) { super(srcNode, null, timestamp, block, isValidator, numValidators, callback); @@ -60,7 +62,8 @@ public ValidatorSamplingOperation( } this.searchTable = searchTable; this.extras = new HashMap<>(); - // createNodes(); + this.validatorList = validatorList; + createNodes(); } public void elaborateResponse(Sample[] sam) { @@ -171,7 +174,7 @@ protected void createNodes() { if (!samples.get(sample).isDownloaded()) { List nodesBySample = new ArrayList<>(); - if (row > 0) { + /*if (row > 0) { // BigInteger radiusUsed = radiusValidator; // while (nodesBySample.isEmpty() && radiusUsed.compareTo(Block.MAX_KEY) == -1) { // nodesBySample.addAll( @@ -198,7 +201,8 @@ protected void createNodes() { // radiusUsed = radiusUsed.multiply(BigInteger.valueOf(2)); // } - } + }*/ + nodesBySample.addAll(validatorList); boolean found = false; nodesBySample.removeAll(askedNodes); if (nodesBySample != null && nodesBySample.size() > 0) { diff --git a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperationDHT.java b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperationDHT.java index 89ad0882..ef4f14f6 100644 --- a/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperationDHT.java +++ b/simulator/src/main/java/peersim/kademlia/das/operations/ValidatorSamplingOperationDHT.java @@ -23,9 +23,19 @@ public ValidatorSamplingOperationDHT( int column, boolean isValidator, int numValidators, + List validatorList, MissingNode callback) { super( - srcNode, timestamp, block, searchTable, row, column, isValidator, numValidators, callback); + srcNode, + timestamp, + block, + searchTable, + row, + column, + isValidator, + numValidators, + validatorList, + callback); // System.out.println("Row " + row + " column " + column); assert (row == 0 || column == 0) : "Either row or column should be set"; From 9c27af9d46152ca3e032a67fd0b1043085c44fcd Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sun, 19 Jan 2025 17:21:02 +0100 Subject: [PATCH 97/98] add random sampling --- simulator/config/malicious/dasprotocolevil0.cfg | 4 ++-- .../main/java/peersim/kademlia/das/DASProtocolValidator.java | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg index bbab57db..61d39151 100644 --- a/simulator/config/malicious/dasprotocolevil0.cfg +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -5,7 +5,7 @@ # ::::: GLOBAL :::::: # Network size -SIZE 10000 +SIZE 1000 # Random seed K 5 @@ -116,7 +116,7 @@ control.0traffic peersim.kademlia.das.TrafficGeneratorSample control.0traffic.step TRAFFIC_STEP control.0traffic.mapping_fn 2 control.0traffic.sample_copy_per_node 2 -control.0traffic.block_dim_size 512 +control.0traffic.block_dim_size 100 control.0traffic.num_samples 75 control.0traffic.kadprotocol 3kademlia diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java index 7db2066b..7a5d4b84 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolValidator.java @@ -76,6 +76,7 @@ protected void handleSeedSample(Message m, int myPid) { protected void handleInitNewBlock(Message m, int myPid) { super.handleInitNewBlock(m, myPid); started = false; + if (!isEvil) startRandomSampling(); /*if (!isEvil) { startRowsandColumnsSampling(); startRandomSampling(); From 4ca396f52596f8b441a88cdb534eaf86894f17d0 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Sun, 19 Jan 2025 17:35:20 +0100 Subject: [PATCH 98/98] nonval random sampling --- simulator/config/malicious/dasprotocolevil0.cfg | 2 +- .../main/java/peersim/kademlia/das/DASProtocolNonValidator.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/simulator/config/malicious/dasprotocolevil0.cfg b/simulator/config/malicious/dasprotocolevil0.cfg index 61d39151..83d5b2d1 100644 --- a/simulator/config/malicious/dasprotocolevil0.cfg +++ b/simulator/config/malicious/dasprotocolevil0.cfg @@ -99,7 +99,7 @@ init.1uniqueNodeID.protocoldasvalidator 5dasprotocol init.1uniqueNodeID.protocoldasnonvalidator 6dasprotocol init.1uniqueNodeID.protocolEvilValDas 7evildasprotocol init.1uniqueNodeID.protocolEvildas 8evildasprotocol -init.1uniqueNodeID.validator_rate 1.0 +init.1uniqueNodeID.validator_rate 0.5 init.1uniqueNodeID.evilNodeRatioValidator 0.0 init.1uniqueNodeID.evilNodeRatioNonValidator 0.0 diff --git a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java index 78a67dca..d9a72fa7 100644 --- a/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java +++ b/simulator/src/main/java/peersim/kademlia/das/DASProtocolNonValidator.java @@ -59,7 +59,7 @@ protected void handleInitNewBlock(Message m, int myPid) { validatorsContacted.clear(); super.handleInitNewBlock(m, myPid); if (!isEvil) { - // startRandomSampling(); + startRandomSampling(); } }