Skip to content

Commit

Permalink
feat: Added Integration Test for NodeCreateTransaction and FQDN suppo…
Browse files Browse the repository at this point in the history
…rt (#787)

Signed-off-by: gsstoykov <[email protected]>
  • Loading branch information
gsstoykov authored Oct 16, 2024
1 parent 35bc1a9 commit 32e7eb8
Show file tree
Hide file tree
Showing 10 changed files with 293 additions and 14 deletions.
4 changes: 2 additions & 2 deletions HederaApi.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
set(HAPI_LIBRARY_HASH "46507656510baa279f3ce6d94e0044ef47128ba051467a3748ed55e6cb779db3" CACHE STRING "Use the configured hash to verify the Hedera API protobuf library release")
set(HAPI_LIBRARY_URL "https://github.com/hashgraph/hedera-protobufs-cpp/releases/download/v0.54.0/hapi-library-bb992044.tar.gz" CACHE STRING "Use the configured URL to download the Hedera API protobuf library package")
set(HAPI_LIBRARY_HASH "248299d525ec55425b755565726fc40a9bb9aa8335447f7c07956c9ace1ef64c" CACHE STRING "Use the configured hash to verify the Hedera API protobuf library release")
set(HAPI_LIBRARY_URL "https://github.com/hashgraph/hedera-protobufs-cpp/releases/download/v0.55.0/hapi-library-32c2a4a2.tar.gz" CACHE STRING "Use the configured URL to download the Hedera API protobuf library package")

set(HAPI_LOCAL_LIBRARY_PATH "" CACHE STRING "Overrides the configured HAPI_LIBRARY_URL setting and instead uses the local path to retrieve the artifacts")

Expand Down
9 changes: 8 additions & 1 deletion src/sdk/main/include/IPv4Address.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,18 @@ class IPv4Address
*/
[[nodiscard]] std::string toString() const;

/**
* Check if the IPV4Address is empty.
*
* @return The boolean representation of an IPV4Address empty state.
*/
[[nodiscard]] bool isEmpty() const;

private:
/**
* The four octets of the address.
*/
std::array<std::byte, 4> mAddress;
std::vector<std::byte> mAddress;
};

} // namespace Hedera
Expand Down
97 changes: 96 additions & 1 deletion src/sdk/main/include/Status.h
Original file line number Diff line number Diff line change
Expand Up @@ -1596,7 +1596,102 @@ enum class Status
* The client SHOULD query mirror node to determine the status of the pending
* airdrop and whether the sender can fulfill the offer.
*/
INVALID_TOKEN_IN_PENDING_AIRDROP
INVALID_TOKEN_IN_PENDING_AIRDROP,

/**
* A transaction failed because the consensus node identified is
* deleted from the address book.
*/
NODE_DELETED,

/**
* A transaction failed because the consensus node identified is not valid or
* does not exist in state.
*/
INVALID_NODE_ID,

/**
* A transaction failed because one or more entries in the list of
* service endpoints for the `gossip_endpoint` field is invalid.<br/>
* The most common cause for this response is a service endpoint that has
* the domain name (DNS) set rather than address and port.
*/
INVALID_GOSSIP_ENDPOINT,

/**
* A transaction failed because the node account identifier provided
* does not exist or is not valid.<br/>
* One common source of this error is providing a node account identifier
* using the "alias" form rather than "numeric" form.
*/
INVALID_NODE_ACCOUNT_ID,

/**
* A transaction failed because the description field cannot be encoded
* as UTF-8 or is more than 100 bytes when encoded.
*/
INVALID_NODE_DESCRIPTION,

/**
* A transaction failed because one or more entries in the list of
* service endpoints for the `service_endpoint` field is invalid.<br/>
* The most common cause for this response is a service endpoint that has
* the domain name (DNS) set rather than address and port.
*/
INVALID_SERVICE_ENDPOINT,

