-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSimulation.java
More file actions
139 lines (113 loc) · 5.72 KB
/
Simulation.java
File metadata and controls
139 lines (113 loc) · 5.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Example of a Simulation. This test runs the nodes on a random graph.
// At the end, it will print out the Transaction ids which each node
// believes consensus has been reached upon. You can use this simulation to
// test your nodes. You will want to try creating some deviant nodes and
// mixing them in the network to fully test.
import javafx.util.Pair;
import java.util.*;
public class Simulation {
public static void main(String[] args) {
// There are four required command line arguments: p_graph (.1, .2, .3),
// p_malicious (.15, .30, .45), p_txDistribution (.01, .05, .10),
// and numRounds (10, 20). You should try to test your CompliantNode
// code for all 3x3x3x2 = 54 combinations.
int numNodes = 100;
double p_graph = Double.parseDouble(args[0]); // parameter for random graph: prob. that an edge will exist
double p_malicious = Double.parseDouble(args[1]); // prob. that a node will be set to be malicious
double p_txDistribution = Double.parseDouble(args[2]); // probability of assigning an initial transaction to each node
int numRounds = Integer.parseInt(args[3]); // number of simulation rounds your nodes will run for
int compliantCount = 0;
// pick which nodes are malicious and which are compliant
Node[] nodes = new Node[numNodes];
for (int i = 0; i < numNodes; i++) {
if(Math.random() < p_malicious)
// When you are ready to try testing with malicious nodes, replace the
// instantiation below with an instantiation of a MaliciousNode
nodes[i] = new MaliciousNode(p_graph, p_malicious, p_txDistribution, numRounds);
else {
nodes[i] = new CompliantNode(p_graph, p_malicious, p_txDistribution, numRounds);
compliantCount++;
}
}
// initialize random follow graph
boolean[][] followees = new boolean[numNodes][numNodes]; // followees[i][j] is true iff i follows j
for (int i = 0; i < numNodes; i++) {
for (int j = 0; j < numNodes; j++) {
if (i == j) continue;
if(Math.random() < p_graph) { // p_graph is .1, .2, or .3
followees[i][j] = true;
}
}
}
// notify all nodes of their followees
for (int i = 0; i < numNodes; i++)
nodes[i].setFollowees(followees[i]);
// initialize a set of 500 valid Transactions with random ids
int numTx = 500;
HashSet<Integer> validTxIds = new HashSet<Integer>();
Random random = new Random();
for (int i = 0; i < numTx; i++) {
int r = random.nextInt();
validTxIds.add(r);
}
// distribute the 500 Transactions throughout the nodes, to initialize
// the starting state of Transactions each node has heard. The distribution
// is random with probability p_txDistribution for each Transaction-Node pair.
for (int i = 0; i < numNodes; i++) {
HashSet<Transaction> pendingTransactions = new HashSet<Transaction>();
for(Integer txID : validTxIds) {
if (Math.random() < p_txDistribution) // p_txDistribution is .01, .05, or .10.
pendingTransactions.add(new Transaction(txID));
}
nodes[i].setPendingTransaction(pendingTransactions);
}
// Simulate for numRounds times
for (int round = 0; round < numRounds; round++) { // numRounds is either 10 or 20
// gather all the proposals into a map. The key is the index of the node receiving
// proposals. The value is an ArrayList containing 1x2 Integer arrays. The first
// element of each array is the id of the transaction being proposed and the second
// element is the index # of the node proposing the transaction.
HashMap<Integer, Set<Candidate>> allProposals = new HashMap<>();
for (int i = 0; i < numNodes; i++) {
Set<Transaction> proposals = nodes[i].sendToFollowers();
for (Transaction tx : proposals) {
if (!validTxIds.contains(tx.id))
continue; // ensure that each tx is actually valid
for (int j = 0; j < numNodes; j++) {
if(!followees[j][i]) continue; // tx only matters if j follows i
if (!allProposals.containsKey(j)) {
Set<Candidate> candidates = new HashSet<>();
allProposals.put(j, candidates);
}
Candidate candidate = new Candidate(tx, i);
allProposals.get(j).add(candidate);
}
}
}
// Distribute the Proposals to their intended recipients as Candidates
for (int i = 0; i < numNodes; i++) {
if (allProposals.containsKey(i)) {
// System.out.print("Round " + round + ", Node " + i + " ");
nodes[i].receiveFromFollowees(allProposals.get(i));
}
}
}
Map<Integer, Integer> counts = new HashMap<>();
// print results
for (int i = 0; i < numNodes; i++) {
Set<Transaction> transactions = nodes[i].sendToFollowers();
System.out.println("Transaction ids that Node " + i + " believes consensus on:");
int size = transactions.size();
System.out.println("Have " + transactions.size() + " txs");
counts.put(size, counts.getOrDefault(size, 0) + 1);
// for (Transaction tx : transactions)
// System.out.println(tx.id);
// System.out.println();
System.out.println();
}
System.out.println("There are " + compliantCount + " compliant nodes");
for (Integer key : counts.keySet()) {
System.out.println(key + " : " + counts.get(key));
}
}
}