use of bftsmart.tom.core.messages.TOMMessage in project aware by bergerch.
the class ServiceProxy method invoke.
/**
* This method sends a request to the replicas, and returns the related reply.
* If the servers take more than invokeTimeout seconds the method returns null.
* This method is thread-safe.
*
* @param request Request to be sent
* @param reqType ORDERED_REQUEST/UNORDERED_REQUEST/UNORDERED_HASHED_REQUEST for normal requests, and RECONFIG for
* reconfiguration requests.
*
* @return The reply from the replicas related to request
*/
public byte[] invoke(byte[] request, TOMMessageType reqType) {
try {
canSendLock.lock();
// Clean all statefull data to prepare for receiving next replies
Arrays.fill(replies, null);
receivedReplies = 0;
response = null;
replyQuorum = getReplyQuorum();
// Send the request to the replicas, and get its ID
reqId = generateRequestId(reqType);
operationId = generateOperationId();
requestType = reqType;
replyServer = -1;
hashResponseController = null;
if (requestType == TOMMessageType.UNORDERED_HASHED_REQUEST) {
replyServer = getRandomlyServerId();
logger.debug("[" + this.getClass().getName() + "] replyServerId(" + replyServer + ") " + "pos(" + getViewManager().getCurrentViewPos(replyServer) + ")");
hashResponseController = new HashResponseController(getViewManager().getCurrentViewPos(replyServer), getViewManager().getCurrentViewProcesses().length);
TOMMessage sm = new TOMMessage(getProcessId(), getSession(), reqId, operationId, request, getViewManager().getCurrentViewId(), requestType);
sm.setReplyServer(replyServer);
TOMulticast(sm);
} else {
TOMulticast(request, reqId, operationId, reqType);
}
logger.debug("Sending request (" + reqType + ") with reqId=" + reqId);
logger.debug("Expected number of matching replies: " + replyQuorum);
// by the client side communication system
try {
if (reqType == TOMMessageType.UNORDERED_HASHED_REQUEST) {
if (!this.sm.tryAcquire(invokeUnorderedHashedTimeout, TimeUnit.SECONDS)) {
logger.info("######## UNORDERED HASHED REQUEST TIMOUT ########");
canSendLock.unlock();
return invoke(request, TOMMessageType.ORDERED_REQUEST);
}
} else {
if (!this.sm.tryAcquire(invokeTimeout, TimeUnit.SECONDS)) {
logger.info("###################TIMEOUT#######################");
logger.info("Reply timeout for reqId=" + reqId + ", Replies received: " + receivedReplies);
canSendLock.unlock();
return null;
}
}
} catch (InterruptedException ex) {
logger.error("Problem aquiring semaphore", ex);
}
logger.debug("Response extracted = " + response);
byte[] ret = null;
if (response == null) {
// the response can be null if n-f replies are received but there isn't
// a replyQuorum of matching replies
logger.debug("Received n-f replies and no response could be extracted.");
canSendLock.unlock();
if (reqType == TOMMessageType.UNORDERED_REQUEST || reqType == TOMMessageType.UNORDERED_HASHED_REQUEST) {
// invoke the operation again, whitout the read-only flag
logger.debug("###################RETRY#######################");
return invokeOrdered(request);
} else {
throw new RuntimeException("Received n-f replies without f+1 of them matching.");
}
} else {
// ******* EDUARDO BEGIN **************//
if (reqType == TOMMessageType.ORDERED_REQUEST) {
// Reply to a normal request!
if (response.getViewID() == getViewManager().getCurrentViewId()) {
// return the response
ret = response.getContent();
} else {
// if(response.getViewID() > getViewManager().getCurrentViewId())
// updated view received
reconfigureTo((View) TOMUtil.getObject(response.getContent()));
canSendLock.unlock();
return invoke(request, reqType);
}
} else if (reqType == TOMMessageType.UNORDERED_REQUEST || reqType == TOMMessageType.UNORDERED_HASHED_REQUEST) {
if (response.getViewID() == getViewManager().getCurrentViewId()) {
// return the response
ret = response.getContent();
} else {
canSendLock.unlock();
return invoke(request, TOMMessageType.ORDERED_REQUEST);
}
} else {
if (response.getViewID() > getViewManager().getCurrentViewId()) {
// Reply to a reconfigure request!
logger.debug("Reconfiguration request' reply received!");
Object r = TOMUtil.getObject(response.getContent());
if (r instanceof View) {
// did not executed the request because it is using an outdated view
reconfigureTo((View) r);
canSendLock.unlock();
return invoke(request, reqType);
} else if (r instanceof ReconfigureReply) {
// reconfiguration executed!
reconfigureTo(((ReconfigureReply) r).getView());
ret = response.getContent();
} else {
logger.debug("Unknown response type");
}
} else {
logger.debug("Unexpected execution flow");
}
}
}
return ret;
} finally {
// always release lock
if (canSendLock.isHeldByCurrentThread())
canSendLock.unlock();
}
}
use of bftsmart.tom.core.messages.TOMMessage in project aware by bergerch.
the class ServiceReplica method receiveReadonlyMessage.
/**
* @deprecated
*/
public final void receiveReadonlyMessage(TOMMessage message, MessageContext msgCtx) {
TOMMessage response;
// This is used to deliver the requests to the application and obtain a reply to deliver
// to the clients. The raw decision does not need to be delivered to the recoverable since
// it is not associated with any consensus instance, and therefore there is no need for
// applications to log it or keep any proof.
response = executor.executeUnordered(id, SVController.getCurrentViewId(), (message.getReqType() == TOMMessageType.UNORDERED_HASHED_REQUEST && message.getReplyServer() != this.id), message.getContent(), msgCtx);
if (response != null) {
if (SVController.getStaticConf().getNumRepliers() > 0) {
repMan.send(response);
} else {
cs.send(new int[] { response.getSender() }, response.reply);
}
}
}
use of bftsmart.tom.core.messages.TOMMessage in project aware by bergerch.
the class CSTState method getCertifiedDecision.
/**
* Retrieves the certified decision for the last consensus present in this object
* @param controller
* @return The certified decision for the last consensus present in this object
*/
@Override
public CertifiedDecision getCertifiedDecision(ServerViewController controller) {
CommandsInfo ci = getMessageBatch(getLastCID());
if (ci != null && ci.msgCtx[0].getProof() != null) {
// do I have a proof for the consensus?
Set<ConsensusMessage> proof = ci.msgCtx[0].getProof();
LinkedList<TOMMessage> requests = new LinkedList<>();
// Recreate all TOMMessages ordered in the consensus
for (int i = 0; i < ci.commands.length; i++) {
requests.add(ci.msgCtx[i].recreateTOMMessage(ci.commands[i]));
}
// Serialize the TOMMessages to re-create the proposed value
BatchBuilder bb = new BatchBuilder(0);
byte[] value = bb.makeBatch(requests, ci.msgCtx[0].getNumOfNonces(), ci.msgCtx[0].getSeed(), ci.msgCtx[0].getTimestamp(), controller.getStaticConf().getUseSignatures() == 1);
// Assemble and return the certified decision
return new CertifiedDecision(pid, getLastCID(), value, proof);
} else
// there was no proof for the consensus
return null;
}
use of bftsmart.tom.core.messages.TOMMessage in project aware by bergerch.
the class Acceptor method insertProof.
/**
* Create a cryptographic proof for a consensus message
*
* This method modifies the consensus message passed as an argument,
* so that it contains a cryptographic proof.
*
* @param cm The consensus message to which the proof shall be set
* @param epoch The epoch during in which the consensus message was created
*/
private void insertProof(ConsensusMessage cm, TOMMessage[] msgs) {
ByteArrayOutputStream bOut = new ByteArrayOutputStream(248);
try {
ObjectOutputStream obj = new ObjectOutputStream(bOut);
obj.writeObject(cm);
obj.flush();
bOut.flush();
} catch (IOException ex) {
logger.error("Failed to serialize consensus message", ex);
}
byte[] data = bOut.toByteArray();
// check if consensus contains reconfiguration request
boolean hasReconf = false;
if (!controller.getStaticConf().getProofType().equalsIgnoreCase("signatures")) {
for (TOMMessage msg : msgs) {
if (msg.getReqType() == TOMMessageType.RECONFIG && msg.getViewID() == controller.getCurrentViewId()) {
hasReconf = true;
// no need to continue, exit the loop
break;
}
}
}
if (// if the library is configured to use signatures...
controller.getStaticConf().getProofType().equalsIgnoreCase("signatures") || hasReconf) {
// ... or if this consensus contains a reconfiguration request, we need to use
// signatures (there might be replicas that will not be part of the next
// consensus instance, and so their MAC will be outdated and useless)...
PrivateKey privKey = controller.getStaticConf().getPrivateKey();
byte[] signature = TOMUtil.signMessage(privKey, data);
cm.setProof(signature);
} else {
// ... otherwise, we must use MAC vectores
Mac mac = null;
try {
mac = TOMUtil.getMacFactory();
} catch (NoSuchAlgorithmException ex) {
logger.error("Failed to create MAC engine", ex);
return;
}
int[] processes = this.controller.getCurrentViewAcceptors();
HashMap<Integer, byte[]> macVector = new HashMap<>();
for (int id : processes) {
try {
SecretKey key = null;
do {
key = communication.getServersConn().getSecretKey(id);
if (key == null) {
logger.warn("I don't have yet a secret key with " + id + ". Retrying.");
Thread.sleep(1000);
}
} while (// JCS: This loop is to solve a race condition where a
key == null);
// replica might have already been inserted in the view or
// recovered after a crash, but it still did not concluded
// the diffie helman protocol. Not an elegant solution,
// but for now it will do
mac.init(key);
macVector.put(id, mac.doFinal(data));
} catch (InterruptedException ex) {
logger.error("Interruption while sleeping", ex);
} catch (InvalidKeyException ex) {
logger.error("Failed to generate MAC vector", ex);
}
}
cm.setProof(macVector);
}
}
use of bftsmart.tom.core.messages.TOMMessage in project aware by bergerch.
the class ServiceReplica method receiveMessages.
/**
* @deprecated
*/
public void receiveMessages(int[] consId, int[] regencies, int[] leaders, CertifiedDecision[] cDecs, TOMMessage[][] requests) {
int numRequests = 0;
int consensusCount = 0;
List<TOMMessage> toBatch = new ArrayList<>();
List<MessageContext> msgCtxts = new ArrayList<>();
boolean noop = true;
for (TOMMessage[] requestsFromConsensus : requests) {
TOMMessage firstRequest = requestsFromConsensus[0];
int requestCount = 0;
noop = true;
for (TOMMessage request : requestsFromConsensus) {
logger.debug("Processing TOMMessage from client " + request.getSender() + " with sequence number " + request.getSequence() + " for session " + request.getSession() + " decided in consensus " + consId[consensusCount]);
if (request.getViewID() == SVController.getCurrentViewId()) {
if (null == request.getReqType()) {
throw new RuntimeException("Should never reach here!");
} else
switch(request.getReqType()) {
case ORDERED_REQUEST:
noop = false;
numRequests++;
MessageContext msgCtx = new MessageContext(request.getSender(), request.getViewID(), request.getReqType(), request.getSession(), request.getSequence(), request.getOperationId(), request.getReplyServer(), request.serializedMessageSignature, firstRequest.timestamp, request.numOfNonces, request.seed, regencies[consensusCount], leaders[consensusCount], consId[consensusCount], cDecs[consensusCount].getConsMessages(), firstRequest, false);
if (requestCount + 1 == requestsFromConsensus.length) {
msgCtx.setLastInBatch();
}
request.deliveryTime = System.nanoTime();
if (executor instanceof BatchExecutable) {
logger.debug("Batching request from " + request.getSender());
// that are asking for a state transfer).
if (this.recoverer != null)
this.recoverer.Op(msgCtx.getConsensusId(), request.getContent(), msgCtx);
// deliver requests and contexts to the executor later
msgCtxts.add(msgCtx);
toBatch.add(request);
} else if (executor instanceof SingleExecutable) {
logger.debug("Delivering request from " + request.getSender() + " via SingleExecutable");
// that are asking for a state transfer).
if (this.recoverer != null)
this.recoverer.Op(msgCtx.getConsensusId(), request.getContent(), msgCtx);
// This is used to deliver the requests to the application and obtain a reply to deliver
// to the clients. The raw decision is passed to the application in the line above.
TOMMessage response = ((SingleExecutable) executor).executeOrdered(id, SVController.getCurrentViewId(), request.getContent(), msgCtx);
if (response != null) {
logger.debug("sending reply to " + response.getSender());
replier.manageReply(response, msgCtx);
}
} else {
// this code should never be executed
throw new UnsupportedOperationException("Non-existent interface");
}
break;
case RECONFIG:
SVController.enqueueUpdate(request);
break;
default:
// this code should never be executed
throw new RuntimeException("Should never reach here!");
}
} else if (request.getViewID() < SVController.getCurrentViewId()) {
// message sender had an old view, resend the message to
// him (but only if it came from consensus an not state transfer)
tomLayer.getCommunication().send(new int[] { request.getSender() }, new TOMMessage(SVController.getStaticConf().getProcessId(), request.getSession(), request.getSequence(), request.getOperationId(), TOMUtil.getBytes(SVController.getCurrentView()), SVController.getCurrentViewId(), request.getReqType()));
}
requestCount++;
}
// hence the invocation of "noop"
if (noop && this.recoverer != null) {
logger.debug("Delivering a no-op to the recoverer");
logger.info("A consensus instance finished, but there were no commands to deliver to the application.");
logger.info("Notifying recoverable about a blank consensus.");
byte[][] batch = null;
MessageContext[] msgCtx = null;
if (requestsFromConsensus.length > 0) {
// Make new batch to deliver
batch = new byte[requestsFromConsensus.length][];
msgCtx = new MessageContext[requestsFromConsensus.length];
// Put messages in the batch
int line = 0;
for (TOMMessage m : requestsFromConsensus) {
batch[line] = m.getContent();
msgCtx[line] = new MessageContext(m.getSender(), m.getViewID(), m.getReqType(), m.getSession(), m.getSequence(), m.getOperationId(), m.getReplyServer(), m.serializedMessageSignature, firstRequest.timestamp, m.numOfNonces, m.seed, regencies[consensusCount], leaders[consensusCount], consId[consensusCount], cDecs[consensusCount].getConsMessages(), firstRequest, true);
msgCtx[line].setLastInBatch();
line++;
}
}
this.recoverer.noOp(consId[consensusCount], batch, msgCtx);
// MessageContext msgCtx = new MessageContext(-1, -1, null, -1, -1, -1, -1, null, // Since it is a noop, there is no need to pass info about the client...
// -1, 0, 0, regencies[consensusCount], leaders[consensusCount], consId[consensusCount], cDecs[consensusCount].getConsMessages(), //... but there is still need to pass info about the consensus
// null, true); // there is no command that is the first of the batch, since it is a noop
// msgCtx.setLastInBatch();
// this.recoverer.noOp(msgCtx.getConsensusId(), msgCtx);
}
consensusCount++;
}
if (executor instanceof BatchExecutable && numRequests > 0) {
// Make new batch to deliver
byte[][] batch = new byte[numRequests][];
// Put messages in the batch
int line = 0;
for (TOMMessage m : toBatch) {
batch[line] = m.getContent();
line++;
}
MessageContext[] msgContexts = new MessageContext[msgCtxts.size()];
msgContexts = msgCtxts.toArray(msgContexts);
// Deliver the batch and wait for replies
TOMMessage[] replies = ((BatchExecutable) executor).executeBatch(id, SVController.getCurrentViewId(), batch, msgContexts);
// Send the replies back to the client
if (replies != null) {
for (TOMMessage reply : replies) {
if (SVController.getStaticConf().getNumRepliers() > 0) {
logger.debug("Sending reply to " + reply.getSender() + " with sequence number " + reply.getSequence() + " and operation ID " + reply.getOperationId() + " via ReplyManager");
repMan.send(reply);
} else {
logger.debug("Sending reply to " + reply.getSender() + " with sequence number " + reply.getSequence() + " and operation ID " + reply.getOperationId());
replier.manageReply(reply, null);
// cs.send(new int[]{request.getSender()}, request.reply);
}
}
}
// DEBUG
logger.debug("BATCHEXECUTOR END");
}
}
Aggregations