auto add_node()

in src/node/rpc/node_frontend.h [181:312]


    auto add_node(
      kv::Tx& tx,
      const std::vector<uint8_t>& node_der,
      const JoinNetworkNodeToNode::In& in,
      NodeStatus node_status,
      ServiceStatus service_status,
      ReconfigurationType reconfiguration_type)
    {
      auto nodes = tx.rw(network.nodes);
      auto node_endorsed_certificates =
        tx.rw(network.node_endorsed_certificates);
      auto config = tx.ro(network.config)->get();

      auto conflicting_node_id =
        check_conflicting_node_network(tx, in.node_info_network);
      if (conflicting_node_id.has_value())
      {
        return make_error(
          HTTP_STATUS_BAD_REQUEST,
          ccf::errors::NodeAlreadyExists,
          fmt::format(
            "A node with the same node address {} already exists "
            "(node id: {}).",
            in.node_info_network.node_to_node_interface.bind_address,
            conflicting_node_id.value()));
      }

      auto pubk_der = crypto::public_key_der_from_cert(node_der);
      NodeId joining_node_id = compute_node_id_from_pubk_der(pubk_der);

      CodeDigest code_digest;

#ifdef GET_QUOTE
      QuoteVerificationResult verify_result =
        this->context.get_node_state().verify_quote(
          tx, in.quote_info, pubk_der, code_digest);
      if (verify_result != QuoteVerificationResult::Verified)
      {
        const auto [code, message] = quote_verification_error(verify_result);
        return make_error(code, ccf::errors::InvalidQuote, message);
      }
#else
      LOG_INFO_FMT("Skipped joining node quote verification");
#endif

      std::optional<kv::Version> ledger_secret_seqno = std::nullopt;
      if (
        node_status == NodeStatus::TRUSTED ||
        node_status == NodeStatus::LEARNER)
      {
        ledger_secret_seqno =
          this->network.ledger_secrets->get_latest(tx).first;
      }

      // Note: All new nodes should specify a CSR from 2.x
      auto client_public_key_pem = crypto::public_key_pem_from_cert(node_der);
      if (in.certificate_signing_request.has_value())
      {
        // Verify that client's public key matches the one specified in the CSR
        auto csr_public_key_pem = crypto::public_key_pem_from_csr(
          in.certificate_signing_request.value());
        if (client_public_key_pem != csr_public_key_pem)
        {
          return make_error(
            HTTP_STATUS_BAD_REQUEST,
            ccf::errors::CSRPublicKeyInvalid,
            "Public key in CSR does not match TLS client identity.");
        }
      }

      NodeInfo node_info = {
        in.node_info_network,
        in.quote_info,
        in.public_encryption_key,
        node_status,
        ledger_secret_seqno,
        ds::to_hex(code_digest.data),
        in.certificate_signing_request,
        client_public_key_pem};

      // Because the certificate signature scheme is non-deterministic, only
      // self-signed node certificate is recorded in the node info table
      if (this->network.consensus_type == ConsensusType::BFT)
      {
        node_info.cert = crypto::cert_der_to_pem(node_der);
      }

      nodes->put(joining_node_id, node_info);

      LOG_INFO_FMT("Node {} added as {}", joining_node_id, node_status);

      JoinNetworkNodeToNode::Out rep;
      rep.node_status = node_status;
      rep.node_id = joining_node_id;

      if (
        node_status == NodeStatus::TRUSTED ||
        node_status == NodeStatus::LEARNER)
      {
        // Joining node only submit a CSR from 2.x
        std::optional<crypto::Pem> endorsed_certificate = std::nullopt;
        if (
          in.certificate_signing_request.has_value() &&
          this->network.consensus_type == ConsensusType::CFT)
        {
          // For a pre-open service, extract the validity period of self-signed
          // node certificate and use it verbatim in endorsed certificate
          auto [valid_from, valid_to] =
            crypto::make_verifier(node_der)->validity_period();
          endorsed_certificate = crypto::create_endorsed_cert(
            in.certificate_signing_request.value(),
            valid_from,
            valid_to,
            this->network.identity->priv_key,
            this->network.identity->cert);

          node_endorsed_certificates->put(
            joining_node_id, {endorsed_certificate.value()});
        }

        rep.network_info = JoinNetworkNodeToNode::Out::NetworkInfo{
          context.get_node_state().is_part_of_public_network(),
          context.get_node_state().get_last_recovered_signed_idx(),
          this->network.consensus_type,
          reconfiguration_type,
          this->network.ledger_secrets->get(tx),
          *this->network.identity.get(),
          service_status,
          endorsed_certificate};
      }
      return make_success(rep);
    }