Skip to content

Commit

Permalink
Add example on how to generate transaction IDs on demand and scenarios (
Browse files Browse the repository at this point in the history
#1860)

* add example on how to generate transaction IDs on demand and scenarios

Signed-off-by: Petar Tonev <[email protected]>

* add updated mainnet/testnet nodes from addressbook after build

Signed-off-by: Petar Tonev <[email protected]>

---------

Signed-off-by: Petar Tonev <[email protected]>
  • Loading branch information
petreze authored Sep 8, 2023
1 parent daf009c commit 2b53502
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 2 deletions.
169 changes: 169 additions & 0 deletions examples/generate-txid-on-demand.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import {
AccountId,
PrivateKey,
Client,
Hbar,
Timestamp,
TransactionId,
AccountCreateTransaction,
TransferTransaction,
} from "@hashgraph/sdk";

import dotenv from "dotenv";
dotenv.config();

/*
Examples that demonstrates the use of generating transaction IDs on demand
## Example 1:
Sometimes, when you are trying to execute transactions `asynchronosly`,
there is a tiny bit of chance to generate the same `transactionId` given the same `accountId`
and the current timestamp.
With the following approach to generate custom `transactionId`, this issue is avoided
### Steps
1. Create an account to whom to send tinybars
2. Make a thousand iterations of transfer transactions with custom generated `transactionId`
3. Await the receipts of every transaction
4. Check if the count of receipts with status `SUCCESS` equals the count of transactions (should be 1000)
## Example 2:
The `TransactionId` object contains the valid start time for the transaction. This means that
by setting the valid start time to a moment in the future, you would be able to execute the transaction
after the set period (in seconds)
1. Create custom `transactionId` with valid start 10 seconds after the current time
2. Wait 15 seconds in order for the transaction to be valid and then submit it
*/

async function main() {
if (process.env.OPERATOR_ID == null || process.env.OPERATOR_KEY == null) {
throw new Error(
"Environment variables OPERATOR_ID, and OPERATOR_KEY are required."
);
}
const operatorId = AccountId.fromString(process.env.OPERATOR_ID);
const operatorKey = PrivateKey.fromString(process.env.OPERATOR_KEY);

const client = Client.forTestnet().setOperator(operatorId, operatorKey);

/**
* Example 1
*
* Step 1
*
* Create an account to whom to send tinybars
*/
const newKey = PrivateKey.generate();

console.log(`New account private key: ${newKey.toString()}`);
console.log(`New account public key: ${newKey.publicKey.toString()}`);

const accountCreateTx = await new AccountCreateTransaction()
.setInitialBalance(new Hbar(10)) // 10 h
.setKey(newKey.publicKey)
.freezeWith(client)
.execute(client);

const newAccountId = (
await accountCreateTx.getReceipt(client)
).accountId.toString();
console.log(`New account id: ${newAccountId}`);

/**
* Step 2
*
* Make a thousand iterations of transfer transactions
* with custom generated `transactionId`
*/
const transactionsCount = 1000;
let transactions = [];
let nanosOffset = 1000000;
for (let i = 0; i < transactionsCount; i++) {
const seconds = Math.round(Date.now() / 1000);
const validStart = new Timestamp(seconds, nanosOffset);
nanosOffset += 10000;

const transactionId = TransactionId.withValidStart(
operatorId,
validStart
);

const transferHbar = new TransferTransaction()
.setTransactionId(transactionId)
.addHbarTransfer(operatorId, Hbar.fromTinybars(-1))
.addHbarTransfer(newAccountId, Hbar.fromTinybars(1));

transactions.push(transferHbar.execute(client));
}
const responsesResult = await Promise.all(transactions);

/**
* Step 3
*
* Await the receipts of every transaction
*/
let count = 0;
let receipts = [];
for (let i = 0; i < responsesResult.length; i++) {
receipts.push(responsesResult[i].getReceipt(client));
}
const receiptsResult = await Promise.all(receipts);

/**
* Step 4
*
* Check if the count of receipts with status `SUCCESS` equals the count of transactions (should be 1000)
*/
receiptsResult.forEach((receipt) =>
receipt.status.toString() == "SUCCESS"
? count++
: console.log(`Failed with: ${receipt.status.toString()}`)
);
transactionsCount == count
? console.log(`All transactions are executed successfully`)
: console.log(`${transactionsCount - count} unsuccessful transactions`);

/**
* Example 2
*
* Step 1
*
* Create custom `transactionId` with valid start 10 seconds after the current time
*/
const nowInSeconds = Math.floor(Date.now() / 1000);
const secondsDelay = 10;
const seconds = nowInSeconds + secondsDelay;
const validStart = new Timestamp(seconds, 0);
const transactionId = TransactionId.withValidStart(operatorId, validStart);

/**
* Step 2
*
* Wait 15 seconds in order for the transaction to be valid and then submit it
*/
await wait(15000);

const transferHbar = await new TransferTransaction()
.setTransactionId(transactionId)
.addHbarTransfer(operatorId, Hbar.fromTinybars(-1))
.addHbarTransfer(newAccountId, Hbar.fromTinybars(1))
.execute(client);

const status = (await transferHbar.getReceipt(client)).status.toString();
console.log(status);
}

/**
* @param {number} timeout
* @returns {Promise<any>}
*/
function wait(timeout) {
return new Promise((resolve) => {
setTimeout(resolve, timeout);
});
}

void main();
2 changes: 1 addition & 1 deletion src/client/addressbooks/mainnet.js

Large diffs are not rendered by default.

Loading

0 comments on commit 2b53502

Please sign in to comment.