Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,18 +143,18 @@ export default {
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
// snapshotSerializers: [],

// The test environment that will be used for testing
// Every test in this suite drives the live Partisia testnet: each action
// waits for a transaction to be broadcast, executed and finalized. CI runners
// are slower than a local machine, so the timeout is generous and global
// rather than repeated per test.
testTimeout: 30_000,

// The test environment that will be used for testing.
// The suite exercises the SDK the way a Node consumer does and talks to the
// testnet over HTTP. Under jsdom, axios picks its XMLHttpRequest adapter,
// whose requests intermittently died with "read ETIMEDOUT"; a hung request
// times the test out mid-broadcast and the next transaction then reuses a
// spent nonce, which the reader node rejects with 400 Bad Request.
// testnet over HTTP. jsdom implements neither fetch nor a reliable HTTP
// stack: it made axios fall back to its XMLHttpRequest adapter, whose
// requests intermittently died with "read ETIMEDOUT", and it has no global
// fetch for the client to call at all.
testEnvironment: 'node',

// Options that will be passed to the testEnvironment
Expand Down
5 changes: 1 addition & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,14 @@
"@partisiablockchain/abi-client": "^6.0.0",
"@secata-public/bitmanipulation-ts": "^3.4.0",
"bip32-path": "^0.4.2",
"node-fetch": "2",
"partisia-blockchain-applications-crypto": "^1.0.34",
"partisia-blockchain-applications-rpc": "^1.0.13",
"partisia-blockchain-applications-sdk": "^0.1.4",
"tr46": "^4.1.1"
},
"devDependencies": {
"@types/jest": "^29.5.14",
"@types/node": "^18.19.130",
"@types/node-fetch": "^2.6.13",
"@types/node": "^20.19.9",
"@types/tr46": "^3.0.3",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
Expand All @@ -46,7 +44,6 @@
"eslint-plugin-n": "^15.0.0",
"eslint-plugin-promise": "^6.6.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"ts-jest": "^29.4.6",
"ts-node": "^10.9.2",
"typedoc": "^0.24.8",
Expand Down
12 changes: 8 additions & 4 deletions src/repositories/contracts/meta-names-contract-repository.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ContractAbi } from "@partisiablockchain/abi-client"
import { FetchError } from "node-fetch"
import { IPartisiaRpcConfig } from "partisia-blockchain-applications-rpc/lib/main/accountInfo"
import { Contract, ContractParams, GetStateParams, IMetaNamesContractRepository, ITransactionIntent, MetaNamesAvlTrees, MetaNamesState, TransactionParams } from "../../interface"
import { Enviroment } from "../../providers"
Expand Down Expand Up @@ -73,10 +72,15 @@ export class MetaNamesContractRepository extends ContractRepository implements I
const metaNamesContractAddress = await this.getContractAddress()

try {
return this.avlClient.getContractStateAvlValue(metaNamesContractAddress, treeId, key)
// Must be awaited: returning the promise unawaited let rejections escape
// this try/catch entirely, making the handler below unreachable.
return await this.avlClient.getContractStateAvlValue(metaNamesContractAddress, treeId, key)
} catch (e) {
if (e instanceof FetchError && e.code === '404') return
else console.log(e)
// A missing AVL value is already surfaced as `undefined` by `getRequest`,
// which only resolves a body on HTTP 200. Anything reaching here is a
// transport-level failure.
console.error(e)
return
}
}

Expand Down
27 changes: 20 additions & 7 deletions src/repositories/helpers/client.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
import fetch, { Response } from 'node-fetch'

const getHeaders = {
Accept: "application/json, text/plain, */*",
}

export type RequestType = "GET"

function buildOptions(method: RequestType, headers: Record<string, string>) {
const result = { method, headers }
/**
* Requests that never settle would otherwise pin a retry chain open forever,
* since `promiseRetry` only advances when the underlying promise settles.
*/
export const DEFAULT_TIMEOUT_MS = 30_000

function buildOptions(method: RequestType, headers: Record<string, string>, signal: AbortSignal) {
const result = { method, headers, signal }

return result
}

export function getRequest<R>(url: string): Promise<R | undefined> {
const options = buildOptions("GET", getHeaders)
export function getRequest<R>(url: string, timeoutMs = DEFAULT_TIMEOUT_MS): Promise<R | undefined> {
return handleFetch(promiseRetry(() => fetchWithTimeout(url, timeoutMs)))
}

async function fetchWithTimeout(url: string, timeoutMs: number): Promise<Response> {
const controller = new AbortController()
const timer = setTimeout(() => controller.abort(), timeoutMs)

return handleFetch(promiseRetry(() => fetch(url, options)))
try {
return await fetch(url, buildOptions("GET", getHeaders, controller.signal))
} finally {
clearTimeout(timer)
}
}

async function handleFetch<T>(promise: Promise<Response>): Promise<T | undefined> {
Expand Down
Loading
Loading