Skip to content

Commit b3250c0

Browse files
authored
Merge pull request #135 from ainblockchain/release/0.3.2
Release/0.3.2
2 parents f1def85 + 5a8e310 commit b3250c0

File tree

25 files changed

+406
-284
lines changed

25 files changed

+406
-284
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# This is a basic workflow to help you get started with Actions
2+
3+
name: CI
4+
5+
# Controls when the action will run. Triggers the workflow on push or pull request
6+
# events but only for the master branch
7+
on:
8+
pull_request:
9+
types: [opened, edited]
10+
11+
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
12+
jobs:
13+
# This workflow contains a single job called "build"
14+
build-and-test:
15+
# The type of runner that the job will run on
16+
runs-on: ubuntu-latest
17+
18+
# Steps represent a sequence of tasks that will be executed as part of the job
19+
steps:
20+
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
21+
- uses: actions/checkout@v2
22+
# Setup node environment for testing
23+
- uses: actions/setup-node@v1
24+
with:
25+
node-version: '10.x'
26+
registry-url: 'https://registry.npmjs.org'
27+
- name: npm install
28+
run: npm install
29+
- name: run unittest
30+
run: npm run test_unit
31+
- name: run integration test
32+
run: npm run test_integration

blockchain/block.js

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const stringify = require('fast-json-stable-stringify');
22
const zipper = require('zip-local');
33
const sizeof = require('object-sizeof');
44
const ainUtil = require('@ainblockchain/ain-util');
5-
const logger = require('../logger');
5+
const logger = require('../logger')('BLOCK');
66
const ChainUtil = require('../chain-util');
77
const Transaction = require('../tx-pool/transaction');
88
const DB = require('../db');
@@ -19,8 +19,6 @@ const {
1919
} = require('../constants');
2020
const BlockFilePatterns = require('./block-file-patterns');
2121

