主页 > 最新imtoken官方下载链接 > 使用 Javascript 的小型区块链
使用 Javascript 的小型区块链
区块链概念
狭义的定义:区块链是一种链式数据结构,将数据块按照时间顺序依次组合起来,是加密保证不可篡改、不可伪造的分布式账本。
一、挖矿(生成新区块)
首先,区块链是由每个区块的连接形成的。在生成新块之前,必须有一个初始块,也称为创世块。通过这个创世块,通过不断改变随机数来计算合格块。以下是创世区块的基本信息:
const initBlock = {
index: 0,
data: 'hey,this is a block chain',
previousHash: '0',
timestamp: '1551806536961',
nonce: 80490,
hash: '0000352fb27dd1141fa7265833190a53e5776b1111e275db0d9a77bf840081e6'
};
index:指每个区块的序号 data:这里存储了区块中的所有信息,如转账、余额等数据 previousHash:指上一个区块的哈希值,创世区块中没有上一个区块,显示0可以是timestamp:指的是创建区块的时间nonce:这是一个随机数,挖矿就是通过不断改变这个nonce来计算一个合格的hash。hash:这个区块的hash值,对前5个字段的信息进行hash得到的值。
然后,通过不间断的哈希运算,计算出合格的哈希,即挖矿。挖矿还可以调整难度。比如计算出来的hash值的前3位一定是1或者后3位一定是1等等,这个可以自己定义,只要最后有一个控制开关,方便控制它. 你可以定义一个变量
哈希计算:
.createHash('sha256')
.update(index + data + previousHash + timestamp + nonce)
.digest('hex')
1:_that.difficulty = 3 // 即前3位或者末3位数必须为1,数量越多难度越大
生成合格的哈希后,会生成一个新的区块,但必须检查该区块是否有效,因为它可能是被篡改的非法区块区块链怎么查询账户余额,也可能与这条链无关。任何关系的块都符合上述哈希规则。因此,有必要检查前后块的有效性。
isValidaBlock(newBlock,lastBlock) {
if (newBlock.index !== lastBlock.index+1) return false
if (newBlock.previousHash !== lastBlock.hash) return false
if (newBlock.timestamp <= lastBlock.timestamp) return false
if (newBlock.hash.slice(1 ,_that.difficulty) !== '1'.repeat(_that.difficulty)) return false
if (newBlock.hash !== this.computeHashForBlock(newBlock)) return false //确保随机数正确
// 都满足则返回true
return true
}
除了上述验证之外,还需要使用上述功能对整个链上的每一个区块进行验证,以确保每一个区块的信息在没有被篡改的情况下都是正确合法的。
二、搭建P2P网络
区块链网络是去中心化的,即没有中心服务器的网络,客户端不需要依赖中心服务器来获取或处理数据。在区块链网络中,有很多节点。每个节点都是一个独立的成员。它们既是客户端又是服务器。节点和节点直接对等连接。转移是通过某个中央服务器进行的。因此,从信息安全的角度来看,点对点的连接方式对于信息隐私来说是非常可靠的。
虽然区块链通过点对点的连接来传输数据,但在此之前还有一件事需要作为指导,那就是种子节点。因为,它们可能不在两个节点之间的同一个域中。如果要联系对方,一方必须知道对方的IP和端口,才能联系对方。节点 ip 和端口号。节点创建后,种子节点会将区块链中所有节点的ip和端口号发送给它,并记录新伙伴的ip和端口号。然后,新节点得到这个“通讯录”后,会向这个“通讯录”中的所有朋友发送消息,告诉他们有新的伙伴加入,然后其他节点收到这个信息,也会添加新伙伴的 ip 和端口号到您的“
我们用代码来演示一下:
(res)=>{
_that.remotePeerInfo = res.data.data //1
_that.addPeersList(res.peersList) //2
_that.boardCast(_that.remotePeerInfo) //3
_that.blockChainUpdate(blockChain,blockData) //4
}
addPeersList(peers) {
peers.forEach(peer => {
if (!_that.peers.find(v => _that.isEqualPeer(peer, v))) {
_that.peers.push(peer)
}
})
}
boardCast(remotePeerInfo) {
this.peers.forEach(v => {
this.send(action, v.port, v.address)
})
}
blockChainUpdate(blockChain,blockData){
if(newChain.length === 1 ){
return
}
if(_that.isValidaChain(newChain) && newChain.length>_that.blockchain.length){
_that.blockchain = Object.assign({}, newChain)
}else{
console.log('error')
return
}
if (trans.every(v => _that.isValidTransfer(v))) {
_that.data = trans
}
}
1.从种子节点保存新节点的信息,包括ip和端口号,因为新节点的ip和端口号会改变。
2.从种子节点接受节点列表,遍历并检查列表的节点,如果不相同则写入列表。
3.将新节点的信息广播给所有节点,同时接收到信息的节点更新节点列表
4.在本地同步一份区块链上信息的副本,同时进行从种子节点传来的区块链上各个区块的信息
三、转账交易
BTC的交易模型是使用UTXO
而这个小区块链的交易模型使用了最简单的方法。
区块链中的“现金”,它是一个虚拟的东西,是一个字符串,来源于挖矿。每次挖矿成功都会有一定的奖励,获得的“钱”可以在区块链网络中自由转移和交易。
在区块链中,需要一种加密算法来记录转账交易。将所有信息加密后,推送到新区块中的数据,从而完成新交易的记录。以BTC为例,BTC的加密算法采用椭圆加密算法。椭圆是一种非对称加密算法。非对称加密算法的特点是私钥是唯一的,只有拥有者才能与他的私钥进行通信。验证相应的公钥。Nodejs也有对应的库,在github上搜索elliptic即可。
{
"privateKey": "34a425df3eb1f22fb6cb74b0e7298b16ffd7f3fb",
"publicKey": "ac208623a38d2906b090dbcf3a09378dfe79b77bf39c2b753ef98ea94fe08dc3995a1bd05c917"
}
以上是生成的密钥对格式,只是为了演示,我剪掉了一部分长度。
使用银行卡进行转账交易时,会有一个出账账户和一个入账账户,这个账户也会被计入区块链中的记账。这个账户就是上面生成的密钥对中的公共账户。密钥,公钥就是地址,或者公钥代表你自己的钱包。
验证方式,先用“from”、“to”、“amount”字段的参数进行sign签名,然后每次挖矿(记账)都使用verify(),传入前三个参数。, 并用 sig 检查
verify(type,data){
swtich(type){
case 'sign':
const bufferMsg = Buffer.from(`${data.from}-${data.to}-${data.amount}`)
let signature = Buffer.from(keypair.sign(bufferMsg).toDER()).toString('hex')
this.signature = signature
break;
case 'verify':
const keypairTemp = ec.keyFromPublic(pub, 'hex')
const bufferMsg = Buffer.from(`${data.from}-${data.to}-${data.amount}`)
this.keypair = keypairTemp.verify(bufferMsg, sig)
break;
default;
}
}
转账需要3个步骤,分别是验证转账账户是否有足够的金额,转账账户是本地公钥。如果有,将使用两个地址、金额、时间和签名加密进行计费和打包,然后广播到所有节点。其他节点收到这个信息后第一件事就是检查新区块的有效性,检查通过后写入数据。
transfer(data) {
const timestamp = new Date().getTime()
const sig = rsa.sign({data.from, data.to, data.amount , timestamp})
const sigTrans = {data.from, data.to, data.amount ,timestamp, sig }
// 非创世区块
if (trans.from !== '0') {
// 检验余额
if (!(_that.blance < amount)) { //_that.blance 当前账户余额
//全节点广播
_that.send('trans', sigTrans)
}else{
console.log('not enough blance')
return
}
}
this.data.push(sigTrans)
return sigTrans
}
其他节点收到消息后,首先进行去重验证,然后更新数据。
四、查看余额
这条链的查询方式比较简单,就是对区块中每笔交易的信息进行校验匹配,满足条件就增减,而忽略了准确性的问题。
this.blance = blance(address)
blance(address) {
let blance = 0;
this.blockchain.forEach(block => {
block.data.forEach(trans => {
if (address == trans.from) {
blance -= trans.amount
}
if (address == trans.to) {
blance += trans.amount
}
})
});
return blance
}
至此,区块链最简单的功能已经实现。
如果觉得不错区块链怎么查询账户余额,请点赞和支持,欢迎留言或进入我的个人群855801563领取【架构资料收集90期】、【BATJTMD工厂JAVA面试题1000+】,本群致力于学习交流技巧和分享面试机会。如果我拒绝广告,我会不定期在群里回答问题和讨论。