@ar.io/sdk 3.10.0-alpha.6 → 3.10.1

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.
Files changed (104) hide show
  1. package/README.md +66 -125
  2. package/bundles/web.bundle.min.js +147 -126
  3. package/lib/cjs/cli/commands/antCommands.js +3 -4
  4. package/lib/cjs/cli/commands/arnsPurchaseCommands.js +5 -6
  5. package/lib/cjs/cli/commands/gatewayWriteCommands.js +11 -12
  6. package/lib/cjs/cli/commands/readCommands.js +21 -22
  7. package/lib/cjs/cli/commands/transfer.js +6 -7
  8. package/lib/cjs/cli/options.js +0 -12
  9. package/lib/cjs/cli/utils.js +52 -74
  10. package/lib/cjs/common/ant-versions.js +5 -5
  11. package/lib/cjs/common/faucet.js +2 -2
  12. package/lib/cjs/common/index.js +0 -2
  13. package/lib/cjs/common/io.js +5 -64
  14. package/lib/cjs/types/ant.js +2 -13
  15. package/lib/cjs/types/index.js +0 -1
  16. package/lib/cjs/types/io.js +5 -5
  17. package/lib/cjs/utils/ao.js +9 -14
  18. package/lib/cjs/utils/arweave.js +4 -4
  19. package/lib/cjs/utils/base64.js +4 -5
  20. package/lib/cjs/utils/json.js +1 -2
  21. package/lib/cjs/utils/schema.js +1 -2
  22. package/lib/cjs/version.js +1 -1
  23. package/lib/cjs/web/index.js +1 -3
  24. package/lib/esm/cli/options.js +0 -12
  25. package/lib/esm/cli/utils.js +10 -31
  26. package/lib/esm/common/ant-versions.js +5 -5
  27. package/lib/esm/common/index.js +0 -2
  28. package/lib/esm/common/io.js +5 -64
  29. package/lib/esm/types/ant.js +0 -11
  30. package/lib/esm/types/index.js +0 -1
  31. package/lib/esm/types/io.js +1 -1
  32. package/lib/esm/utils/ao.js +0 -5
  33. package/lib/esm/version.js +1 -1
  34. package/lib/esm/web/index.js +1 -1
  35. package/lib/types/cli/commands/antCommands.d.ts +3 -3
  36. package/lib/types/cli/commands/arnsPurchaseCommands.d.ts +1 -1
  37. package/lib/types/cli/commands/gatewayWriteCommands.d.ts +9 -9
  38. package/lib/types/cli/commands/readCommands.d.ts +3 -4
  39. package/lib/types/cli/commands/transfer.d.ts +3 -3
  40. package/lib/types/cli/options.d.ts +0 -9
  41. package/lib/types/cli/types.d.ts +0 -3
  42. package/lib/types/cli/utils.d.ts +0 -4
  43. package/lib/types/common/ant-versions.d.ts +6 -3
  44. package/lib/types/common/http.d.ts +0 -1
  45. package/lib/types/common/index.d.ts +0 -1
  46. package/lib/types/common/io.d.ts +9 -15
  47. package/lib/types/types/ant.d.ts +1 -53
  48. package/lib/types/types/common.d.ts +2 -8
  49. package/lib/types/types/index.d.ts +0 -1
  50. package/lib/types/types/io.d.ts +7 -9
  51. package/lib/types/types/token.d.ts +0 -2
  52. package/lib/types/utils/ao.d.ts +12 -1
  53. package/lib/types/utils/base64.d.ts +0 -2
  54. package/lib/types/version.d.ts +1 -1
  55. package/lib/types/web/index.d.ts +1 -1
  56. package/package.json +3 -5
  57. package/lib/cjs/common/turbo.js +0 -208
  58. package/lib/cjs/common/wayfinder/gateways.js +0 -75
  59. package/lib/cjs/common/wayfinder/index.js +0 -36
  60. package/lib/cjs/common/wayfinder/routers/fixed.js +0 -14
  61. package/lib/cjs/common/wayfinder/routers/fixed.test.js +0 -14
  62. package/lib/cjs/common/wayfinder/routers/priority.js +0 -38
  63. package/lib/cjs/common/wayfinder/routers/priority.test.js +0 -155
  64. package/lib/cjs/common/wayfinder/routers/random.js +0 -23
  65. package/lib/cjs/common/wayfinder/routers/random.test.js +0 -104
  66. package/lib/cjs/common/wayfinder/routers/simple-cache.js +0 -25
  67. package/lib/cjs/common/wayfinder/routers/simple-cache.test.js +0 -41
  68. package/lib/cjs/common/wayfinder/wayfinder.js +0 -194
  69. package/lib/cjs/common/wayfinder/wayfinder.test.js +0 -254
  70. package/lib/cjs/types/wayfinder.js +0 -2
  71. package/lib/cjs/utils/url.js +0 -28
  72. package/lib/cjs/utils/url.test.js +0 -24
  73. package/lib/esm/common/turbo.js +0 -200
  74. package/lib/esm/common/wayfinder/gateways.js +0 -69
  75. package/lib/esm/common/wayfinder/index.js +0 -20
  76. package/lib/esm/common/wayfinder/routers/fixed.js +0 -10
  77. package/lib/esm/common/wayfinder/routers/fixed.test.js +0 -12
  78. package/lib/esm/common/wayfinder/routers/priority.js +0 -34
  79. package/lib/esm/common/wayfinder/routers/priority.test.js +0 -153
  80. package/lib/esm/common/wayfinder/routers/random.js +0 -19
  81. package/lib/esm/common/wayfinder/routers/random.test.js +0 -102
  82. package/lib/esm/common/wayfinder/routers/simple-cache.js +0 -21
  83. package/lib/esm/common/wayfinder/routers/simple-cache.test.js +0 -39
  84. package/lib/esm/common/wayfinder/wayfinder.js +0 -187
  85. package/lib/esm/common/wayfinder/wayfinder.test.js +0 -249
  86. package/lib/esm/types/wayfinder.js +0 -1
  87. package/lib/esm/utils/url.js +0 -24
  88. package/lib/esm/utils/url.test.js +0 -19
  89. package/lib/types/common/turbo.d.ts +0 -62
  90. package/lib/types/common/wayfinder/gateways.d.ts +0 -44
  91. package/lib/types/common/wayfinder/index.d.ts +0 -19
  92. package/lib/types/common/wayfinder/routers/fixed.d.ts +0 -25
  93. package/lib/types/common/wayfinder/routers/fixed.test.d.ts +0 -1
  94. package/lib/types/common/wayfinder/routers/priority.d.ts +0 -34
  95. package/lib/types/common/wayfinder/routers/priority.test.d.ts +0 -1
  96. package/lib/types/common/wayfinder/routers/random.d.ts +0 -28
  97. package/lib/types/common/wayfinder/routers/random.test.d.ts +0 -1
  98. package/lib/types/common/wayfinder/routers/simple-cache.d.ts +0 -29
  99. package/lib/types/common/wayfinder/routers/simple-cache.test.d.ts +0 -1
  100. package/lib/types/common/wayfinder/wayfinder.d.ts +0 -106
  101. package/lib/types/common/wayfinder/wayfinder.test.d.ts +0 -1
  102. package/lib/types/types/wayfinder.d.ts +0 -20
  103. package/lib/types/utils/url.d.ts +0 -19
  104. package/lib/types/utils/url.test.d.ts +0 -1
