Skip to content

Commit 586f593

Browse files
authored
Merge pull request #154 from joaomlneto/fixed-fab-with-network-faults
Fixed fab with network faults
2 parents eb18fbf + 7693d02 commit 586f593

File tree

79 files changed

+6913
-46
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+6913
-46
lines changed

.idea/misc.xml

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

simulator/src/main/java/byzzbench/simulator/BaseScenario.java

+10
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public abstract class BaseScenario implements Scenario {
3737
/**
3838
* The timekeeper for the scenario.
3939
*/
40+
@JsonIgnore
4041
protected final transient Timekeeper timekeeper;
4142
/**
4243
* The scheduler for the scenario.
@@ -236,6 +237,15 @@ public final void runScenario() {
236237
*/
237238
@Override
238239
public final boolean invariantsHold() {
240+
// Write to file which invariant is violated
241+
// BufferedWriter writer = new BufferedWriter(new FileWriter("", true));
242+
// for (ScenarioPredicate invariant : this.invariants) {
243+
// if (!invariant.test(this)) {
244+
// writer.write(this.id + " " + invariant.getClass().getSimpleName() + "\n");
245+
// writer.close();
246+
// }
247+
// }
248+
239249
return this.invariants.stream().allMatch(invariant -> invariant.test(this));
240250
}
241251

simulator/src/main/java/byzzbench/simulator/BaseScenarioFactory.java

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
public abstract class BaseScenarioFactory implements ScenarioFactory {
1515
@Getter(AccessLevel.PROTECTED)
1616
private final SchedulerFactoryService schedulerFactoryService;
17+
@Getter
1718
private final ByzzBenchConfig byzzBenchConfig;
1819
private final ObjectMapper mapper;
1920

simulator/src/main/java/byzzbench/simulator/Client.java

+12-5
Original file line numberDiff line numberDiff line change
@@ -28,23 +28,23 @@ public class Client implements Serializable, Node {
2828
*/
2929
@JsonIgnore
3030
@NonNull
31-
protected final transient Scenario scenario;
31+
private final transient Scenario scenario;
3232

3333
/**
3434
* The unique ID of the client.
3535
*/
3636
@NonNull
37-
protected final String id;
37+
private final String id;
3838

3939
/**
4040
* The sequence number of the next request to be sent by the client.
4141
*/
42-
protected final AtomicLong requestSequenceNumber = new AtomicLong(0);
42+
private final AtomicLong requestSequenceNumber = new AtomicLong(0);
4343

4444
/**
4545
* The maximum number of requests that can be sent by the client.
4646
*/
47-
protected final long maxRequests = 100;
47+
private final long maxRequests = 1000;
4848

4949
/**
5050
* The replies received by the client.
@@ -60,10 +60,17 @@ public void initialize() {
6060
}
6161

6262
/**
63-
* Sends a request to a replica in the system.
63+
* Sends a request to any replica in the system.
6464
*/
6565
public void sendRequest() {
6666
String recipientId = this.getScenario().getReplicas().keySet().iterator().next();
67+
this.sendRequest(recipientId);
68+
}
69+
70+
/**
71+
* Sends a request to a given replica in the system.
72+
*/
73+
public void sendRequest(String recipientId) {
6774
MessagePayload payload = new ClientRequestMessage(this.getCurrentTime().toEpochMilli(), recipientId);
6875
this.getScenario().getTransport().sendMessage(this, payload, recipientId);
6976
}

simulator/src/main/java/byzzbench/simulator/HbftClient.java

+20-20
Original file line numberDiff line numberDiff line change
@@ -71,39 +71,39 @@ public class HbftClient extends Client {
7171
*/
7272
@Override
7373
public void sendRequest() {
74-
String requestId = String.format("%s/%d", super.id, super.requestSequenceNumber.incrementAndGet());
74+
String requestId = String.format("%s/%d", getId(), getRequestSequenceNumber().incrementAndGet());
7575
long timestamp = this.getCurrentTime().toEpochMilli();
76-
RequestMessage request = new RequestMessage(requestId, timestamp, super.id);
77-
this.sentRequests.put(super.requestSequenceNumber.get(), request);
76+
RequestMessage request = new RequestMessage(requestId, timestamp, getId());
77+
this.sentRequests.put(getRequestSequenceNumber().get(), request);
7878
this.sentRequestsByTimestamp.put(timestamp, requestId);
7979
this.broadcastRequest(timestamp, requestId);
8080

8181
// Set timeout
8282
Long timeoutId = this.setTimeout("REQUEST", this::retransmitOrPanic, this.timeout);
83-
timeouts.put(super.requestSequenceNumber.get(), timeoutId);
83+
timeouts.put(getRequestSequenceNumber().get(), timeoutId);
8484
}
8585

8686
public void retransmitOrPanic() {
87-
long tolerance = (long) Math.floor((super.scenario.getTransport().getNodeIds().size() - 1) / 3);
87+
long tolerance = (long) Math.floor((getScenario().getTransport().getNodeIds().size() - 1) / 3);
8888
if (this.shouldRetransmit(tolerance)) {
89-
String requestId = String.format("%s/%d", super.id, super.requestSequenceNumber.get());
89+
String requestId = String.format("%s/%d", getId(), getRequestSequenceNumber().get());
9090
// Based on hBFT 4.1 it uses the identical request
9191
// TODO: It probably should not be the same timestamp
92-
long timestamp = this.sentRequests.get(super.requestSequenceNumber.get()).getTimestamp();
92+
long timestamp = this.sentRequests.get(getRequestSequenceNumber().get()).getTimestamp();
9393
this.broadcastRequest(timestamp, requestId);
9494
} else if (this.shouldPanic(tolerance)) {
95-
RequestMessage message = this.sentRequests.get(super.requestSequenceNumber.get());
96-
PanicMessage panic = new PanicMessage(this.digest(message), this.getCurrentTime().toEpochMilli(), super.id);
97-
super.scenario.getTransport().multicast(this, super.scenario.getTransport().getNodeIds(), panic);
95+
RequestMessage message = this.sentRequests.get(getRequestSequenceNumber().get());
96+
PanicMessage panic = new PanicMessage(this.digest(message), this.getCurrentTime().toEpochMilli(), getId());
97+
getScenario().getTransport().multicast(this, getScenario().getTransport().getNodeIds(), panic);
9898
}
99-
this.clearTimeout(timeouts.get(super.requestSequenceNumber.get()));
99+
this.clearTimeout(timeouts.get(getRequestSequenceNumber().get()));
100100
Long timeoutId = this.setTimeout("REQUEST", this::retransmitOrPanic, this.timeout);
101-
timeouts.put(super.requestSequenceNumber.get(), timeoutId);
101+
timeouts.put(getRequestSequenceNumber().get(), timeoutId);
102102
}
103103

104104
private void broadcastRequest(long timestamp, String requestId) {
105105
MessagePayload payload = new ClientRequestMessage(timestamp, requestId);
106-
SortedSet<String> replicaIds = super.scenario.getTransport().getNodeIds();
106+
SortedSet<String> replicaIds = getScenario().getTransport().getNodeIds();
107107
getScenario().getTransport().multicast(this, replicaIds, payload);
108108
}
109109

@@ -131,9 +131,9 @@ public void handleMessage(String senderId, MessagePayload payload) {
131131
*/
132132
if (this.completedReplies(clientReplyMessage.getTolerance())
133133
&& !this.completedRequests.contains(key)
134-
&& super.requestSequenceNumber.get() <= this.maxRequests) {
134+
&& getRequestSequenceNumber().get() <= getMaxRequests()) {
135135
this.completedRequests.add(key);
136-
this.clearTimeout(this.timeouts.get(super.requestSequenceNumber.get()));
136+
this.clearTimeout(this.timeouts.get(getRequestSequenceNumber().get()));
137137
this.sendRequest();
138138
}
139139
}
@@ -148,15 +148,15 @@ public void handleMessage(String senderId, MessagePayload payload) {
148148
*/
149149
public long setTimeout(String name, Runnable r, long timeout) {
150150
Duration duration = Duration.ofSeconds(timeout);
151-
return super.scenario.getTransport().setTimeout(this, r, duration, name);
151+
return getScenario().getTransport().setTimeout(this, r, duration, name);
152152
}
153153

154154
/**
155155
* Checks whether client should retransmit the request
156156
* if #replies < f + 1
157157
*/
158158
public boolean shouldRetransmit(long tolerance) {
159-
String currRequest = String.format("%s/%d", super.id, super.requestSequenceNumber.get());
159+
String currRequest = String.format("%s/%d", getId(), getRequestSequenceNumber().get());
160160
if (!hbftreplies.containsKey(currRequest)) {
161161
return true;
162162
}
@@ -171,7 +171,7 @@ public boolean shouldRetransmit(long tolerance) {
171171
* if f + 1 <= #replies < 2f + 1
172172
*/
173173
public boolean shouldPanic(long tolerance) {
174-
String currRequest = String.format("%s/%d", super.id, super.requestSequenceNumber.get());
174+
String currRequest = String.format("%s/%d", getId(), getRequestSequenceNumber().get());
175175
for (ClientReplyKey key : hbftreplies.get(currRequest).keySet()) {
176176
return this.hbftreplies.get(currRequest).get(key).size() >= tolerance + 1
177177
&& this.hbftreplies.get(currRequest).get(key).size() < tolerance * 2 + 1;
@@ -183,7 +183,7 @@ public boolean shouldPanic(long tolerance) {
183183
* Checks whether it has received 2f + 1 replies
184184
*/
185185
public boolean completedReplies(long tolerance) {
186-
String currRequest = String.format("%s/%d", super.id, super.requestSequenceNumber.get());
186+
String currRequest = String.format("%s/%d", getId(), getRequestSequenceNumber().get());
187187
if (!hbftreplies.containsKey(currRequest)) {
188188
return false;
189189
}
@@ -199,7 +199,7 @@ public boolean completedReplies(long tolerance) {
199199
* Clear all timeouts for this client.
200200
*/
201201
// public void clearAllTimeouts() {
202-
// super.scenario.getTransport().clearClientTimeouts(super.id);
202+
// getScenario.getTransport().clearClientTimeouts(getId());
203203
// }
204204

205205
/**

simulator/src/main/java/byzzbench/simulator/config/ByzzBenchConfig.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ public final class BehaviorConfig {
171171
@Data
172172
public final class ScenarioConfig {
173173
private TerminationConfig termination = new TerminationConfig();
174-
private String id = "hbft";
174+
private String id = "pbft-java";
175175
private Map<String, String> params = new HashMap<>();
176176
}
177177
}

simulator/src/main/java/byzzbench/simulator/faults/behaviors/ByzzFuzzDropMessageBehavior.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,9 @@ public void accept(FaultContext context) {
100100
if (router.haveConnectivity(sender, recipient)) {
101101
return;
102102
}
103+
104+
// otherwise, drop the message: the sender and recipient are in different partitions
103105
if(e.getStatus() == Event.Status.QUEUED) {
104-
// otherwise, drop the message: the sender and recipient are in different partitions
105106
context.getScenario().getTransport().dropEvent(e.getEventId());
106107
}
107108
}

simulator/src/main/java/byzzbench/simulator/faults/behaviors/MutateMessageBehavior.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public void accept(FaultContext context) {
6767
// apply the random mutator
6868
MessageMutationFault mutator = mutators.get(rand.nextInt(mutators.size()));
6969

70-
// apply the mutation (if the message is still queued)
70+
// apply the mutation if the message is queued
7171
if (e.getStatus() == Event.Status.QUEUED) {
7272
context.getScenario().getTransport().applyMutation(e.getEventId(), mutator);
7373
}

simulator/src/main/java/byzzbench/simulator/faults/factories/ByzzFuzzScenarioFaultFactory.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import byzzbench.simulator.faults.faults.ByzzFuzzProcessFault;
99
import byzzbench.simulator.scheduler.ByzzFuzzScheduler;
1010
import byzzbench.simulator.utils.SetSubsets;
11+
import lombok.extern.java.Log;
1112
import org.springframework.stereotype.Component;
1213

1314
import java.util.ArrayList;
@@ -18,6 +19,7 @@
1819
/**
1920
* Fault factory that generates faults for a given scenario.
2021
*/
22+
@Log
2123
@Component
2224
public class ByzzFuzzScenarioFaultFactory implements FaultFactory {
2325
private final Random rand = new Random();
@@ -59,7 +61,6 @@ public List<Fault> generateFaults(FaultContext input) {
5961
}
6062

6163
// Faults
62-
System.out.println("ByzzFuzzFaults:");
6364
faults.forEach(fault -> System.out.println(fault.getId()));
6465

6566
return faults;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package byzzbench.simulator.protocols.fab;
2+
3+
import byzzbench.simulator.Client;
4+
import byzzbench.simulator.Scenario;
5+
import byzzbench.simulator.protocols.pbft.message.RequestMessage;
6+
import byzzbench.simulator.transport.MessagePayload;
7+
import lombok.extern.java.Log;
8+
9+
import java.io.Serializable;
10+
import java.util.ArrayList;
11+
import java.util.List;
12+
import java.util.concurrent.atomic.AtomicBoolean;
13+
import java.util.concurrent.atomic.AtomicLong;
14+
15+
@Log
16+
//public class FastByzantineClient extends Client {
17+
// private final AtomicLong learners = new AtomicLong(0);
18+
// private final AtomicBoolean isFinished = new AtomicBoolean(false);
19+
// private final List<String> learnersList = new ArrayList<>();
20+
// private final List<String> proposersList = new ArrayList<>();
21+
// /**
22+
// * The replies received by the client.
23+
// */
24+
// private final List<Serializable> replies = new ArrayList<>();
25+
// /**
26+
// * The sequence number of the next request to be sent by the client.
27+
// */
28+
// private final AtomicLong requestSequenceNumber = new AtomicLong(0);
29+
// /**
30+
// * The maximum number of requests that can be sent by the client.
31+
// */
32+
// private final long maxRequests = 1000;
33+
//
34+
// public FastByzantineClient(Scenario scenario, String id, List<String> learnersList, List<String> proposersList) {
35+
// super(scenario, id);
36+
// this.learnersList.addAll(learnersList);
37+
// this.proposersList.addAll(proposersList);
38+
// }
39+
//
40+
// @Override
41+
// public void sendRequest(String senderId) {
42+
// long sequenceNumber = this.getRequestSequenceNumber().getAndIncrement();
43+
// String command = String.format("%s/%d", this.getId(), sequenceNumber);
44+
// // TODO: compute the digest
45+
// RequestMessage request = new RequestMessage(this.getId(), sequenceNumber, "-1", command);
46+
// this.getScenario().getTransport().sendClientRequest(this.getId(), request, senderId);
47+
// }
48+
//
49+
// @Override
50+
// public void handleMessage(String senderId, MessagePayload reply) {
51+
// log.info("Client received a message from " + senderId);
52+
//
53+
// this.replies.add(reply);
54+
// if (learnersList.contains(senderId)) {
55+
// learners.incrementAndGet();
56+
// if (learners.get() == 4) {
57+
// for (String proposer : proposersList) {
58+
// this.sendRequest(proposer);
59+
// }
60+
//
61+
// learners.set(0);
62+
// }
63+
// } else {
64+
// log.info("Client received a message from a non-learner node");
65+
// }
66+
// }
67+
//}
68+
69+
public class FastByzantineClient extends Client {
70+
private final AtomicLong learners = new AtomicLong(0);
71+
private final AtomicBoolean isFinished = new AtomicBoolean(false);
72+
private final List<String> learnersList = new ArrayList<>();
73+
private final List<String> proposersList = new ArrayList<>();
74+
/**
75+
* The replies received by the client.
76+
*/
77+
private final List<Serializable> replies = new ArrayList<>();
78+
/**
79+
* The sequence number of the next request to be sent by the client.
80+
*/
81+
private final AtomicLong requestSequenceNumber = new AtomicLong(0);
82+
/**
83+
* The maximum number of requests that can be sent by the client.
84+
*/
85+
private final long maxRequests = 1000;
86+
87+
public FastByzantineClient(Scenario scenario, String id, List<String> learnersList, List<String> proposersList) {
88+
super(scenario, id);
89+
this.learnersList.addAll(learnersList);
90+
this.proposersList.addAll(proposersList);
91+
}
92+
93+
@Override
94+
public void sendRequest(String senderId) {
95+
long sequenceNumber = this.getRequestSequenceNumber().getAndIncrement();
96+
String command = String.format("%s/%d", this.getId(), sequenceNumber);
97+
// TODO: compute the digest
98+
RequestMessage request = new RequestMessage(this.getId(), sequenceNumber, "-1", command);
99+
this.getScenario().getTransport().sendMessage(this, request, senderId);
100+
}
101+
102+
@Override
103+
public void handleMessage(String senderId, MessagePayload reply) {
104+
log.info("Client received a message from " + senderId);
105+
106+
this.replies.add(reply);
107+
if (learnersList.contains(senderId)) {
108+
learners.incrementAndGet();
109+
if (learners.get() == 4) {
110+
for (String proposer : proposersList) {
111+
this.sendRequest(proposer);
112+
}
113+
114+
learners.set(0);
115+
}
116+
} else {
117+
log.info("Client received a message from a non-learner node");
118+
}
119+
}
120+
}

0 commit comments

Comments
 (0)