@across-protocol/sdk 4.3.143 → 4.3.144
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/src/caching/Arweave/ArweaveClient.d.ts +11 -6
- package/dist/cjs/src/caching/Arweave/ArweaveClient.js +98 -74
- package/dist/cjs/src/caching/Arweave/ArweaveClient.js.map +1 -1
- package/dist/esm/src/caching/Arweave/ArweaveClient.d.ts +21 -8
- package/dist/esm/src/caching/Arweave/ArweaveClient.js +113 -80
- package/dist/esm/src/caching/Arweave/ArweaveClient.js.map +1 -1
- package/dist/types/src/caching/Arweave/ArweaveClient.d.ts +21 -8
- package/dist/types/src/caching/Arweave/ArweaveClient.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/caching/Arweave/ArweaveClient.ts +126 -76
|
@@ -2,16 +2,22 @@ import { JWKInterface } from "arweave/node/lib/wallet";
|
|
|
2
2
|
import { Struct } from "superstruct";
|
|
3
3
|
import winston from "winston";
|
|
4
4
|
import { BigNumber } from "../../utils";
|
|
5
|
+
export interface ArweaveGatewayConfig {
|
|
6
|
+
host: string;
|
|
7
|
+
protocol?: string;
|
|
8
|
+
port?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const DEFAULT_ARWEAVE_GATEWAYS: ArweaveGatewayConfig[];
|
|
5
11
|
export declare class ArweaveClient {
|
|
6
12
|
private arweaveJWT;
|
|
7
13
|
private logger;
|
|
8
|
-
gatewayURL: string;
|
|
9
|
-
protocol: string;
|
|
10
14
|
private readonly retries;
|
|
11
15
|
private readonly retryDelaySeconds;
|
|
12
|
-
private
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
private gateways;
|
|
17
|
+
constructor(arweaveJWT: JWKInterface, logger: winston.Logger, gateways?: ArweaveGatewayConfig[], retries?: number, retryDelaySeconds?: number);
|
|
18
|
+
private _raceGateways;
|
|
19
|
+
private _failoverGateways;
|
|
20
|
+
private _retryRequest;
|
|
15
21
|
set(value: Record<string, unknown>, topicTag?: string | undefined): Promise<string | undefined>;
|
|
16
22
|
get<T>(transactionID: string, validator: Struct<T>): Promise<T | null>;
|
|
17
23
|
getByTopic<T>(tag: string, validator: Struct<T>, originQueryAddress?: string): Promise<{
|
|
@@ -20,6 +26,5 @@ export declare class ArweaveClient {
|
|
|
20
26
|
}[]>;
|
|
21
27
|
getMetadata(transactionID: string): Promise<Record<string, string> | null>;
|
|
22
28
|
getAddress(): Promise<string>;
|
|
23
|
-
private _retryRequest;
|
|
24
29
|
getBalance(): Promise<BigNumber>;
|
|
25
30
|
}
|
|
@@ -1,83 +1,127 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ArweaveClient = void 0;
|
|
3
|
+
exports.ArweaveClient = exports.DEFAULT_ARWEAVE_GATEWAYS = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const arweave_1 = tslib_1.__importDefault(require("arweave"));
|
|
6
6
|
const superstruct_1 = require("superstruct");
|
|
7
7
|
const constants_1 = require("../../constants");
|
|
8
8
|
const utils_1 = require("../../utils");
|
|
9
|
+
exports.DEFAULT_ARWEAVE_GATEWAYS = [{ host: "arweave.net" }, { host: "ar-io.net" }];
|
|
9
10
|
class ArweaveClient {
|
|
10
11
|
arweaveJWT;
|
|
11
12
|
logger;
|
|
12
|
-
gatewayURL;
|
|
13
|
-
protocol;
|
|
14
13
|
retries;
|
|
15
14
|
retryDelaySeconds;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
constructor(arweaveJWT, logger, gatewayURL = "arweave.net", protocol = "https", port = 443, retries = 2, retryDelaySeconds = 1) {
|
|
15
|
+
gateways;
|
|
16
|
+
constructor(arweaveJWT, logger, gateways = exports.DEFAULT_ARWEAVE_GATEWAYS, retries = 2, retryDelaySeconds = 1) {
|
|
19
17
|
this.arweaveJWT = arweaveJWT;
|
|
20
18
|
this.logger = logger;
|
|
21
|
-
this.gatewayURL = gatewayURL;
|
|
22
|
-
this.protocol = protocol;
|
|
23
19
|
this.retries = retries;
|
|
24
20
|
this.retryDelaySeconds = retryDelaySeconds;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
port,
|
|
29
|
-
protocol,
|
|
30
|
-
timeout: 20000,
|
|
31
|
-
logging: false,
|
|
32
|
-
});
|
|
33
|
-
this.logger.debug({
|
|
34
|
-
at: "ArweaveClient:constructor",
|
|
35
|
-
message: "Arweave client initialized",
|
|
36
|
-
gateway: this.gatewayUrl,
|
|
37
|
-
});
|
|
21
|
+
if (gateways.length === 0) {
|
|
22
|
+
throw new Error("At least one gateway must be provided");
|
|
23
|
+
}
|
|
38
24
|
if (this.retries < 0) {
|
|
39
25
|
throw new Error(`retries cannot be < 0 and must be an integer. Currently set to ${this.retries}`);
|
|
40
26
|
}
|
|
41
27
|
if (this.retryDelaySeconds < 0) {
|
|
42
28
|
throw new Error(`delay cannot be < 0. Currently set to ${this.retryDelaySeconds}`);
|
|
43
29
|
}
|
|
30
|
+
this.gateways = gateways.map(({ host, protocol = "https", port = 443 }) => ({
|
|
31
|
+
client: new arweave_1.default({ host, port, protocol, timeout: 20000, logging: false }),
|
|
32
|
+
url: `${protocol}://${host}:${port}`,
|
|
33
|
+
}));
|
|
34
|
+
this.logger.debug({
|
|
35
|
+
at: "ArweaveClient:constructor",
|
|
36
|
+
message: "Arweave client initialized",
|
|
37
|
+
gateways: this.gateways.map((g) => g.url),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
async _raceGateways(label, fn) {
|
|
41
|
+
try {
|
|
42
|
+
return await Promise.any(this.gateways.map((gw) => this._retryRequest(() => fn(gw), 0)));
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
if (e instanceof AggregateError) {
|
|
46
|
+
const details = this.gateways.map((gw, i) => `${gw.url}: ${e.errors[i]}`).join("; ");
|
|
47
|
+
throw new Error(`All Arweave gateways failed for ${label}: ${details}`);
|
|
48
|
+
}
|
|
49
|
+
throw e;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async _failoverGateways(label, fn) {
|
|
53
|
+
const errors = [];
|
|
54
|
+
for (const gw of this.gateways) {
|
|
55
|
+
try {
|
|
56
|
+
return await this._retryRequest(() => fn(gw), 0);
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
errors.push(e);
|
|
60
|
+
this.logger.debug({
|
|
61
|
+
at: "ArweaveClient:failoverGateways",
|
|
62
|
+
message: `Gateway ${gw.url} failed for ${label}, trying next: ${e}`,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const details = this.gateways.map((gw, i) => `${gw.url}: ${errors[i]}`).join("; ");
|
|
67
|
+
throw new Error(`All Arweave gateways failed for ${label}: ${details}`);
|
|
68
|
+
}
|
|
69
|
+
async _retryRequest(request, retryCount) {
|
|
70
|
+
try {
|
|
71
|
+
return await request();
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
if (retryCount < this.retries) {
|
|
75
|
+
const baseDelay = this.retryDelaySeconds * Math.pow(2, retryCount);
|
|
76
|
+
const delayS = baseDelay + baseDelay * Math.random();
|
|
77
|
+
this.logger.debug({
|
|
78
|
+
at: "ArweaveClient:retryRequest",
|
|
79
|
+
message: `Arweave request failed, retrying after waiting ${delayS} seconds: ${e}`,
|
|
80
|
+
retryCount,
|
|
81
|
+
});
|
|
82
|
+
await (0, utils_1.delay)(delayS);
|
|
83
|
+
return this._retryRequest(request, retryCount + 1);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
throw e;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
44
89
|
}
|
|
45
90
|
async set(value, topicTag) {
|
|
46
|
-
const
|
|
91
|
+
const templateClient = this.gateways[0].client;
|
|
92
|
+
const transaction = await templateClient.createTransaction({ data: JSON.stringify(value, utils_1.jsonReplacerWithBigNumbers) }, this.arweaveJWT);
|
|
47
93
|
transaction.addTag("Content-Type", "application/json");
|
|
48
94
|
transaction.addTag("App-Name", constants_1.ARWEAVE_TAG_APP_NAME);
|
|
49
95
|
transaction.addTag("App-Version", constants_1.ARWEAVE_TAG_APP_VERSION.toString());
|
|
50
96
|
if ((0, utils_1.isDefined)(topicTag)) {
|
|
51
97
|
transaction.addTag("Topic", topicTag);
|
|
52
98
|
}
|
|
53
|
-
await
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
99
|
+
await templateClient.transactions.sign(transaction, this.arweaveJWT);
|
|
100
|
+
return await this._failoverGateways("set", async ({ client }) => {
|
|
101
|
+
const result = await client.transactions.post(transaction);
|
|
102
|
+
if (result.status !== 200) {
|
|
103
|
+
const message = result?.data?.error?.msg ?? "Unknown error";
|
|
104
|
+
this.logger.error({
|
|
105
|
+
at: "ArweaveClient:set",
|
|
106
|
+
message,
|
|
107
|
+
result,
|
|
108
|
+
txn: transaction.id,
|
|
109
|
+
address: await this.getAddress(),
|
|
110
|
+
balance: (await this.getBalance()).toString(),
|
|
111
|
+
});
|
|
112
|
+
throw new Error(message);
|
|
113
|
+
}
|
|
68
114
|
this.logger.debug({
|
|
69
115
|
at: "ArweaveClient:set",
|
|
70
116
|
message: `Arweave transaction posted with ${transaction.id}`,
|
|
71
117
|
});
|
|
72
|
-
|
|
73
|
-
|
|
118
|
+
return transaction.id;
|
|
119
|
+
});
|
|
74
120
|
}
|
|
75
121
|
async get(transactionID, validator) {
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
};
|
|
80
|
-
const data = await this._retryRequest(request, 0);
|
|
122
|
+
const data = await this._raceGateways("get", async ({ url }) => {
|
|
123
|
+
return await (0, utils_1.fetchWithTimeout)(`${url}/${transactionID}`, {}, {}, 20_000);
|
|
124
|
+
});
|
|
81
125
|
try {
|
|
82
126
|
return (0, superstruct_1.create)(data, validator);
|
|
83
127
|
}
|
|
@@ -102,13 +146,13 @@ class ArweaveClient {
|
|
|
102
146
|
]
|
|
103
147
|
) { edges { node { id } } }
|
|
104
148
|
}`;
|
|
105
|
-
const response = await this.
|
|
106
|
-
const response = await
|
|
149
|
+
const response = await this._raceGateways("getByTopic", async ({ client }) => {
|
|
150
|
+
const response = await client.api.post("/graphql", { query });
|
|
107
151
|
if (!response.ok) {
|
|
108
152
|
throw new Error(`Arweave GraphQL request failed with status ${response.status}`);
|
|
109
153
|
}
|
|
110
154
|
return response;
|
|
111
|
-
}
|
|
155
|
+
});
|
|
112
156
|
const entries = response?.data?.data?.transactions?.edges ?? [];
|
|
113
157
|
this.logger.debug({
|
|
114
158
|
at: "ArweaveClient:getByTopic",
|
|
@@ -141,7 +185,9 @@ class ArweaveClient {
|
|
|
141
185
|
return results.filter(utils_1.isDefined);
|
|
142
186
|
}
|
|
143
187
|
async getMetadata(transactionID) {
|
|
144
|
-
const transaction = await this.client
|
|
188
|
+
const transaction = await this._raceGateways("getMetadata", async ({ client }) => {
|
|
189
|
+
return await client.transactions.get(transactionID);
|
|
190
|
+
});
|
|
145
191
|
if (!(0, utils_1.isDefined)(transaction)) {
|
|
146
192
|
return null;
|
|
147
193
|
}
|
|
@@ -156,33 +202,12 @@ class ArweaveClient {
|
|
|
156
202
|
};
|
|
157
203
|
}
|
|
158
204
|
getAddress() {
|
|
159
|
-
return this.client.wallets.jwkToAddress(this.arweaveJWT);
|
|
160
|
-
}
|
|
161
|
-
async _retryRequest(request, retryCount) {
|
|
162
|
-
try {
|
|
163
|
-
return await request();
|
|
164
|
-
}
|
|
165
|
-
catch (e) {
|
|
166
|
-
if (retryCount < this.retries) {
|
|
167
|
-
const baseDelay = this.retryDelaySeconds * Math.pow(2, retryCount);
|
|
168
|
-
const delayS = baseDelay + baseDelay * Math.random();
|
|
169
|
-
this.logger.debug({
|
|
170
|
-
at: "ArweaveClient:retryRequest",
|
|
171
|
-
message: `Arweave request failed, retrying after waiting ${delayS} seconds: ${e}`,
|
|
172
|
-
retryCount,
|
|
173
|
-
});
|
|
174
|
-
await (0, utils_1.delay)(delayS);
|
|
175
|
-
return this._retryRequest(request, retryCount + 1);
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
throw e;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
205
|
+
return this.gateways[0].client.wallets.jwkToAddress(this.arweaveJWT);
|
|
181
206
|
}
|
|
182
207
|
async getBalance() {
|
|
183
208
|
const address = await this.getAddress();
|
|
184
|
-
|
|
185
|
-
const balanceInFloat = await
|
|
209
|
+
return this._raceGateways("getBalance", async ({ client }) => {
|
|
210
|
+
const balanceInFloat = await client.wallets.getBalance(address);
|
|
186
211
|
if (balanceInFloat.includes("e")) {
|
|
187
212
|
const [balance, exponent] = balanceInFloat.split("e");
|
|
188
213
|
const resultingBN = utils_1.BigNumber.from(balance).mul((0, utils_1.toBN)(10).pow(exponent.replace("+", "")));
|
|
@@ -191,8 +216,7 @@ class ArweaveClient {
|
|
|
191
216
|
else {
|
|
192
217
|
return utils_1.BigNumber.from(balanceInFloat);
|
|
193
218
|
}
|
|
194
|
-
};
|
|
195
|
-
return await this._retryRequest(request, 0);
|
|
219
|
+
});
|
|
196
220
|
}
|
|
197
221
|
}
|
|
198
222
|
exports.ArweaveClient = ArweaveClient;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArweaveClient.js","sourceRoot":"","sources":["../../../../../src/caching/Arweave/ArweaveClient.ts"],"names":[],"mappings":";;;;AAAA,8DAA8B;AAG9B,6CAA6C;AAE7C,+CAAiH;AACjH,uCAA8G;
|
|
1
|
+
{"version":3,"file":"ArweaveClient.js","sourceRoot":"","sources":["../../../../../src/caching/Arweave/ArweaveClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,16 +2,30 @@ import { JWKInterface } from "arweave/node/lib/wallet";
|
|
|
2
2
|
import { Struct } from "superstruct";
|
|
3
3
|
import winston from "winston";
|
|
4
4
|
import { BigNumber } from "../../utils";
|
|
5
|
+
export interface ArweaveGatewayConfig {
|
|
6
|
+
host: string;
|
|
7
|
+
protocol?: string;
|
|
8
|
+
port?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const DEFAULT_ARWEAVE_GATEWAYS: ArweaveGatewayConfig[];
|
|
5
11
|
export declare class ArweaveClient {
|
|
6
12
|
private arweaveJWT;
|
|
7
13
|
private logger;
|
|
8
|
-
gatewayURL: string;
|
|
9
|
-
protocol: string;
|
|
10
14
|
private readonly retries;
|
|
11
15
|
private readonly retryDelaySeconds;
|
|
12
|
-
private
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
private gateways;
|
|
17
|
+
constructor(arweaveJWT: JWKInterface, logger: winston.Logger, gateways?: ArweaveGatewayConfig[], retries?: number, retryDelaySeconds?: number);
|
|
18
|
+
/**
|
|
19
|
+
* Races a request across all gateways, returning the first successful response.
|
|
20
|
+
* If all gateways fail, throws an error with details from each gateway.
|
|
21
|
+
*/
|
|
22
|
+
private _raceGateways;
|
|
23
|
+
/**
|
|
24
|
+
* Tries gateways sequentially, returning the first successful response.
|
|
25
|
+
* Used for write operations where we want exactly one successful submission.
|
|
26
|
+
*/
|
|
27
|
+
private _failoverGateways;
|
|
28
|
+
private _retryRequest;
|
|
15
29
|
/**
|
|
16
30
|
* Stores an arbitrary record in the Arweave network. The record is stored as a JSON string and uses
|
|
17
31
|
* JSON.stringify to convert the record to a string. The record has all of its big numbers converted
|
|
@@ -19,7 +33,6 @@ export declare class ArweaveClient {
|
|
|
19
33
|
* @param value The value to store
|
|
20
34
|
* @param topicTag An optional topic tag to add to the transaction
|
|
21
35
|
* @returns The transaction ID of the stored value
|
|
22
|
-
* @
|
|
23
36
|
*/
|
|
24
37
|
set(value: Record<string, unknown>, topicTag?: string | undefined): Promise<string | undefined>;
|
|
25
38
|
/**
|
|
@@ -53,11 +66,11 @@ export declare class ArweaveClient {
|
|
|
53
66
|
*/
|
|
54
67
|
getMetadata(transactionID: string): Promise<Record<string, string> | null>;
|
|
55
68
|
/**
|
|
56
|
-
* Returns the address of the signer of the JWT
|
|
69
|
+
* Returns the address of the signer of the JWT. This is a local crypto
|
|
70
|
+
* operation and does not require a network call.
|
|
57
71
|
* @returns The address of the signer in this client
|
|
58
72
|
*/
|
|
59
73
|
getAddress(): Promise<string>;
|
|
60
|
-
private _retryRequest;
|
|
61
74
|
/**
|
|
62
75
|
* The balance of the signer
|
|
63
76
|
* @returns The balance of the signer in winston units
|
|
@@ -2,41 +2,95 @@ import Arweave from "arweave";
|
|
|
2
2
|
import { create } from "superstruct";
|
|
3
3
|
import { ARWEAVE_TAG_APP_NAME, ARWEAVE_TAG_APP_VERSION, DEFAULT_ARWEAVE_STORAGE_ADDRESS } from "../../constants";
|
|
4
4
|
import { BigNumber, delay, fetchWithTimeout, isDefined, jsonReplacerWithBigNumbers, toBN } from "../../utils";
|
|
5
|
+
export const DEFAULT_ARWEAVE_GATEWAYS = [{ host: "arweave.net" }, { host: "ar-io.net" }];
|
|
5
6
|
export class ArweaveClient {
|
|
6
7
|
arweaveJWT;
|
|
7
8
|
logger;
|
|
8
|
-
gatewayURL;
|
|
9
|
-
protocol;
|
|
10
9
|
retries;
|
|
11
10
|
retryDelaySeconds;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
constructor(arweaveJWT, logger, gatewayURL = "arweave.net", protocol = "https", port = 443, retries = 2, retryDelaySeconds = 1) {
|
|
11
|
+
gateways;
|
|
12
|
+
constructor(arweaveJWT, logger, gateways = DEFAULT_ARWEAVE_GATEWAYS, retries = 2, retryDelaySeconds = 1) {
|
|
15
13
|
this.arweaveJWT = arweaveJWT;
|
|
16
14
|
this.logger = logger;
|
|
17
|
-
this.gatewayURL = gatewayURL;
|
|
18
|
-
this.protocol = protocol;
|
|
19
15
|
this.retries = retries;
|
|
20
16
|
this.retryDelaySeconds = retryDelaySeconds;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
port,
|
|
25
|
-
protocol,
|
|
26
|
-
timeout: 20000,
|
|
27
|
-
logging: false,
|
|
28
|
-
});
|
|
29
|
-
this.logger.debug({
|
|
30
|
-
at: "ArweaveClient:constructor",
|
|
31
|
-
message: "Arweave client initialized",
|
|
32
|
-
gateway: this.gatewayUrl,
|
|
33
|
-
});
|
|
17
|
+
if (gateways.length === 0) {
|
|
18
|
+
throw new Error("At least one gateway must be provided");
|
|
19
|
+
}
|
|
34
20
|
if (this.retries < 0) {
|
|
35
21
|
throw new Error(`retries cannot be < 0 and must be an integer. Currently set to ${this.retries}`);
|
|
36
22
|
}
|
|
37
23
|
if (this.retryDelaySeconds < 0) {
|
|
38
24
|
throw new Error(`delay cannot be < 0. Currently set to ${this.retryDelaySeconds}`);
|
|
39
25
|
}
|
|
26
|
+
this.gateways = gateways.map(({ host, protocol = "https", port = 443 }) => ({
|
|
27
|
+
client: new Arweave({ host, port, protocol, timeout: 20000, logging: false }),
|
|
28
|
+
url: `${protocol}://${host}:${port}`,
|
|
29
|
+
}));
|
|
30
|
+
this.logger.debug({
|
|
31
|
+
at: "ArweaveClient:constructor",
|
|
32
|
+
message: "Arweave client initialized",
|
|
33
|
+
gateways: this.gateways.map((g) => g.url),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Races a request across all gateways, returning the first successful response.
|
|
38
|
+
* If all gateways fail, throws an error with details from each gateway.
|
|
39
|
+
*/
|
|
40
|
+
async _raceGateways(label, fn) {
|
|
41
|
+
try {
|
|
42
|
+
return await Promise.any(this.gateways.map((gw) => this._retryRequest(() => fn(gw), 0)));
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
if (e instanceof AggregateError) {
|
|
46
|
+
const details = this.gateways.map((gw, i) => `${gw.url}: ${e.errors[i]}`).join("; ");
|
|
47
|
+
throw new Error(`All Arweave gateways failed for ${label}: ${details}`);
|
|
48
|
+
}
|
|
49
|
+
throw e;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Tries gateways sequentially, returning the first successful response.
|
|
54
|
+
* Used for write operations where we want exactly one successful submission.
|
|
55
|
+
*/
|
|
56
|
+
async _failoverGateways(label, fn) {
|
|
57
|
+
const errors = [];
|
|
58
|
+
for (const gw of this.gateways) {
|
|
59
|
+
try {
|
|
60
|
+
return await this._retryRequest(() => fn(gw), 0);
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
errors.push(e);
|
|
64
|
+
this.logger.debug({
|
|
65
|
+
at: "ArweaveClient:failoverGateways",
|
|
66
|
+
message: `Gateway ${gw.url} failed for ${label}, trying next: ${e}`,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const details = this.gateways.map((gw, i) => `${gw.url}: ${errors[i]}`).join("; ");
|
|
71
|
+
throw new Error(`All Arweave gateways failed for ${label}: ${details}`);
|
|
72
|
+
}
|
|
73
|
+
async _retryRequest(request, retryCount) {
|
|
74
|
+
try {
|
|
75
|
+
return await request();
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
if (retryCount < this.retries) {
|
|
79
|
+
// Implement a slightly aggressive exponential backoff to account for fierce parallelism.
|
|
80
|
+
const baseDelay = this.retryDelaySeconds * Math.pow(2, retryCount);
|
|
81
|
+
const delayS = baseDelay + baseDelay * Math.random();
|
|
82
|
+
this.logger.debug({
|
|
83
|
+
at: "ArweaveClient:retryRequest",
|
|
84
|
+
message: `Arweave request failed, retrying after waiting ${delayS} seconds: ${e}`,
|
|
85
|
+
retryCount,
|
|
86
|
+
});
|
|
87
|
+
await delay(delayS);
|
|
88
|
+
return this._retryRequest(request, retryCount + 1);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
throw e;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
40
94
|
}
|
|
41
95
|
/**
|
|
42
96
|
* Stores an arbitrary record in the Arweave network. The record is stored as a JSON string and uses
|
|
@@ -45,10 +99,12 @@ export class ArweaveClient {
|
|
|
45
99
|
* @param value The value to store
|
|
46
100
|
* @param topicTag An optional topic tag to add to the transaction
|
|
47
101
|
* @returns The transaction ID of the stored value
|
|
48
|
-
* @
|
|
49
102
|
*/
|
|
50
103
|
async set(value, topicTag) {
|
|
51
|
-
|
|
104
|
+
// Get a template client to use for creating a transaction. Since clients are equal up to the gateway URL,
|
|
105
|
+
// it does not matter which gateway is used, so we just choose the first one.
|
|
106
|
+
const templateClient = this.gateways[0].client;
|
|
107
|
+
const transaction = await templateClient.createTransaction({ data: JSON.stringify(value, jsonReplacerWithBigNumbers) }, this.arweaveJWT);
|
|
52
108
|
// Add tags to the transaction
|
|
53
109
|
transaction.addTag("Content-Type", "application/json");
|
|
54
110
|
transaction.addTag("App-Name", ARWEAVE_TAG_APP_NAME);
|
|
@@ -57,29 +113,29 @@ export class ArweaveClient {
|
|
|
57
113
|
transaction.addTag("Topic", topicTag);
|
|
58
114
|
}
|
|
59
115
|
// Sign the transaction
|
|
60
|
-
await
|
|
116
|
+
await templateClient.transactions.sign(transaction, this.arweaveJWT);
|
|
61
117
|
// Send the transaction
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
118
|
+
return await this._failoverGateways("set", async ({ client }) => {
|
|
119
|
+
const result = await client.transactions.post(transaction);
|
|
120
|
+
// Ensure that the result is successful
|
|
121
|
+
if (result.status !== 200) {
|
|
122
|
+
const message = result?.data?.error?.msg ?? "Unknown error";
|
|
123
|
+
this.logger.error({
|
|
124
|
+
at: "ArweaveClient:set",
|
|
125
|
+
message,
|
|
126
|
+
result,
|
|
127
|
+
txn: transaction.id,
|
|
128
|
+
address: await this.getAddress(),
|
|
129
|
+
balance: (await this.getBalance()).toString(),
|
|
130
|
+
});
|
|
131
|
+
throw new Error(message);
|
|
132
|
+
}
|
|
77
133
|
this.logger.debug({
|
|
78
134
|
at: "ArweaveClient:set",
|
|
79
135
|
message: `Arweave transaction posted with ${transaction.id}`,
|
|
80
136
|
});
|
|
81
|
-
|
|
82
|
-
|
|
137
|
+
return transaction.id;
|
|
138
|
+
});
|
|
83
139
|
}
|
|
84
140
|
/**
|
|
85
141
|
* Retrieves a record from the Arweave network. The record is expected to be a JSON string and is
|
|
@@ -89,15 +145,12 @@ export class ArweaveClient {
|
|
|
89
145
|
* @returns The record if it exists, otherwise null
|
|
90
146
|
*/
|
|
91
147
|
async get(transactionID, validator) {
|
|
92
|
-
//
|
|
93
|
-
const transactionUrl = `${this.gatewayUrl}/${transactionID}`;
|
|
94
|
-
// We should query in via Axios directly to the gateway URL. The reasoning behind this is
|
|
148
|
+
// We query via fetchWithTimeout directly to the gateway URL. The reasoning behind this is
|
|
95
149
|
// that the Arweave SDK's `getData` method is too slow and does not provide a way to set a timeout.
|
|
96
150
|
// Therefore, something that could take milliseconds to complete could take tens of minutes.
|
|
97
|
-
const
|
|
98
|
-
return await fetchWithTimeout(
|
|
99
|
-
};
|
|
100
|
-
const data = await this._retryRequest(request, 0);
|
|
151
|
+
const data = await this._raceGateways("get", async ({ url }) => {
|
|
152
|
+
return await fetchWithTimeout(`${url}/${transactionID}`, {}, {}, 20_000);
|
|
153
|
+
});
|
|
101
154
|
try {
|
|
102
155
|
// We should validate the data and perform any logical coercion here.
|
|
103
156
|
return create(data, validator);
|
|
@@ -136,13 +189,13 @@ export class ArweaveClient {
|
|
|
136
189
|
]
|
|
137
190
|
) { edges { node { id } } }
|
|
138
191
|
}`;
|
|
139
|
-
const response = await this.
|
|
140
|
-
const response = await
|
|
192
|
+
const response = await this._raceGateways("getByTopic", async ({ client }) => {
|
|
193
|
+
const response = await client.api.post("/graphql", { query });
|
|
141
194
|
if (!response.ok) {
|
|
142
195
|
throw new Error(`Arweave GraphQL request failed with status ${response.status}`);
|
|
143
196
|
}
|
|
144
197
|
return response;
|
|
145
|
-
}
|
|
198
|
+
});
|
|
146
199
|
const entries = response?.data?.data?.transactions?.edges ?? [];
|
|
147
200
|
this.logger.debug({
|
|
148
201
|
at: "ArweaveClient:getByTopic",
|
|
@@ -180,7 +233,9 @@ export class ArweaveClient {
|
|
|
180
233
|
* @returns The metadata of the transaction if it exists, otherwise null
|
|
181
234
|
*/
|
|
182
235
|
async getMetadata(transactionID) {
|
|
183
|
-
const transaction = await this.client
|
|
236
|
+
const transaction = await this._raceGateways("getMetadata", async ({ client }) => {
|
|
237
|
+
return await client.transactions.get(transactionID);
|
|
238
|
+
});
|
|
184
239
|
if (!isDefined(transaction)) {
|
|
185
240
|
return null;
|
|
186
241
|
}
|
|
@@ -195,33 +250,12 @@ export class ArweaveClient {
|
|
|
195
250
|
};
|
|
196
251
|
}
|
|
197
252
|
/**
|
|
198
|
-
* Returns the address of the signer of the JWT
|
|
253
|
+
* Returns the address of the signer of the JWT. This is a local crypto
|
|
254
|
+
* operation and does not require a network call.
|
|
199
255
|
* @returns The address of the signer in this client
|
|
200
256
|
*/
|
|
201
257
|
getAddress() {
|
|
202
|
-
return this.client.wallets.jwkToAddress(this.arweaveJWT);
|
|
203
|
-
}
|
|
204
|
-
async _retryRequest(request, retryCount) {
|
|
205
|
-
try {
|
|
206
|
-
return await request();
|
|
207
|
-
}
|
|
208
|
-
catch (e) {
|
|
209
|
-
if (retryCount < this.retries) {
|
|
210
|
-
// Implement a slightly aggressive exponential backoff to account for fierce parallelism.
|
|
211
|
-
const baseDelay = this.retryDelaySeconds * Math.pow(2, retryCount); // ms; attempt = [0, 1, 2, ...]
|
|
212
|
-
const delayS = baseDelay + baseDelay * Math.random();
|
|
213
|
-
this.logger.debug({
|
|
214
|
-
at: "ArweaveClient:retryRequest",
|
|
215
|
-
message: `Arweave request failed, retrying after waiting ${delayS} seconds: ${e}`,
|
|
216
|
-
retryCount,
|
|
217
|
-
});
|
|
218
|
-
await delay(delayS);
|
|
219
|
-
return this._retryRequest(request, retryCount + 1);
|
|
220
|
-
}
|
|
221
|
-
else {
|
|
222
|
-
throw e;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
258
|
+
return this.gateways[0].client.wallets.jwkToAddress(this.arweaveJWT);
|
|
225
259
|
}
|
|
226
260
|
/**
|
|
227
261
|
* The balance of the signer
|
|
@@ -229,9 +263,9 @@ export class ArweaveClient {
|
|
|
229
263
|
*/
|
|
230
264
|
async getBalance() {
|
|
231
265
|
const address = await this.getAddress();
|
|
232
|
-
|
|
233
|
-
const balanceInFloat = await
|
|
234
|
-
// @dev The reason we add in the BN.from
|
|
266
|
+
return this._raceGateways("getBalance", async ({ client }) => {
|
|
267
|
+
const balanceInFloat = await client.wallets.getBalance(address);
|
|
268
|
+
// @dev The reason we add in the BN.from here is because the client.getBalance call
|
|
235
269
|
// does not correctly throw an error if the request fails, instead it will return the error string as the
|
|
236
270
|
// balanceInFloat.
|
|
237
271
|
// Sometimes the balance is returned in scientific notation, so we need to
|
|
@@ -244,8 +278,7 @@ export class ArweaveClient {
|
|
|
244
278
|
else {
|
|
245
279
|
return BigNumber.from(balanceInFloat);
|
|
246
280
|
}
|
|
247
|
-
};
|
|
248
|
-
return await this._retryRequest(request, 0);
|
|
281
|
+
});
|
|
249
282
|
}
|
|
250
283
|
}
|
|
251
284
|
//# sourceMappingURL=ArweaveClient.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArweaveClient.js","sourceRoot":"","sources":["../../../../../src/caching/Arweave/ArweaveClient.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAG9B,OAAO,EAAU,MAAM,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,+BAA+B,EAAE,MAAM,iBAAiB,CAAC;AACjH,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,0BAA0B,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"ArweaveClient.js","sourceRoot":"","sources":["../../../../../src/caching/Arweave/ArweaveClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,16 +2,30 @@ import { JWKInterface } from "arweave/node/lib/wallet";
|
|
|
2
2
|
import { Struct } from "superstruct";
|
|
3
3
|
import winston from "winston";
|
|
4
4
|
import { BigNumber } from "../../utils";
|
|
5
|
+
export interface ArweaveGatewayConfig {
|
|
6
|
+
host: string;
|
|
7
|
+
protocol?: string;
|
|
8
|
+
port?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const DEFAULT_ARWEAVE_GATEWAYS: ArweaveGatewayConfig[];
|
|
5
11
|
export declare class ArweaveClient {
|
|
6
12
|
private arweaveJWT;
|
|
7
13
|
private logger;
|
|
8
|
-
gatewayURL: string;
|
|
9
|
-
protocol: string;
|
|
10
14
|
private readonly retries;
|
|
11
15
|
private readonly retryDelaySeconds;
|
|
12
|
-
private
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
private gateways;
|
|
17
|
+
constructor(arweaveJWT: JWKInterface, logger: winston.Logger, gateways?: ArweaveGatewayConfig[], retries?: number, retryDelaySeconds?: number);
|
|
18
|
+
/**
|
|
19
|
+
* Races a request across all gateways, returning the first successful response.
|
|
20
|
+
* If all gateways fail, throws an error with details from each gateway.
|
|
21
|
+
*/
|
|
22
|
+
private _raceGateways;
|
|
23
|
+
/**
|
|
24
|
+
* Tries gateways sequentially, returning the first successful response.
|
|
25
|
+
* Used for write operations where we want exactly one successful submission.
|
|
26
|
+
*/
|
|
27
|
+
private _failoverGateways;
|
|
28
|
+
private _retryRequest;
|
|
15
29
|
/**
|
|
16
30
|
* Stores an arbitrary record in the Arweave network. The record is stored as a JSON string and uses
|
|
17
31
|
* JSON.stringify to convert the record to a string. The record has all of its big numbers converted
|
|
@@ -19,7 +33,6 @@ export declare class ArweaveClient {
|
|
|
19
33
|
* @param value The value to store
|
|
20
34
|
* @param topicTag An optional topic tag to add to the transaction
|
|
21
35
|
* @returns The transaction ID of the stored value
|
|
22
|
-
* @
|
|
23
36
|
*/
|
|
24
37
|
set(value: Record<string, unknown>, topicTag?: string | undefined): Promise<string | undefined>;
|
|
25
38
|
/**
|
|
@@ -53,11 +66,11 @@ export declare class ArweaveClient {
|
|
|
53
66
|
*/
|
|
54
67
|
getMetadata(transactionID: string): Promise<Record<string, string> | null>;
|
|
55
68
|
/**
|
|
56
|
-
* Returns the address of the signer of the JWT
|
|
69
|
+
* Returns the address of the signer of the JWT. This is a local crypto
|
|
70
|
+
* operation and does not require a network call.
|
|
57
71
|
* @returns The address of the signer in this client
|
|
58
72
|
*/
|
|
59
73
|
getAddress(): Promise<string>;
|
|
60
|
-
private _retryRequest;
|
|
61
74
|
/**
|
|
62
75
|
* The balance of the signer
|
|
63
76
|
* @returns The balance of the signer in winston units
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArweaveClient.d.ts","sourceRoot":"","sources":["../../../../../src/caching/Arweave/ArweaveClient.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,MAAM,EAAU,MAAM,aAAa,CAAC;AAC7C,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,SAAS,EAAwE,MAAM,aAAa,CAAC;AAE9G,
|
|
1
|
+
{"version":3,"file":"ArweaveClient.d.ts","sourceRoot":"","sources":["../../../../../src/caching/Arweave/ArweaveClient.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,MAAM,EAAU,MAAM,aAAa,CAAC;AAC7C,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,SAAS,EAAwE,MAAM,aAAa,CAAC;AAE9G,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,wBAAwB,EAAE,oBAAoB,EAAqD,CAAC;AAOjH,qBAAa,aAAa;IAItB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,MAAM;IAEd,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAPpC,OAAO,CAAC,QAAQ,CAAY;gBAGlB,UAAU,EAAE,YAAY,EACxB,MAAM,EAAE,OAAO,CAAC,MAAM,EAC9B,QAAQ,GAAE,oBAAoB,EAA6B,EAC1C,OAAO,SAAI,EACX,iBAAiB,SAAI;IAsBxC;;;OAGG;YACW,aAAa;IAY3B;;;OAGG;YACW,iBAAiB;YAiBjB,aAAa;IAqB3B;;;;;;;OAOG;IACG,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IA8CrG;;;;;;OAMG;IACG,GAAG,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAoB5E;;;;;;;;;;;OAWG;IACG,UAAU,CAAC,CAAC,EAChB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,EACpB,kBAAkB,SAAkC,GACnD,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAyDvC;;;;OAIG;IACG,WAAW,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IAoBhF;;;;OAIG;IACH,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAI7B;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,SAAS,CAAC;CAkBvC"}
|
package/package.json
CHANGED
|
@@ -6,38 +6,105 @@ import winston from "winston";
|
|
|
6
6
|
import { ARWEAVE_TAG_APP_NAME, ARWEAVE_TAG_APP_VERSION, DEFAULT_ARWEAVE_STORAGE_ADDRESS } from "../../constants";
|
|
7
7
|
import { BigNumber, delay, fetchWithTimeout, isDefined, jsonReplacerWithBigNumbers, toBN } from "../../utils";
|
|
8
8
|
|
|
9
|
+
export interface ArweaveGatewayConfig {
|
|
10
|
+
host: string;
|
|
11
|
+
protocol?: string;
|
|
12
|
+
port?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const DEFAULT_ARWEAVE_GATEWAYS: ArweaveGatewayConfig[] = [{ host: "arweave.net" }, { host: "ar-io.net" }];
|
|
16
|
+
|
|
17
|
+
interface Gateway {
|
|
18
|
+
client: Arweave;
|
|
19
|
+
url: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
9
22
|
export class ArweaveClient {
|
|
10
|
-
private
|
|
11
|
-
private gatewayUrl: string;
|
|
23
|
+
private gateways: Gateway[];
|
|
12
24
|
|
|
13
25
|
public constructor(
|
|
14
26
|
private arweaveJWT: JWKInterface,
|
|
15
27
|
private logger: winston.Logger,
|
|
16
|
-
|
|
17
|
-
public protocol = "https",
|
|
18
|
-
port = 443,
|
|
28
|
+
gateways: ArweaveGatewayConfig[] = DEFAULT_ARWEAVE_GATEWAYS,
|
|
19
29
|
private readonly retries = 2,
|
|
20
30
|
private readonly retryDelaySeconds = 1
|
|
21
31
|
) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
port,
|
|
26
|
-
protocol,
|
|
27
|
-
timeout: 20000,
|
|
28
|
-
logging: false,
|
|
29
|
-
});
|
|
30
|
-
this.logger.debug({
|
|
31
|
-
at: "ArweaveClient:constructor",
|
|
32
|
-
message: "Arweave client initialized",
|
|
33
|
-
gateway: this.gatewayUrl,
|
|
34
|
-
});
|
|
32
|
+
if (gateways.length === 0) {
|
|
33
|
+
throw new Error("At least one gateway must be provided");
|
|
34
|
+
}
|
|
35
35
|
if (this.retries < 0) {
|
|
36
36
|
throw new Error(`retries cannot be < 0 and must be an integer. Currently set to ${this.retries}`);
|
|
37
37
|
}
|
|
38
38
|
if (this.retryDelaySeconds < 0) {
|
|
39
39
|
throw new Error(`delay cannot be < 0. Currently set to ${this.retryDelaySeconds}`);
|
|
40
40
|
}
|
|
41
|
+
this.gateways = gateways.map(({ host, protocol = "https", port = 443 }) => ({
|
|
42
|
+
client: new Arweave({ host, port, protocol, timeout: 20000, logging: false }),
|
|
43
|
+
url: `${protocol}://${host}:${port}`,
|
|
44
|
+
}));
|
|
45
|
+
this.logger.debug({
|
|
46
|
+
at: "ArweaveClient:constructor",
|
|
47
|
+
message: "Arweave client initialized",
|
|
48
|
+
gateways: this.gateways.map((g) => g.url),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Races a request across all gateways, returning the first successful response.
|
|
54
|
+
* If all gateways fail, throws an error with details from each gateway.
|
|
55
|
+
*/
|
|
56
|
+
private async _raceGateways<T>(label: string, fn: (gw: Gateway) => Promise<T>): Promise<T> {
|
|
57
|
+
try {
|
|
58
|
+
return await Promise.any(this.gateways.map((gw) => this._retryRequest(() => fn(gw), 0)));
|
|
59
|
+
} catch (e) {
|
|
60
|
+
if (e instanceof AggregateError) {
|
|
61
|
+
const details = this.gateways.map((gw, i) => `${gw.url}: ${e.errors[i]}`).join("; ");
|
|
62
|
+
throw new Error(`All Arweave gateways failed for ${label}: ${details}`);
|
|
63
|
+
}
|
|
64
|
+
throw e;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Tries gateways sequentially, returning the first successful response.
|
|
70
|
+
* Used for write operations where we want exactly one successful submission.
|
|
71
|
+
*/
|
|
72
|
+
private async _failoverGateways<T>(label: string, fn: (gw: Gateway) => Promise<T>): Promise<T> {
|
|
73
|
+
const errors: Error[] = [];
|
|
74
|
+
for (const gw of this.gateways) {
|
|
75
|
+
try {
|
|
76
|
+
return await this._retryRequest(() => fn(gw), 0);
|
|
77
|
+
} catch (e) {
|
|
78
|
+
errors.push(e as Error);
|
|
79
|
+
this.logger.debug({
|
|
80
|
+
at: "ArweaveClient:failoverGateways",
|
|
81
|
+
message: `Gateway ${gw.url} failed for ${label}, trying next: ${e}`,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const details = this.gateways.map((gw, i) => `${gw.url}: ${errors[i]}`).join("; ");
|
|
86
|
+
throw new Error(`All Arweave gateways failed for ${label}: ${details}`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private async _retryRequest<T>(request: () => Promise<T>, retryCount: number): Promise<T> {
|
|
90
|
+
try {
|
|
91
|
+
return await request();
|
|
92
|
+
} catch (e) {
|
|
93
|
+
if (retryCount < this.retries) {
|
|
94
|
+
// Implement a slightly aggressive exponential backoff to account for fierce parallelism.
|
|
95
|
+
const baseDelay = this.retryDelaySeconds * Math.pow(2, retryCount);
|
|
96
|
+
const delayS = baseDelay + baseDelay * Math.random();
|
|
97
|
+
this.logger.debug({
|
|
98
|
+
at: "ArweaveClient:retryRequest",
|
|
99
|
+
message: `Arweave request failed, retrying after waiting ${delayS} seconds: ${e}`,
|
|
100
|
+
retryCount,
|
|
101
|
+
});
|
|
102
|
+
await delay(delayS);
|
|
103
|
+
return this._retryRequest(request, retryCount + 1);
|
|
104
|
+
} else {
|
|
105
|
+
throw e;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
41
108
|
}
|
|
42
109
|
|
|
43
110
|
/**
|
|
@@ -47,10 +114,12 @@ export class ArweaveClient {
|
|
|
47
114
|
* @param value The value to store
|
|
48
115
|
* @param topicTag An optional topic tag to add to the transaction
|
|
49
116
|
* @returns The transaction ID of the stored value
|
|
50
|
-
* @
|
|
51
117
|
*/
|
|
52
118
|
async set(value: Record<string, unknown>, topicTag?: string | undefined): Promise<string | undefined> {
|
|
53
|
-
|
|
119
|
+
// Get a template client to use for creating a transaction. Since clients are equal up to the gateway URL,
|
|
120
|
+
// it does not matter which gateway is used, so we just choose the first one.
|
|
121
|
+
const templateClient = this.gateways[0].client;
|
|
122
|
+
const transaction = await templateClient.createTransaction(
|
|
54
123
|
{ data: JSON.stringify(value, jsonReplacerWithBigNumbers) },
|
|
55
124
|
this.arweaveJWT
|
|
56
125
|
);
|
|
@@ -64,29 +133,32 @@ export class ArweaveClient {
|
|
|
64
133
|
}
|
|
65
134
|
|
|
66
135
|
// Sign the transaction
|
|
67
|
-
await
|
|
136
|
+
await templateClient.transactions.sign(transaction, this.arweaveJWT);
|
|
68
137
|
// Send the transaction
|
|
69
|
-
const result = await this.client.transactions.post(transaction);
|
|
70
138
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
message
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
139
|
+
return await this._failoverGateways("set", async ({ client }) => {
|
|
140
|
+
const result = await client.transactions.post(transaction);
|
|
141
|
+
|
|
142
|
+
// Ensure that the result is successful
|
|
143
|
+
if (result.status !== 200) {
|
|
144
|
+
const message = result?.data?.error?.msg ?? "Unknown error";
|
|
145
|
+
this.logger.error({
|
|
146
|
+
at: "ArweaveClient:set",
|
|
147
|
+
message,
|
|
148
|
+
result,
|
|
149
|
+
txn: transaction.id,
|
|
150
|
+
address: await this.getAddress(),
|
|
151
|
+
balance: (await this.getBalance()).toString(),
|
|
152
|
+
});
|
|
153
|
+
throw new Error(message);
|
|
154
|
+
}
|
|
155
|
+
|
|
84
156
|
this.logger.debug({
|
|
85
157
|
at: "ArweaveClient:set",
|
|
86
158
|
message: `Arweave transaction posted with ${transaction.id}`,
|
|
87
159
|
});
|
|
88
|
-
|
|
89
|
-
|
|
160
|
+
return transaction.id;
|
|
161
|
+
});
|
|
90
162
|
}
|
|
91
163
|
|
|
92
164
|
/**
|
|
@@ -97,15 +169,12 @@ export class ArweaveClient {
|
|
|
97
169
|
* @returns The record if it exists, otherwise null
|
|
98
170
|
*/
|
|
99
171
|
async get<T>(transactionID: string, validator: Struct<T>): Promise<T | null> {
|
|
100
|
-
//
|
|
101
|
-
const transactionUrl = `${this.gatewayUrl}/${transactionID}`;
|
|
102
|
-
// We should query in via Axios directly to the gateway URL. The reasoning behind this is
|
|
172
|
+
// We query via fetchWithTimeout directly to the gateway URL. The reasoning behind this is
|
|
103
173
|
// that the Arweave SDK's `getData` method is too slow and does not provide a way to set a timeout.
|
|
104
174
|
// Therefore, something that could take milliseconds to complete could take tens of minutes.
|
|
105
|
-
const
|
|
106
|
-
return await fetchWithTimeout(
|
|
107
|
-
};
|
|
108
|
-
const data = await this._retryRequest(request, 0);
|
|
175
|
+
const data = await this._raceGateways("get", async ({ url }) => {
|
|
176
|
+
return await fetchWithTimeout(`${url}/${transactionID}`, {}, {}, 20_000);
|
|
177
|
+
});
|
|
109
178
|
try {
|
|
110
179
|
// We should validate the data and perform any logical coercion here.
|
|
111
180
|
return create(data, validator);
|
|
@@ -149,15 +218,15 @@ export class ArweaveClient {
|
|
|
149
218
|
) { edges { node { id } } }
|
|
150
219
|
}`;
|
|
151
220
|
|
|
152
|
-
const response = await this.
|
|
153
|
-
const response = await
|
|
221
|
+
const response = await this._raceGateways("getByTopic", async ({ client }) => {
|
|
222
|
+
const response = await client.api.post<{
|
|
154
223
|
data: { transactions: { edges: { node: { id: string } }[] } };
|
|
155
224
|
}>("/graphql", { query });
|
|
156
225
|
if (!response.ok) {
|
|
157
226
|
throw new Error(`Arweave GraphQL request failed with status ${response.status}`);
|
|
158
227
|
}
|
|
159
228
|
return response;
|
|
160
|
-
}
|
|
229
|
+
});
|
|
161
230
|
|
|
162
231
|
const entries = response?.data?.data?.transactions?.edges ?? [];
|
|
163
232
|
this.logger.debug({
|
|
@@ -198,7 +267,9 @@ export class ArweaveClient {
|
|
|
198
267
|
* @returns The metadata of the transaction if it exists, otherwise null
|
|
199
268
|
*/
|
|
200
269
|
async getMetadata(transactionID: string): Promise<Record<string, string> | null> {
|
|
201
|
-
const transaction = await this.client
|
|
270
|
+
const transaction = await this._raceGateways("getMetadata", async ({ client }) => {
|
|
271
|
+
return await client.transactions.get(transactionID);
|
|
272
|
+
});
|
|
202
273
|
if (!isDefined(transaction)) {
|
|
203
274
|
return null;
|
|
204
275
|
}
|
|
@@ -216,32 +287,12 @@ export class ArweaveClient {
|
|
|
216
287
|
}
|
|
217
288
|
|
|
218
289
|
/**
|
|
219
|
-
* Returns the address of the signer of the JWT
|
|
290
|
+
* Returns the address of the signer of the JWT. This is a local crypto
|
|
291
|
+
* operation and does not require a network call.
|
|
220
292
|
* @returns The address of the signer in this client
|
|
221
293
|
*/
|
|
222
294
|
getAddress(): Promise<string> {
|
|
223
|
-
return this.client.wallets.jwkToAddress(this.arweaveJWT);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
private async _retryRequest<T>(request: () => Promise<T>, retryCount: number): Promise<T> {
|
|
227
|
-
try {
|
|
228
|
-
return await request();
|
|
229
|
-
} catch (e) {
|
|
230
|
-
if (retryCount < this.retries) {
|
|
231
|
-
// Implement a slightly aggressive exponential backoff to account for fierce parallelism.
|
|
232
|
-
const baseDelay = this.retryDelaySeconds * Math.pow(2, retryCount); // ms; attempt = [0, 1, 2, ...]
|
|
233
|
-
const delayS = baseDelay + baseDelay * Math.random();
|
|
234
|
-
this.logger.debug({
|
|
235
|
-
at: "ArweaveClient:retryRequest",
|
|
236
|
-
message: `Arweave request failed, retrying after waiting ${delayS} seconds: ${e}`,
|
|
237
|
-
retryCount,
|
|
238
|
-
});
|
|
239
|
-
await delay(delayS);
|
|
240
|
-
return this._retryRequest(request, retryCount + 1);
|
|
241
|
-
} else {
|
|
242
|
-
throw e;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
295
|
+
return this.gateways[0].client.wallets.jwkToAddress(this.arweaveJWT);
|
|
245
296
|
}
|
|
246
297
|
|
|
247
298
|
/**
|
|
@@ -250,9 +301,9 @@ export class ArweaveClient {
|
|
|
250
301
|
*/
|
|
251
302
|
async getBalance(): Promise<BigNumber> {
|
|
252
303
|
const address = await this.getAddress();
|
|
253
|
-
|
|
254
|
-
const balanceInFloat = await
|
|
255
|
-
// @dev The reason we add in the BN.from
|
|
304
|
+
return this._raceGateways("getBalance", async ({ client }) => {
|
|
305
|
+
const balanceInFloat = await client.wallets.getBalance(address);
|
|
306
|
+
// @dev The reason we add in the BN.from here is because the client.getBalance call
|
|
256
307
|
// does not correctly throw an error if the request fails, instead it will return the error string as the
|
|
257
308
|
// balanceInFloat.
|
|
258
309
|
// Sometimes the balance is returned in scientific notation, so we need to
|
|
@@ -264,7 +315,6 @@ export class ArweaveClient {
|
|
|
264
315
|
} else {
|
|
265
316
|
return BigNumber.from(balanceInFloat);
|
|
266
317
|
}
|
|
267
|
-
};
|
|
268
|
-
return await this._retryRequest(request, 0);
|
|
318
|
+
});
|
|
269
319
|
}
|
|
270
320
|
}
|