## 北京项目目前的POA共识及存在问题
北京项目是网贷资金存管项目,其业务模式是以XX银行为中心的,为此我们采用了POA共识机制(同时也是限于修改代码的时间因素),其特点是单点出块,中心化方式也是一种共识,叫POA(proof of authurity)
miner = '0x12345678' //取nodeid开头几位
其他节点加入和退出,都是由中心节点控制的
定时出块。由于是中心化的方式,竞争出块的POW方式取消了,那么中心节点自然不需要在消耗大部分cpu时间在寻找hash上,直接读秒出块就可以了
Pending队列处理:目前是所有在Pending的交易都进入这个块,但是有总gas和总数量的限制
首先,nonce已经改成snowflake码了,按时间戳来,所以是有序的
其次,生成Pending的时候,
pendingTransactions.add(new PendingTransaction(tx, getBestBlock().getNumber()));
//这里拷贝生成了
protected List<Transaction> getAllPendingTransactions() {
PendingStateImpl.TransactionSortedSet ret = new PendingStateImpl.TransactionSortedSet();
//这里看出是在区块最大交易条数限制中取交易,poll是从原交易集合中取数据
public List<Transaction> getPendingTransactionsWithRemove(){
List<Transaction> txs=new ArrayList<>();
int n=0;
int cnt = config.minerBlockMaxTransactionCount();
while (pendingTransactions.peek()!=null&&n<cnt){
txs.add(pendingTransactions.poll().getTransaction());
n++;
}
return txs;
}
执行不成功的说明是报错了,只能由前端改了继续发;包含在区块中的必然是本机的,而且排除了gas的原因,如果出错就是必然是客户端交易的问题,所以不需要重新纳入Pending(纳入Pending的应该是miner的问题造成没有入链,所以必须给其下次入链)
存在的问题:
运行风险大,单点风险,中心节点服务器挂了,要重新启动才能出链
扩展性差,不易说服客户,有些客户可能想参与记账
Quorum投票共识算法是JPMorgan的共识算法,利用了以太坊平台支持智能合约的优势,投票程序预编译到创世区块中,或者这步干脆省略,也作为java的一个包
因为智能合约的优势是可以修改、定制;但是这个投票逻辑是非常固定的,所以不需要有智能合约;但是交易记录时要有扩展的交易类型,因为以太坊只能记录转账交易、合约调用
2个miner(同时兼容voter),一个voter(更像是一个仲裁者)
Eth62,新增一种特殊类型的投票交易
对应的是quorum包下特殊的程序逻辑(各个节点是一样的)
收到的投票交易,各节点都记录到日志中,miner节点也将上个区块投票情况打包到这个区块中(因为生成的区块是不能变了)
miner和voter的添加删除也可以通过智能合约管理,由管理员账户发起
miner1发起的区块,并大家投票选中后,miner2会接受,但是接受时,要对自己的Pending队列做一个筛选处理,去掉已经被包含在区块中的交易
正常情况下,miner1读秒出块(比如3秒,加减随机0.5秒),区块先给自己投上一票,然后广播给miner2和voter1,然后voter1给miner1投票(这个投票过程也是广播的),票数达到要求后各个节点都看到了这个区块票数够了入链,这个区块中也记载了投票的情况
1.miner1发出块的时候,可能miner2也发出了块(这个问题,首先要靠3秒,加减随机0.5秒来解决,但是还是有小概率是重合的),关键看voter投谁。miner1是不会投票给对方的,因为已经投给了自己,所以这里的关键是voter1投票给谁
先收到miner1的块,投票给miner1,这时候如果通讯不畅,miner1没收到反馈,但是miner2收到了,认为miner1有2票,commit了,voter1也commit了;只剩下miner1还在等并重新发起投票,但是相同区块高度已经commit并被其他2人拒绝了;然后miner2会发起下一个高度的区块,但是现在miner1怎么办?它发现对方的新区块跳号了,这时候exception,打印日志,然后根据配置的应对的Rule进行处理,可以人工介入,也可以以长链为准,检查签名后同步,同步到最新后再出块
先收到miner2的块,投票给miner2,则miner2入链
2.voter1挂了。miner1和miner2各自独立出块,互相发对方,票数平;这时候双方有出块的先后,最终某轮投票,会有胜者
3.miner1脑裂。miner2继续出块
4.整个网络瘫痪。miner1,miner2均无法出块; 网络恢复后,以最长链并核对后commit;如果两个miner的最新区块不一致,重新发起投票
5.miner1和miner2同时发出后,voter1选了miner1(经过验证签名和块高的,以及前序hash),并commit自己,但是广播的消息没有达到miner1和miner2;miner1和miner2没有规定票数,重新发起投票并选了miner2,这时候voter1活了,下一轮投票就来了,这时候voter发现问题了,前序hash不对,报exception,获取2个miner的区块情况,如果一致,就从其同步,如果不一致,2个miner分叉了,选择miner1并投固定miner1,逼死miner2(因为轮到miner2发现前序节点不对了,然后其发起同步流程,纠正过来再出块)
当然这个无法对付作恶,比如voter节点不顾只有一票的规定,给miner1和miner2都发送投票