/**
* A transaction failed because the TLS certificate provided for the
* node is missing or invalid.<br/>
* The certificate MUST be a TLS certificate of a type permitted for gossip
* signatures.<br/>
* The value presented MUST be a UTF-8 NFKD encoding of the TLS
* certificate.<br/>
* The certificate encoded MUST be in PEM format.<br/>
* The `gossip_ca_certificate` field is REQUIRED and MUST NOT be empty.
*/
INVALID_GOSSIP_CA_CERTIFICATE,

/**
* A transaction failed because the hash provided for the gRPC certificate
* is present but invalid.<br/>
* The `grpc_certificate_hash` MUST be a SHA-384 hash.<br/>
* The input hashed MUST be a UTF-8 NFKD encoding of the actual TLS
* certificate.<br/>
* The certificate to be encoded MUST be in PEM format.
*/
INVALID_GRPC_CERTIFICATE,

/**
* The maximum number of nodes allowed in the address book have been created.
*/
MAX_NODES_CREATED,

/**
* In ServiceEndpoint, domain_name and ipAddressV4 are mutually exclusive
*/
IP_FQDN_CANNOT_BE_SET_FOR_SAME_ENDPOINT,

/**
* Fully qualified domain name is not allowed in gossip_endpoint
*/
GOSSIP_ENDPOINT_CANNOT_HAVE_FQDN,

/**
* In ServiceEndpoint, domain_name size too large
*/
FQDN_SIZE_TOO_LARGE,

/**
* ServiceEndpoint is invalid
*/
INVALID_ENDPOINT,

/**
* The number of gossip endpoints exceeds the limit
*/
GOSSIP_ENDPOINTS_EXCEEDED_LIMIT

};

/**
Expand Down
6 changes: 6 additions & 0 deletions src/sdk/main/include/impl/Node.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#ifndef HEDERA_SDK_CPP_IMPL_NODE_H_
#define HEDERA_SDK_CPP_IMPL_NODE_H_

#include <proto/address_book_service.grpc.pb.h>
#include <proto/consensus_service.grpc.pb.h>
#include <proto/crypto_service.grpc.pb.h>
#include <proto/file_service.grpc.pb.h>
Expand Down Expand Up @@ -236,6 +237,11 @@ class Node : public BaseNode<Node, AccountId>
*/
std::unique_ptr<proto::UtilService::Stub> mUtilStub = nullptr;

/**
* Pointer to the gRPC stub used to communicate with the address book service living on the remote node.
*/
std::unique_ptr<proto::AddressBookService::Stub> mAddressBookStub = nullptr;

/**
* The AccountId that runs the remote node represented by this Node.
*/
Expand Down
9 changes: 8 additions & 1 deletion src/sdk/main/src/Endpoint.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,14 @@ std::unique_ptr<proto::ServiceEndpoint> Endpoint::toProtobuf() const
//-----
std::string Endpoint::toString() const
{
return mAddress.toString() + ':' + std::to_string(mPort);
if (!mAddress.isEmpty())
{
return mAddress.toString() + ':' + std::to_string(mPort);
}
else
{
return mDomainName + ':' + std::to_string(mPort);
}
}

//-----
Expand Down
31 changes: 25 additions & 6 deletions src/sdk/main/src/IPv4Address.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*
*/
#include "IPv4Address.h"
#include "exceptions/IllegalStateException.h"

#include <stdexcept>

Expand All @@ -32,23 +33,41 @@ IPv4Address IPv4Address::fromBytes(const std::vector<std::byte>& bytes)
}

IPv4Address iPv4Address;
std::copy(bytes.cbegin(), bytes.cend(), iPv4Address.mAddress.begin());

for (const auto& byte : bytes)
{
iPv4Address.mAddress.push_back(byte);
}
return iPv4Address;
}

//-----
std::vector<std::byte> IPv4Address::toBytes() const
{
return { mAddress.at(0), mAddress.at(1), mAddress.at(2), mAddress.at(3) };
return mAddress;
}

//-----
std::string IPv4Address::toString() const
{
return std::to_string(std::to_integer<unsigned char>(mAddress.at(0))) + '.' +
std::to_string(std::to_integer<unsigned char>(mAddress.at(1))) + '.' +
std::to_string(std::to_integer<unsigned char>(mAddress.at(2))) + '.' +
std::to_string(std::to_integer<unsigned char>(mAddress.at(3)));
if (mAddress.size() != 4)
{
throw IllegalStateException("Incorrect byte array size, should be 4 bytes but is " +
std::to_string(mAddress.size()));
}
else
{
return std::to_string(std::to_integer<unsigned char>(mAddress.at(0))) + '.' +
std::to_string(std::to_integer<unsigned char>(mAddress.at(1))) + '.' +
std::to_string(std::to_integer<unsigned char>(mAddress.at(2))) + '.' +
std::to_string(std::to_integer<unsigned char>(mAddress.at(3)));
}
}

//-----
bool IPv4Address::isEmpty() const
{
return mAddress.empty();
}

} // namespace Hedera
50 changes: 47 additions & 3 deletions src/sdk/main/src/Status.cc
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,22 @@ const std::unordered_map<proto::ResponseCodeEnum, Status> gProtobufResponseCodeT
{ proto::ResponseCodeEnum::THROTTLED_AT_CONSENSUS, Status::THROTTLED_AT_CONSENSUS },
{ proto::ResponseCodeEnum::INVALID_PENDING_AIRDROP_ID, Status::INVALID_PENDING_AIRDROP_ID },
{ proto::ResponseCodeEnum::TOKEN_AIRDROP_WITH_FALLBACK_ROYALTY, Status::TOKEN_AIRDROP_WITH_FALLBACK_ROYALTY },
{ proto::ResponseCodeEnum::INVALID_TOKEN_IN_PENDING_AIRDROP, Status::INVALID_TOKEN_IN_PENDING_AIRDROP }
{ proto::ResponseCodeEnum::INVALID_TOKEN_IN_PENDING_AIRDROP, Status::INVALID_TOKEN_IN_PENDING_AIRDROP },
{ proto::ResponseCodeEnum::NODE_DELETED, Status::NODE_DELETED },
{ proto::ResponseCodeEnum::INVALID_NODE_ID, Status::INVALID_NODE_ID },
{ proto::ResponseCodeEnum::INVALID_GOSSIP_ENDPOINT, Status::INVALID_GOSSIP_ENDPOINT },
{ proto::ResponseCodeEnum::INVALID_NODE_ACCOUNT_ID, Status::INVALID_NODE_ACCOUNT_ID },
{ proto::ResponseCodeEnum::INVALID_NODE_DESCRIPTION, Status::INVALID_NODE_DESCRIPTION },
{ proto::ResponseCodeEnum::INVALID_SERVICE_ENDPOINT, Status::INVALID_SERVICE_ENDPOINT },
{ proto::ResponseCodeEnum::INVALID_GOSSIP_CA_CERTIFICATE, Status::INVALID_GOSSIP_CA_CERTIFICATE },
{ proto::ResponseCodeEnum::INVALID_GRPC_CERTIFICATE, Status::INVALID_GRPC_CERTIFICATE },
{ proto::ResponseCodeEnum::MAX_NODES_CREATED, Status::MAX_NODES_CREATED },
{ proto::ResponseCodeEnum::IP_FQDN_CANNOT_BE_SET_FOR_SAME_ENDPOINT,
Status::IP_FQDN_CANNOT_BE_SET_FOR_SAME_ENDPOINT },
{ proto::ResponseCodeEnum::GOSSIP_ENDPOINT_CANNOT_HAVE_FQDN, Status::GOSSIP_ENDPOINT_CANNOT_HAVE_FQDN },
{ proto::ResponseCodeEnum::FQDN_SIZE_TOO_LARGE, Status::FQDN_SIZE_TOO_LARGE },
{ proto::ResponseCodeEnum::INVALID_ENDPOINT, Status::INVALID_ENDPOINT },
{ proto::ResponseCodeEnum::GOSSIP_ENDPOINTS_EXCEEDED_LIMIT, Status::GOSSIP_ENDPOINTS_EXCEEDED_LIMIT }
};

