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

docs: add configuration.md file #2687

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
311 changes: 311 additions & 0 deletions CONFIGURATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
# Introduction

The JS SDK package supports loading of configuration from an .env file or via the environment. You can use these environmental variables to configure the client. This document will explain the environmental variables needed and the client configuration.

# Table of content

- [Environment Variables](#environment-variables)
- [Required](#required)
- [ED25519 or ECDSA key](#ed25519-or-ecdsa-key)
- [Integration tests](#integration-tests)
- [Examples](#examples)
- [`fromStringDer`](#-fromstringder-)
- [Optional Parameters](#optional-parameters)
- [React Native Example](#react-native-example)
- [Simple REST Signature Provider](#simple-rest-signature-provider)
- [Which network to use?](#which-network-to-use-)
- [How to get my account keys and IDs?](#how-to-get-my-account-keys-and-ids-)
- [Local network](#local-network)
- [Testnet and previewnet](#testnet-and-previewnet)
- [Possible configuration issues](#possible-configuration-issues)
- [Should I have multiple .env files like .env.local, .env.production, .envdevelopment etc?](#should-i-have-multiple-env-files-like-envlocal--envproduction--envdevelopment-etc-)
- [Client Configuration](#client-configuration)
- [Network Configuration](#network-configuration)
- [Operator Settings](#operator-settings)
- [Transaction Settings](#transaction-settings)
- [Query Settings](#query-settings)
- [Retry and Timeout Settings](#retry-and-timeout-settings)
- [Node Management](#node-management)
- [Network Update Settings](#network-update-settings)
- [Logging](#logging)

# Environment Variables

## Required

| Name | Value | Example |
| -------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| OPERATOR_ID | Account ID of the operator account used to pay for transactions and queries | 0.0.12345 |
| OPERATOR_KEY | ED25519 private key of the operator account | 302e020100300506032b657004220420db484b828e64b2d8f12ce3c0a0e93a0b8cce7af1bb8f39c97732394482538e10 |
| HEDERA_NETWORK | Network to connect to: mainnet, testnet, previewnet, or localhost | localhost |

## ED25519 or ECDSA key

### Integration tests

For integration tests, an Ed25519 private key should be used. This is configured here. If you are using an ECDSA key, update the line as follows:

```javascript
const operatorKey = PrivateKey.fromStringECDSA(options.env.OPERATOR_KEY);
```

It's recomended to use ED25519 due to it's better speed and performance.

### Examples

The examples use both ED25519 and ECDSA keys. These examples come with a pre-filled .env file, so you generally don’t need to make changes. However, if you modify the .env file, ensure the correct type of private key is used.
Copy link
Contributor

Choose a reason for hiding this comment

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

I would emphasize the word .env either by bolding it or formatting it as code.


To verify which type of key is required, check the example code for the initialization method in the client/wallet. Look for either `fromStringED25519` or `fromStringECDSA`.

_Note that some examples (like the ones that interact with the relay) are designed to work only with ECDSA private keys. _
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe format error here?


#### `fromStringDer`

This example uses `fromString`, which internally calls `fromStringED25519`.

#### Optional Parameters

Certain examples simulate different actors in the network, such as Alice, Bob, or Treasury. These examples require additional environment variables, which are pre-configured in the .env file. Examples of such variables include:

- `ALICE_KEY`
- `BOB_KEY`
- `TREASURY_KEY`
- `ALICE_ID`
- `BOB_ID`
- `TREASURY_ID`

### React Native Example

This example uses `fromString`, which internally will try to execute the example with `fromStringED25519`.

### Simple REST Signature Provider

This example behaves the same as the React Native example.
Comment on lines +77 to +83
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider including the file path in the examples to make it easier for the user to navigate.


## Which network to use?

- The maintainers of this repository use `hedera-local-node` when running integration tests. Running integration tests on testnet costs far too much HBARs making it unsustainable.
- When running the examples, you can use any network of your choice. These examples are designed to demonstrate how a feature is intended to work and are optimized to function on any network you prefer.
- Unit tests do not require environment variables.

## How to get my account keys and IDs?

### Local network

If you have followed our best practices, such as using hedera-local-node for running integration tests, you can retrieve account keys and IDs when starting the local node. Upon startup, the local node generates accounts and displays their details.

You can copy one of these accounts and use its key and ID for the following:

- `OPERATOR_KEY` and `OPERATOR_ID`
- `ALICE_ID` and `ALICE_KEY`
- `BOB_ID` and `BOB_KEY`
- `TREASURY_ID` and `TREASURY_KEY`

### Testnet and previewnet

To run the examples on the testnet, you can obtain your account keys and IDs from the Hedera Portal Dashboard.

## Possible configuration issues

- The most common issue occurs when users mistakenly use an ED25519 key instead of an ECDSA key, or vice versa. Please verify that you are using the correct key type.
- Running unit tests while the local-node is active can disrupt multiple tests. Ensure the node is not running when executing tests.
- Occasionally, some tests may fail unexpectedly. However, rerunning them usually resolves the issue.
- If local-node has been inactive for a while, it might enter sleep mode. Restarting it is often necessary to rerun tests. This is not an SDK-related issue but is a frequently encountered scenario.
- Always use the `task install` command to install dependencies. Avoid manual installation with npm or yarn, as it can lead to configuration problems.

## Should I have multiple .env files like .env.local, .env.production, .envdevelopment etc?
Copy link
Contributor

Choose a reason for hiding this comment

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

You could give an example what we're doing here—adding environment variables for all networks, commenting out the ones not in use, and leaving only the one needed at the moment.


[Owner of dotenv says - no.](https://github.com/motdotla/dotenv#should-i-have-multiple-env-files)

# Client Configuration

## Network Configuration

- `setNetwork` - The method configures the network nodes that your client will communicate with on the Hedera network. It's a fundamental configuration step that determines which nodes will process your transactions and queries.

Example:

```javascript
const client = Client.forNetwork();
client.setNetwork({
"2.testnet.hedera.com:50211": new AccountId(0, 0, 5),
});
```

You can find the nodes addresses and their `AccountIds` here - `[mainnet](https://docs.hedera.com/hedera/networks/mainnet/mainnet-nodes), [testnet](https://docs.hedera.com/hedera/networks/testnet/testnet-nodes), [previewnet](https://docs.hedera.com/hedera/networks/testnet/testnet-nodes#preview-testnet-nodes).

- `setMirrorNetwork` - Configure the mirror nodes

```javascript
const client = Client.forNetwork();
client.setMirrorNode(["https://testnet.mirrornode.hedera.com"]);
```

- `setNetworkFromAddressBook` - Set network using address book response from the AddressBookQuery execution.

```javascript
const result = await new AddressBookQuery()
.setFileId(FileId.ADDRESS_BOOK)
.execute(client);

client = client.setNetworkFromAddressBook(result);
```

- `setLedgerId` - Set the network ledger ID (mainnet/testnet/previewnet)

```javascript
let client = Client.forNetwork().setLedgerId(LedgerId.PREVIEWNET);
```

or

```javascript
let client = Client.forNetwork().setLedgerId("previewnet");
```

- `setTransportSecurity` - The `setTransportSecurity` method in the Hedera JavaScript SDK is used to enable or disable transport security for the communication between the SDK and the Hedera network nodes. Transport security refers to the mechanisms used to secure the communication channel, typically involving encryption and authentication protocols.
When transport security is enabled, the SDK will establish a secure connection with the Hedera network nodes using protocols like Transport Layer Security (TLS) or its predecessor, Secure Sockets Layer (SSL). This ensures that the data transmitted between the SDK and the nodes is encrypted, protecting it from eavesdropping and tampering. It also provides authentication mechanisms to verify the identity of the nodes and prevent man-in-the-middle attacks.
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's specify that only TLS is being used because that is how it is currently implemented, avoiding any impression that we're uncertain about what is being used.


```javascript
const client = Client.forNetwork();
client.setTransportSecurity(true);
```

## Operator Settings

- `setOperator` - Set the operator account and private key. The operator is the account that will pay for the transactions the user executes.

```javascript
const operatorId = AccountId.fromString("...");
const operatorKey = PrivateKey.generateED25519();
let client = Client.forNetwork().setOperator(operatorId, operatorKey);
Copy link
Contributor

Choose a reason for hiding this comment

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

Use const for consistency across examples.

```

- `setOperatorWith` - Set the operator id and key and also provide a custom transaction signer function instead of using the default one.

```javascript
tx.setOperatorWith(accountId, key.publicKey, (message) =>
Promise.resolve(key.sign(message)),
);
```

## Transaction Settings

- `setDefaultMaxTransactionFee` - Set maximum transaction fee user is willing to pay.

```javascript
const client = Client.forTestnet().setDefaultMaxTransactionFee(
Hbar.fromTinybars(1),
);
// the network used here doesn't matter
```

- `setDefaultRegenerateTransactionId` - Configure transaction ID regeneration. This function accepts a boolean type of value. When set to true it will regenerate the transaction ID when a `TRANSACTION_EXPIRED` status is returned.

```javascript
const client = Client.forTestnet();
client.setDefaultRegenerateTransactionId(true);
```

- `setSignOnDemand` - Configure on-demand transaction signing

The setSignOnDemand method in the Hedera JavaScript SDK allows you to configure how transactions are signed before being submitted to the Hedera network. By default, transactions are signed immediately after being constructed. However, in some cases, you may want to delay the signing process until just before the transaction is submitted. This can be useful in scenarios where you need to perform additional operations or validations on the transaction before signing it.

When you call client.setSignOnDemand(true), it instructs the SDK to defer the signing of transactions until the transaction.sign() method is explicitly called. This means that when you create a transaction using the SDK, it will not be signed automatically. Instead, you will need to call transaction.sign() manually before submitting the transaction to the network.
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe present the code examples with "code" formatting for better visualization


```javascript
const client = Client.forTestnet();
client.setSignOnDemand(true);
```

## Query Settings

- `setDefaultMaxQueryPayment` - Same as `setDefaultMaxTransactionFee` but for queries.

## Retry and Timeout Settings

- `setMaxAttempts` - Sets maximum retry attempts before an error is thrown.
- `setMaxNodeAttempts` - Set maximum node retry attempts
- `setMinBackoff` - Set minimum backoff time for retries.
There's a time the SDK waits for after every failed attempt. A lower minBackoff value will result in more frequent retries initially, which can be useful for faster recovery from transient failures. This time increases exponentially. The default values provided by the SDK are generally reasonable for most use cases, but you may want to adjust them based on your specific requirements.

- `setMaxBackoff` - Set maximum backoff time for retries
Same as above but this sets on the maximum amount of seconds the backoff time may go.

- `setRequestTimeout` - This timeout is the maximum allowed time for the entire transaction/query, including all retries.

```javascript
let client = Client.forTestnet();
client.setOperator(operatorAccountId, operatorPrivateKey);
client.setRequestTimeout(30000);
// Network doesn't matter here.
```

- `setMaxExecutionTime` - this timeout applies to each single gRPC request within the transaction/query. It’s used for the edge cases where 10 seconds are not enough for the execution of a single gRPC request and the user can pass more.

```javascript
const client = Client.forNetwork();
const timeInMs = 10000;
client.setMaxExecutionTime(10000); // Set the request timeout to 10 seconds (10000 milliseconds)
```

### Node Management

- `setMaxNodesPerTransaction` - Set maximum nodes per transaction
This sets the maximum amount of nodes that the transaction will try to execute to.Setting a higher value for setMaxNodesPerTransaction can improve the reliability of transaction execution, but it also increases the network load and the overall cost of the transaction (since you'll be paying transaction fees for each node that executes the transaction).
Copy link
Contributor

Choose a reason for hiding this comment

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

to.Setting typo?

- `setNodeMinBackoff` - The `setNodeMinBackoff` method is SDK is used to set the minimum backoff time (in milliseconds) for retrying operations on a specific node.
When you send a request to a node in the Hedera network, and the node fails to respond or encounters an error, the SDK will attempt to retry the request on the same node after a certain amount of time. This time is known as the backoff time, and it starts at a minimum value (set by setNodeMinBackoff) and increases exponentially with each subsequent retry attempt, up to a maximum value (set by setNodeMaxBackoff).
The backoff mechanism is designed to prevent overwhelming the nodes with too many retries in a short period of time, while still allowing the SDK to recover from transient failures or network issues.
Here's an example of how you can set the minimum node backoff time using the setNodeMinBackoff method:

```javascript
const client = Client.forNetwork();
client.setNodeMinBackoff(500); // Set minimum node backoff to 500 milliseconds (0.5 seconds)
```

- `setNodeMaxBackoff` - It sets the maximum seconds allowed for the node backoff explained in the previous setting.

- `setNodeMinReadmitPeriod` - Set minimum node readmit period
Copy link
Contributor

Choose a reason for hiding this comment

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

When typo?

When a node fails to respond or encounters an error while processing a request, the SDK will temporarily remove that node from the pool of available nodes. This is done to prevent the SDK from repeatedly sending requests to a node that is experiencing issues, which could further exacerbate the problem.
The `setNodeMinReadmitPeriod` method allows you to configure the minimum amount of time that a node must wait before it can be readmitted to the pool of available nodes. During this period, the SDK will not send any requests to that node, giving it time to recover or resolve any issues it may be experiencing.

- `setNodeMaxReadmitPeriod` - Set maximum node readmit period.
The setNodeMaxReadmitPeriod method allows you to configure the maximum amount of time that a node can be excluded from the pool of available nodes. After this period has elapsed, the SDK will automatically readmit the node to the pool, regardless of whether it has recovered or not.

- `setNodeWaitTime` - The `setNodeWaitTime` method in the Hedera JavaScript SDK is used to set the minimum amount of time (in milliseconds) that the SDK will wait before attempting to send a request to a node that has recently failed or encountered an error.

```javascript
const client = Client.forNetwork();
client.setNodeWaitTime(5000); // Set node wait time to 5 seconds (5000 milliseconds)
```

### Network Update Settings

- `setNetworkUpdatePeriod` - The setNetworkUpdatePeriod method in the Hedera JavaScript SDK is used to configure the frequency at which the SDK updates its internal representation of the Hedera network topology.
The Hedera network is a distributed ledger system that consists of multiple nodes spread across different geographic locations. These nodes can join or leave the network at any time, and their availability and performance can vary depending on various factors such as network conditions, hardware issues, or software updates.
To ensure that the SDK has an up-to-date view of the network topology, it periodically retrieves information about the available nodes and their respective performance metrics. This information is used to determine which nodes to send requests to and to adjust the load balancing and failover strategies accordingly.

- `setAutoValidateChecksums` - Configure automatic checksum validation

### Logging

- `setLogger` - Configure client logger. Setting a logger can give you additional information for debugging processes. This is an example of how you can use this fucntionality.

```javascript
const infoLogger = new Logger(LogLevel.Info);
client.setLogger(infoLogger);
```

There are different LogLevels: `LogLevel.Info`, ``LogLevel.Silent`, `LogLeve.Trace`, `LogLevel.Debug`, `LogLevel.Warn`, `LogLevel.Error`, `LogLevel.Fatal`.
Copy link
Contributor

Choose a reason for hiding this comment

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

Visualization typo


### Default values:
Copy link
Contributor

Choose a reason for hiding this comment

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

setMaxExecutionTime() is missing


| Key Name | Default Value |
Copy link
Contributor

Choose a reason for hiding this comment

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

I would actually move this to the top right below the table with operator.
As a dev I want to quickly know what all my options are with summaries.
Then I can read further down to dig into details

| --------------------------------- | ---------------------------- |
| setDefaultRegenerateTransactionId | true |
| setSignOnDemand | false |
| setDefaultMaxQueryPayment | 1 Hbar |
| setMinBackoff | 250 (milliseconds) |
| setMaxBackoff | 8000 (milliseconds) |
| setNetworkUpdatePeriod | 24 60 60 1000 (milliseconds) |
| setAutoValidateChecksums | false |
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ See [examples](./examples).

Every example can be executed using the following command from the root directory: `node examples/[name-of-example].js`

## Configuration

For detailed information on configuring the SDK, including environment variables and client settings, please refer to the [CONFIGURATION.md](CONFIGURATION.md) file.

## Start tests

* To start the integration tests follow the next steps:
Expand Down