区块链简单实现之p2p网络多节点同步

承接上文:区块链的简单实现,我们已经实现了一个简单的区块链数据结构。
现状:区块存放在数组中,程序重启就是一条新链,并且也只有单节点,没有引入多节点。
目标:将区块保存为文件,实现多节点之间的同步。

将区块保存为json文件

之前的类BlockChaincreatBlock方法:

creatBlock(data){
        var lastBlock=this.getLastBlock();
        var newIndex=lastBlock.index+1;
        var newTime=new Date().getTime()/1000;
        var newPreHash=lastBlock.hash;
        var newhash=Block.caHash(newIndex,newPreHash,newTime,data.toString());
        return this.blocks[this.blocks.length]= new Block.Block(
            newIndex, newPreHash, newTime, data, newhash
        );
   }

可以看的出来,是直接保存在数组blocks中,我们稍作改进:

creatBlock(data){
        var lastBlock=this.getLastBlock();
        var newIndex=lastBlock.index+1;
        var newTime=new Date().getTime()/1000;
        var newPreHash=lastBlock.hash;
        var creator= this.path;//简单的用路径来代替用户,creator是Block新增的一个属性
        var newhash=Block.caHash(newIndex,newPreHash,newTime,data.toString(),creator);
        var newblock= new Block.Block(
            newIndex, newPreHash, newTime, data, newhash,creator
        );
        fs.writeFile("./blcs/"+this.path+"/block"+this.head.nums+".json",JSON.stringify(newblock,"","\t"),function (err){
            if (err!=null)
                console.log(err);
        });
        
	//此处注释掉的为后续增加的代码,此时可暂不阅读
       // this.head.nums++;
       // this.head.existsHash.push(newhash);
      //  if (!this.head.creators.includes(newblock.creator))
       //     this.head.creators.push(newblock.creator);
            
     //   fs.writeFile("./blcs/"+this.path+"/head.json",JSON.stringify(this.head,"","\t"),function (err){
     //       if (err!=null)
     //           console.log(err);
     //   });
        return this.blocks[this.blocks.length]=newblock;
    }

增加了一步写文件的操作,将newblock对象写入./blcs/path/blockx.json,如图:

区块被写入为json文件

如此,便能解决区块的存储问题。

节点

一个节点可以简单理解为一个用户,他们各有一条链,理想情况下,他们链上的内容不应起冲突并且应该能够实时同步,但我们都知道,一个分布式系统想要实时同步几乎是不可能的,我们需要一种合理的同步机制,尽量减少错误的发生。

p2p网络能帮助我们实现各节点的同步与通信,我们希望在每个节点生成区块或者接收区块时能广播通知网络中的其他节点也接收区块。

不确定性

但是有一个摆在面前的问题:

  • 我们无法得知网络中各节点的信息。

解决这个问题的一个思路是,建立一个中心化的服务器来存放各个节点的信息,但是显然这样不合我们的思路。
还有一个思路,就是在每个区块中保存一些有关节点的信息。

区块里保存节点信息

我采取的办法是,在每个区块增加一个creator的属性,用来保存产生它的那个节点的信息,便于我们能在网络中找到这个节点。

class Block {
    constructor(index, previousHash, timestamp, data, hash, creator) {
        this.index = index;
        this.previousHash = previousHash;
        this.timestamp = timestamp;
        this.data = data;
        this.hash = hash.toString();
        this.creator = creator;//保存产生它的节点的信息
    }
    toString(){
        return "\n{\nindex:"+this.index+",\npreviousHash:'"+this.previousHash+"',\ntimestamp:"+this.timestamp+",\ndata:'"+this.data+"',\nhash:'"+this.hash+"',\ncreator:'"+this.creator+ "'\n}\n"
    }
}

比如我本地运行的各个节点是运行在不同的端口号,我就可以通过在creator属性里保存端口号从而能找到节点,放在更大的网络里,我们可以保存产生它的节点的ip地址。

这样在其他节点接收到区块后,就可以从自己已有的区块里和其他节点联系上了,那么就可以实现广播。

并未向所有节点广播

其实很容易看出来,上面的思路不是真的广播,因为只有那些产生过区块并广播出去的节点才可能收到来自其他节点的广播。

那么那些没有产生过区块的节点呢?很多节点都是产生交易单然后经由矿工打包成区块,那么他们就不能收到广播,这是不合理的。不过这已经不在我们目前讨论范围了,因为我们区块的数据并没有什么实际含义,我们可以简单的认为节点就是各个矿机,随便拿着数据然后在做工作量证明然后签名发给其他节点。

简单模拟

我本地模拟多个节点采取的办法是,将程序运行在多个端口,让它们在各端口间同步数据,其实也具备p2p网络的特性了:

  • 不知道有哪些端口号有区块链程序在运行
  • 不知道运行的区块链程序是否已经停止运行
  • 各个端口之间可以互相发送http请求和响应

所以我给各个端口上的区块链程序之间同步信息的解决方法如下:

各个节点都会从自己的链中整理出各个区块的hashcreator,然后遵循以下策略:

  1. 接受一个区块后,要向自己知道的节点广播。
  2. 新生成一个区块后,要向自己知道的节点广播。
  3. 在接收到一个区块时判断自己是否已经接受过该区块的hash值,如果接受过就不再接受也不广播,否则接受并广播。
  4. 在接收到区块时都应当先作验证,验证区块是否有效。
  5. 接收到一个区块时,发现该区块的序号远大于自己序号最大的区块,应当从区块发出节点拉取前面的区块。