//-----
Expand Down Expand Up @@ -672,7 +687,22 @@ const std::unordered_map<Status, proto::ResponseCodeEnum> gStatusToProtobufRespo
{ Status::THROTTLED_AT_CONSENSUS, proto::ResponseCodeEnum::THROTTLED_AT_CONSENSUS },
{ Status::INVALID_PENDING_AIRDROP_ID, proto::ResponseCodeEnum::INVALID_PENDING_AIRDROP_ID },
{ Status::TOKEN_AIRDROP_WITH_FALLBACK_ROYALTY, proto::ResponseCodeEnum::TOKEN_AIRDROP_WITH_FALLBACK_ROYALTY },
{ Status::INVALID_TOKEN_IN_PENDING_AIRDROP, proto::ResponseCodeEnum::INVALID_TOKEN_IN_PENDING_AIRDROP }
{ Status::INVALID_TOKEN_IN_PENDING_AIRDROP, proto::ResponseCodeEnum::INVALID_TOKEN_IN_PENDING_AIRDROP },
{ Status::NODE_DELETED, proto::ResponseCodeEnum::NODE_DELETED },
{ Status::INVALID_NODE_ID, proto::ResponseCodeEnum::INVALID_NODE_ID },
{ Status::INVALID_GOSSIP_ENDPOINT, proto::ResponseCodeEnum::INVALID_GOSSIP_ENDPOINT },
{ Status::INVALID_NODE_ACCOUNT_ID, proto::ResponseCodeEnum::INVALID_NODE_ACCOUNT_ID },
{ Status::INVALID_NODE_DESCRIPTION, proto::ResponseCodeEnum::INVALID_NODE_DESCRIPTION },
{ Status::INVALID_SERVICE_ENDPOINT, proto::ResponseCodeEnum::INVALID_SERVICE_ENDPOINT },
{ Status::INVALID_GOSSIP_CA_CERTIFICATE, proto::ResponseCodeEnum::INVALID_GOSSIP_CA_CERTIFICATE },
{ Status::INVALID_GRPC_CERTIFICATE, proto::ResponseCodeEnum::INVALID_GRPC_CERTIFICATE },
{ Status::MAX_NODES_CREATED, proto::ResponseCodeEnum::MAX_NODES_CREATED },
{ Status::IP_FQDN_CANNOT_BE_SET_FOR_SAME_ENDPOINT,
proto::ResponseCodeEnum::IP_FQDN_CANNOT_BE_SET_FOR_SAME_ENDPOINT },
{ Status::GOSSIP_ENDPOINT_CANNOT_HAVE_FQDN, proto::ResponseCodeEnum::GOSSIP_ENDPOINT_CANNOT_HAVE_FQDN },
{ Status::FQDN_SIZE_TOO_LARGE, proto::ResponseCodeEnum::FQDN_SIZE_TOO_LARGE },
{ Status::INVALID_ENDPOINT, proto::ResponseCodeEnum::INVALID_ENDPOINT },
{ Status::GOSSIP_ENDPOINTS_EXCEEDED_LIMIT, proto::ResponseCodeEnum::GOSSIP_ENDPOINTS_EXCEEDED_LIMIT }
};

