Search in sources :

Example 1 with TOMMessage

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();
    }
}
Also used : TOMMessage(bftsmart.tom.core.messages.TOMMessage) ReconfigureReply(bftsmart.reconfiguration.ReconfigureReply) View(bftsmart.reconfiguration.views.View)

Example 2 with TOMMessage

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);
        }
    }
}
Also used : TOMMessage(bftsmart.tom.core.messages.TOMMessage)

Example 3 with TOMMessage

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;
}
Also used : TOMMessage(bftsmart.tom.core.messages.TOMMessage) ConsensusMessage(bftsmart.consensus.messages.ConsensusMessage) CertifiedDecision(bftsmart.tom.leaderchange.CertifiedDecision) BatchBuilder(bftsmart.tom.util.BatchBuilder) CommandsInfo(bftsmart.tom.server.defaultservices.CommandsInfo) LinkedList(java.util.LinkedList)

Example 4 with TOMMessage

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);
    }
}
Also used : TOMMessage(bftsmart.tom.core.messages.TOMMessage) PrivateKey(java.security.PrivateKey) HashMap(java.util.HashMap) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) ObjectOutputStream(java.io.ObjectOutputStream) InvalidKeyException(java.security.InvalidKeyException) Mac(javax.crypto.Mac) SecretKey(javax.crypto.SecretKey)

Example 5 with TOMMessage

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");
    }
}
Also used : TOMMessage(bftsmart.tom.core.messages.TOMMessage) SingleExecutable(bftsmart.tom.server.SingleExecutable) ArrayList(java.util.ArrayList) BatchExecutable(bftsmart.tom.server.BatchExecutable)

Aggregations

TOMMessage (bftsmart.tom.core.messages.TOMMessage)72 IOException (java.io.IOException)12 ConsensusMessage (bftsmart.consensus.messages.ConsensusMessage)10 ByteArrayOutputStream (java.io.ByteArrayOutputStream)10 LCMessage (bftsmart.tom.leaderchange.LCMessage)8 View (bftsmart.reconfiguration.views.View)7 CertifiedDecision (bftsmart.tom.leaderchange.CertifiedDecision)7 ByteArrayInputStream (java.io.ByteArrayInputStream)7 LinkedList (java.util.LinkedList)7 BatchReader (bftsmart.tom.util.BatchReader)6 ObjectOutputStream (java.io.ObjectOutputStream)6 Entry (java.util.Map.Entry)6 DataInputStream (java.io.DataInputStream)5 ArrayList (java.util.ArrayList)5 BatchBuilder (bftsmart.tom.util.BatchBuilder)4 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)4 HashMap (java.util.HashMap)4 Consensus (bftsmart.consensus.Consensus)3 ForwardedMessage (bftsmart.tom.core.messages.ForwardedMessage)3 CollectData (bftsmart.tom.leaderchange.CollectData)3