use of bftsmart.tom.leaderchange.LeaderRegency in project bftsmart by blockchain-jd-com.
the class Synchronizer method process_LC_STOPDATA.
/**
* 处理从其它节点发来的 STOPDATA 消息;
* <p>
*
* @param msg
*/
private synchronized void process_LC_STOPDATA(LCMessage msg) {
log_debug("process_LC_STOPDATA", "start processing STOPDATA message...", msg.getType(), msg.getSender());
// 检查执政期是否过期;
if (msg.getReg() < lcManager.getLastReg()) {
// 执政期过期的消息,直接抛弃 ;
log_error("process_LC_STOPDATA", "receive an outdated STOPDATA message with wrong view!", msg.getType(), msg.getSender());
return;
}
// 检查消息的视图;
if (!msg.matchesView(this.controller.getCurrentView())) {
// STOPDATA 消息的视图与当前视图不一致;
// 由于执政期未过期,或者当前正处于选举进程中,尽管视图不一致,但也可以先放到超前消息列表里,暂时不做处理;
log_info("process_LC_STOPDATA", "Keep STOPDATA message as out of context for regency[" + msg.getReg() + "]!", msg.getType(), msg.getSender());
outOfContextLC.add(msg);
return;
}
// STOPDATA 消息是由新的一轮执政期中的非领导者节点向领导者节点发送的选举结果的信息;
// 当前节点需要确认如果自己是新领导者节点
final int newRegency = msg.getReg();
final int newLeader = msg.getLeader();
LeaderRegency currentRegency = this.lcManager.getCurrentRegency();
if (newRegency == currentRegency.getId()) {
// 新的执政期与当前执政期相同;
if (newLeader != currentRegency.getLeaderId()) {
// 相同的执政期,但是领导者不相同,属于无效消息;
log_error("process_LC_STOPDATA", "Discard STOPDATA message due to different leader[curr=" + currentRegency.getId() + ", new=" + newLeader + "] in the same regency[" + newRegency + "]!", msg.getType(), msg.getSender());
return;
}
if (newLeader != getCurrentId()) {
log_error("process_LC_STOPDATA", "Discarding STOPDATA message", msg.getType(), msg.getSender());
return;
}
// 当前节点是领导者;
log_info("process_LC_STOPDATA", "This is new leader of regency[" + newRegency + "]!", msg.getType(), msg.getSender());
processSTOPDATA(msg, new LeaderRegency(newLeader, newRegency));
return;
}
// 综合来看,除了 2.3 这种情况之外,其它都是需要当做超前消息来处理;
if (lcManager.isInProgress()) {
ElectionResult result = lcManager.generateElectionResult(lcManager.getNextReg());
int nextRegency = lcManager.getNextReg();
if (result != null && (newRegency < nextRegency || (newRegency == nextRegency && newLeader != result.getRegency().getLeaderId()))) {
// 执政期过期的消息,直接抛弃 ;
String errorMessage = String.format("Discard the STOPDATA message that will expire soon! --[nextRegency=%s][msgRegency=%s]", nextRegency, msg.getReg());
log_warn("process_LC_STOPDATA", errorMessage, msg.getType(), msg.getSender());
return;
}
}
log_info("process_LC_STOPDATA", "Keep STOPDATA message as out of context for regency[" + msg.getReg() + "]!", msg.getType(), msg.getSender());
outOfContextLC.add(msg);
// 原来的处理;
// // Am I the new leader, and am I expecting this messages?
// if (newRegency == lcManager.getLastReg() && this.controller.getStaticConf().getProcessId() == execManager
// .getCurrentLeader()/* (regency % this.reconfManager.getCurrentViewN()) */) {
//
// LOGGER.info(
// "(Synchronizer.deliverTimeoutRequest) [{}] -> I am proc {} I'm the new leader and I received a STOPDATA, from proc {}, from port {}",
// this.execManager.getTOMLayer().getRealName(), controller.getStaticConf().getProcessId(),
// msg.getSender(), controller.getStaticConf().getRemoteAddress(msg.getSender()).getConsensusPort());
// processSTOPDATA(msg, newRegency);
// } else if (msg.getReg() > lcManager.getLastReg()) { // send STOPDATA to out of context if
// // it is for a future regency
// LOGGER.info(
// "(Synchronizer.process_LC_STOPDATA) [{}] -> I am proc {} Keeping STOPDATA message as out of context for regency {}, from proc {}, from port {}",
// this.execManager.getTOMLayer().getRealName(), controller.getStaticConf().getProcessId(),
// msg.getReg(), msg.getSender(),
// controller.getStaticConf().getRemoteAddress(msg.getSender()).getConsensusPort());
// outOfContextLC.add(msg);
//
// } else {
// log_error("process_LC_STOPDATA", "Discarding STOPDATA message", msg.getType(), msg.getSender());
// }
}
use of bftsmart.tom.leaderchange.LeaderRegency in project bftsmart by blockchain-jd-com.
the class Synchronizer method process_LC_STOP.
private synchronized void process_LC_STOP(LCMessage msg) {
// message STOP
log_debug("process_LC_STOP", "begin...", msg.getType(), msg.getSender());
// TODO: 收到 STOP 消息;
// this message is for the next leader change?
LeaderRegencyPropose regencyPropose = copyPropose(msg);
final int proposedRegencyId = regencyPropose.getRegency().getId();
if (lcManager.canPropose(proposedRegencyId)) {
if (lcManager.isFutureAfterNextRegency(proposedRegencyId)) {
// send STOP to out of context
// 处于选举进程中,但是提议的执政期Id 大于当前选举中的执政期 Id,说明这是一个执政期Id超前的提议;
// it is for a future regency
log_debug("process_LC_STOP", "Keeping STOP message as out of context for regency[" + msg.getReg() + "]!", msg.getType(), msg.getSender());
outOfContextLC.add(msg);
// 解决节点处于选举中,新一轮选举的消息放入缓存没有机会处理的问题
LeaderRegency maxRegency = getMaxRegencyFromOutofContextLC();
// 对超出预期的,且个数满足f+1条件的最大regency进行处理
for (int outofregency = maxRegency.getId(); outofregency > lcManager.getNextReg(); outofregency--) {
if (maxRegencyOutOfContextSTOPs(outofregency) == lcManager.getBeginQuorum()) {
LOGGER.info("I am proc {}, process out of context msg for regency {}", this.controller.getStaticConf().getProcessId(), outofregency);
processOutOfContextSTOPs(outofregency);
lcManager.updateNextReg(outofregency);
// 生成本地的附议Stop消息
LeaderRegencyPropose leaderRegencyPropose = LeaderRegencyPropose.copy(maxRegency.getLeaderId(), maxRegency.getId(), this.controller.getCurrentView().getId(), this.controller.getCurrentView().getProcesses(), getCurrentId());
lcManager.addStop(leaderRegencyPropose);
try {
byte[] payload = makeTomMessageReplyBatch(maxRegency.getId());
LCMessage msgSTOP_APPEND = LCMessage.createSTOP_APPEND(this.controller.getStaticConf().getProcessId(), leaderRegencyPropose.getRegency(), controller.getCurrentView(), payload);
// make replica re-transmit the stop
requestsTimer.setSTOP(maxRegency.getId(), msgSTOP_APPEND);
communication.send(this.controller.getCurrentViewOtherAcceptors(), msgSTOP_APPEND);
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
} else {
// 未开始选举进程,或者已经开始选举进程并且提议的执政期等于正在选举中的执政期;
// 等同于表达式:(!lcManager.isInProgress()) || proposedRegencyId ==
// lcManager.getNextReg()
log_debug("process_LC_STOP", "received regency change request.", msg.getType(), msg.getSender());
TOMMessage[] requests = deserializeTOMMessages(msg.getPayload());
// store requests that came with the STOP message
lcManager.addRequestsFromSTOP(requests);
// 当前的领导者;
// store information about the message STOP
lcManager.addStop(regencyPropose);
// the replica might have received STOPs
processOutOfContextSTOPs(msg.getReg());
// that were out of context at the time they
// were received, but now can be processed
// evaluate STOP messages
startSynchronization(regencyPropose);
}
} else {
log_warn("process_LC_STOP", "Discard the outdated STOP message with regency[" + proposedRegencyId + "]!", msg.getType(), msg.getSender());
}
}
use of bftsmart.tom.leaderchange.LeaderRegency in project bftsmart by blockchain-jd-com.
the class Synchronizer method startSynchronization.
// this method is called when a timeout occurs or when a STOP message is
// recevied
private synchronized void startSynchronization(LeaderRegencyPropose regencyPropose) {
LOGGER.info("(Synchronizer.startSynchronization) [{}] -> I am proc {}, initialize synchr phase", this.execManager.getTOMLayer().getRealName(), controller.getStaticConf().getProcessId());
// Ask to start the synchronizations phase if enough messages have been received
// already
final int proposedRegencyId = regencyPropose.getRegency().getId();
// 如果此时已经处于选举进程,则不作后续处理;
if (!lcManager.isInProgress()) {
// 对非领导者而言,如果请求是有当前执政期的领导者节点主动触发的,并计入自己的一票;
LeaderRegency currentRegency = lcManager.getCurrentRegency();
if ((!tom.isLeader()) && regencyPropose.getSender() == currentRegency.getLeaderId() && regencyPropose.getRegency().getId() == currentRegency.getId() + 1) {
// 这是来自当前执政期领导者的主动选举提议;
// 进一步校验视图的一致性;
// 基于当前视图预测下一个执政期(即:当前执政期Id + 1),校验预测结果与来自远程的领导者的提议是否一致;
// 如果一致,则直接投赞成票,并主动发出 STOP_APPEND 消息;
View currentView = controller.getCurrentView();
LeaderRegencyPropose nextRegencyPropose = LeaderRegencyPropose.chooseFromView(currentRegency.getId() + 1, currentView, this.getCurrentId());
if (regencyPropose.isViewEquals(currentView) && nextRegencyPropose.getRegency().getLeaderId() == regencyPropose.getRegency().getLeaderId()) {
lcManager.addStop(nextRegencyPropose);
// 发送 STOP_APPEND 消息;
sendSTOP_APPEND(nextRegencyPropose);
}
}
if (lcManager.isUpToBeginQuorum(proposedRegencyId)) {
beginElection(regencyPropose);
}
}
// Did the synchronization phase really started?
// LCManager有两种状态:
// 1: 进入“选举中”状态;
// 2:在本次“选举周期”下并发地收到其它节点的 STOPDATA 消息,完成了本次轮选举;
ElectionResult electionResult = lcManager.generateQuorumElectionResult(proposedRegencyId);
if (lcManager.isInProgress(proposedRegencyId) && electionResult != null) {
commitElection(proposedRegencyId);
}
// End of: if (canSendStopData && lcManager.getNextReg() >
// lcManager.getLastReg());
}
use of bftsmart.tom.leaderchange.LeaderRegency in project bftsmart by blockchain-jd-com.
the class DurableStateManager method SMReplyDeliver.
@Override
public void SMReplyDeliver(SMMessage msg, boolean isBFT) {
lockTimer.lock();
CSTSMMessage reply = (CSTSMMessage) msg;
if (topology.getStaticConf().isStateTransferEnabled()) {
LOGGER.debug("(TOMLayer.SMReplyDeliver) The state transfer protocol is enabled");
LOGGER.info("(TOMLayer.SMReplyDeliver) I received a state reply for CID {} from replica {}", reply.getCID(), reply.getSender());
LOGGER.info("--- Received CID: {}, Waiting CID: {}", reply.getCID(), waitingCID);
if (waitingCID != -1 && reply.getCID() == waitingCID) {
int currentRegency = -1;
int currentLeader = -1;
View currentView = null;
if (!appStateOnly) {
senderRegencies.put(reply.getSender(), reply.getRegency());
senderLeaders.put(reply.getSender(), reply.getLeader());
senderViews.put(reply.getSender(), reply.getView());
// msg.getState().getCertifiedDecision(SVController));
if (enoughRegencies(reply.getRegency()))
currentRegency = reply.getRegency();
if (enoughLeaders(reply.getLeader()))
currentLeader = reply.getLeader();
if (enoughViews(reply.getView())) {
currentView = reply.getView();
if (!currentView.isMember(topology.getStaticConf().getProcessId())) {
LOGGER.error("Not a member!");
}
}
// if (enoughProofs(waitingCID, this.tomLayer.getSynchronizer().getLCManager()))
// currentProof = msg.getState().getCertifiedDecision(SVController);
} else {
currentLeader = tomLayer.execManager.getCurrentLeader();
currentRegency = tomLayer.getSynchronizer().getLCManager().getLastReg();
currentView = topology.getCurrentView();
}
LOGGER.info("(TOMLayer.SMReplyDeliver) The reply is for the CID that I want!");
NodeNetwork address = reply.getCstConfig().getAddress();
Socket clientSocket;
ApplicationState stateReceived = null;
try {
clientSocket = new Socket(address.getHost(), address.getConsensusPort());
ObjectInputStream in = new ObjectInputStream(clientSocket.getInputStream());
stateReceived = (ApplicationState) in.readObject();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (stateReceived instanceof CSTState) {
senderStates.put(reply.getSender(), stateReceived);
if (reply.getSender() == cstRequest.getCheckpointReplica())
this.stateCkp = (CSTState) stateReceived;
if (reply.getSender() == cstRequest.getLogLower())
this.stateLower = (CSTState) stateReceived;
if (reply.getSender() == cstRequest.getLogUpper())
this.stateUpper = (CSTState) stateReceived;
}
if (senderStates.size() == 3) {
CommandsInfo[] lowerLog = stateLower.getLogLower();
CommandsInfo[] upperLog = stateUpper.getLogUpper();
LOGGER.debug("lowerLog ");
if (lowerLog != null)
LOGGER.debug("Lower log length size: {} ", lowerLog.length);
LOGGER.debug("upperLog ");
if (upperLog != null)
LOGGER.debug("Upper log length size: {} ", upperLog.length);
boolean haveState = false;
byte[] lowerbytes = TOMUtil.getBytes(lowerLog);
LOGGER.debug("Log lower bytes size: {}", lowerbytes.length);
byte[] upperbytes = TOMUtil.getBytes(upperLog);
LOGGER.debug("Log upper bytes size: {}", upperbytes.length);
byte[] lowerLogHash = new byte[0];
byte[] upperLogHash = new byte[0];
try {
lowerLogHash = TOMUtil.computeHash(lowerbytes);
upperLogHash = TOMUtil.computeHash(upperbytes);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
// validate lower log
if (Arrays.equals(stateCkp.getHashLogLower(), lowerLogHash))
haveState = true;
else
LOGGER.error("Lower log don't match");
// validate upper log
if (!haveState || !Arrays.equals(stateCkp.getHashLogUpper(), upperLogHash)) {
haveState = false;
LOGGER.error("Upper log don't match");
}
CSTState statePlusLower = new CSTState(stateCkp.getSerializedState(), TOMUtil.getBytes(stateCkp.getSerializedState()), stateLower.getLogLower(), stateCkp.getHashLogLower(), null, null, stateCkp.getCheckpointCID(), stateUpper.getCheckpointCID(), topology.getStaticConf().getProcessId());
if (haveState) {
// validate checkpoint
LOGGER.debug("validating checkpoint!!!");
dt.getRecoverer().setState(statePlusLower);
byte[] currentStateHash = ((DurabilityCoordinator) dt.getRecoverer()).getCurrentStateHash();
if (!Arrays.equals(currentStateHash, stateUpper.getHashCheckpoint())) {
LOGGER.error("ckp hash don't match");
haveState = false;
}
}
LOGGER.info("-- current regency: {} ", currentRegency);
LOGGER.info("-- current leader: {}", currentLeader);
LOGGER.info("-- current view: {}", currentView);
if (currentRegency > -1 && currentLeader > -1 && currentView != null && haveState && (!isBFT || /* currentProof != null || */
appStateOnly)) {
LOGGER.info("---- RECEIVED VALID STATE ----");
LOGGER.info("(TOMLayer.SMReplyDeliver) The state of those replies is good!");
LOGGER.info("(TOMLayer.SMReplyDeliver) CID State requested: {}", reply.getCID());
LOGGER.info("(TOMLayer.SMReplyDeliver) CID State received: {}", stateUpper.getLastCID());
if (currentRegency > tomLayer.getSynchronizer().getLCManager().getCurrentRegency().getId()) {
tomLayer.getSynchronizer().getLCManager().jumpToRegency(new LeaderRegency(currentLeader, currentRegency));
tomLayer.execManager.setNewLeader(currentLeader);
}
// one
if (currentRegency > 0)
tomLayer.getSynchronizer().removeSTOPretransmissions(currentRegency - 1);
LOGGER.debug("trying to acquire deliverlock");
dt.deliverLock();
LOGGER.debug("acquired");
// this makes the isRetrievingState() evaluates to false
waitingCID = -1;
dt.update(stateUpper);
// synchronization phase
if (!appStateOnly && execManager.stopped()) {
Queue<ConsensusMessage> stoppedMsgs = execManager.getStoppedMsgs();
for (ConsensusMessage stopped : stoppedMsgs) {
if (stopped.getNumber() > state.getLastCID())
execManager.addOutOfContextMessage(stopped);
}
execManager.clearStopped();
execManager.restart();
}
LOGGER.info("Processing out of context messages");
tomLayer.processOutOfContext();
if (topology.getCurrentViewId() != currentView.getId()) {
LOGGER.info("Installing current view!");
topology.reconfigureTo(currentView);
}
isInitializing = false;
dt.canDeliver();
dt.deliverUnlock();
reset();
LOGGER.info("I updated the state!");
// tomLayer.requestsTimer.startTimer();
if (stateTimer != null)
stateTimer.cancel();
if (appStateOnly) {
appStateOnly = false;
tomLayer.getSynchronizer().resumeLC();
}
} else if (state == null && (topology.getCurrentViewN() / 2) < getReplies()) {
LOGGER.error("---- DIDNT RECEIVE STATE ----");
LOGGER.error("(TOMLayer.SMReplyDeliver) I have more than {} messages that are no good!", (topology.getCurrentViewN() / 2));
waitingCID = -1;
reset();
if (stateTimer != null)
stateTimer.cancel();
if (appStateOnly) {
requestState();
}
} else if (!haveState) {
LOGGER.error("---- RECEIVED INVALID STATE ----");
LOGGER.error("(TOMLayer.SMReplyDeliver) The replica from which I expected the state, sent one which doesn't match the hash of the others, or it never sent it at all");
reset();
requestState();
if (stateTimer != null)
stateTimer.cancel();
}
}
}
}
lockTimer.unlock();
}
Aggregations