当前位置: 首页 > 科技观察

使用Javascript实现一个简单的小区块链

时间:2023-03-13 08:12:22 科技观察

狭义的区块链概念:区块链是一种链式数据结构,它按时间顺序将数据块以顺序方式组合在一起,并以密码学方式保证不可变、不可伪造的分布式账本。1.挖矿(产生新的区块)首先,区块链是通过连接每个区块形成的。在产生新区块之前,必须有一个初始区块,也称为创世区块。通过这个创世块,通过改变nonce不断计算符合条件的块。以下是创世块的基本信息:constinitBlock={index:0,data:'hey,thisisablockchain',previousHash:'0',timestamp:'1551806536961',nonce:80490,hash:'0000352fb27dd1141fa7265833190a53e5776b1111e275db10d9':;指的是每个区块的序号data:区块中的所有信息都存储在这里,比如转账、余额等数据只显示0时间戳:指区块创建的时间。nonce:这是一个随机数,挖矿就是通过不断改变nonce来计算出符合条件的hash。hash:该区块的哈希值,将前5个字段的信息哈希得到的值。然后,通过不停的哈希运算,计算出合格的哈希值,即挖矿。挖矿也可以调整难度级别。比如计算出的hash值前3位必须为1或者后3位必须为1等等,这个可以自己定义,只要有一个控制开关即可,方便控制。可以定义变量哈希计算:.createHash('sha256').update(index+data+previousHash+timestamp+nonce).digest('hex')_that.difficulty=3//即前3位或最后3位必须是1,数字越多越难。生成合格的哈希后,生成一个新的块,但是需要检查这个块是否有效,因为它可能是一个被篡改过的非法块,也可能有与这条链无关的块但只符合上述哈希规则。因此,需要检查前后块的有效性。isValidaBlock(newBlock,lastBlock){if(newBlock.index!==lastBlock.index+1)返回falseif(newBlock.previousHash!==lastBlock.hash)returnfalseif(newBlock.timestamp<=lastBlock.timestamp)returnfalseif(newBlock.hash.slice(1,_that.difficulty)!=='1'.repeat(_that.difficulty))returnfalseif(newBlock.hash!==this.computeHashForBlock(newBlock))returnfalse//保证随机numberiscorrect//如果全部满足则返回truereturntrue}除了上面的验证之外,还需要用上面的函数来验证整个链的每个区块,确保每个区块的信息正确合法如果有没有被篡改。2.构建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}如果(trans.every(v=>_that.isValidTransfer(v))){_that.data=trans}}1。从种子节点保存这个新节点的信息,包括ip和端口号,因为新节点的ip和端口号是有变化的。2.接受种子节点发送过来的节点列表,遍历检查列表中的节点,没有相同的就写入列表中。3.将新节点的信息广播给所有节点,同时收到信息的节点更新节点列表。4.在本地同步一份区块链上的信息,同时对种子节点传来的区块链的每一个区块进行执行。区块信息3.转账交易BTC的交易模型是使用UTXO。而这个小区块链的交易模型用的是最简单的方法。区块链中的“现金”是一种虚拟的东西,是一种字符串,来源于挖矿。每次挖矿成功都会有一定的奖励,获得的“钱”可以在区块链网络中自由转移和交易。在区块链中,在记录转账交易时,需要通过加密算法对所有信息进行加密,然后推送到新区块中的数据中,完成一笔新交易的记录。以BTC为例,BTC的加密算法采用椭圆加密算法。Elliptic是一种非对称加密算法。非对称加密算法的特点是私钥是唯一的,只有拥有者才能与他共享私钥。相应的公钥被验证。nodejs也有相应的库,在github上搜索elliptic即可。{"privateKey":"34a425df3eb1f22fb6cb74b0e7298b16ffd7f3fb","publicKey":"ac208623a38d2906b090dbcf3a09378dfe79b77bf39c2b753ef98ea94fe08dc3995a1bd05c917"}上面是一个生成好的密钥对格式,仅作为展示,我删减了一部分长度。Whenusingabankcardfortransfertransactions,therewill是一个转出账户和一个转入账户,这个账户也会在区块链中记账。这个账号就是上面生成的密钥对中的公钥对。key,公钥就是地址,或者公钥代表你自己的钱包。验证的方法,先用“from”、“to”、“amount”字段的参数进行签名,然后在每次挖矿(记账)的时候使用verify(),传递前三个参数,然后用于验证的签名verify(type,data){swtich(type){case'sign':constbufferMsg=Buffer.from(`${data.from}-${data.to}-${data.amount}`)letsignature=Buffer.from(keypair.sign(bufferMsg).toDER()).toString('hex')this.signature=signaturebreak;case'verify':constkeypairTemp=ec.keyFromPublic(pub,'hex')constbufferMsg=Buffer。from(`${data.from}-${data.to}-${data.amount}`)this.keypair=keypairTemp.verify(bufferMsg,sig)break;default;}}转账需要第三步验证转账账户是否有足够的钱,转账账户是本地公钥。如果有,则计费并打包两个地址,金额,时间,签名加密,然后广播给全节点。其他节点收到这个信息后,首先要做的就是验证新区块的有效性,验证通过后写入数据。传输(数据){consttimestamp=newDate().getTime()constsig=rsa.sign({data.from,data.to,data.amount,timestamp})constsigTrans={data.from,data.to,data.amount,timestamp,sig}//非创世块if(trans.from!=='0'){//查看余额if(!(_that.blance{block.data.forEach(trans=>{if(address==trans.from){blance-=trans.amount}if(address==trans.to){blance+=trans.amount}})});returnblance}至此,实现了区块链最简单的功能。