def testPrimaryElectionCase2(case2Setup, looper, keySharedNodes): """ Case 2 - A node making nominations for a multiple other nodes. Consider 4 nodes A, B, C, and D. Lets say node B is malicious and nominates node C to all nodes. Again node B nominates node D to all nodes. """ nodeSet = keySharedNodes A, B, C, D = nodeSet.nodes.values() looper.run(checkNodesConnected(nodeSet)) # Node B sends multiple NOMINATE msgs but only after A has nominated itself looper.run(eventually(checkNomination, A, A.name, retryWait=.25, timeout=1)) instId = getSelfNominationByNode(A) BRep = Replica.generateName(B.name, instId) CRep = Replica.generateName(C.name, instId) DRep = Replica.generateName(D.name, instId) # Node B first sends NOMINATE msgs for Node C to all nodes B.send(Nomination(CRep, instId, B.viewNo)) # Node B sends NOMINATE msgs for Node D to all nodes B.send(Nomination(DRep, instId, B.viewNo)) # Ensure elections are done ensureElectionsDone(looper=looper, nodes=nodeSet, retryWait=1, timeout=45) # All nodes from node A, node C, node D(node B is malicious anyway so # not considering it) should have nomination for node C from node B since # node B first nominated node C for node in [A, C, D]: assert node.elector.nominations[instId][BRep] == CRep
def sendNomination(self, name: str, instId: int, viewNo: int): """ Broadcast a nomination message with the given parameters. :param name: node name :param instId: instance id :param viewNo: view number """ self.send(Nomination(name, instId, viewNo))
def testNodeDiscardMessageFromUnknownView(txnPoolNodeSet, nodeSetWithNodeAddedAfterSomeTxns, newNodeCaughtUp, tdirWithPoolTxns, tconf, allPluginsPath): """ Node discards 3-phase and election messages from view nos that it does not know of (view nos before it joined the pool) :return: """ looper, nodeX, client, wallet, _, _ = nodeSetWithNodeAddedAfterSomeTxns viewNo = nodeX.viewNo # Delay processing of PRE-PREPARE from all non primary replicas of master # so master's performance falls and view changes delayNonPrimaries(txnPoolNodeSet, 0, 10) sendReqsToNodesAndVerifySuffReplies(looper, wallet, client, 4) looper.run(eventually(partial(checkViewNoForNodes, txnPoolNodeSet, viewNo + 1), retryWait=1, timeout=20)) newStewardName = "testClientSteward" + randomString(3) nodeName = "Theta" _, _, nodeTheta = addNewStewardAndNode(looper, client, wallet, newStewardName, nodeName, tdirWithPoolTxns, tconf, allPluginsPath) txnPoolNodeSet.append(nodeTheta) looper.run(checkNodesConnected(txnPoolNodeSet)) looper.run(client.ensureConnectedToNodes()) looper.run(eventually(checkNodeLedgersForEquality, nodeTheta, *txnPoolNodeSet[:-1], retryWait=1, timeout=5)) checkProtocolInstanceSetup(looper, txnPoolNodeSet, retryWait=1, timeout=10) electMsg = Nomination(nodeX.name, 0, viewNo) threePMsg = PrePrepare( 0, viewNo, 10, wallet.defaultId, wallet._getIdData().lastReqId+1, "random digest", time.time() ) ridTheta = nodeX.nodestack.getRemote(nodeTheta.name).uid nodeX.send(electMsg, ridTheta) nodeX.send(threePMsg, ridTheta) nodeX.send(electMsg, ridTheta) looper.run(eventually(checkDiscardMsg, [nodeTheta, ], electMsg, 'un-acceptable viewNo', retryWait=1, timeout=5)) nodeX.send(threePMsg, ridTheta) looper.run(eventually(checkDiscardMsg, [nodeTheta, ], threePMsg, 'un-acceptable viewNo', retryWait=1, timeout=5))
def testPrimaryElectionCase1(case1Setup, looper, keySharedNodes): """ Case 1 - A node making multiple nominations for a particular node. Consider 4 nodes A, B, C and D. Lets say node B is malicious and is repeatedly nominating Node D """ nodes = keySharedNodes nodeA, nodeB, nodeC, nodeD = [nodes.getNode(nm) for nm in nodes.nodeNames] # Doesn't matter if nodes reach the ready state or not. Just start them looper.run(checkNodesConnected(nodes)) # Node B sends multiple NOMINATE msgs for Node D but only after A has # nominated itself looper.run( eventually(checkNomination, nodeA, nodeA.name, retryWait=.25, timeout=1)) instId = getSelfNominationByNode(nodeA) for i in range(5): nodeB.send(Nomination(nodeD.name, instId, nodeB.viewNo)) nodeB.nodestack.flushOutBoxes() # No node from node A, node C, node D(node B is malicious anyway so not # considering it) should have more than one nomination for node D since # node D is slow. The one nomination for D, that nodes A, C # and D might have would be because of node B for node in [nodeA, nodeC, nodeD]: assert list(node.elector.nominations[instId].values()).count( Replica.generateName(nodeD.name, instId)) \ <= 1 primaryReplicas = ensureElectionsDone(looper=looper, nodes=nodes, retryWait=1, timeout=30) for node in nodes: logger.debug("{}'s nominations {}".format(node, node.elector.nominations)) # Node D should not have any primary assert not nodeD.hasPrimary # A node other than Node D should not have any replica among the # primary replicas assert nodeD.name not in [pr.name for pr in primaryReplicas]
def testBlacklistNodeOnMultipleNominations(looper, keySharedNodes, ready): """ A node that sends multiple nominations must be blacklisted by other nodes """ nodeSet = keySharedNodes A, B, C, D = nodeSet.nodes.values() # B sends more than 2 nominations for i in range(3): B.send(Nomination(D.name, 0, B.viewNo)) # B should be blacklisted by A, C, D def chk(): for node in A, C, D: assert node.isNodeBlacklisted(B.name) looper.run(eventually(chk, retryWait=1, timeout=3))
def getElectionMsgsForInstance(self, instId: int) -> \ Sequence[Union[Nomination, Primary]]: """ Get nomination and primary messages for instance with id `instId`. """ msgs = [] replica = self.replicas[instId] # If a primary for this instance has been selected then send a # primary declaration for the selected primary if replica.isPrimary is not None: msgs.append(Primary(replica.primaryName, instId, self.viewNo)) else: # If a primary for this instance has not been selected then send # nomination and primary declaration that this node made for the # instance with id `instId` if self.didReplicaNominate(instId): msgs.append(Nomination(self.nominations[instId][ replica.name], instId, self.viewNo)) if self.didReplicaDeclarePrimary(instId): msgs.append(Primary(self.primaryDeclarations[instId][replica.name], instId, self.viewNo)) return msgs