viewchange test-遇到的问题(1)
触发
viewchange的方法:修改配置文件config.yaml里request的时间为0.00003s,这个参数代表的是一个请求(block或者是收到的preprepare消息等)从接收到一直到处于committed状态所需要的时间。如果超过这个时间就会触发viewchange.
一、
出现的问题:当触发viewchange操作的时候,各个节点会曝出类似于如下错误:
2017/11/07 19:50:58 Replica 0 found incorrect signature in view-change message: %!s(<nil>)出现问题的原因:在
func (instance *pbftCore) sendViewChange() events.Event里,形成vc.Signature的时候有用到了vc:vc.Signature, _ = signFn(accounts.Account{Address: signer}, sigHash(nil, vc).Bytes())此时,
sigHash里的vc里的参数vc.Signature是没有被赋值的。而在func (instance *pbftCore) recvViewChange(vc *types.ViewChange) events.Event里验证签名的时候用的vc,里面的vc.Signature是已经被赋值的,所以导致签名验证失败。解决问题的方法:在
pbft.go里的func sigHash(header *types.Header, viewChange *types.ViewChange) (hash common.Hash)把viewChange.Signature注释掉。二、
出现错误:
在signer1:
2017/11/07 20:41:28 Replica 0 ignoring processNewView as it could not find view 1 in its newViewStore在signer2:
2017/11/07 20:41:28 Replica 1 received view change quorum, processing new view 2017/11/07 20:41:28 Replica 1 appending checkpoint from replica 0 with seqNo=0, h=0, and checkpoint digest XXX GENESIS 2017/11/07 20:41:28 Replica 1 appending checkpoint from replica 1 with seqNo=0, h=0, and checkpoint digest XXX GENESIS 2017/11/07 20:41:28 Replica 1 appending checkpoint from replica 2 with seqNo=0, h=0, and checkpoint digest XXX GENESIS 2017/11/07 20:41:28 Stopping timer panic: runtime error: index out of range出现错误的原因:经打印排查发现,问题出现在函数
func ConvertMapToStruct(msgList map[uint64]string) []*types.XSet里面,在该函数里只定义了数组xset,但是没有给他分配空间。解决问题的方法:增加两条语句
l := len(msgList) xset := make([]*types.XSet, l)问题解决。
三、
出现的问题:
signer1发送viewchange消息后,其他节点包括signer1一直循环输出如下语句(以signer1为例):2017/11/09 09:27:39 Replica 0 already has a view change message for view 1 from replica 0不能进行接下来的操作。
出现问题的原因:出现这种状态的原因是因为只有
signer1发送了viewchange消息,其他节点都没有发送,这样会造成永远无法收到一个quorum的viewchange消息,也就无法进行接下来的操作。解决问题的方法:在
config.yaml里把nullrequest的时间由0变为5s。nullrequest对应的时间是nullRequestTimeout。当block处于committed状态或者是触发stateUpdatedEvent的时候会通过调用func (instance *pbftCore) executeOutstanding()层层调用进而调用func (instance *pbftCore) startTimerIfOutstandingBlocks()来触发nullRequestEvent。该事件触发后,如果该节点是主节点,会重新发送preprepare消息,如果是非主节点,会发送viewchange消息。由于在这里循环输出如上语句,所以无论是主节点还是非主节点都无法进行接下来的操作,于是在func (instance *pbftCore) recvViewChange(vc *types.ViewChange) events.Event的if条件语句里增加了如下语句来触发nullRequestEvent:if _, ok := instance.viewChangeStore[vcidx{vc.View, vc.ReplicaId}]; ok { logger.Warningf("Replica %d already has a view change message for view %d from replica %d", instance.id, vc.View, vc.ReplicaId) ///////// ////--xiaobei 11.9 if !flag && instance.nullRequestTimeout > 0 { timeout := instance.nullRequestTimeout if instance.primary(instance.view) != instance.id { // we're waiting for the primary to deliver a null request - give it a bit more time timeout += instance.requestTimeout } instance.nullRequestTimer.Reset(timeout, nullRequestEvent{}) flag = true } ///////// return nil }flag的作用是使该事件的开启只开启一次。加入后该段语句后,viewchange就可以不止主节点触发,防止进入无限循环之中。四、
出现的问题:各个节点不能正确验证
new view里的xset,以replica0为例:2017/11/09 17:27:35 Replica 0 failed to verify new-view Xset: computed map[19:>��>�E�#�_Tg�)�bIvh��<V}!S 7:�}f/7� ��ʜ��䤿������V��0 18:�#l�7����Q?���d/��V?1Rp��5�� 4:��oz�<a�>L��d�v*����-/��)���f�� 11:&^ɶ��t)�w4�S����F�-e�mѩ 15:��D;�+��i���Ǥ�xF`Iٚ���z�%���� 16:U�c�V߲�Փ$&���F۽ �c��9۴�=� 6:ѻ��GB�($���ݶ����9/))���/6MV 2:/'�K�9ަ�GG�TH�E:�]������, 12:�i܀0���0C\E�����|�C��[6��W 5:_��E�^�uR� �q�q��r���.�� 14:]�pft=�������Θ��Tb+�8z;�q�S�� 17:��k<*�� �j��AH��#�+ 3:��A �Y�;Ls�.v����Qb�yAq�М 9:h������N�iƩCY�� �|�7k�촚�� 13:? �1���Ѳ����1/��mؿ;V��� 20:��'�<���Q!��R�?rwr�� m��n�Q�Wݓ 8:�C����m�������*5s�>#�(��cC 10:�Qt&�'����u��|��p��~8|���Pn 1:4]�$%©bRRGXU�B�A����A��W�a��], received [0xc42131f7e0 0xc42131f800 0xc42131f820 0xc42131f840 0xc42131f880 0xc42131f8a0 0xc42131f8e0 0xc42131f900 0xc42131f920 0xc42131f960 0xc42131f9a0 0xc42131f9c0 0xc42131f9e0 0xc42131fa20 0xc42131fa40 0xc42131fa60 0xc42131fa80 0xc42131faa0 0xc42131fac0 0xc42131fb00]出现错误的原因:在
func (instance *pbftCore) processNewView() events.Event里将msgList和nv.Xset进行了比较,而nv.Xset是进行结构体转换后的msgList,他俩不可能相等,自然报错。解决问题的方法:将
msgList先进行格式变化,再与nv.Xset进行比较,msglist := ConvertMapToStruct(msgList),问题解决。五、
出现的问题:当
signer1触发viewchange之后,signer2成为了主节点,但是signer2不能进行挖矿,报错:panic:assignment to entry in nil map出现错误的原因:当
viewchange完成之后,会触发viewchangedEvent,在func (instance *pbftCore) ProcessEvent(e events.Event) events.Event里对该事件进行处理的时候,误将instance.blockStore置为了nil。解决问题的方法:在对
viewchangedEvent进行处理的时候,重新给instance.blockStore分配空间,而不是置为空:instance.blockStore = make(map[string]*types.Block) ////--xiaobei 11.9六、
出现的问题:解决完上述问题之后,开启四个节点能够正确进行
viewchange,viewchange完毕后也能正确进行挖矿、同步。但是当我把所有的节点都exit后再重新开启四个节点进行挖矿的时候,就会不断出现类似于以下的问题:Replica 1 failed to verify new-view Xset: computed [0xc42179c300 0xc42179c320 0xc42179c340 0xc42179c360 0xc42179c380 0xc42179c3e0 0xc42179c420 0xc42179c440 0xc42179c460 0xc42179c4a0 0xc42179c4c0 0xc42179c500 0xc42179c520 0xc42179c560 0xc42179c580 0xc42179c5a0 0xc42179c5c0 0xc42179c5e0 0xc42179c600 0xc42179c620], received [0xc421785ee0 0xc421785f00 0xc421785f20 0xc421785f40 0xc421785f80 0xc421785fc0 0xc421792000 0xc421792020 0xc421792060 0xc4217920e0 0xc421792100 0xc421792120 0xc421792140 0xc421792180 0xc4217921a0 0xc4217921c0 0xc4217921e0 0xc421792200 0xc421792220 0xc421792260]进而不断的触发
viewchange。出现错误的原因:~看了一下
Xset没有在数据库中进行存储,所以猜想是这个原因导致每次重启之后报错。~当收到一个
quorum的viewchange消息,处理NewView的时候:如果节点是主节点:触发
func (instance *pbftCore) sendNewView() events.Event如果节点是非主节点:触发
func (instance *pbftCore) recvNewView(nv *types.NewView) events.Event两个函数都会最终触发
func (instance *pbftCore) processNewView() events.Event。奇怪的是在同一个节点当中,无论是主节点还是非主节点,在调用msgList := instance.assignSequenceNumbers(vset, cp.SequenceNumber)生成msgList的时候,processNewView()与sendNewView()/recvNewView(nv *types.NewView)里调用func (instance *pbftCore) assignSequenceNumbers(vset []*types.ViewChange, h uint64) (msgList map[uint64]string)传递的参数是相同的,但是生成的msgList却不相同:
signer2:(非主节点)
signer4:(主节点)
但是对于同一节点来说,发送或接收到的xset与处理时的xset是相同的。
在func (instance *pbftCore) sendNewView() events.Event和func (instance *pbftCore) processNewView() events.Event里都加入了两个循环:
分别查看经过func (instance *pbftCore) assignSequenceNumbers(vset []*types.ViewChange, h uint64) (msgList map[uint64]string)和func ConvertMapToStruct(msgList map[uint64]string) []*types.XSet之后,msgList的值是否发生变化,结果发现能够正确进行转换,没有发生变化。接着比较了sendNewView()和processNewView()里的xset[],发现二者相同下标对应的值却不同,比如:
sendNewView():
processNewView():
两个函数里面seq:6对应的xset[]的下标一个是0,一个是9。在第一次进行viewchange的时候能够正确进行是因为当时xset里面只有一个值:
解决问题的方法:在
processNewView()里面初始化一个数组msglist2,与msglist类型相同。当收到的NewView里的Xset与新生成的msgList里的seq相同时,就执行msglist2[i] = msglist[j],这样就能保证新生成的msgList与nv.Xset相同数组下标对应的seq相同:
Last updated
Was this helpful?