Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Enhance gRPC TLS by Dynamic Certificate Retrieval #2718

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

ivaylogarnev-limechain
Copy link
Contributor

@ivaylogarnev-limechain ivaylogarnev-limechain commented Dec 13, 2024

Description:
This PR fixes an issue where the Hedera SDK fails to establish secure connections with nodes whose certificates are not included in the NODE_CERT.js file. It enhances the SDK to dynamically retrieve and validate certificates during the TLS handshake, ensuring secure communication with all nodes on mainnet, testnet, and previewnet.

Related issue(s):
#2717

Checklist

  • Documented (Code comments, README, etc.)
  • Tested (unit, integration, etc.)

@ivaylogarnev-limechain ivaylogarnev-limechain changed the title bug: Added dynamically retrieving for the gRPC certifications chore: Added dynamically retrieving for the gRPC certifications Dec 13, 2024
@ivaylogarnev-limechain ivaylogarnev-limechain changed the title chore: Added dynamically retrieving for the gRPC certifications chore: Enhance gRPC TLS by Dynamic Certificate Retrieval Dec 13, 2024
@ivaylogarnev-limechain ivaylogarnev-limechain marked this pull request as ready for review December 13, 2024 13:38
Copy link
Contributor

@0xivanov 0xivanov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GJ, just some clarification questions.

// TESTNET
"34.94.106.61:50211": "0.0.3",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why remove the ports

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue arises from this part of the code:

new GrpcServicesError(
   GrpcStatus.Timeout,
   ALL_NETWORK_IPS[this.nodeIp],
),

A client requested that we display which node the failure occurs on. Previously, this wasn't working for both TLS and non-TLS scenarios due to differing ports. Now, we are only comparing the IP addresses to address this.

* @returns {Promise<void>}
*/
async _initializeClient() {
if (clientCache[this.address]) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if i have 1 client executing 2 transactions, the flow will get through here 2 times, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep and since we have caching in place, it will check if the client is already in the cache and return the cached client instead of going through the entire flow again.

*/
async _retrieveCertificate(address) {
if (certificateCache[address]) {
return certificateCache[address];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we have the cert in the cache, it will not return a Promise, but the String?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that's correct.

this._client.close();
if (this._client) {
this._client.close();
delete clientCache[this.address];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not clean the cert cache as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good question, I might have forgotten about it. I'll make sure to clean the cert as well.

/** @type {{ [key: string]: string }} */
const certificateCache = {};
/** @type {{ [key: string]: Client }} */
const clientCache = {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the clientCache? If we have the cert in cache, the only step we skip with the addition of the clientCache is security = credentials.createSsl(certificate); OR security = credentials.createInsecure();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, by using the clientCache, we essentially skip the entire _initializeClient process. As you mentioned, the main logic is around creating the security credentials. However, I don't think it's a significant overhead, so keeping the clientCache makes sense as it helps skip even that small step.

Copy link

sonarcloud bot commented Dec 16, 2024

Quality Gate Failed Quality Gate failed

Failed conditions
98 Security Hotspots

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants