# BlockChain.js

• PoW工作量证明算法挖矿
• P2P网络，挖到的区块后广播给其他节点

## 区块结构

block.js

/*

*/
function Block(index, previousHash, timestamp, data, hash,bits,nonce,mip) {
this.index = index;
this.previousHash = previousHash.toString();
this.timestamp = timestamp;
this.data = data;
this.hash = hash.toString();
this.bits = bits;
this.nonce = nonce;
this.minerip = mip;
}

module.exports = Block;


## 使用Pow算法挖矿

/*

2、转成16进制
3、var target = coefficient * 2^(8 * (exponent – 3))
*/
function proof_of_work(data){

var previousBlock = blockChain.getLatestBlock();
var nextIndex = previousBlock.index + 1;
var nextTimestamp = new Date().getTime() / 1000;

var nextHash = blockChain.calculateHash(nextIndex, previousBlock.hash, nextTimestamp,data,bits,nonce);
nonce++;
var hex = helper.strToHexCharCode(nextHash)

var coefficient =  '0x' + bits.substr(4,6);
var exponent = bits.substr(0,4);
var target = coefficient * Math.pow(2,8*(exponent-3));

target = target.toString(16);
nextHash = nextHash.toString(16);

// console.log(target)
// console.log(nextHash)
// console.log('>>',(('0x'+nextHash) - ('0x'+target))<0)
if( (('0x'+nextHash) - ('0x'+target))<0 ){
find = true;
var newBlock = blockChain.generateNextBlock(data,nonce);
});

nonce = 0;

//延时两秒再去挖下一个块
setTimeout(function(){
find = false;

startMiner()
},2000)
}

}


### 难度目标计算的公式为：

target = coefficient * 2^(8 * (exponent – 3))

    target = 0x500000 * 2^(0x08 * (0x1e - 0x03))^

=> target = 0x500000 * 2^(0x08 * 0x1b)^

=> target = 238348 * 2^216^


5.521397077432451e+71

0x0000500000000000000000000000000000000000000000000000000000000000

var calculateHash = (index, previousHash, timestamp, data,bits,nonce) => {
return CryptoJS.SHA256(index + previousHash + timestamp + data + bits + nonce).toString();
};


function startMiner(){
console.time('  ⏰  挖矿花费时间：')
while (!find) {
var random = Math.random();
var str = 'Davie kong-' + nonce + nonce++;
proof_of_work(str)
}
console.timeEnd('  ⏰  挖矿花费时间：')
}

500000000000000000000000000000000000000000000000000000000000
⏰  挖矿花费时间：: 4317.532ms
🔨 🔨 🔨  添加区块: {"index":1,"previousHash":"816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7","timestamp":1522984377.542,"data":"Davie kong-0.2835468136083028244236","hash":"ce6226b3eb8b5bfd2ea7dde12ee3391015587f0023d7d7b3d46ace2bc5012ce5","bits":"0x1e500000","nonce":244238,"minerip":"10.42.0.40"}


0x0000500000000000000000000000000000000000000000000000000000000000

var newBlock = blockChain.generateNextBlock(data,nonce);
});


## 添加区块


var addBlock = (newBlock,cb) => {
if (isValidNewBlock(newBlock, getLatestBlock())) {
blockchain.push(newBlock);

if(err){
console.log(err)
}else{
var res = JSON.parse(res.toString())
res.push(newBlock)
fs.writeFile(__dirname + '/blocks.json',JSON.stringify(res),function(err){
if(err){
console.log(err)
}else{
cb(newBlock)
console.log(' 🔨 🔨 🔨  添加区块: ' + JSON.stringify(newBlock));
}
})
}
})
}
};


## 创世区块

var getGenesisBlock = () => {
return new Block(0, "0", 1465154705, "my genesis block!!", "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7");
};
var blockchain = [getGenesisBlock()];



## 检查添加区块是否合法

var isValidNewBlock = (newBlock, previousBlock) => {
if (previousBlock.index + 1 !== newBlock.index) {
console.log('invalid index');
return false;
} else if (previousBlock.hash !== newBlock.previousHash) {
console.log('invalid previoushash');
return false;
} else if (calculateHashForBlock(newBlock) !== newBlock.hash) {
console.log(typeof (newBlock.hash) + ' ' + typeof calculateHashForBlock(newBlock));
console.log('invalid hash: ' + calculateHashForBlock(newBlock) + ' ' + newBlock.hash);
return false;
}
return true;
};


## 与其他节点通信

在一个矿机产生了一个区块后，要把这个区块广播给其他节点，其他节点验证通过后，添加到自己的区块链上。

var broadcast = (blockData) => {

var bip = '255.255.255.255';
server.send(JSON.stringify(blockData),8060,bip,function(err,bytes){
console.log('>>把新加的区块数据广播到出去...')
});

};


UDP协议广播前，需要开启广播

  server.on('listening',()=>{
server.setTTL(128);
console.log('节点持续监听中，等待其他节点的广播....');
});


  server.on('message',(blockData,rinfo)=>{

console.log(<<<<<<接受其他节点广播来的数据 ${rinfo.address}:${rinfo.port}-\${blockData});
console.log('验证其他节点产生的区块合法，添加到本地区块链中')
})
}
});

server.bind(8060);


var os=require('os'),
localIp='',
ifaces=os.networkInterfaces();
for (var dev in ifaces) {
ifaces[dev].forEach(function(details,alias){
if (details.family=='IPv4') {
}
}
});
}
console.log("IP:",localIp);