-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBlockChain.js
More file actions
140 lines (109 loc) · 4.14 KB
/
BlockChain.js
File metadata and controls
140 lines (109 loc) · 4.14 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
/* ===== Blockchain Class ==========================
| Class with a constructor for new blockchain |
| ================================================*/
const SHA256 = require('crypto-js/sha256');
const LevelSandbox = require('./LevelSandbox.js');
const Block = require('./Block.js');
class Blockchain {
constructor() {
this.bd = new LevelSandbox.LevelSandbox();
this.generateGenesisBlock = this.generateGenesisBlock.bind(this);
this.addBlock = this.addBlock.bind(this);
this.generateGenesisBlock();
}
// Helper method to create a Genesis Block (always with height= 0)
// You have to options, because the method will always execute when you create your blockchain
// you will need to set this up statically or instead you can verify if the height !== 0 then you
// will not create the genesis block
async generateGenesisBlock(){
let value = await this.bd.getBlocksCount();
var height = value;
if (height !== 0) {
let genesisBlock = new Block.Block('Genesis Block');
await this.addBlock(genesisBlock);
}
}
async getBlockHeightAsync() {
let value = await this.bd.getBlocksCount();
console.log("Block Height ", value);
return value;
}
// Get block height, it is a helper method that return the height of the blockchain
async getBlockHeight() {
let value = await this.bd.getBlocksCount();
console.log("Block Height ", value);
return value;
}
// Add new block
async addBlock(block) {
/* BLOCK SCHEMA:
this.hash = '';
this.height = '';
this.time = '';
this.data = data;
this.previousHask = '0x';
*/
//hash
block.hash = SHA256(block).toString();
//time
block.time = new Date().getTime().toString().slice(0, -3);
//height
block.height = await this.getBlockHeight();
if (block.height > 0) {
let value = await this.bd.getLevelDBData(block.height-1);
block.previousHash = value.hash;
}
await this.bd.addLevelDBData(block.height, JSON.stringify(block).toString());
}
// Get Block By Height
async getBlock(height) {
let value = await this.bd.getLevelDBData(height);
return value;
}
// Validate if Block is being tampered by Block Height
async validateBlock(height) {
let block = await this.getBlock(height);
let blockHash = block.hash;
block.hash = '';
let validBlockHash = SHA256(JSON.stringify(block)).toString();
if (blockHash===validBlockHash) {
return true;
} else {
console.log('Block #'+height+' invalid hash:\n'+blockHash+'<>'+validBlockHash);
return false;
}
}
// Validate Blockchain
async validateChain() {
let errorLog = [];
let validationPromises = [];
for (let b = 0; b < this.getBlockHeight()-1; b++) {
validationPromises.push(async function () {
let result = this.validateBlock(b);
if (!result) errorLog.push(b);
let [ hash, previousHash ] = await Promise.all(
this.getBlock(b).then((block) => block.hash),
this.getBlock(b+1).then((block) => block.previousHash)
);
if (hash === previousHash) {
errorLog.push(b);
}
}.bind(this));
}
await Promise.all(validationPromises)
if (errorLog.length > 0) {
console.log('Block Integrity Errors: ' + errorLog.length);
console.log('Blocks: ' + errorLog);
} else {
console.log('Blockchain successfully validated');
}
return errorLog;
}
// Utility Method to Tamper a Block for Test Validation
// This method is for testing purpose
async _modifyBlock(height, block) {
let blockModified = await this.bd.addLevelDBData(height, JSON.stringify(block).toString());
return blockModified;
}
}
module.exports.Blockchain = Blockchain;