上述规则看似能解决问题,但是存在一个重大的问题:
在网络起步阶段时,各个节点都还没有接收过其他节点的区块,那么是无法从0到有的。
这时候需要我们给定一个默认的联系节点,只要网络运行起来了,哪怕这个默认节点停用了也无所谓。

广播的代码:

function broadcastBlock(block) {
    var blockString=JSON.stringify(block,"","\t");
    console.log("broadcast");
    var options = {
        hostname: 'localhost',
        port: 2343,//默认的联系节点的端口
        path: '/receive',
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Content-Length': Buffer.byteLength(blockString)
        }
    };


    var ports=BlockChain.head.creators;//获取链中所有区块的creator,然后逐一发送
    for (var i=0;i<ports.length;i++){
        options.port=ports[i];
        try {
            var req=http.request(options,function (res) {
                res.on('end',function () {
                    console.log("已经发送至:"+ports[i]);
                });
                res.on('data',function (chunk) {
                    console.log("没什么");
                    console.log(chunk);
                })
                res.on('error',function (err) {
                    console.log(port[i]+"数据传输出错");
                })
            });
            req.on('error',function (err) {
                console.log((port[i])+"未上线,未向其发送2");
                req.end();
                //console.log(err);
            })
            req.write(blockString);
            req.end();
            //console.log("已经发送至:"+ports[i]);
        }catch (err) {
            console.log(ports[i]+"发送失败");
        }

    }

}

实现效果:

上次运行保存的区块信息:
启动前

分别运行程序在2343,2344,2345三个端口上,然后从2343端口抓取的区块:

2343端口的节点的区块信息
在2343端口生成一个区块:
输入数据段
生成区块成功

到2344和2345端口查看是否同步过来了:
其实之间看自己文件有没有多就知道了,下图中明显同步了。
在这里插入图片描述

完整的代码:

你可以从仓库里获取完整代码:

github: https://github.com/Lixingwei0623/ablockchain.
gitee: https://gitee.com/li-xingwei/simple-block-chain.

Windows 安装版 1.5.0 beta 大小:4.4MB 更新:2014-12-20 XP/Vista/Win7/Win8 自同步是一款由国内创业团队推出的局域网P2P免费文件同步工具。处在同一个局域网下的多台电脑,可通过自同步来建立电脑里文件夹之间同步关系,做到文件夹中文件的数量、内容相一致,并且不需要云和外网。此外,自同步特有的密钥加密更保证了数据的安全性。并且,其特有的分享功能又可以做到轻轻松松将同步目录分享给周围的朋友们。 软件特点 1. 无需网盘,局域同步 与市面上流行的网盘不同,自同步不需要您的设备时时刻刻连接互联网完成文件同步工作,而只需要在同一个局域网内就能完成文件同步工作。 2. 实时同步,多台互联 处于同步中的目录,只要其中一个目录发生变化,如文件/目录添加、修改、删除等操作,那么与该目录建立同步关系的其它目录也会迅速反应,进行相应的修改,保持与原目录的文件一致;此外,只需将文件放到同步目录,程序将自动上传这些文件,同时其它电脑登陆自同步时自动下载到新电脑,实现多台电脑的文件同步。 3. 目录分享,轻松同步 同步目录分享功能,可以轻松将同步目录分享给周围的朋友(无需同步口令相同)。 4. 密钥加密,保护数据 在局域网内采用AES加密方式传输数据并建立密钥,防止处于同一局域网内的非法设备窃取数据。 5. 优化传输,极速速度 千兆路由的局域网环境下传输速度最高可达70MB/s,同步过程犹如硬盘间的复制粘贴一样方便快捷。
Android 1.5.1 beta 大小:6.3MB 更新:2014-12-24 Android 4.0.4 自同步是一款由国内创业团队推出的局域网P2P免费文件同步工具。处在同一个局域网下的多台电脑,可通过自同步来建立电脑里文件夹之间同步关系,做到文件夹中文件的数量、内容相一致,并且不需要云和外网。此外,自同步特有的密钥加密更保证了数据的安全性。并且,其特有的分享功能又可以做到轻轻松松将同步目录分享给周围的朋友们。 软件特点 1. 无需网盘,局域同步 与市面上流行的网盘不同,自同步不需要您的设备时时刻刻连接互联网完成文件同步工作,而只需要在同一个局域网内就能完成文件同步工作。 2. 实时同步,多台互联 处于同步中的目录,只要其中一个目录发生变化,如文件/目录添加、修改、删除等操作,那么与该目录建立同步关系的其它目录也会迅速反应,进行相应的修改,保持与原目录的文件一致;此外,只需将文件放到同步目录,程序将自动上传这些文件,同时其它电脑登陆自同步时自动下载到新电脑,实现多台电脑的文件同步。 3. 目录分享,轻松同步 同步目录分享功能,可以轻松将同步目录分享给周围的朋友(无需同步口令相同)。 4. 密钥加密,保护数据 在局域网内采用AES加密方式传输数据并建立密钥,防止处于同一局域网内的非法设备窃取数据。 5. 优化传输,极速速度 千兆路由的局域网环境下传输速度最高可达70MB/s,同步过程犹如硬盘间的复制粘贴一样方便快捷。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值