-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBlockChain.java
More file actions
233 lines (180 loc) · 5.74 KB
/
Copy pathBlockChain.java
File metadata and controls
233 lines (180 loc) · 5.74 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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
public class BlockChain {
private Terminal terminal;
private int zeros;
private AVLTree<Integer> tree = new AVLTree<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
});
private List<Block> blockChain = new ArrayList<Block>();
public BlockChain(int zeros, Terminal terminal) {
this.terminal = terminal;
this.zeros = zeros;
createGenesisBlock();
}
public int getZeros() {
return zeros;
}
public AVLTree<Integer> getTree() {
return tree;
}
private class Block {
private int index;
private long nonce;
private String instruction; //"add 5 true", "remove 3 true"
private String hash;
private String prevHash;
public Block(int index, String instruction, String prevHash) {
this.index = index;
this.instruction = instruction;
this.prevHash = prevHash;
this.hash = calculateHash();
}
public String getPrevHash() {
return prevHash;
}
public long getNonce() {
return nonce;
}
public String getHash() {
return hash;
}
public void setHash(String hash) {
this.hash = hash;
}
public int getIndex() {
return index;
}
public String getInstruction() {
return instruction;
}
public String calculateHash() { //calculates a valid hash according to zeros
int nonce = 0;
String comb = getIndex() + getInstruction() + getPrevHash();
String hash = sha256(comb + nonce);
while(!validHash(hash)) {
nonce++;
hash = sha256(comb + nonce);
}
this.nonce = nonce;
return hash;
}
public String calculateHashNoNonce() { //calculates hash of Block with current nonce and data.
String combination = getIndex() + getInstruction() + getPrevHash() + getNonce();
return sha256(combination);
}
private boolean validHash(String hash) {
boolean valid = true;
for(int i = 0 ; i < getZeros() ; i++) {
if(hash.charAt(i) != '0')
valid = false;
}
return valid;
}
private String sha256(String base) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(base.getBytes("UTF-8"));
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < hash.length; i++) {
String hex = Integer.toHexString(0xff & hash[i]);
if(hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
} catch(Exception ex){
throw new RuntimeException(ex);
}
}
public void setinstruction(String data){
this.instruction = data;
}
public String toString() {
String ret = "[ " + "index:" + index + "/nonce: " + nonce;
ret += "/instruction: " + instruction + "]";
return ret;
}
}
/**
* Receives instruction to perform on AVLTree, calls the correct method to excecute it and stores result in new block.
* @param action Method to call
* @param number
*/
public void operate(String action, int number){
int currentIndex = size();
Boolean success;
String instruction;
switch(action){
case "add": success = tree.add(number, currentIndex); break;
case "remove": success = tree.remove(number,currentIndex); break;
case "lookup": DataPair<Boolean,Set<Integer>> aux = tree.lookup(number);
success = aux.getElement1();
if(success) {
terminal.printMessage("Indexes that modified Node with data (" + number + "):");
terminal.printMessage(aux.getElement2().toString());
} else {
terminal.printMessage("Element (" + number + ") was not found in AVL Tree" );
}break;
default: throw new IllegalOperationException("not a valid operation to perform");
}
instruction = action + number + success.toString();
Block block = new Block(currentIndex, instruction, getLatestBlock().getHash());
add(block);
}
public void add(Block block){
blockChain.add(block);
}
public void modify(int number, String data){
if(number < 0 || number >= size()){
throw new IndexOutOfBoundsException("Index is out of bounds. BlockChain does not contain that block.");
}
blockChain.get(number).setinstruction(data);
return;
}
private void createGenesisBlock() {
blockChain.add(new Block(0,"No instruction","00000000"));
}
public List<Block> getChain() {
return blockChain;
}
public boolean validateChain() {
List<Block> bc = getChain();
for(int i=1 ; i < bc.size() ; i++) {
Block current = bc.get(i);
Block prev = bc.get(i-1);
if(!current.getHash().equals(current.calculateHashNoNonce())) {
return false;
}
if(!current.getPrevHash().equals(prev.getHash())){
return false;
}
}
return true;
}
public int size(){
return blockChain.size();
}
public Block getLatestBlock() {
return blockChain.get(size() - 1);
}
@Override
public String toString(){
String ret = new String();
int i = 0;
for(Block block: blockChain){
ret += block.toString() + "-->";
i++;
if(i%4 == 0) ret += "\n";
}
return ret;
}
protected void showInsider(){
TreePrinter.print(tree.getRoot());
}
}