22-
const LOG_PREFIX = 'BLOCK';
23-
2422
class Block {
2523
constructor(lastHash, lastVotes, transactions, number, epoch, timestamp, stateProofHash, proposer, validators) {
2624
this.last_votes = lastVotes;
@@ -111,18 +109,18 @@ class Block {
111109

112110
static validateHashes(block) {
113111
if (block.hash !== Block.hash(block)) {
114-
logger.error(`[${LOG_PREFIX}] Block hash is incorrect for block ${block.hash}`);
112+
logger.error(`Block hash is incorrect for block ${block.hash}`);
115113
return false;
116114
}
117115
if (block.transactions_hash !== ChainUtil.hashString(stringify(block.transactions))) {
118-
logger.error(`[${LOG_PREFIX}] Transactions or transactions_hash is incorrect for block ${block.hash}`);
116+
logger.error(`Transactions or transactions_hash is incorrect for block ${block.hash}`);
119117
return false;
120118
}
121119
if (block.last_votes_hash !== ChainUtil.hashString(stringify(block.last_votes))) {
122-
logger.error(`[${LOG_PREFIX}] Last votes or last_votes_hash is incorrect for block ${block.hash}`);
120+
logger.error(`Last votes or last_votes_hash is incorrect for block ${block.hash}`);
123121
return false;
124122
}
125-
logger.info(`[${LOG_PREFIX}] Hash check successfully done`);
123+
logger.info(`Hash check successfully done`);
126124
return true;
127125
}
128126

@@ -140,15 +138,15 @@ class Block {
140138
continue;
141139
}
142140
if (transaction.nonce != nonceTracker[transaction.address] + 1) {
143-
logger.error(`[${LOG_PREFIX}] Invalid noncing for ${transaction.address} ` +
141+
logger.error(`Invalid noncing for ${transaction.address} ` +
144142
`Expected ${nonceTracker[transaction.address] + 1} ` +
145143
`Received ${transaction.nonce}`);
146144
return false;
147145
}
148146
nonceTracker[transaction.address] = transaction.nonce;
149147
}
150148

151-
logger.info(`[${LOG_PREFIX}] Valid block of number ${block.number}`);
149+
logger.info(`Valid block of number ${block.number}`);
152150
return true;
153151
}
154152

@@ -246,7 +244,7 @@ class Block {
246244
for (const tx of genesisTransactions) {
247245
const res = tempGenesisState.executeTransaction(tx);
248246
if (ChainUtil.transactionFailed(res)) {
249-
logger.error(`[${LOG_PREFIX}] Genesis transaction failed:\n${JSON.stringify(tx, null, 2)}\nRESULT: ${JSON.stringify(res)}`)
247+
logger.error(`Genesis transaction failed:\n${JSON.stringify(tx, null, 2)}\nRESULT: ${JSON.stringify(res)}`)
250248
return null;
251249
}
252250
}

blockchain/index.js

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ const fs = require('fs');
44
const glob = require('glob');
55
const zipper = require('zip-local');
66
const naturalSort = require('node-natural-sort');
7-
const logger = require('../logger')
7+
const logger = require('../logger')('BLOCKCHAIN');
88
const { Block } = require('./block');
99
const BlockFilePatterns = require('./block-file-patterns');
1010
const { BLOCKCHAINS_DIR } = require('../constants');
1111
const CHAIN_SUBSECT_LENGTH = 20;
1212
const ON_MEM_CHAIN_LENGTH = 20;
1313

14-
const LOG_PREFIX = 'BLOCKCHAIN';
15-
1614
class Blockchain {
1715
constructor(blockchainDir) {
1816
// Finalized chain
@@ -173,11 +171,11 @@ class Blockchain {
173171
static isValidChain(chain) {
174172
const firstBlock = Block.parse(chain[0]);
175173
if (!firstBlock || firstBlock.hash !== Block.genesis().hash) {
176-
logger.error(`[${LOG_PREFIX}] First block is not the Genesis block`);
174+
logger.error(`First block is not the Genesis block`);
177175
return false;
178176
}
179177
if (!Block.validateHashes(firstBlock)) {
180-
logger.error(`[${LOG_PREFIX}] Genesis block is corrupted`);
178+
logger.error(`Genesis block is corrupted`);
181179
return false;
182180
}
183181
// TODO (lia): Check if the tx nonces are correct.
@@ -241,20 +239,20 @@ class Blockchain {
241239
const refBlockNumber = !!refBlock ? refBlock.number : -1;
242240
const nextBlockNumber = refBlockNumber + 1;
243241

244-
logger.info(`[${LOG_PREFIX}] Current last block number: ${this.lastBlockNumber()}, ` +
245-
`[${LOG_PREFIX}] Requester's last block number: ${refBlockNumber}`);
242+
logger.info(`Current last block number: ${this.lastBlockNumber()}, ` +
243+
`Requester's last block number: ${refBlockNumber}`);
246244

247245
const blockFiles = this.getBlockFiles(nextBlockNumber, nextBlockNumber + CHAIN_SUBSECT_LENGTH);
248246

249247
if (blockFiles.length > 0 &&
250248
(!!(refBlock) && Block.loadBlock(blockFiles[0]).last_hash !== refBlock.hash)) {
251-
logger.error(`[${LOG_PREFIX}] Invalid blockchain request. Requesters last block does not belong to this blockchain`);
249+
logger.error(`Invalid blockchain request. Requesters last block does not belong to this blockchain`);
252250
return;
253251
}
254252

255253
const refBlockHash = refBlock ? refBlock.hash : null;
256254
if (refBlockHash === this.lastBlock().hash) {
257-
logger.info(`[${LOG_PREFIX}] Requesters blockchain is up to date with this blockchain`);
255+
logger.info(`Requesters blockchain is up to date with this blockchain`);
258256
return [this.lastBlock()];
259257
}
260258

@@ -267,9 +265,9 @@ class Blockchain {
267265

268266
merge(chainSubSection) {
269267
// Call to shift here is important as it removes the first element from the list !!
270-
logger.info(`[${LOG_PREFIX}] Last block number before merge: ${this.lastBlockNumber()}`);
268+
logger.info(`Last block number before merge: ${this.lastBlockNumber()}`);
271269
if (!chainSubSection || chainSubSection.length === 0) {
272-
logger.info(`[${LOG_PREFIX}] Empty chain sub section`);
270+
logger.info(`Empty chain sub section`);
273271
if (!this.syncedAfterStartup) {
274272
// Regard this situation as if you're synced.
275273
// TODO (lia): ask the tracker server for another peer.
@@ -278,11 +276,11 @@ class Blockchain {
278276
return false;
279277
}
280278
if (chainSubSection[chainSubSection.length - 1].number < this.lastBlockNumber()) {
281-
logger.info(`[${LOG_PREFIX}] Received chain is of lower block number than current last block number`);
279+
logger.info(`Received chain is of lower block number than current last block number`);
282280
return false;
283281
}
284282
if (chainSubSection[chainSubSection.length - 1].number === this.lastBlockNumber()) {
285-
logger.info(`[${LOG_PREFIX}] Received chain is at the same block number`);
283+
logger.info(`Received chain is at the same block number`);
286284
if (!this.syncedAfterStartup) {
287285
// Regard this situation as if you're synced.
288286
// TODO (lia): ask the tracker server for another peer.
@@ -305,13 +303,13 @@ class Blockchain {
305303
} else {
306304
// Case 2: A cold start.
307305
if (firstBlock.last_hash !== '') {
308-
logger.info(`[${LOG_PREFIX}] First block of hash ${firstBlock.hash.substring(0, 5)} ` +
306+
logger.info(`First block of hash ${firstBlock.hash.substring(0, 5)} ` +
309307
`and last hash ${firstBlock.last_hash.substring(0, 5)} is not a genesis block`);
310308
return false;
311309
}
312310
}
313311
if (!Blockchain.isValidChainSubsection(chainSubSection)) {
314-
logger.error(`[${LOG_PREFIX}] Invalid chain subsection`);
312+
logger.error(`Invalid chain subsection`);
315313
return false;
316314
}
317315
for (let i = 0; i < chainSubSection.length; i++) {
@@ -322,11 +320,11 @@ class Blockchain {
322320
}
323321
// TODO(lia): validate the state proof of each block
324322
if (!this.addNewBlockToChain(block)) {
325-
logger.error(`[${LOG_PREFIX}] Failed to add block ` + block);
323+
logger.error(`Failed to add block ` + block);
326324
return false;
327325
}
328326
}
329-
logger.info(`[${LOG_PREFIX}] Last block number after merge: ${this.lastBlockNumber()}`);
327+
logger.info(`Last block number after merge: ${this.lastBlockNumber()}`);
330328
return true;
331329
}
332330

@@ -339,10 +337,10 @@ class Blockchain {
339337
});
340338

341339
if (Blockchain.isValidChain(newChain)) {
342-
logger.info(`[${LOG_PREFIX}] Valid chain of size ${newChain.length}`);
340+
logger.info(`Valid chain of size ${newChain.length}`);
343341
return newChain;
344342
}
345-
logger.error(`[${LOG_PREFIX}] Invalid chain`);
343+
logger.error(`Invalid chain`);
346344
rimraf.sync(chainPath + '/*');
347345
return null;
348346
}

chain-util.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,14 @@ class ChainUtil {
131131
return (formatted.startsWith('/') ? '' : '/') + formatted;
132132
}
133133

134+
static appendPath(path, ...pathsToAppend) {
135+
const labels = ChainUtil.parsePath(path);
136+
for (let toAppend of pathsToAppend) {
137+
labels.push(...ChainUtil.parsePath(toAppend));
138+
}
139+
return ChainUtil.formatPath(labels);
140+
}
141+
134142
static getJsObject(obj, path) {
135143
if (!ChainUtil.isArray(path)) {
136144
return null;

client/index.js

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const fs = require('fs');
55
const semver = require('semver');
66
const express = require('express');
77
const jayson = require('jayson');
8-
const logger = require('../logger');
8+
const logger = require('../logger')('CLIENT');
99
const BlockchainNode = require('../node');
1010
const P2pServer = require('../server');
1111
const ChainUtil = require('../chain-util');
@@ -14,11 +14,10 @@ const { ConsensusStatus } = require('../consensus/constants');
1414
const CURRENT_PROTOCOL_VERSION = require('../package.json').version;
1515

1616
const MAX_BLOCKS = 20;
17-
const CLIENT_PREFIX = 'CLIENT';
1817

1918
// NOTE(seo): This is very useful when the server dies without any logs.
2019
process.on('uncaughtException', function (err) {
21-
logger.error(`[${CLIENT_PREFIX}]` + err);
20+
logger.error(err);
2221
});
2322

2423
process.on('SIGINT', _ => {
@@ -34,17 +33,9 @@ if (!semver.valid(CURRENT_PROTOCOL_VERSION)) {
3433
throw Error("Wrong version format is specified in package.json");
3534
}
3635
const VERSION_LIST = JSON.parse(fs.readFileSync(PROTOCOL_VERSIONS));
37-
const MAJOR_MINOR_VERSION =
38-
`${semver.major(CURRENT_PROTOCOL_VERSION)}.${semver.minor(CURRENT_PROTOCOL_VERSION)}`;
39-
if (!semver.valid(semver.coerce(MAJOR_MINOR_VERSION))) {
40-
throw Error("Given major and minor version does not correctly setup");
41-
}
42-
if (!VERSION_LIST[MAJOR_MINOR_VERSION]) {
43-
throw Error("Current protocol version doesn't exist in the protocol versions file");
44-
}
45-
const minProtocolVersion =
46-
VERSION_LIST[MAJOR_MINOR_VERSION].min || CURRENT_PROTOCOL_VERSION;
47-
const maxProtocolVersion = VERSION_LIST[MAJOR_MINOR_VERSION].max;
36+
const { min, max } = matchVersions(CURRENT_PROTOCOL_VERSION);
37+
const minProtocolVersion = min === undefined ? CURRENT_PROTOCOL_VERSION : min;
38+
const maxProtocolVersion = max;
4839

4940
const app = express();
5041
app.use(express.json()); // support json encoded bodies
@@ -326,6 +317,14 @@ app.get('/get_address', (req, res, next) => {
326317
.end();
327318
});
328319

320+
app.get('/get_sharding', (req, res, next) => {
321+
const result = node.getSharding();
322+
res.status(200)
323+
.set('Content-Type', 'application/json')
324+
.send({code: result !== null ? 0 : 1, result})
325+
.end();
326+
});
327+
329328
app.get('/get_raw_consensus_state', (req, res) => {
330329
const result = p2pServer.consensus.getRawState();
331330
res.status(200)
@@ -345,8 +344,8 @@ app.get('/get_consensus_state', (req, res) => {
345344
// We will want changes in ports and the database to be broadcast across
346345
// all instances so lets pass this info into the p2p server
347346
const server = app.listen(PORT, () => {
348-
logger.info(`[${CLIENT_PREFIX}] App listening on port ${PORT}`);
349-
logger.info(`[${CLIENT_PREFIX}] Press Ctrl+C to quit.`);
347+
logger.info(`App listening on port ${PORT}`);
348+
logger.info(`Press Ctrl+C to quit.`);
350349
});
351350

352351
server.keepAliveTimeout = 620 * 1000; // 620 seconds
@@ -410,13 +409,37 @@ function checkIfTransactionShouldBeNonced(input) {
410409
return input.is_nonced_transaction !== undefined ? input.is_nonced_transaction : true;
411410
}
412411

412+
function isValidVersionMatch(ver) {
413+
return ver && semver.valid(semver.coerce(ver.min)) &&
414+
(!ver.max || semver.valid(semver.coerce(ver.max)));
415+
}
416+
417+
function matchVersions(ver) {
418+
let match = VERSION_LIST[ver];
419+
if (isValidVersionMatch(match)) {
420+
return match;
421+
}
422+
const majorVer = semver.major(ver);
423+
const majorMinorVer = `${majorVer}.${semver.minor(ver)}`;
424+
match = VERSION_LIST[majorMinorVer];
425+
if (isValidVersionMatch(match)) {
426+
return match;
427+
}
428+
match = VERSION_LIST[majorVer];
429+
if (isValidVersionMatch(match)) {
430+
return match;
431+
}
432+
return {};
433+
}
434+
413435
function validateVersion(req, res, next) {
414436
let version = null;
415437
if (req.query.protoVer) {
416438
version = req.query.protoVer;
417439
} else if (req.body.params) {
418440
version = req.body.params.protoVer;
419441
}
442+
const coercedVer = semver.coerce(version);
420443
if (req.body.method === 'ain_getProtocolVersion' ||
421444
req.body.method === 'ain_checkProtocolVersion') {
422445
next();
@@ -426,14 +449,14 @@ function validateVersion(req, res, next) {
426449
.send({code: 1, message: "Protocol version not specified.",
427450
protoVer: CURRENT_PROTOCOL_VERSION})
428451
.end();
429-
} else if (!semver.valid(version)) {
452+
} else if (!semver.valid(coercedVer)) {
430453
res.status(200)
431454
.set('Content-Type', 'application/json')
432455
.send({code: 1, message: "Invalid protocol version.",
433456
protoVer: CURRENT_PROTOCOL_VERSION})
434457
.end();
435-
} else if (semver.gt(minProtocolVersion, version) ||
436-
(maxProtocolVersion && semver.lt(maxProtocolVersion, version))) {
458+
} else if (semver.lt(coercedVer, minProtocolVersion) ||
459+
(maxProtocolVersion && semver.gt(coercedVer, maxProtocolVersion))) {
437460
res.status(200)
438461
.set('Content-Type', 'application/json')
439462
.send({code: 1, message: "Incompatible protocol version.",

client/protocol_versions.json

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{
2-
"0.3": {
3-
"min": "0.3.1",
4-
"max": "0.3.1"
5-
}
2+
"0.3.2": {
3+
"min": "0.3.2"
4+
}
65
}

0 commit comments

Comments
 (0)