//-----
Expand Down Expand Up @@ -980,7 +1010,21 @@ const std::unordered_map<Status, std::string> gStatusToString = {
{ Status::THROTTLED_AT_CONSENSUS, "THROTTLED_AT_CONSENSUS" },
{ Status::INVALID_PENDING_AIRDROP_ID, "INVALID_PENDING_AIRDROP_ID" },
{ Status::TOKEN_AIRDROP_WITH_FALLBACK_ROYALTY, "TOKEN_AIRDROP_WITH_FALLBACK_ROYALTY" },
{ Status::INVALID_TOKEN_IN_PENDING_AIRDROP, "INVALID_TOKEN_IN_PENDING_AIRDROP" }
{ Status::INVALID_TOKEN_IN_PENDING_AIRDROP, "INVALID_TOKEN_IN_PENDING_AIRDROP" },
{ Status::NODE_DELETED, "NODE_DELETED" },
{ Status::INVALID_NODE_ID, "INVALID_NODE_ID" },
{ Status::INVALID_GOSSIP_ENDPOINT, "INVALID_GOSSIP_ENDPOINT" },
{ Status::INVALID_NODE_ACCOUNT_ID, "INVALID_NODE_ACCOUNT_ID" },
{ Status::INVALID_NODE_DESCRIPTION, "INVALID_NODE_DESCRIPTION" },
{ Status::INVALID_SERVICE_ENDPOINT, "INVALID_SERVICE_ENDPOINT" },
{ Status::INVALID_GOSSIP_CA_CERTIFICATE, "INVALID_GOSSIP_CA_CERTIFICATE" },
{ Status::INVALID_GRPC_CERTIFICATE, "INVALID_GRPC_CERTIFICATE" },
{ Status::MAX_NODES_CREATED, "MAX_NODES_CREATED" },
{ Status::IP_FQDN_CANNOT_BE_SET_FOR_SAME_ENDPOINT, "IP_FQDN_CANNOT_BE_SET_FOR_SAME_ENDPOINT" },
{ Status::GOSSIP_ENDPOINT_CANNOT_HAVE_FQDN, "GOSSIP_ENDPOINT_CANNOT_HAVE_FQDN" },
{ Status::FQDN_SIZE_TOO_LARGE, "FQDN_SIZE_TOO_LARGE" },
{ Status::INVALID_ENDPOINT, "INVALID_ENDPOINT" },
{ Status::GOSSIP_ENDPOINTS_EXCEEDED_LIMIT, "GOSSIP_ENDPOINTS_EXCEEDED_LIMIT" }
};

} // namespace Hedera
4 changes: 4 additions & 0 deletions src/sdk/main/src/impl/Node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ grpc::Status Node::submitTransaction(proto::TransactionBody::DataCase funcEnum,

switch (funcEnum)
{
case proto::TransactionBody::DataCase::kNodeCreate:
return mAddressBookStub->createNode(&context, transaction, response);
case proto::TransactionBody::DataCase::kConsensusCreateTopic:
return mConsensusStub->createTopic(&context, transaction, response);
case proto::TransactionBody::DataCase::kConsensusDeleteTopic:
Expand Down Expand Up @@ -286,6 +288,7 @@ void Node::initializeStubs()
if (!mSmartContractStub) mSmartContractStub = proto::SmartContractService::NewStub(getChannel());
if (!mTokenStub) mTokenStub = proto::TokenService::NewStub(getChannel());
if (!mUtilStub) mUtilStub = proto::UtilService::NewStub(getChannel());
if (!mAddressBookStub) mAddressBookStub = proto::AddressBookService::NewStub(getChannel());
// clang-format on
}

Expand All @@ -301,6 +304,7 @@ void Node::closeStubs()
mSmartContractStub = nullptr;
mTokenStub = nullptr;
mUtilStub = nullptr;
mAddressBookStub = nullptr;
}

} // namespace Hedera::internal
1 change: 1 addition & 0 deletions src/sdk/tests/integration/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ add_executable(${TEST_PROJECT_NAME}
JSONIntegrationTests.cc
MirrorNodeGatewayIntegrationTests.cc
NetworkVersionInfoQueryIntegrationTests.cc
NodeCreateTransactionIntegrationTests.cc
PrngTransactionIntegrationTests.cc
QueryIntegrationTests.cc
ScheduleCreateTransactionIntegrationTests.cc
Expand Down
Loading

0 comments on commit 32e7eb8

Please sign in to comment.