-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
157 lines (132 loc) · 5.52 KB
/
server.js
File metadata and controls
157 lines (132 loc) · 5.52 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
// 🔧 Core Setup
const express = require('express');
const path = require('path');
const { Worker } = require('worker_threads');
const fs = require('fs');
const app = express();
const PORT = process.env.PORT || 3000;
// 📦 Modular Components
const walletCore = require('./wallet');
const minerCore = require('./miner');
const chainCore = require('./chain');
const blockCore = require('./block');
const networkCore = require('./network');
const cliInterface = require('./cli');
// 🔐 Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, 'public')));
// 🧠 View Engine
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// 🧱 Data Fallback (sinkron ke file chain.json & transactions.json)
let chain;
try {
chain = chainCore.getChain?.() || JSON.parse(fs.readFileSync('./chain.json'));
} catch (err) {
chain = [
{
index: 0,
hash: '0000000000000000',
previousHash: 'null',
timestamp: Date.now(),
transactions: [{ from: 'SYSTEM', to: '0xabc123', amount: 25000000 }]
}
];
}
let transactions;
try {
transactions = chainCore.getTransactions?.() || JSON.parse(fs.readFileSync('./transactions.json'));
} catch (err) {
transactions = [];
}
const wallets = walletCore.getAll?.() || [
{ name: 'Main Wallet', address: '0xabc123', balance: 120 },
{ name: 'Mining Wallet', address: '0xdef456', balance: 45 }
];
const peers = networkCore.getPeers?.() || ['node1.jschain.net', 'node2.jschain.net'];
const minerStats = minerCore.getStatus?.() || { active: true, hashRate: 0.42, address: '0xminer001' };
const chainVersion = chainCore.version || 'v1.0.3';
const latestHash = chain.length ? chain[chain.length - 1].hash : 'N/A';
// 🧭 View Routes
app.get('/', (req, res) => res.render('home', { chainVersion, latestHash }));
app.get('/explorer', (req, res) => res.render('explorer', { chain }));
app.get('/wallets', (req, res) => res.render('wallets', { wallets }));
app.get('/wallet_detail', (req, res) => res.render('wallet_detail', { wallet: wallets[0] }));
app.get('/wallet_history', (req, res) => res.render('wallet_history', { wallets }));
app.get('/address_detail', (req, res) => res.render('address_detail', { address: wallets[0].address, balance: wallets[0].balance }));
app.get('/miner', (req, res) => res.render('miner_stats', { minerStats }));
app.get('/transactions', (req, res) => res.render('transactions', { transactions }));
app.get('/tx_detail', (req, res) => res.render('tx_detail', { tx: transactions[0] }));
app.get('/block_detail', (req, res) => res.render('block_detail', { block: chain[0] }));
app.get('/block_details', (req, res) => res.render('block_details', { blocks: blockCore.getAll?.() || chain }));
app.get('/block', (req, res) => res.render('block', { block: blockCore.getLatest?.() || chain[chain.length - 1] }));
app.get('/send', (req, res) => res.render('send'));
app.get('/balance', (req, res) => res.render('balance'));
app.get('/peers', (req, res) => res.render('peers', { peers }));
app.get('/login', (req, res) => res.render('login'));
app.get('/index', (req, res) => res.render('index', { chain }));
// 🔧 API Routes
// Buat wallet baru
app.get('/api/wallet/new', (req, res) => {
const newWallet = walletCore.generate?.();
res.json(newWallet || { error: 'Wallet module not available' });
});
// Kirim transaksi baru
app.post('/api/transactions/send', (req, res) => {
const { from, to, amount } = req.body;
if (!from || !to || !amount) {
return res.status(400).json({ error: 'Invalid transaction data' });
}
const tx = { from, to, amount, hash: `tx${Date.now()}` };
transactions.push(tx);
fs.writeFileSync('./transactions.json', JSON.stringify(transactions, null, 2));
res.json({ success: true, tx });
});
// Mulai miner
app.get('/api/miner/start', (req, res) => {
const blockData = JSON.stringify(blockCore.getLatest?.() || chain[chain.length - 1]);
const difficulty = 5; // samakan dengan node.js
const minerAddress = wallets[0].address;
const worker = new Worker('./minerWorker.js', {
workerData: { core: 'js-chain-core', blockData, difficulty, minerAddress }
});
worker.on('message', msg => {
if (msg.found) {
console.log(`✅ Block mined! Hash: ${msg.hash}, Nonce: ${msg.nonce}`);
// Update chain.json setiap block baru
chain.push({
index: chain.length,
hash: msg.hash,
previousHash: latestHash,
timestamp: Date.now(),
transactions: transactions
});
fs.writeFileSync('./chain.json', JSON.stringify(chain, null, 2));
transactions = []; // clear pool setelah mining
fs.writeFileSync('./transactions.json', JSON.stringify(transactions, null, 2));
} else {
console.log(`⛏️ Hashrate: ${msg.hashrate} H/s | Best: ${msg.bestHash}`);
}
});
worker.on('error', err => console.error('❌ Worker error:', err));
res.json({ started: true });
});
// Status chain
app.get('/api/chain/status', (req, res) => {
const status = chainCore.getStatus?.() || { height: chain.length, latestHash };
res.json(status);
});
// Peers
app.get('/api/network/peers', (req, res) => res.json(peers));
// Latest block
app.get('/api/blocks/latest', (req, res) => res.json(blockCore.getLatest?.() || chain[chain.length - 1]));
// CLI help
app.get('/api/cli/help', (req, res) => {
const helpText = cliInterface.getHelp?.() || 'CLI commands not available.';
res.send(`<pre>${helpText}</pre>`);
});
// 🚀 Start Server
app.listen(PORT, () => {
console.log(`✅ JavaScript-chain server running on port ${PORT}`);
});