feat: handle fetch errors
This commit is contained in:
@@ -137,7 +137,7 @@ describe('WarpGatewayInteractionsLoader -> load', () => {
|
||||
try {
|
||||
await loader.load(contractId, fromBlockHeight, toBlockHeight);
|
||||
} catch (e) {
|
||||
expect(e).toEqual(new Error('Unable to retrieve transactions. Warp gateway responded with status 504.'));
|
||||
expect(e).toEqual(new Error('Error while communicating with gateway: {"status":504,"ok":false}'));
|
||||
}
|
||||
});
|
||||
it('should throw an error when request fails', async () => {
|
||||
@@ -148,7 +148,7 @@ describe('WarpGatewayInteractionsLoader -> load', () => {
|
||||
try {
|
||||
await loader.load(contractId, fromBlockHeight, toBlockHeight);
|
||||
} catch (e) {
|
||||
expect(e).toEqual(new Error('Unable to retrieve transactions. Warp gateway responded with status 500.'));
|
||||
expect(e).toEqual(new Error('Error while communicating with gateway: {"status":500,"ok":false,"body":{"message":"request fails"}}'));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ import { Benchmark } from '../logging/Benchmark';
|
||||
import { LoggerFactory } from '../logging/LoggerFactory';
|
||||
import { Evolve } from '../plugins/Evolve';
|
||||
import { ArweaveWrapper } from '../utils/ArweaveWrapper';
|
||||
import { sleep, stripTrailingSlash } from '../utils/utils';
|
||||
import { getJsonResponse, sleep, stripTrailingSlash } from '../utils/utils';
|
||||
import {
|
||||
BenchmarkStats,
|
||||
Contract,
|
||||
@@ -32,7 +32,7 @@ import {
|
||||
import { ArTransfer, ArWallet, emptyTransfer, Tags } from './deploy/CreateContract';
|
||||
import { InnerWritesEvaluator } from './InnerWritesEvaluator';
|
||||
import { generateMockVrf } from '../utils/vrf';
|
||||
import { Signature, CustomSignature } from './Signature';
|
||||
import { CustomSignature, Signature } from './Signature';
|
||||
import { EvaluationOptionsEvaluator } from './EvaluationOptionsEvaluator';
|
||||
import { WarpFetchWrapper } from '../core/WarpFetchWrapper';
|
||||
import { Mutex } from 'async-mutex';
|
||||
@@ -334,8 +334,9 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
options.vrf
|
||||
);
|
||||
|
||||
const response = await this.warpFetchWrapper
|
||||
.fetch(`${stripTrailingSlash(this._evaluationOptions.sequencerUrl)}/gateway/sequencer/register`, {
|
||||
const response = this.warpFetchWrapper.fetch(
|
||||
`${stripTrailingSlash(this._evaluationOptions.sequencerUrl)}/gateway/sequencer/register`,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify(interactionTx),
|
||||
headers: {
|
||||
@@ -343,21 +344,11 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json'
|
||||
}
|
||||
})
|
||||
.then((res) => {
|
||||
this.logger.debug(res);
|
||||
return res.ok ? res.json() : Promise.reject(res);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.logger.error(error);
|
||||
if (error.body?.message) {
|
||||
this.logger.error(error.body.message);
|
||||
}
|
||||
throw new Error(`Unable to bundle interaction: ${JSON.stringify(error)}`);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
bundlrResponse: response,
|
||||
bundlrResponse: await getJsonResponse(response),
|
||||
originalTxId: interactionTx.id
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ import { SortKeyCache } from '../cache/SortKeyCache';
|
||||
import { ContractDefinition, SrcCache } from './ContractDefinition';
|
||||
import { CustomSignature } from '../contract/Signature';
|
||||
import { Transaction } from '../utils/types/arweave-types';
|
||||
import {DEFAULT_LEVEL_DB_LOCATION, WARP_GW_URL} from './WarpFactory';
|
||||
import { DEFAULT_LEVEL_DB_LOCATION, WARP_GW_URL } from './WarpFactory';
|
||||
import { LevelDbCache } from '../cache/impl/LevelDbCache';
|
||||
import { SourceData } from '../contract/deploy/Source';
|
||||
import { BundlerSigner, DataItem } from '../contract/deploy/DataItem';
|
||||
|
||||
@@ -13,7 +13,7 @@ import { Warp, WarpEnvironment } from '../../Warp';
|
||||
import { TagsParser } from './TagsParser';
|
||||
import { CacheKey, SortKeyCache, SortKeyCacheResult } from '../../../cache/SortKeyCache';
|
||||
import { Transaction } from '../../../utils/types/arweave-types';
|
||||
import { stripTrailingSlash } from '../../../utils/utils';
|
||||
import { getJsonResponse, stripTrailingSlash } from '../../../utils/utils';
|
||||
|
||||
/**
|
||||
* An extension to {@link ContractDefinitionLoader} that makes use of
|
||||
@@ -66,20 +66,10 @@ export class WarpGatewayContractDefinitionLoader implements DefinitionLoader {
|
||||
async doLoad<State>(contractTxId: string, forcedSrcTxId?: string): Promise<ContractDefinition<State>> {
|
||||
try {
|
||||
const baseUrl = stripTrailingSlash(this._warp.gwUrl());
|
||||
const result: ContractDefinition<State> = await fetch(
|
||||
`${baseUrl}/gateway/contract?txId=${contractTxId}${forcedSrcTxId ? `&srcTxId=${forcedSrcTxId}` : ''}`
|
||||
)
|
||||
.then((res) => {
|
||||
return res.ok ? res.json() : Promise.reject(res);
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.body?.message) {
|
||||
this.rLogger.error(error.body.message);
|
||||
}
|
||||
throw new Error(
|
||||
`Unable to retrieve contract data. Warp gateway responded with status ${error.status}:${error.body?.message}`
|
||||
);
|
||||
});
|
||||
const result: ContractDefinition<State> = await getJsonResponse(
|
||||
fetch(`${baseUrl}/gateway/contract?txId=${contractTxId}${forcedSrcTxId ? `&srcTxId=${forcedSrcTxId}` : ''}`)
|
||||
);
|
||||
|
||||
if (result.srcBinary != null && !(result.srcBinary instanceof Buffer)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
result.srcBinary = Buffer.from((result.srcBinary as any).data);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { GQLNodeInterface } from '../../../legacy/gqlResult';
|
||||
import { Benchmark } from '../../../logging/Benchmark';
|
||||
import { LoggerFactory } from '../../../logging/LoggerFactory';
|
||||
import 'warp-isomorphic';
|
||||
import { stripTrailingSlash } from '../../../utils/utils';
|
||||
import { getJsonResponse, stripTrailingSlash } from '../../../utils/utils';
|
||||
import { GW_TYPE, InteractionsLoader } from '../InteractionsLoader';
|
||||
import { EvaluationOptions } from '../StateEvaluator';
|
||||
import { Warp } from '../../Warp';
|
||||
@@ -23,6 +23,14 @@ export const enum SourceType {
|
||||
BOTH = 'both'
|
||||
}
|
||||
|
||||
type InteractionsResult = {
|
||||
interactions: GQLNodeInterface[];
|
||||
paging: {
|
||||
limit: number;
|
||||
items: number;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* The aim of this implementation of the {@link InteractionsLoader} is to make use of
|
||||
* Warp Gateway ({@link https://github.com/redstone-finance/redstone-sw-gateway})
|
||||
@@ -75,29 +83,24 @@ export class WarpGatewayInteractionsLoader implements InteractionsLoader {
|
||||
|
||||
const url = `${baseUrl}/gateway/v2/interactions-sort-key`;
|
||||
|
||||
const response = await fetch(
|
||||
`${url}?${new URLSearchParams({
|
||||
contractId: contractId,
|
||||
...(fromSortKey ? { from: fromSortKey } : ''),
|
||||
...(toSortKey ? { to: toSortKey } : ''),
|
||||
page: (++page).toString(),
|
||||
fromSdk: 'true',
|
||||
...(this.confirmationStatus && this.confirmationStatus.confirmed ? { confirmationStatus: 'confirmed' } : ''),
|
||||
...(this.confirmationStatus && this.confirmationStatus.notCorrupted
|
||||
? { confirmationStatus: 'not_corrupted' }
|
||||
: ''),
|
||||
...(effectiveSourceType == SourceType.BOTH ? '' : { source: effectiveSourceType })
|
||||
})}`
|
||||
)
|
||||
.then((res) => {
|
||||
return res.ok ? res.json() : Promise.reject(res);
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.body?.message) {
|
||||
this.logger.error(error.body.message);
|
||||
}
|
||||
throw new Error(`Unable to retrieve transactions. Warp gateway responded with status ${error.status}.`);
|
||||
});
|
||||
const response = await getJsonResponse<InteractionsResult>(
|
||||
fetch(
|
||||
`${url}?${new URLSearchParams({
|
||||
contractId: contractId,
|
||||
...(fromSortKey ? { from: fromSortKey } : ''),
|
||||
...(toSortKey ? { to: toSortKey } : ''),
|
||||
page: (++page).toString(),
|
||||
fromSdk: 'true',
|
||||
...(this.confirmationStatus && this.confirmationStatus.confirmed
|
||||
? { confirmationStatus: 'confirmed' }
|
||||
: ''),
|
||||
...(this.confirmationStatus && this.confirmationStatus.notCorrupted
|
||||
? { confirmationStatus: 'not_corrupted' }
|
||||
: ''),
|
||||
...(effectiveSourceType == SourceType.BOTH ? '' : { source: effectiveSourceType })
|
||||
})}`
|
||||
)
|
||||
);
|
||||
this.logger.debug(`Loading interactions: page ${page} loaded in ${benchmarkRequestTime.elapsed()}`);
|
||||
|
||||
interactions.push(...response.interactions);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Buffer as isomorphicBuffer } from 'warp-isomorphic';
|
||||
import { LoggerFactory } from '../logging/LoggerFactory';
|
||||
import { BlockData, NetworkInfoInterface, Transaction } from './types/arweave-types';
|
||||
import { Warp } from '../core/Warp';
|
||||
import { stripTrailingSlash } from './utils';
|
||||
import { getJsonResponse, stripTrailingSlash } from './utils';
|
||||
|
||||
export class ArweaveWrapper {
|
||||
private readonly logger = LoggerFactory.INST.create('ArweaveWrapper');
|
||||
@@ -115,22 +115,6 @@ export class ArweaveWrapper {
|
||||
}
|
||||
|
||||
private async doFetchInfo<R>(url: string): Promise<R> {
|
||||
try {
|
||||
const response = await fetch(url)
|
||||
.then((res) => {
|
||||
return res.ok ? res.json() : Promise.reject(res);
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.body?.message) {
|
||||
this.logger.error(error.body.message);
|
||||
}
|
||||
throw new Error(`Unable to retrieve info. ${error.status}: ${error.body?.message}`);
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (e) {
|
||||
this.logger.error('Error while loading info', e);
|
||||
throw e;
|
||||
}
|
||||
return await getJsonResponse<R>(fetch(url));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable */
|
||||
import copy from 'fast-copy';
|
||||
import { Buffer } from 'warp-isomorphic';
|
||||
import {Buffer} from 'warp-isomorphic';
|
||||
|
||||
export const sleep = (ms: number): Promise<void> => {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
@@ -86,3 +86,20 @@ export function bufToBn(buf: Buffer) {
|
||||
}
|
||||
|
||||
export const isBrowser = new Function('try {return this===window;}catch(e){ return false;}');
|
||||
|
||||
export async function getJsonResponse<T>(response: Promise<Response>): Promise<T> {
|
||||
let r: Response;
|
||||
try {
|
||||
r = await response;
|
||||
} catch (e) {
|
||||
throw new Error(`Error while communicating with gateway: ${JSON.stringify(e)}`);
|
||||
}
|
||||
|
||||
if (!r?.ok) {
|
||||
const text = await r.text();
|
||||
throw new Error(`${r.status}: ${text}`);
|
||||
}
|
||||
const result = await r.json();
|
||||
return result as T;
|
||||
|
||||
}
|
||||
|
||||
@@ -20,18 +20,14 @@ async function main() {
|
||||
|
||||
const warp = WarpFactory
|
||||
.forMainnet({...defaultCacheOptions, inMemory: true})
|
||||
.useGwUrl("http://localhost:5666/")
|
||||
|
||||
let wallet: JWKInterface = readJSON('./.secrets/33F0QHcb22W7LwWR1iRC8Az1ntZG09XQ03YWuw2ABqA.json');
|
||||
|
||||
try {
|
||||
const contract = warp
|
||||
.contract("dD1DuvgM_Vigtnv4vl2H1IYn9CgLvYuhbEWPOL-_4Mw")
|
||||
const cacheResult = await contract
|
||||
.setEvaluationOptions({
|
||||
remoteStateSyncEnabled: true
|
||||
})
|
||||
.readState(/*'000001110120,1675251724861,1e1115cbd63aaf205584e2dcb2ca669b40409a0392e0ebf15ff7efac1ecbb24b'*/);
|
||||
console.log(cacheResult.sortKey);
|
||||
.contract("G89hzE_P9xCWErQebDuIRdB6zsrmAIjw-WU0g0e8J3M")
|
||||
await contract.readState();
|
||||
//console.dir(cacheResult.cachedValue.state, {depth: null});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
@@ -20,25 +20,26 @@ async function main() {
|
||||
|
||||
try {
|
||||
const warp = WarpFactory.forMainnet({...defaultCacheOptions, inMemory: true})
|
||||
.use(new DeployPlugin());
|
||||
.use(new DeployPlugin())
|
||||
.useGwUrl("http://localhost:5666/");
|
||||
|
||||
const jsContractSrc = fs.readFileSync(path.join(__dirname, 'data/js/token-pst.js'), 'utf8');
|
||||
const initialState = fs.readFileSync(path.join(__dirname, 'data/js/token-pst.json'), 'utf8');
|
||||
|
||||
// case 1 - full deploy, js contract
|
||||
const { contractTxId, srcTxId } = await warp.deploy({
|
||||
/* const { contractTxId, srcTxId } = await warp.deploy({
|
||||
wallet: new ArweaveSigner(wallet),
|
||||
initState: initialState,
|
||||
src: jsContractSrc
|
||||
/*evaluationManifest: {
|
||||
/!*evaluationManifest: {
|
||||
evaluationOptions: {
|
||||
useKVStorage: true
|
||||
}
|
||||
}*/
|
||||
}*!/
|
||||
});
|
||||
|
||||
console.log('contractTxId:', contractTxId);
|
||||
console.log('srcTxId:', srcTxId);
|
||||
console.log('srcTxId:', srcTxId);*/
|
||||
// case 2 - deploy from source, js contract
|
||||
/*const {contractTxId} = await warp.createContract.deployFromSourceTx({
|
||||
wallet,
|
||||
@@ -62,15 +63,17 @@ async function main() {
|
||||
srcTxId: "5wXT-A0iugP9pWEyw-iTbB0plZ_AbmvlNKyBfGS3AUY",
|
||||
});*/
|
||||
|
||||
const contract = warp.contract<any>(contractTxId).setEvaluationOptions({}).connect(wallet);
|
||||
const contract = warp.contract<any>('SG9sKOZvKFQ7EcpJU3bS0pQWp2idQf3VY2Ki_5-hDjo').setEvaluationOptions({
|
||||
sequencerUrl: 'http://localhost:5666/'
|
||||
}).connect(wallet);
|
||||
|
||||
await Promise.all([
|
||||
contract.writeInteraction<any>({
|
||||
/* contract.writeInteraction<any>({
|
||||
function: 'transfer',
|
||||
target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI',
|
||||
qty: 100
|
||||
}),
|
||||
contract.writeInteraction<any>({
|
||||
}),*/
|
||||
/*contract.writeInteraction<any>({
|
||||
function: 'transfer',
|
||||
target: 'M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI',
|
||||
qty: 100
|
||||
@@ -81,14 +84,8 @@ async function main() {
|
||||
qty: 100
|
||||
}, {
|
||||
disableBundling: true
|
||||
})
|
||||
/*contract.writeInteraction<any>({
|
||||
function: "mint",
|
||||
target: 'follows:0xe0',
|
||||
qty: 100
|
||||
}),*/
|
||||
})*/
|
||||
]);
|
||||
|
||||
const {cachedValue} = await contract.readState();
|
||||
|
||||
//logger.info("Result", await contract.getStorageValue('33F0QHcb22W7LwWR1iRC8Az1ntZG09XQ03YWuw2ABqA'));
|
||||
|
||||
Reference in New Issue
Block a user