Skip to content

Commit c9c9e46

Browse files
Merge pull request #79 from nguyenphuminh/big-fix-5
Big fix 5
2 parents 37ff69e + b03021e commit c9c9e46

File tree

10 files changed

+116
-60
lines changed

10 files changed

+116
-60
lines changed

Diff for: package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "jechain",
3-
"version": "0.27.0",
3+
"version": "0.28.0",
44
"description": "Node for JeChain - an experimental smart contract blockchain network",
55
"main": "./index.js",
66
"scripts": {

Diff for: src/core/block.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ class Block {
223223
// Finalize state and contract storage into DB
224224

225225
for (const address in storage) {
226-
const storageDB = new Level(__dirname + "/../log/accountStore/" + address);
226+
const storageDB = new Level(__dirname + "/../../log/accountStore/" + address);
227227
const keys = Object.keys(storage[address]);
228228

229229
states[address].storageRoot = buildMerkleTree(keys.map(key => key + " " + storage[address][key])).val;

Diff for: src/core/genesis.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"use strict";
2+
13
const EC = require("elliptic").ec, ec = new EC("secp256k1");
24
const crypto = require("crypto"), SHA256 = message => crypto.createHash("sha256").update(message).digest("hex");
35

Diff for: src/core/merkle.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"use strict";
2+
13
const crypto = require("crypto"), SHA256 = message => crypto.createHash("sha256").update(message).digest("hex");
24

35
function Node(val, left = null, right = null) {

Diff for: src/core/runtime.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"use strict";
2+
13
const { Level } = require('level');
24

35
const { bigIntable, isHex, deserializeState, serializeState } = require("../utils/utils");
@@ -8,7 +10,7 @@ const { EMPTY_HASH } = require("../config.json");
810
const crypto = require("crypto"), SHA256 = message => crypto.createHash("sha256").update(message).digest("hex");
911

1012
async function jelscript(input, originalState = {}, gas, stateDB, block, txInfo, contractInfo, enableLogging = false) {
11-
const storageDB = new Level(__dirname + "/../log/accountStore/" + contractInfo.address);
13+
const storageDB = new Level(__dirname + "/../../log/accountStore/" + contractInfo.address);
1214

1315
const instructions = input.trim().replace(/\t/g, "").split("\n").map(ins => ins.trim()).filter(ins => ins !== "");
1416

Diff for: src/core/state.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ async function changeState(newBlock, stateDB, codeDB, enableLogging = false) { /
6666

6767
const [ newState, newStorage ] = await jelscript(await codeDB.get(dataFromRecipient.codeHash), {}, BigInt(tx.additionalData.contractGas || 0), stateDB, newBlock, tx, contractInfo, enableLogging);
6868

69-
const storageDB = new Level(__dirname + "/../log/accountStore/" + tx.recipient);
69+
const storageDB = new Level(__dirname + "/../../log/accountStore/" + tx.recipient);
7070
const keys = Object.keys(newStorage);
7171

7272
newState[tx.recipient].storageRoot = buildMerkleTree(keys.map(key => key + " " + newStorage[key])).val;

Diff for: src/core/txPool.js

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"use strict";
2+
13
const crypto = require("crypto"), SHA256 = message => crypto.createHash("sha256").update(message).digest("hex");
24
const EC = require("elliptic").ec, ec = new EC("secp256k1");
35

@@ -11,6 +13,8 @@ async function addTransaction(transaction, chainInfo, stateDB) {
1113
try {
1214
transaction = Transaction.deserialize(transaction);
1315
} catch (e) {
16+
console.log(`\x1b[31mERROR\x1b[0m [${(new Date()).toISOString()}] Failed to add one transaction to pool.`);
17+
1418
// If transaction can not be deserialized, it's faulty
1519
return;
1620
}
@@ -21,6 +25,7 @@ async function addTransaction(transaction, chainInfo, stateDB) {
2125
BigInt(transaction.additionalData.contractGas || 0) > BigInt(BLOCK_GAS_LIMIT)
2226
) {
2327
console.log(`\x1b[31mERROR\x1b[0m [${(new Date()).toISOString()}] Failed to add one transaction to pool.`);
28+
2429
return;
2530
}
2631

@@ -32,6 +37,7 @@ async function addTransaction(transaction, chainInfo, stateDB) {
3237

3338
if (!(await stateDB.keys().all()).includes(txSenderAddress)) {
3439
console.log(`\x1b[31mERROR\x1b[0m [${(new Date()).toISOString()}] Failed to add one transaction to pool.`);
40+
3541
return;
3642
}
3743

@@ -49,6 +55,7 @@ async function addTransaction(transaction, chainInfo, stateDB) {
4955

5056
if (maxNonce + 1 !== transaction.nonce) {
5157
console.log(`\x1b[31mERROR\x1b[0m [${(new Date()).toISOString()}] Failed to add one transaction to pool.`);
58+
5259
return;
5360
}
5461

Diff for: src/node/queue.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"use strict";
2+
3+
class SyncQueue {
4+
constructor (chainInfo) {
5+
this.queue = [];
6+
this.chainInfo = chainInfo;
7+
}
8+
9+
async add(block, verificationHandler) {
10+
this.queue.push(block);
11+
12+
if (!this.chainInfo.syncing) {
13+
this.chainInfo.syncing = true;
14+
await this.sync(verificationHandler);
15+
}
16+
}
17+
18+
async sync(verificationHandler) {
19+
while (this.queue.length !== 0) {
20+
const block = this.queue.shift();
21+
22+
if (await verificationHandler(block)) break;
23+
}
24+
25+
this.chainInfo.syncing = false;
26+
}
27+
28+
wipe() {
29+
this.queue = [];
30+
}
31+
}
32+
33+
module.exports = { SyncQueue };

Diff for: src/node/server.js

+64-54
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const { verifyBlock, updateDifficulty } = require("../consensus/consensus");
1919
const { parseJSON, indexTxns, numToBuffer, serializeState, deserializeState } = require("../utils/utils");
2020
const jelscript = require("../core/runtime");
2121
const { buildMerkleTree } = require("../core/merkle");
22+
const { SyncQueue } = require("./queue");
2223

2324
const opened = []; // Addresses and sockets from connected nodes.
2425
const connected = []; // Addresses from connected nodes.
@@ -33,15 +34,16 @@ const chainInfo = {
3334
transactionPool: [],
3435
latestBlock: generateGenesisBlock(),
3536
latestSyncBlock: null,
37+
syncQueue: new SyncQueue(this),
38+
syncing: false,
3639
checkedBlock: {},
37-
tempStates: {},
3840
difficulty: 1
3941
};
4042

41-
const stateDB = new Level(__dirname + "/../log/stateStore", { valueEncoding: "buffer" });
42-
const blockDB = new Level(__dirname + "/../log/blockStore", { valueEncoding: "buffer" });
43-
const bhashDB = new Level(__dirname + "/../log/bhashStore", { valueEncoding: "buffer" });
44-
const codeDB = new Level(__dirname + "/../log/codeStore");
43+
const stateDB = new Level(__dirname + "/../../log/stateStore", { valueEncoding: "buffer" });
44+
const blockDB = new Level(__dirname + "/../../log/blockStore", { valueEncoding: "buffer" });
45+
const bhashDB = new Level(__dirname + "/../../log/bhashStore", { valueEncoding: "buffer" });
46+
const codeDB = new Level(__dirname + "/../../log/codeStore");
4547

4648
async function startServer(options) {
4749
const PORT = options.PORT || 3000; // Node's PORT
@@ -189,22 +191,23 @@ async function startServer(options) {
189191
break;
190192

191193
case TYPE.REQUEST_BLOCK:
192-
if (!ENABLE_CHAIN_REQUEST) { // Unsynced nodes should not be able to send blocks
193-
const { blockNumber, requestAddress } = _message.data;
194+
const { blockNumber, requestAddress } = _message.data;
194195

195-
const socket = opened.find(node => node.address === requestAddress).socket; // Get socket from address
196+
let requestedBlock;
197+
198+
try {
199+
requestedBlock = [ ...await blockDB.get( blockNumber.toString() ) ]; // Get block
200+
} catch (e) {
201+
// If block does not exist, break
202+
break;
203+
}
196204

197-
const currentBlockNumber = Math.max(...(await blockDB.keys().all()).map(key => parseInt(key))); // Get latest block number
205+
const socket = opened.find(node => node.address === requestAddress).socket; // Get socket from address
198206

199-
if (blockNumber > 0 && blockNumber <= currentBlockNumber) { // Check if block number is valid
200-
const block = [ ...await blockDB.get( blockNumber.toString() ) ]; // Get block
207+
socket.send(produceMessage(TYPE.SEND_BLOCK, requestedBlock)); // Send block
208+
209+
console.log(`\x1b[32mLOG\x1b[0m [${(new Date()).toISOString()}] Sent block at position ${blockNumber} to ${requestAddress}.`);
201210

202-
socket.send(produceMessage(TYPE.SEND_BLOCK, block)); // Send block
203-
204-
console.log(`\x1b[32mLOG\x1b[0m [${(new Date()).toISOString()}] Sent block at position ${blockNumber} to ${requestAddress}.`);
205-
}
206-
}
207-
208211
break;
209212

210213
case TYPE.SEND_BLOCK:
@@ -214,45 +217,54 @@ async function startServer(options) {
214217
block = Block.deserialize(_message.data);
215218
} catch (e) {
216219
// If block fails to be deserialized, it's faulty
217-
218220
return;
219221
}
220222

221-
if (ENABLE_CHAIN_REQUEST && currentSyncBlock === block.blockNumber) {
222-
if (
223-
chainInfo.latestSyncBlock === null // If latest synced block is null then we immediately add the block into the chain without verification.
224-
|| // This happens due to the fact that the genesis block can discard every possible set rule ¯\_(ツ)_/¯
225-
await verifyBlock(block, chainInfo, stateDB, codeDB, ENABLE_LOGGING)
226-
) {
227-
currentSyncBlock += 1;
228-
229-
await blockDB.put(block.blockNumber.toString(), Buffer.from(_message.data)); // Add block to chain.
230-
await bhashDB.put(block.hash, numToBuffer(block.blockNumber)); // Assign block number to the matching block hash
231-
232-
if (!chainInfo.latestSyncBlock) {
233-
chainInfo.latestSyncBlock = block; // Update latest synced block.
234-
235-
await changeState(block, stateDB, codeDB, ENABLE_LOGGING); // Transit state
236-
}
237-
238-
chainInfo.latestBlock = block; // Update latest block cache
239-
240-
await updateDifficulty(block, chainInfo, blockDB); // Update difficulty.
241-
242-
console.log(`\x1b[32mLOG\x1b[0m [${(new Date()).toISOString()}] Synced block at position ${block.blockNumber}.`);
243-
244-
// Continue requesting the next block
245-
for (const node of opened) {
246-
node.socket.send(
247-
produceMessage(
248-
TYPE.REQUEST_BLOCK,
249-
{ blockNumber: currentSyncBlock, requestAddress: MY_ADDRESS }
250-
)
251-
);
252-
253-
await new Promise(r => setTimeout(r, 5000)); // Delay for block verification
223+
if (ENABLE_CHAIN_REQUEST && block.blockNumber === currentSyncBlock) {
224+
const verificationHandler = async function(block) {
225+
if (
226+
chainInfo.latestSyncBlock === null // If latest synced block is null, we immediately add the block into the chain without verification.
227+
|| // This happens due to the fact that the genesis block can discard every possible set rule ¯\_(ツ)_/¯
228+
await verifyBlock(block, chainInfo, stateDB, codeDB, ENABLE_LOGGING)
229+
) {
230+
await blockDB.put(block.blockNumber.toString(), Buffer.from(_message.data)); // Add block to chain
231+
await bhashDB.put(block.hash, numToBuffer(block.blockNumber)); // Assign block number to the matching block hash
232+
233+
if (!chainInfo.latestSyncBlock) {
234+
chainInfo.latestSyncBlock = block; // Update latest synced block.
235+
236+
await changeState(block, stateDB, codeDB, ENABLE_LOGGING); // Force transit state
237+
}
238+
239+
chainInfo.latestBlock = block; // Update latest block cache
240+
241+
await updateDifficulty(block, chainInfo, blockDB); // Update difficulty
242+
243+
console.log(`\x1b[32mLOG\x1b[0m [${(new Date()).toISOString()}] Synced block at position ${block.blockNumber}.`);
244+
245+
chainInfo.syncing = false;
246+
// Wipe sync queue
247+
chainInfo.syncQueue.wipe();
248+
249+
currentSyncBlock++;
250+
251+
// Continue requesting the next block
252+
for (const node of opened) {
253+
node.socket.send(
254+
produceMessage(
255+
TYPE.REQUEST_BLOCK,
256+
{ blockNumber: currentSyncBlock, requestAddress: MY_ADDRESS }
257+
)
258+
);
259+
}
260+
261+
return true;
254262
}
263+
264+
return false;
255265
}
266+
267+
chainInfo.syncQueue.add(block, verificationHandler);
256268
}
257269

258270
break;
@@ -315,8 +327,6 @@ async function startServer(options) {
315327
{ blockNumber: currentSyncBlock, requestAddress: MY_ADDRESS }
316328
)
317329
);
318-
319-
await new Promise(r => setTimeout(r, 5000)); // Delay for block verification
320330
}
321331
}, 5000);
322332
}
@@ -514,7 +524,7 @@ async function mine(publicKey, ENABLE_LOGGING) {
514524

515525
// Transit state
516526
for (const address in storage) {
517-
const storageDB = new Level(__dirname + "/../log/accountStore/" + address);
527+
const storageDB = new Level(__dirname + "/../../log/accountStore/" + address);
518528
const keys = Object.keys(storage[address]);
519529

520530
states[address].storageRoot = buildMerkleTree(keys.map(key => key + " " + storage[address][key])).val;

Diff for: src/rpc/rpc.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ function rpc(PORT, client, transactionHandler, keyPair, stateDB, blockDB, bhashD
224224
) {
225225
throwError("Invalid request.", 400);
226226
} else {
227-
const storageDB = new Level(__dirname + "/../log/accountStore/" + contractInfo.address);
227+
const storageDB = new Level(__dirname + "/../../log/accountStore/" + contractInfo.address);
228228

229229
respond({ storage: await storageDB.get(req.body.params.key) });
230230

@@ -240,7 +240,7 @@ function rpc(PORT, client, transactionHandler, keyPair, stateDB, blockDB, bhashD
240240
) {
241241
throwError("Invalid request.", 400);
242242
} else {
243-
const storageDB = new Level(__dirname + "/../log/accountStore/" + contractInfo.address);
243+
const storageDB = new Level(__dirname + "/../../log/accountStore/" + contractInfo.address);
244244

245245
respond({ storage: await storageDB.keys().all() });
246246
}

0 commit comments

Comments
 (0)