def testPrimaryElectionCase4(case4Setup, looper): """ Case 4 - A node making multiple primary declarations for a particular node. Consider 4 nodes A, B, C and D. Lets say node B is malicious and is repeatedly declaring Node D as primary """ allNodes = case4Setup A, B, C, D = allNodes looper.run(checkNodesConnected(allNodes)) # Node B sends multiple declarations of node D's 0th protocol instance as # primary to all nodes for i in range(5): B.send(Primary(D.name, 0, B.viewNo)) # No node from node A, node C, node D(node B is malicious anyway so not # considering it) should have more than one primary declaration for node # D since node D is slow. The one primary declaration for node D, # that nodes A, C and D might have would be because of node B def x(): primDecs = list(node.elector.primaryDeclarations[0].values()) assert primDecs.count(D.name) <= 1 for node in (A, C, D): looper.run(eventually(x, retryWait=.5, timeout=2)) ensureElectionsDone(looper=looper, nodes=allNodes, retryWait=1, timeout=45) # Node D should not have any primary replica assert not D.hasPrimary
def testPrimaryElectionCase5(case5Setup, looper, keySharedNodes): """ Case 5 - A node making primary declarations for a multiple other nodes. Consider 4 nodes A, B, C, and D. Lets say node B is malicious and declares node C as primary to all nodes. Again node B declares node D as primary to all nodes. """ nodeSet = keySharedNodes A, B, C, D = nodeSet.nodes.values() looper.run(checkNodesConnected(nodeSet)) BRep = Replica.generateName(B.name, 0) CRep = Replica.generateName(C.name, 0) DRep = Replica.generateName(D.name, 0) # Node B first sends PRIMARY msgs for Node C to all nodes B.send(Primary(CRep, 0, B.viewNo)) # Node B sends PRIMARY msgs for Node D to all nodes B.send(Primary(DRep, 0, 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 primary declarations for node C from node B # since node B first nominated node C for node in [A, C, D]: logger.debug( "node {} should have primary declaration for C from node B" .format(node)) assert node.elector.primaryDeclarations[0][BRep] == CRep
def testPrimaryElectionCase5(case5Setup, looper, keySharedNodes): """ Case 5 - A node making primary declarations for a multiple other nodes. Consider 4 nodes A, B, C, and D. Lets say node B is malicious and declares node C as primary to all nodes. Again node B declares node D as primary to all nodes. """ nodeSet = keySharedNodes A, B, C, D = nodeSet.nodes.values() looper.run(checkNodesConnected(nodeSet)) BRep = Replica.generateName(B.name, 0) CRep = Replica.generateName(C.name, 0) DRep = Replica.generateName(D.name, 0) # Node B first sends PRIMARY msgs for Node C to all nodes B.send(Primary(CRep, 0, B.viewNo)) # Node B sends PRIMARY msgs for Node D to all nodes B.send(Primary(DRep, 0, 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 primary declarations for node C from node B # since node B first nominated node C for node in [A, C, D]: logging.debug( "node {} should have primary declaration for C from node B" .format(node)) assert node.elector.primaryDeclarations[0][BRep] == CRep
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 testRequestReturnToNodeWhenPrePrepareNotReceivedByOneNode(tdir_for_func): """Test no T-3""" nodeNames = genNodeNames(7) nodeReg = genNodeReg(names=nodeNames) with TestNodeSet(nodeReg=nodeReg, tmpdir=tdir_for_func) as nodeSet: with Looper(nodeSet) as looper: prepareNodeSet(looper, nodeSet) logger.debug("Add the seven nodes back in") # Every node except A delays self nomination so A can become primary nodeA = addNodeBack(nodeSet, looper, nodeNames[0]) for i in range(1, 7): node = addNodeBack(nodeSet, looper, nodeNames[i]) node.delaySelfNomination(15) nodeB = nodeSet.getNode(nodeNames[1]) # Node B delays PREPREPARE from node A(which would be the primary) # for a long time. nodeB.nodeIbStasher.delay( delayerMsgTuple(120, PrePrepare, nodeA.name)) # Ensure elections are done ensureElectionsDone(looper=looper, nodes=nodeSet, retryWait=1, timeout=30) assert nodeA.hasPrimary instNo = nodeA.primaryReplicaNo client1, wallet1 = setupClient(looper, nodeSet, tmpdir=tdir_for_func) req = sendRandomRequest(wallet1, client1) # All nodes including B should return their ordered requests for node in nodeSet: looper.run( eventually(checkRequestReturnedToNode, node, wallet1.defaultId, req.reqId, req.digest, instNo, retryWait=1, timeout=30)) # Node B should not have received the PRE-PREPARE request yet replica = nodeB.replicas[instNo] # type: Replica assert len(replica.prePrepares) == 0
def testSelfNominationDelay(tdir_for_func): nodeNames = ["testA", "testB", "testC", "testD"] with TestNodeSet(names=nodeNames, tmpdir=tdir_for_func) as nodeSet: with Looper(nodeSet) as looper: prepareNodeSet(looper, nodeSet) delay = 30 # Add node A nodeA = addNodeBack(nodeSet, looper, nodeNames[0]) nodeA.delaySelfNomination(delay) nodesBCD = [] for name in nodeNames[1:]: # nodesBCD.append(nodeSet.addNode(name, i+1, AutoMode.never)) nodesBCD.append(addNodeBack(nodeSet, looper, name)) # Ensuring that NodeA is started before any other node to demonstrate # that it is delaying self nomination looper.run( eventually(lambda: assertExp(nodeA.isReady()), retryWait=1, timeout=5)) # Elections should be done ensureElectionsDone(looper=looper, nodes=nodeSet, retryWait=1, timeout=10) # node A should not have any primary replica looper.run( eventually(lambda: assertExp(not nodeA.hasPrimary), retryWait=1, timeout=10)) # Make sure that after at the most 30 seconds, nodeA's # `startElection` is called looper.run( eventually(lambda: assertExp( len(nodeA.spylog.getAll(Node.decidePrimaries.__name__)) > 0 ), retryWait=1, timeout=30))
def testRequestReturnToNodeWhenPrePrepareNotReceivedByOneNode(tdir_for_func): """Test no T-3""" nodeNames = genNodeNames(7) nodeReg = genNodeReg(names=nodeNames) with TestNodeSet(nodeReg=nodeReg, tmpdir=tdir_for_func) as nodeSet: with Looper(nodeSet) as looper: prepareNodeSet(looper, nodeSet) logging.debug("Add the seven nodes back in") # Every node except A delays self nomination so A can become primary nodeA = addNodeBack(nodeSet, looper, nodeNames[0]) for i in range(1, 7): node = addNodeBack(nodeSet, looper, nodeNames[i]) node.delaySelfNomination(15) nodeB = nodeSet.getNode(nodeNames[1]) # Node B delays PREPREPARE from node A(which would be the primary) # for a long time. nodeB.nodeIbStasher.delay( delayerMsgTuple(120, PrePrepare, nodeA.name)) # Ensure elections are done ensureElectionsDone(looper=looper, nodes=nodeSet, retryWait=1, timeout=30) assert nodeA.hasPrimary instNo = nodeA.primaryReplicaNo client1 = setupClient(looper, nodeSet, tmpdir=tdir_for_func) req = sendRandomRequest(client1) # All nodes including B should return their ordered requests for node in nodeSet: looper.run(eventually(checkRequestReturnedToNode, node, client1.defaultIdentifier, req.reqId, req.digest, instNo, retryWait=1, timeout=30)) # Node B should not have received the PRE-PREPARE request yet replica = nodeB.replicas[instNo] # type: Replica assert len(replica.prePrepares) == 0
def testSelfNominationDelay(tdir_for_func): nodeNames = ["testA", "testB", "testC", "testD"] with TestNodeSet(names=nodeNames, tmpdir=tdir_for_func) as nodeSet: with Looper(nodeSet) as looper: prepareNodeSet(looper, nodeSet) delay = 30 # Add node A nodeA = addNodeBack(nodeSet, looper, nodeNames[0]) nodeA.delaySelfNomination(delay) nodesBCD = [] for name in nodeNames[1:]: # nodesBCD.append(nodeSet.addNode(name, i+1, AutoMode.never)) nodesBCD.append(addNodeBack(nodeSet, looper, name)) # Ensuring that NodeA is started before any other node to demonstrate # that it is delaying self nomination looper.run( eventually(lambda: assertExp(nodeA.isReady()), retryWait=1, timeout=5)) # Elections should be done ensureElectionsDone(looper=looper, nodes=nodeSet, retryWait=1, timeout=10) # node A should not have any primary replica looper.run( eventually(lambda: assertExp(not nodeA.hasPrimary), retryWait=1, timeout=10)) # Make sure that after at the most 30 seconds, nodeA's # `startElection` is called looper.run(eventually(lambda: assertExp( len(nodeA.spylog.getAll( Node.decidePrimaries.__name__)) > 0), retryWait=1, timeout=30))
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 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.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: logging.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 up(looper, ready): ensureElectionsDone(looper=looper, nodes=ready, retryWait=1, timeout=30)
def whitelistClient(nodes, *clientNames): for node in nodes: for nm in clientNames: node.whitelistClient(nm) looper = Looper(nodes, autoStart=True) for node in nodes: node.startKeySharing() node.start(looper) # node.addGenesisTxns(genesisTxns(stewardSigner)) looper.run(checkNodesConnected(nodes)) ensureElectionsDone(looper=looper, nodes=nodes, retryWait=1, timeout=30) steward, _ = genTestClient(nodes, tmpdir=tdir) # whitelistClient(nodes, steward.name) steward.registerObserver(stewardWallet.handleIncomingReply) looper.add(steward) looper.run(steward.ensureConnectedToNodes()) makePendingTxnsRequest(steward, stewardWallet) createNym(looper, sponsorWallet.defaultId, steward, stewardWallet, SPONSOR) sponsor, _ = genTestClient(nodes, tmpdir=tdir) sponsor.registerObserver(sponsorWallet.handleIncomingReply) # whitelistClient(nodes, sponsor.name) looper.add(sponsor) looper.run(sponsor.ensureConnectedToNodes())