forked from ac12644/Blockchain
-
Notifications
You must be signed in to change notification settings - Fork 0
/
p2p.js
273 lines (235 loc) · 10.6 KB
/
p2p.js
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
265
266
267
268
269
270
271
272
273
const crypto = require('crypto');
const Swarm = require('discovery-swarm');
const defaults = require('dat-swarm-defaults');
const getPort = require('get-port');
const chain = require("./chain");
const CronJob = require('cron').CronJob;
const express = require("express");
const bodyParser = require('body-parser');
const wallet = require('./wallet');
// Set your variables to hold an object with the peers and connection sequence
const peers = {};
let connSeq = 0;
let channel = 'myBlockchain';
let registeredMiners = [];
let lastBlockMinedBy = null;
// define a message type to request and receive the latest block
let MessageType = {
REQUEST_BLOCK: 'requestBlock',
RECEIVE_NEXT_BLOCK: 'receiveNextBlock',
RECEIVE_NEW_BLOCK: 'receiveNewBlock',
REQUEST_ALL_REGISTER_MINERS: 'requestAllRegisterMiners',
REGISTER_MINER: 'registerMiner'
};
const myPeerId = crypto.randomBytes(32);
console.log('myPeerId: ' + myPeerId.toString('hex'));
// create a database once you start the code
chain.createDb(myPeerId.toString('hex'));
// create a method called initHttpServer that will initiate the server and create the services
let initHttpServer = (port) => {
let http_port = '80' + port.toString().slice(-2);
let app = express();
app.use(bodyParser.json());
// Blocks service will be retrieving all of your blocks
app.get('/blocks', (req, res) => res.send(JSON.stringify( chain.blockchain )));
// getBlock service will be retrieving one block based on an index
app.get('/getBlock', (req, res) => {
let blockIndex = req.query.index;
res.send(chain.blockchain[blockIndex]);
});
// getDBBlock service will be retrieving a LevelDB database entry based on an index
app.get('/getDBBlock', (req, res) => {
let blockIndex = req.query.index;
chain.getDbBlock(blockIndex, res);
});
//getWallet service will be utilizing the wallet.js file you created in the previous step and generate your public-private key pair
app.get('/getWallet', (req, res) => {
res.send(wallet.initWallet());
});
app.listen(http_port, () => console.log('Listening http on port: ' + http_port));
};
// generate a config object that holds your peer ID
const config = defaults({
id: myPeerId,
});
// initialize swarm library using config as object
const swarm = Swarm(config);
(async () => {
// listen on the random port selected
const port = await getPort();
initHttpServer(port); // call the initHttpServer
swarm.listen(port);
console.log('Listening port: ' + port);
swarm.join(channel);
swarm.on('connection', (conn, info) => {
const seq = connSeq;
const peerId = info.id.toString('hex');
console.log(`Connected #${seq} to peer: ${peerId}`);
if (info.initiator) {
try {
// use setKeepAlive to ensure the network connection stays with other peers
conn.setKeepAlive(true, 600);
} catch (exception) {
console.log('exception', exception);
}
}
// Once you receive a data message on the P2P network, you parse the data using JSON.parse
conn.on('data', data => {
let message = JSON.parse(data);
console.log('----------- Received Message start -------------');
console.log(
'from: ' + peerId.toString('hex'),
'to: ' + peerId.toString(message.to),
'my: ' + myPeerId.toString('hex'),
'type: ' + JSON.stringify(message.type)
);
console.log('----------- Received Message end -------------');
/*
once a connection data event message is received, you can create your switch
code to handle the different types of requests
*/
switch (message.type) {
case MessageType.REQUEST_BLOCK:
console.log('-----------REQUEST_BLOCK-------------');
let requestedIndex = (JSON.parse(JSON.stringify(message.data))).index;
let requestedBlock = chain.getBlock(requestedIndex);
if (requestedBlock)
writeMessageToPeerToId(peerId.toString('hex'), MessageType.RECEIVE_NEXT_BLOCK, requestedBlock);
else
console.log('No block found @ index: ' + requestedIndex);
console.log('-----------REQUEST_BLOCK-------------');
break;
case MessageType.RECEIVE_NEXT_BLOCK:
console.log('-----------RECEIVE_NEXT_BLOCK-------------');
chain.addBlock(JSON.parse(JSON.stringify(message.data)));
console.log(JSON.stringify(chain.blockchain));
let nextBlockIndex = chain.getLatestBlock().index+1;
console.log('-- request next block @ index: ' + nextBlockIndex);
writeMessageToPeers(MessageType.REQUEST_BLOCK, {index: nextBlockIndex});
console.log('-----------RECEIVE_NEXT_BLOCK-------------');
break;
case MessageType.RECEIVE_NEW_BLOCK:
if ( message.to === myPeerId.toString('hex') && message.from !== myPeerId.toString('hex')) {
console.log('-----------RECEIVE_NEW_BLOCK------------- ' + message.to);
chain.addBlock(JSON.parse(JSON.stringify(message.data)));
console.log(JSON.stringify(chain.blockchain));
console.log('-----------RECEIVE_NEW_BLOCK------------- ' + message.to);
}
break;
case MessageType.REQUEST_ALL_REGISTER_MINERS:
console.log('-----------REQUEST_ALL_REGISTER_MINERS------------- ' + message.to);
writeMessageToPeers(MessageType.REGISTER_MINER, registeredMiners);
registeredMiners = JSON.parse(JSON.stringify(message.data));
console.log('-----------REQUEST_ALL_REGISTER_MINERS------------- ' + message.to);
break;
case MessageType.REGISTER_MINER:
console.log('-----------REGISTER_MINER------------- ' + message.to);
let miners = JSON.stringify(message.data);
registeredMiners = JSON.parse(miners);
console.log(registeredMiners);
console.log('-----------REGISTER_MINER------------- ' + message.to);
break;
}
});
/*
listen to a close event, which will indicate that you
lost a connection with peers, so you can take action, such as delete
the peers from your peers ist object.
*/
conn.on('close', () => {
console.log(`Connection ${seq} closed, peerId: ${peerId}`);
if (peers[peerId].seq === seq) {
delete peers[peerId];
console.log('--- registeredMiners before: ' + JSON.stringify(registeredMiners));
let index = registeredMiners.indexOf(peerId);
if (index > -1)
registeredMiners.splice(index, 1);
console.log('--- registeredMiners end: ' + JSON.stringify(registeredMiners));
}
});
if (!peers[peerId]) {
peers[peerId] = {}
}
peers[peerId].conn = conn;
peers[peerId].seq = seq;
connSeq++
})
})();
// writeMessageToPeers method will be sending messages to all the connected peers
writeMessageToPeers = (type, data) => {
for (let id in peers) {
console.log('-------- writeMessageToPeers start -------- ');
console.log('type: ' + type + ', to: ' + id);
console.log('-------- writeMessageToPeers end ----------- ');
sendMessage(id, type, data);
}
};
// writeMessageToPeerToId, that will be sending the message to a specific peer ID
writeMessageToPeerToId = (toId, type, data) => {
for (let id in peers) {
if (id === toId) {
console.log('-------- writeMessageToPeerToId start -------- ');
console.log('type: ' + type + ', to: ' + toId);
console.log('-------- writeMessageToPeerToId end ----------- ');
sendMessage(id, type, data);
}
}
};
/*
sendMessage is a generic method that we will be using to send a
message formatted with the params you would like to pass and includes the
following:
– to/from: The peer ID you are sending the message from and to
– type: The message type
– data: Any data you would like to share on the P2P network
*/
sendMessage = (id, type, data) => {
peers[id].conn.write(JSON.stringify(
{
to: id,
from: myPeerId,
type: type,
data: data
}
));
};
setTimeout(function(){
writeMessageToPeers(MessageType.REQUEST_ALL_REGISTER_MINERS, null);
}, 5000);
// using a setTimeout function to send a message send a request to retrieve the latest block every 5 seconds
setTimeout(function(){
writeMessageToPeers(MessageType.REQUEST_BLOCK, {index: chain.getLatestBlock().index+1});
}, 5000);
setTimeout(function(){
registeredMiners.push(myPeerId.toString('hex'));
console.log('----------Register my miner --------------');
console.log(registeredMiners);
writeMessageToPeers(MessageType.REGISTER_MINER, registeredMiners);
console.log('---------- Register my miner --------------');
}, 7000);
const job = new CronJob('30 * * * * *', function() {
let index = 0; // first block
// requesting next block from your next miner
if (lastBlockMinedBy) {
let newIndex = registeredMiners.indexOf(lastBlockMinedBy);
index = ( newIndex+1 > registeredMiners.length-1) ? 0 : newIndex + 1;
}
/*
To generate and add a new block, you will be calling chain
generateNextBlock and addBlock. Lastly, you will broadcast the new
block to all the connected peers.
*/
lastBlockMinedBy = registeredMiners[index];
console.log('-- REQUESTING NEW BLOCK FROM: ' + registeredMiners[index] + ', index: ' + index);
console.log(JSON.stringify(registeredMiners));
if (registeredMiners[index] === myPeerId.toString('hex')) {
console.log('-----------create next block -----------------');
let newBlock = chain.generateNextBlock(null);
chain.addBlock(newBlock);
console.log(JSON.stringify(newBlock));
writeMessageToPeers(MessageType.RECEIVE_NEW_BLOCK, newBlock);
console.log(JSON.stringify(chain.blockchain));
console.log('-----------create next block -----------------');
}
});
job.start();