def test_follower_server_on_receive_message_where_log_contains_conflicting_entry_at_new_index( self): self.server._log.append({"term": 1, "value": 0}) self.server._log.append({"term": 1, "value": 200}) self.server._log.append({"term": 1, "value": 300}) self.server._log.append({"term": 2, "value": 400}) msg = AppendEntriesMessage( 0, 1, 2, { "prevLogIndex": 0, "prevLogTerm": 1, "leaderCommit": 1, "entries": [{ "term": 1, "value": 100 }] }) self.server.on_message(msg) self.assertEqual({"term": 1, "value": 100}, self.server._log[1]) self.assertEqual([{ "term": 1, "value": 0 }, { "term": 1, "value": 100 }], self.server._log)
def test_leader_server_sends_appendentries_to_all_neighbors_but_some_have_dirtied_logs( self): self.leader._neighbors[0]._log.append({"term": 2, "value": 100}) self.leader._neighbors[0]._log.append({"term": 2, "value": 200}) self.leader._neighbors[1]._log.append({"term": 3, "value": 200}) self.leader._log.append({"term": 1, "value": 100}) self._perform_hearbeat() msg = AppendEntriesMessage( 0, None, 1, { "prevLogIndex": 0, "prevLogTerm": 0, "leaderCommit": 1, "entries": [{ "term": 1, "value": 100 }] }) self.leader.send_message(msg) for i in self.leader._neighbors: i.on_message(i._messageBoard.get_message()) for i in self.leader._neighbors: self.assertEqual([{"term": 1, "value": 100}], i._log)
def test_follower_server_on_receive_message_with_greater_term(self): msg = AppendEntriesMessage(0, 1, 2, {}) self.server.on_message(msg) self.assertEqual(2, self.server._currentTerm)
def test_follower_server_on_receive_message_with_lesser_term(self): msg = AppendEntriesMessage(0, 1, -1, {}) self.server.on_message(msg) self.assertEquals( False, self.oserver._messageBoard.get_message().data["response"])
def on_response_received(self, message): # Was the last AppendEntries good? if (not message.data["response"]): # No, so lets back up the log for this node self._nextIndexes[message.sender] -= 1 # Get the next log entry to send to the client. previousIndex = max(0, self._nextIndexes[message.sender] - 1) previous = self._server._log[previousIndex] current = self._server._log[self._nextIndexes[message.sender]] # Send the new log to the client and wait for it to respond. appendEntry = AppendEntriesMessage( self._server._name, message.sender, self._server._currentTerm, { "leaderId": self._server._name, "prevLogIndex": previousIndex, "prevLogTerm": previous["term"], "entries": [current], "leaderCommit": self._server._commitIndex, }) self._send_response_message(appendEntry) else: # The last append was good so increase their index. self._nextIndexes[message.sender] += 1 # Are they caught up? if (self._nextIndexes[message.sender] > self._server._lastLogIndex): self._nextIndexes[message.sender] = self._server._lastLogIndex return self, None
def _send_heartbeat(self): # "Queue" a call to itself that will be run in the future self.heartbeat_handler = threading.Timer(self.heartbeat_interval, self._send_heartbeat).start() message = AppendEntriesMessage(sender=self.server.name, receiver=None, term=self.server.current_term, data=None) self.server.send_message_to_all(message, self.heartbeat_list)
def _send_heart_beat(self): message = AppendEntriesMessage( self._server._name, None, self._server._currentTerm, { "leaderId": self._server._name, "prevLogIndex": self._server._lastLogIndex, "prevLogTerm": self._server._lastLogTerm, "entries": [], "leaderCommit": self._server._commitIndex, }) self._server.send_message(message)
def send_new_entry(self, new_entry): self._server._log.add_block(new_entry) message = AppendEntriesMessage( self._server._name, None, self._server._currentTerm, { "leaderId": self._server._name, "prevLogIndex": self._server._lastLogIndex, "prevLogTerm": self._server._lastLogTerm, "entries": [new_entry], "leaderCommit": self._server._commitIndex, }) self._server.logger.info('try to append new block') self._server.send_message(message)
def on_message(self, message): """This method is called when a message is received, and calls one of the other corrosponding methods that this state reacts to. """ if ClientRequestMessage.is_client_message(message): message = ClientRequestMessage.from_message_string(message) print "NOT SURE WHAT TO DO NOW..." if (message.term > self._server._currentTerm): self._server._currentTerm = message.term # Is the messages.term < ours? If so we need to tell # them this so they don't get left behind. elif (message.term < self._server._currentTerm): self._send_response_message(message, yes=False) return self, None if AppendEntriesMessage.is_append_entries_message(): message = AppendEntriesMessage.from_message_string(message) return self.on_append_entries(message) elif RequestVoteMessage.is_request_vote_message(message): message = RequestVoteMessage.from_message_string(message) return self.on_vote_request(message) elif RequestVoteResponseMessage.is_request_vote_response_message( message): message = RequestVoteResponseMessage.from_message_string(message) return self.on_vote_received(message) elif ResponseMessage.is_response_message(message): message = ResponseMessage.from_message_string(message) return self.on_response_received(message)
def test_follower_server_on_receive_message_where_log_is_empty_and_receives_its_first_value( self): msg = AppendEntriesMessage( 0, 1, 2, { "prevLogIndex": 0, "prevLogTerm": 100, "leaderCommit": 1, "entries": [{ "term": 1, "value": 100 }] }) self.server.on_message(msg) self.assertEquals({"term": 1, "value": 100}, self.server._log[0])
def test_append(self): self._perform_hearbeat() msg = AppendEntriesMessage(0, None, 1, { "prevLogIndex": 0, "prevLogTerm": 0, "leaderCommit": 1, "entries": [{"term": 1, "value": 100}]}) self.leader.send_message(msg) for i in self.leader._neighbors: i.on_message(i._messageBoard.get_message()) for i in self.leader._neighbors: self.assertEqual([{"term": 1, "value": 100}], i._log)
def test_follower_server_on_receive_message_where_log_does_not_have_prevLogTerm( self): self.server._log.append({"term": 100, "value": 2000}) msg = AppendEntriesMessage( 0, 1, 2, { "prevLogIndex": 0, "prevLogTerm": 1, "leaderCommit": 1, "entries": [{ "term": 1, "value": 100 }] }) self.server.on_message(msg) self.assertEquals( False, self.oserver._messageBoard.get_message().data["response"]) self.assertEquals([], self.server._log)
def test_follower_server_on_message(self): msg = AppendEntriesMessage(0, 1, 2, {}) self.server.on_message(msg)
def on_response_received(self, message): # Was the last AppendEntries good? if (not message.data["response"]): # No, so lets back up the log for this node self._nextIndexes[message.sender] = \ min(self._nextIndexes[message.sender], self._server._log.size()-1) if not message.data['reply_heartbeat']: self._nextIndexes[message.sender] -= 1 # Get the next log entry to send to the client. previousIndex = max(0, self._nextIndexes[message.sender] - 1) previous = self._server._log.get(previousIndex) self._server.logger.info(str(self._nextIndexes[message.sender])) current = self._server._log.get(self._nextIndexes[message.sender]) # Send the new log to the client and wait for it to respond. appendEntry = AppendEntriesMessage( self._server._name, message.sender, self._server._currentTerm, { "leaderId": self._server._name, "prevLogIndex": previousIndex, "prevLogTerm": previous.get_term(), "entries": [current], "leaderCommit": self._server._commitIndex, }) self._server.send_message(appendEntry) else: # The last append was good so increase their index. self._server.logger.info('append an entry to follower') self._nextIndexes[message.sender] += 1 # Are they caught up? if (self._nextIndexes[message.sender] > self._server._lastLogIndex + 1): self._nextIndexes[ message.sender] = self._server._lastLogIndex + 1 self._matchIndex[ message.sender] = self._nextIndexes[message.sender] - 1 commit_count = 1 for _ in self._matchIndex: #print(self._matchIndex[_], self._nextIndexes[_]) if self._matchIndex[_] > self._server._commitIndex: commit_count += 1 if commit_count > (self._server._total_nodes - 1) / 2: self._server.logger.info('commitIndex add 1') self._server._commitIndex += 1 self._server._log.set_commitIndex(self._server._commitIndex) commit_log = self._server._log.get(self._server._commitIndex) log_data = commit_log.txns for txn in log_data: #print(txn) if len(txn.split('\t')) == 1: continue txn_id = txn.split('\t')[0] receiver = txn_id.split('_')[0].replace(' ', '\t') response = ResponseMessage( self._server._name, receiver, None, { "response": True, "currentTerm": self._server._currentTerm, 'txn_id': txn_id }) self._server.send_message(response) return self, None
# print(server) """ _name: 1, _state: <states.follower.Follower object at 0x10ef77048>, _log: [], _messageBoard: board: [], _neighbors: [<servers.server.Server object at 0x10ef71cf8>], _total_nodes: 0, _commitIndex: 0, _currentTerm: 0, _lastApplied: 0, _lastLogIndex: 0, _lastLogTerm: None """ msg = AppendEntriesMessage(0, 1, 2, {}) # print(msg) """ AppendEntries: 0, RequestVote: 1, RequestVoteResponse: 2, Response: 3, _timestamp: 1581654239, _sender: 0, _receiver: 1, _data: {}, _term: 2, _type: 0 """ server.on_message(msg) # print(server) """ _name: 1, _state: <states.follower.Follower object at 0x10d08afd0>, _log: [], _messageBoard: board: [], _neighbors: [<servers.server.Server object at 0x10d08acf8>], _total_nodes: 0, _commitIndex: 0,
def test_mtd(self): print("\n\n***test_mtd***") print("---perform_heartbeat---") self._perform_hearbeat() self.leader._log.append({"term": 1, "value": "10.0.1.1"}) # form and add typical entry msg = AppendEntriesMessage( 0, None, 1, { "prevLogIndex": 0, "prevLogTerm": 0, "leaderCommit": 0, "entries": [{ "term": 1, "value": "10.0.1.1" }] }) self.leader.send_message(msg) for i in self.leader._neighbors: i.on_message(i._messageBoard.get_message()) # for i in self.leader._neighbors: # self.assertEqual([{"term": 1, "value": 100}], i._log) self.printLogs() # print("---perform_heartbeat---") # self._perform_hearbeat() self.leader._log.append({"term": 1, "value": "10.0.1.2"}) # form and add another typical entry msg = AppendEntriesMessage( 0, None, 1, { "prevLogIndex": 0, "prevLogTerm": 1, "leaderCommit": 0, "entries": [{ "term": 1, "value": "10.0.1.2" }] }) self.leader.send_message(msg) for i in self.leader._neighbors: i.on_message(i._messageBoard.get_message()) # for i in self.leader._neighbors: # self.assertEqual([{"term": 1, "value": 100.100.100.100}, {"term": 1, "value": 200}], i._log) self.printLogs() print("---Regular entries added. Request change---") # self._perform_hearbeat() self.leader._log.append({"term": 1, "value": "hashthis"}) # attack detected, leader requests address change via AppendEntries # value of 999 signifies an attack was detected msg = AppendEntriesMessage( 0, None, 1, { "prevLogIndex": 0, "prevLogTerm": 1, "leaderCommit": 1, "entries": [{ "term": 1, "value": 999, "addr": "hashthis" }] }) self.leader.send_message(msg) for i in self.leader._neighbors: i.on_message(i._messageBoard.get_message()) # for i in self.leader._neighbors: # self.assertEqual([{"term": 1, "value": 100}, {"term": 1, "value": 200}, {"term": 1, "value": 999}], i._log) self.printLogs()