export function getDocument()

in src/governance/ccf-app/js/src/endpoints/documents.ts [144:265]


export function getDocument(
  request: ccfapp.Request
): ccfapp.Response<GetDocumentResponse> | ccfapp.Response<ErrorResponse> {
  const id = request.params.documentId;

  // Check if the document is already accepted.
  if (acceptedDocumentsStore.has(id)) {
    const documentItem = acceptedDocumentsStore.get(id);
    const seqno = acceptedDocumentsStore.getVersionOfPreviousWrite(id);
    const view = ccf.consensus.getViewForSeqno(seqno);
    if (view == null) {
      return {
        statusCode: 503,
        body: new ErrorResponse(
          "ViewNotKnown",
          "View for given sequence number not known to the node at this time."
        )
      };
    }
    const version = view + "." + seqno;
    const finalVotes: { memberId: string; vote: boolean }[] = [];
    if (documentItem.finalVotes !== undefined) {
      for (const [memberId, vote] of Object.entries(documentItem.finalVotes)) {
        finalVotes.push({
          memberId: memberId,
          vote: vote === true ? true : false
        });
      }
    }

    const body: GetDocumentResponse = {
      id: id,
      version: version,
      state: "Accepted",
      contractId: documentItem.contractId,
      data: documentItem.data,
      proposalId: documentItem.proposalId,
      finalVotes: finalVotes
    };
    return { body };
  }

  // Check if the document is currently associated with an open proposal.
  let proposedDocument;
  proposalsStore.forEach((v, k) => {
    const proposal = ccf.bufToJsonCompatible(v) as ProposalStoreItem;
    proposal.actions.forEach((value) => {
      if (value.name === "set_document") {
        const args = value.args as SetDocumentArgs;
        if (args.documentId === id) {
          const proposalInfo = ccf.bufToJsonCompatible(
            proposalsInfoStore.get(k)
          ) as ProposalInfoItem;
          if (proposalInfo.state == "Open") {
            const body: GetDocumentResponse = {
              id: id,
              state: "Proposed",
              contractId: args.document.contractId,
              data: args.document.data,
              version: args.document.version,
              proposalId: k
            };

            proposedDocument = { body };
            return false; // break out of the loop.
          }
        }
      }
    });
  });

  if (proposedDocument != null) {
    return proposedDocument;
  }

  if (documentsStore.has(id)) {
    const documentItem = documentsStore.get(id);

    // Capture both seqno (version) and view to create version semantics.
    // Apart from getVersionOfPreviousWrite(key) we also want to call getViewForSeqno(seqno) to
    // get and incorporate the view into the version because the following situation could take place:
    // getVersionOfPreviousWrite(k) -> 5
    // Client goes to prepare write conditional on version being 5
    // Network rolls back to 3 after primary crashes, elects new leader
    // 4 and 5 happen, 5 unluckily writes to k also
    // Client request arrives, expects last write to be at 5, proceeds - but the value is now different
    // If you capture:
    // getVersionOfPreviousWrite(k) -> 5
    // getViewForSeqno(5) -> 2
    // And place (and check) the expectation that the last write for the key must be at 5 in view 2,
    // then this cannot happen.
    const seqno = documentsStore.getVersionOfPreviousWrite(id);
    const view = ccf.consensus.getViewForSeqno(seqno);
    if (view == null) {
      return {
        statusCode: 503,
        body: new ErrorResponse(
          "ViewNotKnown",
          "View for given sequence number not known to the node at this time."
        )
      };
    }
    const version = view + "." + seqno;
    const body: GetDocumentResponse = {
      id: id,
      state: "Draft",
      version: version,
      contractId: documentItem.contractId,
      data: documentItem.data,
      proposalId: ""
    };
    return { body };
  }

  return {
    statusCode: 404,
    body: new ErrorResponse(
      "DocumentNotFound",
      "A document with the specified id was not found."
    )
  };
}