-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathblockchain.js
204 lines (164 loc) · 5.95 KB
/
blockchain.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
const WebSocket = require('ws');
const express = require('express');
const crypto = require('crypto');
const repl = require('repl'); // Import the REPL module
// Function to connect to a peer
const connectToPeer = (peerAddress) => {
const ws = new WebSocket(peerAddress);
ws.on('open', () => {
console.log(`Connected to peer: ${peerAddress}`);
peers.push(ws); // Add the peer to the list
// Send blockchain to the newly connected peer
ws.send(JSON.stringify(blockchain.chain));
});
ws.on('message', (message) => {
const receivedChain = JSON.parse(message);
synchronizeChain(receivedChain);
});
ws.on('error', (error) => {
console.log(`Error connecting to peer: ${peerAddress}`, error);
});
};
// Array to store peers
let peers = [];
// Add peer to the array
const addPeer = (ws) => {
peers.push(ws);
};
// Broadcast chain to all connected peers
const broadcastChain = (blockchain) => {
peers.forEach(peer => {
peer.send(JSON.stringify(blockchain.chain));
});
};
// Synchronize chains when receiving data
const synchronizeChain = (receivedChain) => {
if (receivedChain.length > blockchain.chain.length) {
console.log('Received new chain. Updating blockchain...');
blockchain.chain = receivedChain;
}
};
// Function to start WebSocket server on a separate port
const startWebSocketServer = (wsPort) => {
const server = new WebSocket.Server({ port: wsPort });
server.on('connection', (ws) => {
console.log(`Peer connected on port ${wsPort}`);
addPeer(ws);
ws.on('message', (message) => {
const receivedChain = JSON.parse(message);
synchronizeChain(receivedChain);
});
ws.on('close', () => {
console.log('Peer disconnected');
});
// Send the current blockchain to the new peer
ws.send(JSON.stringify(blockchain.chain));
});
console.log(`WebSocket server started on port ${wsPort}`);
};
// Start the WebSocket server
const wsPort = parseInt(process.argv[2]) + 1; // WebSocket port is HTTP port + 1
startWebSocketServer(wsPort);
// Block class: represents each block in the blockchain
class Block {
constructor(index, previousHash, timestamp, transactions, nonce = 0) {
this.index = index;
this.previousHash = previousHash;
this.timestamp = timestamp;
this.transactions = transactions;
this.nonce = nonce;
this.hash = this.calculateHash();
}
// Hash calculation method
calculateHash() {
return crypto.createHash('sha256').update(this.index + this.previousHash + this.timestamp + JSON.stringify(this.transactions) + this.nonce).digest('hex');
}
// Proof-of-Work mining
mineBlock(difficulty) {
while (this.hash.substring(0, difficulty) !== Array(difficulty + 1).join("0")) {
this.nonce++;
this.hash = this.calculateHash();
}
console.log("Block mined: " + this.hash);
}
}
// Blockchain class: manages the chain of blocks
class Blockchain {
constructor() {
this.chain = [this.createGenesisBlock()];
this.difficulty = 2;
this.pendingTransactions = [];
}
// Create the genesis block (first block in the chain)
createGenesisBlock() {
return new Block(0, "0", Date.now(), "Genesis Block", 0);
}
// Get the latest block in the chain
getLatestBlock() {
return this.chain[this.chain.length - 1];
}
// Mining pending transactions into a block
minePendingTransactions() {
const block = new Block(this.chain.length, this.getLatestBlock().hash, Date.now(), this.pendingTransactions);
block.mineBlock(this.difficulty);
console.log('Block successfully mined!');
this.chain.push(block);
// Reset the pending transactions
this.pendingTransactions = [];
// Broadcast the updated chain to connected peers
broadcastChain(this);
}
// Add a new transaction to the pending transactions
createTransaction(transaction) {
this.pendingTransactions.push(transaction);
}
// Validate the blockchain's integrity
isChainValid() {
for (let i = 1; i < this.chain.length; i++) {
const currentBlock = this.chain[i];
const previousBlock = this.chain[i - 1];
if (currentBlock.hash !== currentBlock.calculateHash()) {
return false;
}
if (currentBlock.previousHash !== previousBlock.hash) {
return false;
}
}
return true;
}
// Synchronize chain with other peers
synchronizeChain(newChain) {
if (newChain.length > this.chain.length && this.isChainValid(newChain)) {
this.chain = newChain;
console.log('Blockchain updated to the longest chain');
}
}
}
// Create a new instance of the blockchain
const blockchain = new Blockchain();
// Express.js setup for HTTP server
const app = express();
const PORT = process.argv[2] || 3000;
// Start the Express server
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
// Example transactions to test the blockchain
blockchain.createTransaction({ sender: "Alice", receiver: "Bob", amount: 50 });
blockchain.minePendingTransactions();
blockchain.createTransaction({ sender: "Bob", receiver: "Charlie", amount: 25 });
blockchain.minePendingTransactions();
// Example: Automatically connect to other peers
if (PORT != 3000) {
connectToPeer('ws://localhost:3001'); // Connecting Node 2 to Node 1
}
// Start REPL to interact with the blockchain
const startRepl = () => {
const replServer = repl.start('> ');
// Expose blockchain and peers array in the REPL context
replServer.context.blockchain = blockchain;
replServer.context.peers = peers;
replServer.context.connectToPeer = connectToPeer;
replServer.context.broadcastChain = broadcastChain;
};
startRepl();