@@ -1,200 +0,0 @@
1
- /**
2
- * Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
- import { ArconnectSigner, ArweaveSigner, EthereumSigner, InjectedEthereumSigner, SignatureConfig, } from '@dha-team/arbundles';
17
- import { v4 as uuidv4 } from 'uuid';
18
- import { mARIOToken } from '../types/token.js';
19
- import { toB64Url } from '../utils/base64.js';
20
- import { createAxiosInstance } from '../utils/http-client.js';
21
- import { urlWithSearchParams } from '../utils/url.js';
22
- import { Logger } from './logger.js';
23
- export async function signedRequestHeadersFromSigner({ signer, nonce = uuidv4(), }) {
24
- let signature = undefined;
25
- let publicKey = undefined;
26
- const signatureType = isWanderArweaveBrowserSigner(signer)
27
- ? SignatureConfig.ARWEAVE
28
- : signer.signatureType;
29
- // equivalent to window.arweaveWallet
30
- if (isWanderArweaveBrowserSigner(signer)) {
31
- signature = toB64Url(Buffer.from(await signer.signMessage(Uint8Array.from(Buffer.from(nonce)))));
32
- }
33
- else if (signer instanceof ArconnectSigner) {
34
- signature = toB64Url(Buffer.from(await signer['signer'].signMessage(Uint8Array.from(Buffer.from(nonce)))));
35
- }
36
- else if (signer instanceof ArweaveSigner ||
37
- signer instanceof EthereumSigner ||
38
- signer instanceof InjectedEthereumSigner) {
39
- if ('setPublicKey' in signer && signer['publicKey'] === undefined) {
40
- await signer.setPublicKey();
41
- }
42
- signature = toB64Url(Buffer.from(await signer.sign(Uint8Array.from(Buffer.from(nonce)))));
43
- }
44
- switch (signatureType) {
45
- case SignatureConfig.ARWEAVE:
46
- if (isWanderArweaveBrowserSigner(signer)) {
47
- publicKey = await signer.getActivePublicKey();
48
- }
49
- else if ('setPublicKey' in signer) {
50
- await signer.setPublicKey();
51
- publicKey = toB64Url(signer.publicKey);
52
- }
53
- break;
54
- case SignatureConfig.ETHEREUM:
55
- if ('publicKey' in signer) {
56
- publicKey = '0x' + signer.publicKey.toString('hex');
57
- }
58
- else {
59
- throw new Error('Public key not found');
60
- }
61
- break;
62
- // TODO: solana sig support
63
- // case SignatureConfig.SOLANA:
64
- // case SignatureConfig.ED25519:
65
- default:
66
- throw new Error(`Unsupported signer type for signing requests: ${signatureType}`);
67
- }
68
- if (publicKey === undefined || signature === undefined) {
69
- throw new Error('Public key or signature not found');
70
- }
71
- return {
72
- 'x-public-key': publicKey,
73
- 'x-nonce': nonce,
74
- 'x-signature': signature,
75
- 'x-signature-type': signatureType,
76
- };
77
- }
78
- export class TurboArNSPaymentFactory {
79
- static init(config) {
80
- const { signer, paymentUrl, axios, logger } = config ?? {};
81
- if (signer !== undefined) {
82
- return new TurboArNSPaymentProviderAuthenticated({
83
- signer,
84
- paymentUrl,
85
- axios,
86
- logger,
87
- });
88
- }
89
- return new TurboArNSPaymentProviderUnauthenticated({
90
- paymentUrl,
91
- axios,
92
- logger,
93
- });
94
- }
95
- }
96
- // Base class for unauthenticated operations
97
- export class TurboArNSPaymentProviderUnauthenticated {
98
- paymentUrl;
99
- axios;
100
- logger;
101
- constructor({ paymentUrl = 'https://payment.ardrive.io', axios = createAxiosInstance(), logger = Logger.default, }) {
102
- this.paymentUrl = paymentUrl;
103
- this.axios = axios;
104
- this.logger = logger;
105
- }
106
- async getArNSPriceDetails({ intent, name, quantity, type, years, }) {
107
- const url = urlWithSearchParams({
108
- baseUrl: `${this.paymentUrl}/v1/arns/price/${intent}/${name}`,
109
- params: {
110
- increaseQty: quantity,
111
- type,
112
- years,
113
- },
114
- });
115
- const { data, status } = await this.axios.get(url);
116
- this.logger.debug('getArNSPriceDetails', {
117
- intent,
118
- name,
119
- quantity,
120
- type,
121
- years,
122
- data,
123
- status,
124
- });
125
- if (status !== 200) {
126
- throw new Error('Failed to get ArNS purchase price ' + JSON.stringify(data));
127
- }
128
- if (!data.winc || !data.mARIO) {
129
- throw new Error('Invalid response from Turbo ' + JSON.stringify(data));
130
- }
131
- return {
132
- winc: data.winc,
133
- mARIO: new mARIOToken(+data.mARIO),
134
- };
135
- }
136
- async getPrice(params) {
137
- const { winc } = await this.getArNSPriceDetails(params);
138
- return +winc;
139
- }
140
- }
141
- // Class for authenticated operations, extending the base class
142
- export class TurboArNSPaymentProviderAuthenticated extends TurboArNSPaymentProviderUnauthenticated {
143
- signer;
144
- constructor({ signer, ...restConfig }) {
145
- super(restConfig); // Pass unauthenticated config to base class+
146
- if (!isTurboArNSSigner(signer)) {
147
- throw new Error('Signer must be a TurboArNSSigner');
148
- }
149
- this.signer = signer;
150
- }
151
- async initiateArNSPurchase({ intent, name, quantity, type, processId, years, }) {
152
- // Signer check is implicitly handled by requiring it in the constructor
153
- const url = urlWithSearchParams({
154
- baseUrl: `${this.paymentUrl}/v1/arns/purchase/${intent}/${name}`,
155
- params: {
156
- increaseQty: quantity,
157
- processId,
158
- type,
159
- years,
160
- },
161
- });
162
- const headers = await signedRequestHeadersFromSigner({
163
- signer: this.signer,
164
- });
165
- const { data, status } = await this.axios.post(url, null, {
166
- headers,
167
- });
168
- this.logger.debug('Initiated ArNS purchase', {
169
- intent,
170
- name,
171
- quantity,
172
- processId,
173
- type,
174
- years,
175
- data,
176
- status,
177
- });
178
- if (status !== 200) {
179
- throw new Error('Failed to initiate ArNS purchase ' + JSON.stringify(data));
180
- }
181
- return {
182
- id: data.arioWriteResult.id,
183
- result: data.purchaseReceipt,
184
- };
185
- }
186
- }
187
- function isWanderArweaveBrowserSigner(signer) {
188
- return (typeof signer === 'object' &&
189
- signer !== null &&
190
- 'signMessage' in signer &&
191
- 'getActivePublicKey' in signer);
192
- }
193
- export function isTurboArNSSigner(signer) {
194
- const isWanderWallet = isWanderArweaveBrowserSigner(signer);
195
- const isSigner = signer instanceof EthereumSigner ||
196
- signer instanceof InjectedEthereumSigner ||
197
- signer instanceof ArweaveSigner ||
198
- signer instanceof ArconnectSigner;
199
- return isWanderWallet || isSigner;
200
- }
@@ -1,69 +0,0 @@
1
- export class ARIOGatewaysProvider {
2
- ario;
3
- constructor({ ario }) {
4
- this.ario = ario;
5
- }
6
- async getGateways() {
7
- let cursor;
8
- let attempts = 0;
9
- const gateways = [];
10
- do {
11
- try {
12
- const { items: newGateways, nextCursor } = await this.ario.getGateways({
13
- limit: 1000,
14
- cursor,
15
- });
16
- gateways.push(...newGateways);
17
- cursor = nextCursor;
18
- attempts = 0; // reset attempts if we get a new cursor
19
- }
20
- catch (error) {
21
- console.error('Error fetching gateways', {
22
- cursor,
23
- attempts,
24
- error,
25
- });
26
- attempts++;
27
- }
28
- } while (cursor !== undefined && attempts < 3);
29
- // filter out any gateways that are not joined
30
- return gateways.filter((g) => g.status === 'joined');
31
- }
32
- }
33
- export class StaticGatewaysProvider {
34
- gateways;
35
- constructor({ gateways }) {
36
- this.gateways = gateways;
37
- }
38
- async getGateways() {
39
- return this.gateways;
40
- }
41
- }
42
- export class SimpleCacheGatewaysProvider {
43
- gatewaysProvider;
44
- ttlSeconds;
45
- lastUpdated;
46
- gatewaysCache;
47
- constructor({ gatewaysProvider, ttlSeconds = 5 * 60, // 5 minutes
48
- }) {
49
- this.gatewaysCache = [];
50
- this.gatewaysProvider = gatewaysProvider;
51
- this.ttlSeconds = ttlSeconds;
52
- }
53
- async getGateways() {
54
- const now = Date.now();
55
- if (this.gatewaysCache.length === 0 ||
56
- now - this.lastUpdated > this.ttlSeconds * 1000) {
57
- try {
58
- // preserve the cache if the fetch fails
59
- const allGateways = await this.gatewaysProvider.getGateways();
60
- this.gatewaysCache = allGateways.filter((g) => g.status === 'joined');
61
- this.lastUpdated = now;
62
- }
63
- catch (error) {
64
- console.error('Error fetching gateways', error);
65
- }
66
- }
67
- return this.gatewaysCache;
68
- }
69
- }
@@ -1,20 +0,0 @@
1
- /**
2
- * Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
- export * from './wayfinder.js';
17
- // routers
18
- export * from './routers/random.js';
19
- export * from './routers/priority.js';
20
- export * from './routers/fixed.js';
@@ -1,10 +0,0 @@
1
- export class FixedGatewayRouter {
2
- name = 'fixed';
3
- gateway;
4
- constructor({ gateway }) {
5
- this.gateway = gateway;
6
- }
7
- async getTargetGateway() {
8
- return this.gateway;
9
- }
10
- }
@@ -1,12 +0,0 @@
1
- import { strict as assert } from 'node:assert';
2
- import { describe, it } from 'node:test';
3
- import { FixedGatewayRouter } from './fixed.js';
4
- describe('FixedRouter', () => {
5
- it('should return the provided gateway', async () => {
6
- const router = new FixedGatewayRouter({
7
- gateway: new URL('http://test-gateway.net'),
8
- });
9
- const result = await router.getTargetGateway();
10
- assert.deepStrictEqual(result, new URL('http://test-gateway.net'));
11
- });
12
- });
@@ -1,34 +0,0 @@
1
- import { randomInt } from '../wayfinder.js';
2
- // TODO: one of N where N are in the last time window have met certain performance thresholds
3
- // TODO: look at bitorrent routing protocols for inspiration
4
- // TODO: router that looks at local stats/metrics and adjusts based on those
5
- export class PriorityGatewayRouter {
6
- name = 'priority';
7
- gatewaysProvider;
8
- limit;
9
- sortBy;
10
- sortOrder;
11
- blocklist;
12
- constructor({ gatewaysProvider, limit = 1, sortBy = 'operatorStake', sortOrder = 'desc', blocklist = [], }) {
13
- this.gatewaysProvider = gatewaysProvider;
14
- this.limit = limit;
15
- this.sortBy = sortBy;
16
- this.sortOrder = sortOrder;
17
- this.blocklist = blocklist;
18
- }
19
- async getTargetGateway() {
20
- const allGateways = await this.gatewaysProvider.getGateways();
21
- const gateways = allGateways.filter((gateway) => gateway.status === 'joined' &&
22
- !this.blocklist.includes(gateway.settings.fqdn));
23
- const sortedGateways = gateways
24
- .sort(this.sortOrder === 'asc'
25
- ? (a, b) => a[this.sortBy] - b[this.sortBy]
26
- : (a, b) => b[this.sortBy] - a[this.sortBy])
27
- .slice(0, this.limit);
28
- const targetGateway = sortedGateways[randomInt(0, sortedGateways.length)];
29
- if (targetGateway === undefined) {
30
- throw new Error('No target gateway found');
31
- }
32
- return new URL(`${targetGateway.settings.protocol}://${targetGateway.settings.fqdn}:${targetGateway.settings.port}`);
33
- }
34
- }
@@ -1,153 +0,0 @@
1
- import { strict as assert } from 'node:assert';
2
- import { describe, it } from 'node:test';
3
- import { PriorityGatewayRouter } from './priority.js';
4
- describe('PriorityRouter', () => {
5
- const mockGateways = [
6
- {
7
- settings: {
8
- fqdn: 'gateway1.net',
9
- port: 443,
10
- protocol: 'https',
11
- allowDelegatedStaking: false,
12
- delegateRewardShareRatio: 0.5,
13
- allowedDelegates: [],
14
- minDelegatedStake: 0,
15
- autoStake: false,
16
- properties: '',
17
- label: '',
18
- note: '',
19
- },
20
- gatewayAddress: 'addr1',
21
- observerAddress: 'addr1',
22
- totalDelegatedStake: 1000,
23
- startTimestamp: 0,
24
- endTimestamp: 0,
25
- operatorStake: 100,
26
- status: 'joined',
27
- weights: {
28
- normalizedCompositeWeight: 0.5,
29
- stakeWeight: 0.5,
30
- tenureWeight: 0.5,
31
- gatewayPerformanceRatio: 0.5,
32
- observerPerformanceRatio: 0.5,
33
- compositeWeight: 0.5,
34
- gatewayRewardRatioWeight: 0.5,
35
- observerRewardRatioWeight: 0.5,
36
- },
37
- stats: {
38
- passedConsecutiveEpochs: 10,
39
- failedConsecutiveEpochs: 5,
40
- totalEpochCount: 15,
41
- passedEpochCount: 10,
42
- failedEpochCount: 5,
43
- observedEpochCount: 15,
44
- prescribedEpochCount: 20,
45
- },
46
- },
47
- {
48
- settings: {
49
- fqdn: 'gateway1.net',
50
- port: 443,
51
- protocol: 'https',
52
- allowDelegatedStaking: false,
53
- delegateRewardShareRatio: 0.5,
54
- allowedDelegates: [],
55
- minDelegatedStake: 0,
56
- autoStake: false,
57
- properties: '',
58
- label: '',
59
- note: '',
60
- },
61
- gatewayAddress: 'addr1',
62
- observerAddress: 'addr1',
63
- totalDelegatedStake: 2000,
64
- startTimestamp: 0,
65
- endTimestamp: 0,
66
- operatorStake: 2000,
67
- status: 'joined',
68
- weights: {
69
- normalizedCompositeWeight: 0.5,
70
- stakeWeight: 0.5,
71
- tenureWeight: 0.5,
72
- gatewayPerformanceRatio: 0.5,
73
- observerPerformanceRatio: 0.5,
74
- compositeWeight: 0.5,
75
- gatewayRewardRatioWeight: 0.5,
76
- observerRewardRatioWeight: 0.5,
77
- },
78
- stats: {
79
- passedConsecutiveEpochs: 10,
80
- failedConsecutiveEpochs: 5,
81
- totalEpochCount: 15,
82
- passedEpochCount: 10,
83
- failedEpochCount: 5,
84
- observedEpochCount: 15,
85
- prescribedEpochCount: 20,
86
- },
87
- },
88
- {
89
- settings: {
90
- fqdn: 'gateway2.net',
91
- port: 443,
92
- protocol: 'https',
93
- allowDelegatedStaking: false,
94
- delegateRewardShareRatio: 0.5,
95
- allowedDelegates: [],
96
- minDelegatedStake: 0,
97
- autoStake: false,
98
- properties: '',
99
- label: '',
100
- note: '',
101
- },
102
- gatewayAddress: 'addr2',
103
- observerAddress: 'addr2',
104
- totalDelegatedStake: 0,
105
- startTimestamp: 0,
106
- endTimestamp: 0,
107
- operatorStake: 0,
108
- status: 'leaving',
109
- weights: {
110
- normalizedCompositeWeight: 0.5,
111
- stakeWeight: 0.5,
112
- tenureWeight: 0.5,
113
- gatewayPerformanceRatio: 0.5,
114
- observerPerformanceRatio: 0.5,
115
- compositeWeight: 0.5,
116
- gatewayRewardRatioWeight: 0.5,
117
- observerRewardRatioWeight: 0.5,
118
- },
119
- stats: {
120
- passedConsecutiveEpochs: 10,
121
- failedConsecutiveEpochs: 5,
122
- totalEpochCount: 15,
123
- passedEpochCount: 10,
124
- failedEpochCount: 5,
125
- observedEpochCount: 15,
126
- prescribedEpochCount: 20,
127
- },
128
- },
129
- ];
130
- const mockGatewaysProvider = {
131
- getGateways: async () => mockGateways,
132
- };
133
- it('should prioritize gateway with highest success rate when using successRate weight', async () => {
134
- const router = new PriorityGatewayRouter({
135
- gatewaysProvider: mockGatewaysProvider,
136
- sortBy: 'totalDelegatedStake',
137
- sortOrder: 'desc',
138
- limit: 1,
139
- });
140
- const result = await router.getTargetGateway();
141
- assert.deepStrictEqual(result, new URL('http://gateway1.net'));
142
- });
143
- it('should prioritize gateway with lowest latency when using latency weight', async () => {
144
- const router = new PriorityGatewayRouter({
145
- gatewaysProvider: mockGatewaysProvider,
146
- sortBy: 'operatorStake',
147
- sortOrder: 'desc',
148
- limit: 1,
149
- });
150
- const result = await router.getTargetGateway();
151
- assert.deepStrictEqual(result, new URL('http://gateway2.net'));
152
- });
153
- });
@@ -1,19 +0,0 @@
1
- import { randomInt } from '../wayfinder.js';
2
- export class RandomGatewayRouter {
3
- name = 'random';
4
- gatewaysProvider;
5
- blocklist;
6
- constructor({ gatewaysProvider, blocklist = [], }) {
7
- this.gatewaysProvider = gatewaysProvider;
8
- this.blocklist = blocklist;
9
- }
10
- async getTargetGateway() {
11
- const allGateways = await this.gatewaysProvider.getGateways();
12
- const gateways = allGateways.filter((g) => g.status === 'joined' && !this.blocklist.includes(g.settings.fqdn));
13
- const targetGateway = gateways[randomInt(0, gateways.length)];
14
- if (targetGateway === undefined) {
15
- throw new Error('No target gateway found');
16
- }
17
- return new URL(`${targetGateway.settings.protocol}://${targetGateway.settings.fqdn}:${targetGateway.settings.port}`);
18
- }
19
- }
@@ -1,102 +0,0 @@
1
- import { strict as assert } from 'node:assert';
2
- import { describe, it } from 'node:test';
3
- import { RandomGatewayRouter } from './random.js';
4
- describe('RandomRouter', () => {
5
- const mockGateways = [
6
- {
7
- settings: {
8
- fqdn: 'gateway1.net',
9
- port: 443,
10
- protocol: 'https',
11
- allowDelegatedStaking: false,
12
- delegateRewardShareRatio: 0.5,
13
- allowedDelegates: [],
14
- minDelegatedStake: 0,
15
- autoStake: false,
16
- properties: '',
17
- label: '',
18
- note: '',
19
- },
20
- gatewayAddress: 'addr1',
21
- observerAddress: 'addr1',
22
- totalDelegatedStake: 1000,
23
- startTimestamp: 0,
24
- endTimestamp: 0,
25
- operatorStake: 100,
26
- status: 'joined',
27
- weights: {
28
- normalizedCompositeWeight: 0.5,
29
- stakeWeight: 0.5,
30
- tenureWeight: 0.5,
31
- gatewayPerformanceRatio: 0.5,
32
- observerPerformanceRatio: 0.5,
33
- compositeWeight: 0.5,
34
- gatewayRewardRatioWeight: 0.5,
35
- observerRewardRatioWeight: 0.5,
36
- },
37
- stats: {
38
- passedConsecutiveEpochs: 10,
39
- failedConsecutiveEpochs: 5,
40
- totalEpochCount: 15,
41
- passedEpochCount: 10,
42
- failedEpochCount: 5,
43
- observedEpochCount: 15,
44
- prescribedEpochCount: 20,
45
- },
46
- },
47
- {
48
- settings: {
49
- fqdn: 'gateway2.net',
50
- port: 443,
51
- protocol: 'https',
52
- allowDelegatedStaking: false,
53
- delegateRewardShareRatio: 0.5,
54
- allowedDelegates: [],
55
- minDelegatedStake: 0,
56
- autoStake: false,
57
- properties: '',
58
- label: '',
59
- note: '',
60
- },
61
- gatewayAddress: 'addr2',
62
- observerAddress: 'addr2',
63
- totalDelegatedStake: 0,
64
- startTimestamp: 0,
65
- endTimestamp: 0,
66
- operatorStake: 0,
67
- status: 'leaving',
68
- weights: {
69
- normalizedCompositeWeight: 0.5,
70
- stakeWeight: 0.5,
71
- tenureWeight: 0.5,
72
- gatewayPerformanceRatio: 0.5,
73
- observerPerformanceRatio: 0.5,
74
- compositeWeight: 0.5,
75
- gatewayRewardRatioWeight: 0.5,
76
- observerRewardRatioWeight: 0.5,
77
- },
78
- stats: {
79
- passedConsecutiveEpochs: 10,
80
- failedConsecutiveEpochs: 5,
81
- totalEpochCount: 15,
82
- passedEpochCount: 10,
83
- failedEpochCount: 5,
84
- observedEpochCount: 15,
85
- prescribedEpochCount: 20,
86
- },
87
- },
88
- ];
89
- const mockGatewaysProvider = {
90
- getGateways: async () => mockGateways,
91
- };
92
- it('should only return joined gateways', async () => {
93
- const router = new RandomGatewayRouter({
94
- gatewaysProvider: mockGatewaysProvider,
95
- });
96
- // Run multiple times to ensure we only get joined gateways
97
- for (let i = 0; i < 10; i++) {
98
- const result = await router.getTargetGateway();
99
- assert.deepStrictEqual(result, new URL('https://gateway1.net'));
100
- }
101
- });
102
- });
@@ -1,21 +0,0 @@
1
- export class SimpleCacheRouter {
2
- name;
3
- lastUpdatedTimestamp;
4
- ttlSeconds;
5
- targetGateway;
6
- router;
7
- constructor({ router, ttlSeconds = 5 * 60, // 5 minutes
8
- }) {
9
- this.router = router;
10
- this.ttlSeconds = ttlSeconds;
11
- }
12
- async getTargetGateway() {
13
- if (this.targetGateway === undefined ||
14
- this.lastUpdatedTimestamp + this.ttlSeconds * 1000 < Date.now()) {
15
- this.targetGateway = await this.router.getTargetGateway();
16
- this.lastUpdatedTimestamp = Date.now();
17
- }
18
- return this.targetGateway;
19
- }
20
- }
21
- // TODO: a router that accepts ario and a router, and adds read through promise cache to ario.getGateways to avoid calling the ARIO contract on every request
@@ -1,39 +0,0 @@
1
- import { strict as assert } from 'node:assert';
2
- import { describe, it } from 'node:test';
3
- import { SimpleCacheRouter } from './simple-cache.js';
4
- describe('SimpleCacheRouter', () => {
5
- it('should cache gateway for TTL period even if underlying gateway changes', async () => {
6
- const gateway1 = new URL('https://gateway1.net');
7
- const gateway2 = new URL('https://gateway2.net');
8
- let currentGateway = gateway1;
9
- const mockRouter = {
10
- name: 'mock',
11
- getTargetGateway: async () => currentGateway,
12
- };
13
- const router = new SimpleCacheRouter({
14
- router: mockRouter,
15
- ttlSeconds: 300, // 5 minutes
16
- });
17
- // Get initial gateway which should be cached
18
- const initial = await router.getTargetGateway();
19
- assert.deepStrictEqual(initial, gateway1);
20
- // Change the underlying gateway
21
- currentGateway = gateway2;
22
- // Should still return cached gateway1 for multiple calls
23
- for (let i = 0; i < 5; i++) {
24
- const result = await router.getTargetGateway();
25
- assert.deepStrictEqual(result, gateway1);
26
- }
27
- // Advance time past TTL
28
- const originalNow = Date.now;
29
- try {
30
- Date.now = () => originalNow() + 300 * 1000 + 1;
31
- // Should now return the new gateway2
32
- const result = await router.getTargetGateway();
33
- assert.deepStrictEqual(result, gateway2);
34
- }
35
- finally {
36
- Date.now = originalNow;
37
- }
38
- });
39
- });