-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.cpp
264 lines (224 loc) · 8.53 KB
/
main.cpp
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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
// author: tko
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <memory>
#include <stdexcept>
#include "hash.hpp"
#include "Block.hpp"
#include "common.hpp"
#include "BlockChain.hpp"
#include "requests.hpp"
#include "json.hh"
using json = nlohmann::json;
using namespace std;
#include "client_http.hpp"
#include "server_http.hpp"
using HttpServer = SimpleWeb::Server<SimpleWeb::HTTP>;
using HttpClient = SimpleWeb::Client<SimpleWeb::HTTP>;
KeyPairHex genKeys() {
KeyPairHex keyPair;
// PGP Random Pool-like generator
CryptoPP::AutoSeededRandomPool rng;
// generate keys
CryptoPP::RSA::PrivateKey privateKey;
privateKey.GenerateRandomWithKeySize(rng, 2048); // KEY_SIZE
CryptoPP::RSA::PublicKey publicKey(privateKey);
// save keys
publicKey.Save( CryptoPP::HexEncoder(
new CryptoPP::StringSink(keyPair.publicKey)).Ref());
privateKey.Save(CryptoPP::HexEncoder(
new CryptoPP::StringSink(keyPair.privateKey)).Ref());
return keyPair;
}
/*
Hash header: index + prevHash + merkleRoot(data) + nonce
*/
/*
* Main function - sets up server, command line interface
*/
int main() {
printf("Welcome! To quit-> Control c \n");
HttpServer server;
// Set up ports
int port;
printf("Enter port: ");
scanf("%d",&port);
server.config.port = port; //server port
vector<int> listOfNodes; //vector of the ports of nodes in the network
// BLOCK CHAIN INITIALIZATION AND ADDING SELF TO NETWORK
char ch;
auto miner = genKeys();
printf("Are you the initial Node? (y or n) ");
scanf(" %c",&ch);
BlockChain bc(miner);
if (ch == 'y'){
// Initial Node: setup Blockchain with genesis block
bc = BlockChain(miner, 0);
}
else if(ch =='n'){
// New Node - need to add self to network by providing ports
bc = BlockChain(miner, 0);
char otherPorts[50];
// Example input: 8000,3000,3030
printf("Enter ports of nodes in network(with commas in between): ");
scanf("%s",otherPorts);
stringstream ss(otherPorts);
int i;
// parse string of nodes and add them to listOfNoes
while (ss >> i)
{
listOfNodes.push_back(i);
if (ss.peek() == ',' || ss.peek() == ' ')
ss.ignore();
}
addSelfToNetwork(&listOfNodes,server.config.port);
json chain = getChainFromNodes(&listOfNodes);
//skips first block - same genesis block across all nodes
for (int a = 1; a <chain["length"].get<int>(); a++ ){
auto block = chain["data"][a];
vector<string> data = block["data"].get<vector<string> >();
vector<Transaction> v;
string trans = block["transactions"];
auto o = split(trans, '|');
for (auto x: o) {
auto o_ = split(x, ';');
v.emplace_back(o_[0], o_[1], o_[2], std::stoi(o_[3]));
}
bc.addBlock(block["index"], block["previousHash"], block["hash"],
block["nonce"], data, v, miner.publicKey);
}
}
else {
return 0;
}
// SERVER INITIALIZATION
/* POST /addnode - used to add node to network, called by new node to all the nodes in the network
* adds node(port) to listOfNodes
*/
server.resource["^/addnode$"]["POST"] = [&listOfNodes](shared_ptr<HttpServer::Response> response,
shared_ptr<HttpServer::Request> request) {
printf("POST /addnode --- New Node adding to network....\n");
try {
json content = json::parse(request->content);
int port = content["port"].get<int>();
listOfNodes.push_back(port); // Adds port to listOfNodes
printf("----Adding node %d to listOfNodes\n",port);
response->write("Added You to our List");
}
catch(const exception &e) {
*response << "HTTP/1.1 400 Bad Request\r\nContent-Length: " <<
strlen(e.what()) << "\r\n\r\n" << e.what();
}
};
/* GET /latestchain gets latest blockchain and sends it*/
server.resource["^/latestchain$"]["GET"] = [&bc](shared_ptr<HttpServer::Response> response,
shared_ptr<HttpServer::Request> request) {
printf("GET /latestchain --- Sending BlockChain....\n");
response->write(bc.toJSON());
printf("---Sent current BlockChain\n");
};
/* POST /newchain called by a node when a new block is added to it -
* checks whether the length of the blockchain is bigger than our own blockchain
* if it is bigger -> replace chain, else don't do anything
*/
server.resource["^/newchain$"]["POST"] = [&bc](shared_ptr<HttpServer::Response> response,
shared_ptr<HttpServer::Request> request) {
cout << "POST /newchain --- Node in Network sent new chain\n";
try {
json content = json::parse(request->content);
if (content["length"].get<int>() > bc.getNumOfBlocks()){
bc.replaceChain(content);
response->write("Replaced Chain\n");
}
else {
cout << "----Chain was not replaced: sent chain had same size" <<endl;
response->write("Same Chain Size -- invalid");
}
}
catch(const exception &e) {
*response << "HTTP/1.1 400 Bad Request\r\nContent-Length: " << strlen(e.what()) <<
"\r\n\r\n" << e.what();
}
};
// On error lambda function
server.on_error = [](shared_ptr<HttpServer::Request> /*request*/, const SimpleWeb::error_code & ec) {
if (ec.message() != "End of file") {
cout << "SERVER ERROR: " << ec.message() << endl;
}
};
printf("Starting server at %d",server.config.port);
// start server
thread server_thread([&server]() {
server.start();
});
//COMMAND LINE INTERFACE
// loop for 20 inputs - can change
for ( int i = 0; i < 20; i++ ) {
vector<string> v;
int temp;
// ask for what to do
printf("\n(1) Look at Blocks \n(2) Add block\n(3) Add transaction\n");
int valid = scanf("%d",&temp);
if ( (valid == 1) && (temp == 1)){ // queue up block if 1
printf("What Block do you want to look at? ");
scanf("%d",&temp);
try {
bc.getBlock(temp).toString();
}
catch (const exception& e){
cout << e.what() << endl;
}
}
else if (temp == 2){ // add a new block if 2
printf("\nADDING BLOCKS!\nEnter your message: ");
string str;
char c;
bool first = true;
while (std::cin >> std::noskipws >> c && c != '\n' || first) {
if (first) {
cin.get(c);
}
if (c == '\n') {break;}
str += c;
first = false;
}
printf("Entered '%s' into block\n",str.c_str());
v.push_back(str);
int in;
printf("Press any number to add block to blockchain: ");
scanf("%d",&in);
try {
if (bc.getNumOfBlocks() == 0) {
printf("----------------------------------\nPlease join the network... "
"Your blockchain doesn't have any blocks ");
continue;
}
// mine for the has
auto pair = findHash(bc.getNumOfBlocks(),bc.getLatestBlockHash(),v);
// add the block to the blockchain
bc.addBlock(bc.getNumOfBlocks(),bc.getLatestBlockHash(),pair.first,pair.second,
v, bc.transactions, miner.publicKey);
// send the blockchain to the network
sendNewChain(&listOfNodes,bc.toJSON());
}
catch (const exception& e) {
cout << e.what() << "\n" << endl;
}
} else if (temp == 3) {
printf("\nADDING TRANSACTION!\nEnter amount: ");
scanf("%d",&temp);
auto keyPair = genKeys();
Transaction t(keyPair.publicKey, keyPair.privateKey, temp);
t.signTransaction(keyPair.privateKey);
bc.addTransaction(t);
} else if (temp == 4) {
cout << bc.isValidChain() << endl;
}
}
// bc.addBlock(0,string("00000000000000"),
// string("003d9dc40cad6b414d45555e4b83045cfde74bcee6b09fb42536ca2500087fd9"),string("46"),v);
printf("\n");
return 0;
}