From e871b5f47ca6c6752ce9f7344fd39ea3202a18db Mon Sep 17 00:00:00 2001 From: timstackblock <49165468+timstackblock@users.noreply.github.com> Date: Thu, 19 Jan 2023 10:15:50 -0500 Subject: [PATCH] chore: addtest chore: addtest --- package.json | 21 +++++ readme.md | 14 ++++ script/index.ts | 9 +++ script/tests/anchor.blocks.spec.ts | 119 +++++++++++++++++++++++++++++ script/utils/curl.ts | 40 ++++++++++ script/utils/helper.ts | 7 ++ tsconfig.json | 14 ++++ 7 files changed, 224 insertions(+) create mode 100644 package.json create mode 100644 readme.md create mode 100644 script/index.ts create mode 100644 script/tests/anchor.blocks.spec.ts create mode 100644 script/utils/curl.ts create mode 100644 script/utils/helper.ts create mode 100644 tsconfig.json diff --git a/package.json b/package.json new file mode 100644 index 0000000..55e5531 --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "stacks", + "version": "1.0.0", + "description": "", + "main": "index.js", + "devDependencies": { + "@types/node": "^18.11.12", + "prettier": "2.8.1", + "ts-node": "^10.9.1", + "typescript": "^4.9.4" + }, + "scripts": { + "test": "ts-node ./script/index.ts" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "axios": "^1.2.1" + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..10c453a --- /dev/null +++ b/readme.md @@ -0,0 +1,14 @@ +# apiTest +apiTest is a node script for testing transactions on micro block api and anchor block api. + +### Prerequisites + +- npm installed and Node v16.* +- Stacks CLI on your machine [@stacks/cli](https://www.npmjs.com/package/@stacks/cli) + +### Run script +1. Go to the root of the project and do `npm install`. Make sure you have satisfied the above Prerequisites. +2. Run the script: + ```sh + $ npm run test + ``` diff --git a/script/index.ts b/script/index.ts new file mode 100644 index 0000000..971ae0c --- /dev/null +++ b/script/index.ts @@ -0,0 +1,9 @@ +import { triggerAnchorBlockTests } from "./tests/anchor.blocks.spec"; + +const anchorBlockOptions = { + accountId: "ST3C4YVASFG37P8E6210J9KHZJB4MF8ZRBQFKH41N", + recipient: "ST297VG59W96DPGBT13SGD542QE1XS954X4ZSWW2J", +}; + +// trigger anchor block testing script +triggerAnchorBlockTests(anchorBlockOptions); diff --git a/script/tests/anchor.blocks.spec.ts b/script/tests/anchor.blocks.spec.ts new file mode 100644 index 0000000..481b3e3 --- /dev/null +++ b/script/tests/anchor.blocks.spec.ts @@ -0,0 +1,119 @@ +import * as util from "util"; +import * as child_process from "child_process"; +const exec = util.promisify(child_process.exec); +let interval, + triggerCount = 0, + foundMicroBlock = false; + +import { getAccountDetail, getMicroBlock, getAnchorBlock } from "../utils/curl"; +import { wait } from "../utils/helper"; + +const runAnchorBlockTest = async (options: any) => { + triggerCount++; + console.log(`Trigger script count: ${triggerCount}`); + + const { accountId, recipient } = options; + try { + // step 1: Fetch nonce from account id + console.log("Fetching Nonce..."); + const nonce = await fetchNonce(accountId); + console.log("Nonce fetched", nonce); + + // step 2: Run the stx command for send_tokens to fetch the TXID + console.log("Sending tokens and fetching TXID..."); + const txid = await sendTokens(nonce, recipient); + console.log("TXID fetched", txid); + + // step 3: CURL the microblock API to make sure that TXID exist + if (!foundMicroBlock) { + await wait(10000); + console.log("Calling microblock API..."); + const isTXIDExistMB = await checkTXIDInMicroBlock(txid); + if (isTXIDExistMB) { + foundMicroBlock = true; + console.log(`The transaction ${txid} is present in Micro Block API`); + } else { + console.log( + `The transaction ${txid} is not present in Micro Block API` + ); + } + } + + // step 4: CURL the Anchor block API to make sure that TXID exist + console.log("Calling Anchor block API..."); + const isTXIDExistAB = await checkTXIDInAnchorBlock(txid); + if (isTXIDExistAB) { + console.log(`The transaction ${txid} is present in Anchor block API`); + process.exit(0); + } else { + console.log(`The transaction ${txid} is not present in Anchor block API`); + } + if (triggerCount === 5) { + console.log("Time limit reached: 30 minutes"); + clearInterval(interval); + process.exit(0); + } + } catch (e) { + console.error( + "An error occurred while processing the anchor block script", + e + ); + clearInterval(interval); + process.exit(1); + } +}; + +export function triggerAnchorBlockTests(options: any) { + runAnchorBlockTest(options); + + interval = setInterval(() => { + runAnchorBlockTest(options); + }, 6 * 60 * 1000); // every 6 minutes +} + +async function fetchNonce(accountId: string): Promise { + const accountDetail = await getAccountDetail(accountId); + if (!accountDetail) { + console.log(`No account detail found for account id - ${accountId}`); + return 0; + } + return accountDetail.nonce; +} + +async function sendTokens(nonce: number, recipient: string): Promise { + const { stdout, stderr } = await exec( + `stx -t send_tokens ${recipient} 12345 999 ${nonce} fd3609e8b9352facf360c950d362afe8f0f108b9041750f54b017efc479efeb001` + ); + if (stderr) { + console.error( + `An error occurred while sending the tokens to recipient ${recipient}` + ); + return; + } + const filteredResponse = stdout.replace(/(\r\n|\n|\r|\s)/gm, ""); + return filteredResponse.split(",")[0].split(":")[1].replace(/\'/g, ""); +} + +async function checkTXIDInMicroBlock(txid: string): Promise { + const microBlockData = await getMicroBlock(); + if (!microBlockData) { + console.log(`No micro block data found`); + return false; + } + const isTXIDExist = microBlockData.results.some( + (result) => result.tx_id === txid + ); + return isTXIDExist; +} + +async function checkTXIDInAnchorBlock(txid: string): Promise { + const anchorBlockData = await getAnchorBlock(); + if (!anchorBlockData) { + console.log(`No anchor block data found`); + return false; + } + const isTXIDExist = anchorBlockData.results.some( + (result) => result.tx_id === txid + ); + return isTXIDExist; +} diff --git a/script/utils/curl.ts b/script/utils/curl.ts new file mode 100644 index 0000000..aa0ca90 --- /dev/null +++ b/script/utils/curl.ts @@ -0,0 +1,40 @@ +import axios from "axios"; + +export async function getAccountDetail(accountId: string): Promise { + return new Promise((resolve, reject) => { + axios + .get(`https://stacks-node-api.testnet.stacks.co/v2/accounts/${accountId}`) + .then((res) => { + resolve(res ? res.data: ''); + }) + .catch((error) => { + reject(error); + }); + }); +} + +export async function getMicroBlock(): Promise { + return new Promise((resolve, reject) => { + axios + .get('https://stacks-node-api.testnet.stacks.co/extended/v1/microblock/unanchored/txs') + .then((res) => { + resolve(res ? res.data: ''); + }) + .catch((error) => { + reject(error); + }); + }); +} + +export async function getAnchorBlock(): Promise { + return new Promise((resolve, reject) => { + axios + .get('https://stacks-node-api.testnet.stacks.co/extended/v1/tx?limit=200') + .then((res) => { + resolve(res ? res.data: ''); + }) + .catch((error) => { + reject(error); + }); + }); +} diff --git a/script/utils/helper.ts b/script/utils/helper.ts new file mode 100644 index 0000000..0a5ce4f --- /dev/null +++ b/script/utils/helper.ts @@ -0,0 +1,7 @@ +export const wait = async (ms: number) => { + return new Promise((resolve) => { + setTimeout(() => { + resolve(true); + }, ms); + }); +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..aae154d --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "lib": ["es6"], + "allowJs": true, + "outDir": "build", + "rootDir": "script", + "strict": true, + "noImplicitAny": false, + "esModuleInterop": true, + "resolveJsonModule": true + } +}