@metamask-previews/eth-json-rpc-middleware 21.0.0-preview-e98a6769 → 21.0.0-preview-772b5970
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/block-ref-rewrite.cjs +8 -2
- package/dist/block-ref-rewrite.cjs.map +1 -1
- package/dist/block-ref-rewrite.d.cts +8 -0
- package/dist/block-ref-rewrite.d.cts.map +1 -1
- package/dist/block-ref-rewrite.d.mts +8 -0
- package/dist/block-ref-rewrite.d.mts.map +1 -1
- package/dist/block-ref-rewrite.mjs +8 -2
- package/dist/block-ref-rewrite.mjs.map +1 -1
- package/dist/block-tracker-inspector.cjs +21 -23
- package/dist/block-tracker-inspector.cjs.map +1 -1
- package/dist/block-tracker-inspector.d.cts +10 -4
- package/dist/block-tracker-inspector.d.cts.map +1 -1
- package/dist/block-tracker-inspector.d.mts +10 -4
- package/dist/block-tracker-inspector.d.mts.map +1 -1
- package/dist/block-tracker-inspector.mjs +21 -23
- package/dist/block-tracker-inspector.mjs.map +1 -1
- package/dist/retryOnEmpty.cjs +15 -0
- package/dist/retryOnEmpty.cjs.map +1 -1
- package/dist/retryOnEmpty.d.cts +10 -4
- package/dist/retryOnEmpty.d.cts.map +1 -1
- package/dist/retryOnEmpty.d.mts +10 -4
- package/dist/retryOnEmpty.d.mts.map +1 -1
- package/dist/retryOnEmpty.mjs +15 -0
- package/dist/retryOnEmpty.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -3,17 +3,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createBlockRefRewriteMiddleware = void 0;
|
|
4
4
|
const json_rpc_engine_1 = require("@metamask/json-rpc-engine");
|
|
5
5
|
const cache_1 = require("./utils/cache.cjs");
|
|
6
|
+
/**
|
|
7
|
+
* Creates a middleware that rewrites "latest" block references to the known
|
|
8
|
+
* latest block number from a block tracker.
|
|
9
|
+
*
|
|
10
|
+
* @param options - The options for the middleware.
|
|
11
|
+
* @param options.blockTracker - The block tracker to use.
|
|
12
|
+
* @returns The middleware.
|
|
13
|
+
*/
|
|
6
14
|
function createBlockRefRewriteMiddleware({ blockTracker, } = {}) {
|
|
7
15
|
if (!blockTracker) {
|
|
8
16
|
throw Error('BlockRefRewriteMiddleware - mandatory "blockTracker" option is missing.');
|
|
9
17
|
}
|
|
10
18
|
return (0, json_rpc_engine_1.createAsyncMiddleware)(async (req, _res, next) => {
|
|
11
19
|
const blockRefIndex = (0, cache_1.blockTagParamIndex)(req.method);
|
|
12
|
-
// skip if method does not include blockRef
|
|
13
20
|
if (blockRefIndex === undefined) {
|
|
14
21
|
return next();
|
|
15
22
|
}
|
|
16
|
-
// skip if not "latest"
|
|
17
23
|
const blockRef = Array.isArray(req.params) && req.params[blockRefIndex]
|
|
18
24
|
? req.params[blockRefIndex]
|
|
19
25
|
: // omitted blockRef implies "latest"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-ref-rewrite.cjs","sourceRoot":"","sources":["../src/block-ref-rewrite.ts"],"names":[],"mappings":";;;AAEA,+DAAkE;AAGlE,6CAAmD;AAMnD,SAAgB,+BAA+B,CAAC,EAC9C,YAAY,MACwB,EAAE;IAItC,IAAI,CAAC,YAAY,EAAE;QACjB,MAAM,KAAK,CACT,yEAAyE,CAC1E,CAAC;KACH;IAED,OAAO,IAAA,uCAAqB,EAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;QACrD,MAAM,aAAa,GAAuB,IAAA,0BAAkB,EAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzE,
|
|
1
|
+
{"version":3,"file":"block-ref-rewrite.cjs","sourceRoot":"","sources":["../src/block-ref-rewrite.ts"],"names":[],"mappings":";;;AAEA,+DAAkE;AAGlE,6CAAmD;AAMnD;;;;;;;GAOG;AACH,SAAgB,+BAA+B,CAAC,EAC9C,YAAY,MACwB,EAAE;IAItC,IAAI,CAAC,YAAY,EAAE;QACjB,MAAM,KAAK,CACT,yEAAyE,CAC1E,CAAC;KACH;IAED,OAAO,IAAA,uCAAqB,EAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;QACrD,MAAM,aAAa,GAAuB,IAAA,0BAAkB,EAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzE,IAAI,aAAa,KAAK,SAAS,EAAE;YAC/B,OAAO,IAAI,EAAE,CAAC;SACf;QAED,MAAM,QAAQ,GACZ,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC;YACpD,CAAC,CAAE,GAAG,CAAC,MAAM,CAAC,aAAa,CAAY;YACvC,CAAC,CAAC,oCAAoC;gBACpC,QAAQ,CAAC;QAEf,IAAI,QAAQ,KAAK,QAAQ,EAAE;YACzB,OAAO,IAAI,EAAE,CAAC;SACf;QAED,mDAAmD;QACnD,MAAM,iBAAiB,GAAG,MAAM,YAAY,CAAC,cAAc,EAAE,CAAC;QAC9D,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YAC7B,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,iBAAiB,CAAC;SAC/C;QACD,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC;AAnCD,0EAmCC","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport type { Json, JsonRpcParams } from '@metamask/utils';\n\nimport { blockTagParamIndex } from './utils/cache';\n\ntype BlockRefRewriteMiddlewareOptions = {\n blockTracker?: PollingBlockTracker;\n};\n\n/**\n * Creates a middleware that rewrites \"latest\" block references to the known\n * latest block number from a block tracker.\n *\n * @param options - The options for the middleware.\n * @param options.blockTracker - The block tracker to use.\n * @returns The middleware.\n */\nexport function createBlockRefRewriteMiddleware({\n blockTracker,\n}: BlockRefRewriteMiddlewareOptions = {}): JsonRpcMiddleware<\n JsonRpcParams,\n Json\n> {\n if (!blockTracker) {\n throw Error(\n 'BlockRefRewriteMiddleware - mandatory \"blockTracker\" option is missing.',\n );\n }\n\n return createAsyncMiddleware(async (req, _res, next) => {\n const blockRefIndex: number | undefined = blockTagParamIndex(req.method);\n if (blockRefIndex === undefined) {\n return next();\n }\n\n const blockRef: string | undefined =\n Array.isArray(req.params) && req.params[blockRefIndex]\n ? (req.params[blockRefIndex] as string)\n : // omitted blockRef implies \"latest\"\n 'latest';\n\n if (blockRef !== 'latest') {\n return next();\n }\n\n // rewrite blockRef to block-tracker's block number\n const latestBlockNumber = await blockTracker.getLatestBlock();\n if (Array.isArray(req.params)) {\n req.params[blockRefIndex] = latestBlockNumber;\n }\n return next();\n });\n}\n"]}
|
|
@@ -4,6 +4,14 @@ import type { Json, JsonRpcParams } from "@metamask/utils";
|
|
|
4
4
|
type BlockRefRewriteMiddlewareOptions = {
|
|
5
5
|
blockTracker?: PollingBlockTracker;
|
|
6
6
|
};
|
|
7
|
+
/**
|
|
8
|
+
* Creates a middleware that rewrites "latest" block references to the known
|
|
9
|
+
* latest block number from a block tracker.
|
|
10
|
+
*
|
|
11
|
+
* @param options - The options for the middleware.
|
|
12
|
+
* @param options.blockTracker - The block tracker to use.
|
|
13
|
+
* @returns The middleware.
|
|
14
|
+
*/
|
|
7
15
|
export declare function createBlockRefRewriteMiddleware({ blockTracker, }?: BlockRefRewriteMiddlewareOptions): JsonRpcMiddleware<JsonRpcParams, Json>;
|
|
8
16
|
export {};
|
|
9
17
|
//# sourceMappingURL=block-ref-rewrite.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-ref-rewrite.d.cts","sourceRoot":"","sources":["../src/block-ref-rewrite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,wBAAwB;AAI3D,KAAK,gCAAgC,GAAG;IACtC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC,CAAC;AAEF,wBAAgB,+BAA+B,CAAC,EAC9C,YAAY,GACb,GAAE,gCAAqC,GAAG,iBAAiB,CAC1D,aAAa,EACb,IAAI,CACL,CA8BA"}
|
|
1
|
+
{"version":3,"file":"block-ref-rewrite.d.cts","sourceRoot":"","sources":["../src/block-ref-rewrite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,wBAAwB;AAI3D,KAAK,gCAAgC,GAAG;IACtC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAAC,EAC9C,YAAY,GACb,GAAE,gCAAqC,GAAG,iBAAiB,CAC1D,aAAa,EACb,IAAI,CACL,CA8BA"}
|
|
@@ -4,6 +4,14 @@ import type { Json, JsonRpcParams } from "@metamask/utils";
|
|
|
4
4
|
type BlockRefRewriteMiddlewareOptions = {
|
|
5
5
|
blockTracker?: PollingBlockTracker;
|
|
6
6
|
};
|
|
7
|
+
/**
|
|
8
|
+
* Creates a middleware that rewrites "latest" block references to the known
|
|
9
|
+
* latest block number from a block tracker.
|
|
10
|
+
*
|
|
11
|
+
* @param options - The options for the middleware.
|
|
12
|
+
* @param options.blockTracker - The block tracker to use.
|
|
13
|
+
* @returns The middleware.
|
|
14
|
+
*/
|
|
7
15
|
export declare function createBlockRefRewriteMiddleware({ blockTracker, }?: BlockRefRewriteMiddlewareOptions): JsonRpcMiddleware<JsonRpcParams, Json>;
|
|
8
16
|
export {};
|
|
9
17
|
//# sourceMappingURL=block-ref-rewrite.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-ref-rewrite.d.mts","sourceRoot":"","sources":["../src/block-ref-rewrite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,wBAAwB;AAI3D,KAAK,gCAAgC,GAAG;IACtC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC,CAAC;AAEF,wBAAgB,+BAA+B,CAAC,EAC9C,YAAY,GACb,GAAE,gCAAqC,GAAG,iBAAiB,CAC1D,aAAa,EACb,IAAI,CACL,CA8BA"}
|
|
1
|
+
{"version":3,"file":"block-ref-rewrite.d.mts","sourceRoot":"","sources":["../src/block-ref-rewrite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,wBAAwB;AAI3D,KAAK,gCAAgC,GAAG;IACtC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAAC,EAC9C,YAAY,GACb,GAAE,gCAAqC,GAAG,iBAAiB,CAC1D,aAAa,EACb,IAAI,CACL,CA8BA"}
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
import { createAsyncMiddleware } from "@metamask/json-rpc-engine";
|
|
2
2
|
import { blockTagParamIndex } from "./utils/cache.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* Creates a middleware that rewrites "latest" block references to the known
|
|
5
|
+
* latest block number from a block tracker.
|
|
6
|
+
*
|
|
7
|
+
* @param options - The options for the middleware.
|
|
8
|
+
* @param options.blockTracker - The block tracker to use.
|
|
9
|
+
* @returns The middleware.
|
|
10
|
+
*/
|
|
3
11
|
export function createBlockRefRewriteMiddleware({ blockTracker, } = {}) {
|
|
4
12
|
if (!blockTracker) {
|
|
5
13
|
throw Error('BlockRefRewriteMiddleware - mandatory "blockTracker" option is missing.');
|
|
6
14
|
}
|
|
7
15
|
return createAsyncMiddleware(async (req, _res, next) => {
|
|
8
16
|
const blockRefIndex = blockTagParamIndex(req.method);
|
|
9
|
-
// skip if method does not include blockRef
|
|
10
17
|
if (blockRefIndex === undefined) {
|
|
11
18
|
return next();
|
|
12
19
|
}
|
|
13
|
-
// skip if not "latest"
|
|
14
20
|
const blockRef = Array.isArray(req.params) && req.params[blockRefIndex]
|
|
15
21
|
? req.params[blockRefIndex]
|
|
16
22
|
: // omitted blockRef implies "latest"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-ref-rewrite.mjs","sourceRoot":"","sources":["../src/block-ref-rewrite.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,kCAAkC;AAGlE,OAAO,EAAE,kBAAkB,EAAE,0BAAsB;AAMnD,MAAM,UAAU,+BAA+B,CAAC,EAC9C,YAAY,MACwB,EAAE;IAItC,IAAI,CAAC,YAAY,EAAE;QACjB,MAAM,KAAK,CACT,yEAAyE,CAC1E,CAAC;KACH;IAED,OAAO,qBAAqB,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;QACrD,MAAM,aAAa,GAAuB,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzE,
|
|
1
|
+
{"version":3,"file":"block-ref-rewrite.mjs","sourceRoot":"","sources":["../src/block-ref-rewrite.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,kCAAkC;AAGlE,OAAO,EAAE,kBAAkB,EAAE,0BAAsB;AAMnD;;;;;;;GAOG;AACH,MAAM,UAAU,+BAA+B,CAAC,EAC9C,YAAY,MACwB,EAAE;IAItC,IAAI,CAAC,YAAY,EAAE;QACjB,MAAM,KAAK,CACT,yEAAyE,CAC1E,CAAC;KACH;IAED,OAAO,qBAAqB,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;QACrD,MAAM,aAAa,GAAuB,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzE,IAAI,aAAa,KAAK,SAAS,EAAE;YAC/B,OAAO,IAAI,EAAE,CAAC;SACf;QAED,MAAM,QAAQ,GACZ,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC;YACpD,CAAC,CAAE,GAAG,CAAC,MAAM,CAAC,aAAa,CAAY;YACvC,CAAC,CAAC,oCAAoC;gBACpC,QAAQ,CAAC;QAEf,IAAI,QAAQ,KAAK,QAAQ,EAAE;YACzB,OAAO,IAAI,EAAE,CAAC;SACf;QAED,mDAAmD;QACnD,MAAM,iBAAiB,GAAG,MAAM,YAAY,CAAC,cAAc,EAAE,CAAC;QAC9D,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YAC7B,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,iBAAiB,CAAC;SAC/C;QACD,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport type { Json, JsonRpcParams } from '@metamask/utils';\n\nimport { blockTagParamIndex } from './utils/cache';\n\ntype BlockRefRewriteMiddlewareOptions = {\n blockTracker?: PollingBlockTracker;\n};\n\n/**\n * Creates a middleware that rewrites \"latest\" block references to the known\n * latest block number from a block tracker.\n *\n * @param options - The options for the middleware.\n * @param options.blockTracker - The block tracker to use.\n * @returns The middleware.\n */\nexport function createBlockRefRewriteMiddleware({\n blockTracker,\n}: BlockRefRewriteMiddlewareOptions = {}): JsonRpcMiddleware<\n JsonRpcParams,\n Json\n> {\n if (!blockTracker) {\n throw Error(\n 'BlockRefRewriteMiddleware - mandatory \"blockTracker\" option is missing.',\n );\n }\n\n return createAsyncMiddleware(async (req, _res, next) => {\n const blockRefIndex: number | undefined = blockTagParamIndex(req.method);\n if (blockRefIndex === undefined) {\n return next();\n }\n\n const blockRef: string | undefined =\n Array.isArray(req.params) && req.params[blockRefIndex]\n ? (req.params[blockRefIndex] as string)\n : // omitted blockRef implies \"latest\"\n 'latest';\n\n if (blockRef !== 'latest') {\n return next();\n }\n\n // rewrite blockRef to block-tracker's block number\n const latestBlockNumber = await blockTracker.getLatestBlock();\n if (Array.isArray(req.params)) {\n req.params[blockRefIndex] = latestBlockNumber;\n }\n return next();\n });\n}\n"]}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createBlockTrackerInspectorMiddleware = void 0;
|
|
4
4
|
const json_rpc_engine_1 = require("@metamask/json-rpc-engine");
|
|
5
|
+
const utils_1 = require("@metamask/utils");
|
|
5
6
|
const logging_utils_1 = require("./logging-utils.cjs");
|
|
6
7
|
const log = (0, logging_utils_1.createModuleLogger)(logging_utils_1.projectLogger, 'block-tracker-inspector');
|
|
7
8
|
const futureBlockRefRequests = [
|
|
@@ -9,44 +10,29 @@ const futureBlockRefRequests = [
|
|
|
9
10
|
'eth_getTransactionReceipt',
|
|
10
11
|
];
|
|
11
12
|
/**
|
|
12
|
-
*
|
|
13
|
+
* Creates a middleware that checks whether response block references are higher than the current block.
|
|
14
|
+
* If the block reference is higher, the middleware will make the block tracker check for a new block.
|
|
13
15
|
*
|
|
14
|
-
* @param
|
|
15
|
-
* @param
|
|
16
|
-
* @returns
|
|
16
|
+
* @param options - The options for the middleware.
|
|
17
|
+
* @param options.blockTracker - The block tracker to use.
|
|
18
|
+
* @returns The middleware.
|
|
17
19
|
*/
|
|
18
|
-
function hasProperty(objectToCheck, property) {
|
|
19
|
-
return Object.hasOwnProperty.call(objectToCheck, property);
|
|
20
|
-
}
|
|
21
|
-
function getResultBlockNumber(response) {
|
|
22
|
-
const { result } = response;
|
|
23
|
-
if (!result ||
|
|
24
|
-
typeof result !== 'object' ||
|
|
25
|
-
!hasProperty(result, 'blockNumber')) {
|
|
26
|
-
return undefined;
|
|
27
|
-
}
|
|
28
|
-
if (typeof result.blockNumber === 'string') {
|
|
29
|
-
return result.blockNumber;
|
|
30
|
-
}
|
|
31
|
-
return undefined;
|
|
32
|
-
}
|
|
33
|
-
// inspect if response contains a block ref higher than our latest block
|
|
34
20
|
function createBlockTrackerInspectorMiddleware({ blockTracker, }) {
|
|
35
21
|
return (0, json_rpc_engine_1.createAsyncMiddleware)(async (req, res, next) => {
|
|
36
22
|
if (!futureBlockRefRequests.includes(req.method)) {
|
|
37
23
|
return next();
|
|
38
24
|
}
|
|
39
25
|
await next();
|
|
40
|
-
// abort if no result or no block number
|
|
41
26
|
const responseBlockNumber = getResultBlockNumber(res);
|
|
42
27
|
if (!responseBlockNumber) {
|
|
43
28
|
return undefined;
|
|
44
29
|
}
|
|
45
30
|
log('res.result.blockNumber exists, proceeding. res = %o', res);
|
|
46
|
-
//
|
|
31
|
+
// If number is higher, suggest block-tracker check for a new block
|
|
47
32
|
const blockNumber = Number.parseInt(responseBlockNumber, 16);
|
|
33
|
+
const currentBlockNumber = Number.parseInt(
|
|
48
34
|
// Typecast: If getCurrentBlock returns null, currentBlockNumber will be NaN, which is fine.
|
|
49
|
-
|
|
35
|
+
blockTracker.getCurrentBlock(), 16);
|
|
50
36
|
if (blockNumber > currentBlockNumber) {
|
|
51
37
|
log('blockNumber from response is greater than current block number, refreshing current block number');
|
|
52
38
|
await blockTracker.checkForLatestBlock();
|
|
@@ -55,4 +41,16 @@ function createBlockTrackerInspectorMiddleware({ blockTracker, }) {
|
|
|
55
41
|
});
|
|
56
42
|
}
|
|
57
43
|
exports.createBlockTrackerInspectorMiddleware = createBlockTrackerInspectorMiddleware;
|
|
44
|
+
function getResultBlockNumber(response) {
|
|
45
|
+
const { result } = response;
|
|
46
|
+
if (!result ||
|
|
47
|
+
typeof result !== 'object' ||
|
|
48
|
+
!(0, utils_1.hasProperty)(result, 'blockNumber')) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
if (typeof result.blockNumber === 'string') {
|
|
52
|
+
return result.blockNumber;
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
58
56
|
//# sourceMappingURL=block-tracker-inspector.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-tracker-inspector.cjs","sourceRoot":"","sources":["../src/block-tracker-inspector.ts"],"names":[],"mappings":";;;AAEA,+DAAkE;
|
|
1
|
+
{"version":3,"file":"block-tracker-inspector.cjs","sourceRoot":"","sources":["../src/block-tracker-inspector.ts"],"names":[],"mappings":";;;AAEA,+DAAkE;AAClE,2CAA8C;AAO9C,uDAAoE;AAEpE,MAAM,GAAG,GAAG,IAAA,kCAAkB,EAAC,6BAAa,EAAE,yBAAyB,CAAC,CAAC;AACzE,MAAM,sBAAsB,GAAsB;IAChD,0BAA0B;IAC1B,2BAA2B;CAC5B,CAAC;AAEF;;;;;;;GAOG;AACH,SAAgB,qCAAqC,CAAC,EACpD,YAAY,GAGb;IACC,OAAO,IAAA,uCAAqB,EAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACpD,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YAChD,OAAO,IAAI,EAAE,CAAC;SACf;QACD,MAAM,IAAI,EAAE,CAAC;QAEb,MAAM,mBAAmB,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;QACtD,IAAI,CAAC,mBAAmB,EAAE;YACxB,OAAO,SAAS,CAAC;SAClB;QAED,GAAG,CAAC,qDAAqD,EAAE,GAAG,CAAC,CAAC;QAEhE,mEAAmE;QACnE,MAAM,WAAW,GAAW,MAAM,CAAC,QAAQ,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;QACrE,MAAM,kBAAkB,GAAW,MAAM,CAAC,QAAQ;QAChD,4FAA4F;QAC5F,YAAY,CAAC,eAAe,EAAY,EACxC,EAAE,CACH,CAAC;QACF,IAAI,WAAW,GAAG,kBAAkB,EAAE;YACpC,GAAG,CACD,iGAAiG,CAClG,CAAC;YACF,MAAM,YAAY,CAAC,mBAAmB,EAAE,CAAC;SAC1C;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC;AAjCD,sFAiCC;AAED,SAAS,oBAAoB,CAC3B,QAAgC;IAEhC,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC;IAC5B,IACE,CAAC,MAAM;QACP,OAAO,MAAM,KAAK,QAAQ;QAC1B,CAAC,IAAA,mBAAW,EAAC,MAAM,EAAE,aAAa,CAAC,EACnC;QACA,OAAO,SAAS,CAAC;KAClB;IAED,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,EAAE;QAC1C,OAAO,MAAM,CAAC,WAAW,CAAC;KAC3B;IACD,OAAO,SAAS,CAAC;AACnB,CAAC","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport { hasProperty } from '@metamask/utils';\nimport type {\n Json,\n JsonRpcParams,\n PendingJsonRpcResponse,\n} from '@metamask/utils';\n\nimport { projectLogger, createModuleLogger } from './logging-utils';\n\nconst log = createModuleLogger(projectLogger, 'block-tracker-inspector');\nconst futureBlockRefRequests: readonly string[] = [\n 'eth_getTransactionByHash',\n 'eth_getTransactionReceipt',\n];\n\n/**\n * Creates a middleware that checks whether response block references are higher than the current block.\n * If the block reference is higher, the middleware will make the block tracker check for a new block.\n *\n * @param options - The options for the middleware.\n * @param options.blockTracker - The block tracker to use.\n * @returns The middleware.\n */\nexport function createBlockTrackerInspectorMiddleware({\n blockTracker,\n}: {\n blockTracker: PollingBlockTracker;\n}): JsonRpcMiddleware<JsonRpcParams, Json> {\n return createAsyncMiddleware(async (req, res, next) => {\n if (!futureBlockRefRequests.includes(req.method)) {\n return next();\n }\n await next();\n\n const responseBlockNumber = getResultBlockNumber(res);\n if (!responseBlockNumber) {\n return undefined;\n }\n\n log('res.result.blockNumber exists, proceeding. res = %o', res);\n\n // If number is higher, suggest block-tracker check for a new block\n const blockNumber: number = Number.parseInt(responseBlockNumber, 16);\n const currentBlockNumber: number = Number.parseInt(\n // Typecast: If getCurrentBlock returns null, currentBlockNumber will be NaN, which is fine.\n blockTracker.getCurrentBlock() as string,\n 16,\n );\n if (blockNumber > currentBlockNumber) {\n log(\n 'blockNumber from response is greater than current block number, refreshing current block number',\n );\n await blockTracker.checkForLatestBlock();\n }\n return undefined;\n });\n}\n\nfunction getResultBlockNumber(\n response: PendingJsonRpcResponse,\n): string | undefined {\n const { result } = response;\n if (\n !result ||\n typeof result !== 'object' ||\n !hasProperty(result, 'blockNumber')\n ) {\n return undefined;\n }\n\n if (typeof result.blockNumber === 'string') {\n return result.blockNumber;\n }\n return undefined;\n}\n"]}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import type { PollingBlockTracker } from "@metamask/eth-block-tracker";
|
|
2
2
|
import type { JsonRpcMiddleware } from "@metamask/json-rpc-engine";
|
|
3
3
|
import type { Json, JsonRpcParams } from "@metamask/utils";
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Creates a middleware that checks whether response block references are higher than the current block.
|
|
6
|
+
* If the block reference is higher, the middleware will make the block tracker check for a new block.
|
|
7
|
+
*
|
|
8
|
+
* @param options - The options for the middleware.
|
|
9
|
+
* @param options.blockTracker - The block tracker to use.
|
|
10
|
+
* @returns The middleware.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createBlockTrackerInspectorMiddleware({ blockTracker, }: {
|
|
5
13
|
blockTracker: PollingBlockTracker;
|
|
6
|
-
}
|
|
7
|
-
export declare function createBlockTrackerInspectorMiddleware({ blockTracker, }: BlockTrackerInspectorMiddlewareOptions): JsonRpcMiddleware<JsonRpcParams, Json>;
|
|
8
|
-
export {};
|
|
14
|
+
}): JsonRpcMiddleware<JsonRpcParams, Json>;
|
|
9
15
|
//# sourceMappingURL=block-tracker-inspector.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-tracker-inspector.d.cts","sourceRoot":"","sources":["../src/block-tracker-inspector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;
|
|
1
|
+
{"version":3,"file":"block-tracker-inspector.d.cts","sourceRoot":"","sources":["../src/block-tracker-inspector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAGnE,OAAO,KAAK,EACV,IAAI,EACJ,aAAa,EAEd,wBAAwB;AAUzB;;;;;;;GAOG;AACH,wBAAgB,qCAAqC,CAAC,EACpD,YAAY,GACb,EAAE;IACD,YAAY,EAAE,mBAAmB,CAAC;CACnC,GAAG,iBAAiB,CAAC,aAAa,EAAE,IAAI,CAAC,CA6BzC"}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import type { PollingBlockTracker } from "@metamask/eth-block-tracker";
|
|
2
2
|
import type { JsonRpcMiddleware } from "@metamask/json-rpc-engine";
|
|
3
3
|
import type { Json, JsonRpcParams } from "@metamask/utils";
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Creates a middleware that checks whether response block references are higher than the current block.
|
|
6
|
+
* If the block reference is higher, the middleware will make the block tracker check for a new block.
|
|
7
|
+
*
|
|
8
|
+
* @param options - The options for the middleware.
|
|
9
|
+
* @param options.blockTracker - The block tracker to use.
|
|
10
|
+
* @returns The middleware.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createBlockTrackerInspectorMiddleware({ blockTracker, }: {
|
|
5
13
|
blockTracker: PollingBlockTracker;
|
|
6
|
-
}
|
|
7
|
-
export declare function createBlockTrackerInspectorMiddleware({ blockTracker, }: BlockTrackerInspectorMiddlewareOptions): JsonRpcMiddleware<JsonRpcParams, Json>;
|
|
8
|
-
export {};
|
|
14
|
+
}): JsonRpcMiddleware<JsonRpcParams, Json>;
|
|
9
15
|
//# sourceMappingURL=block-tracker-inspector.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-tracker-inspector.d.mts","sourceRoot":"","sources":["../src/block-tracker-inspector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;
|
|
1
|
+
{"version":3,"file":"block-tracker-inspector.d.mts","sourceRoot":"","sources":["../src/block-tracker-inspector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAGnE,OAAO,KAAK,EACV,IAAI,EACJ,aAAa,EAEd,wBAAwB;AAUzB;;;;;;;GAOG;AACH,wBAAgB,qCAAqC,CAAC,EACpD,YAAY,GACb,EAAE;IACD,YAAY,EAAE,mBAAmB,CAAC;CACnC,GAAG,iBAAiB,CAAC,aAAa,EAAE,IAAI,CAAC,CA6BzC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createAsyncMiddleware } from "@metamask/json-rpc-engine";
|
|
2
|
+
import { hasProperty } from "@metamask/utils";
|
|
2
3
|
import { projectLogger, createModuleLogger } from "./logging-utils.mjs";
|
|
3
4
|
const log = createModuleLogger(projectLogger, 'block-tracker-inspector');
|
|
4
5
|
const futureBlockRefRequests = [
|
|
@@ -6,44 +7,29 @@ const futureBlockRefRequests = [
|
|
|
6
7
|
'eth_getTransactionReceipt',
|
|
7
8
|
];
|
|
8
9
|
/**
|
|
9
|
-
*
|
|
10
|
+
* Creates a middleware that checks whether response block references are higher than the current block.
|
|
11
|
+
* If the block reference is higher, the middleware will make the block tracker check for a new block.
|
|
10
12
|
*
|
|
11
|
-
* @param
|
|
12
|
-
* @param
|
|
13
|
-
* @returns
|
|
13
|
+
* @param options - The options for the middleware.
|
|
14
|
+
* @param options.blockTracker - The block tracker to use.
|
|
15
|
+
* @returns The middleware.
|
|
14
16
|
*/
|
|
15
|
-
function hasProperty(objectToCheck, property) {
|
|
16
|
-
return Object.hasOwnProperty.call(objectToCheck, property);
|
|
17
|
-
}
|
|
18
|
-
function getResultBlockNumber(response) {
|
|
19
|
-
const { result } = response;
|
|
20
|
-
if (!result ||
|
|
21
|
-
typeof result !== 'object' ||
|
|
22
|
-
!hasProperty(result, 'blockNumber')) {
|
|
23
|
-
return undefined;
|
|
24
|
-
}
|
|
25
|
-
if (typeof result.blockNumber === 'string') {
|
|
26
|
-
return result.blockNumber;
|
|
27
|
-
}
|
|
28
|
-
return undefined;
|
|
29
|
-
}
|
|
30
|
-
// inspect if response contains a block ref higher than our latest block
|
|
31
17
|
export function createBlockTrackerInspectorMiddleware({ blockTracker, }) {
|
|
32
18
|
return createAsyncMiddleware(async (req, res, next) => {
|
|
33
19
|
if (!futureBlockRefRequests.includes(req.method)) {
|
|
34
20
|
return next();
|
|
35
21
|
}
|
|
36
22
|
await next();
|
|
37
|
-
// abort if no result or no block number
|
|
38
23
|
const responseBlockNumber = getResultBlockNumber(res);
|
|
39
24
|
if (!responseBlockNumber) {
|
|
40
25
|
return undefined;
|
|
41
26
|
}
|
|
42
27
|
log('res.result.blockNumber exists, proceeding. res = %o', res);
|
|
43
|
-
//
|
|
28
|
+
// If number is higher, suggest block-tracker check for a new block
|
|
44
29
|
const blockNumber = Number.parseInt(responseBlockNumber, 16);
|
|
30
|
+
const currentBlockNumber = Number.parseInt(
|
|
45
31
|
// Typecast: If getCurrentBlock returns null, currentBlockNumber will be NaN, which is fine.
|
|
46
|
-
|
|
32
|
+
blockTracker.getCurrentBlock(), 16);
|
|
47
33
|
if (blockNumber > currentBlockNumber) {
|
|
48
34
|
log('blockNumber from response is greater than current block number, refreshing current block number');
|
|
49
35
|
await blockTracker.checkForLatestBlock();
|
|
@@ -51,4 +37,16 @@ export function createBlockTrackerInspectorMiddleware({ blockTracker, }) {
|
|
|
51
37
|
return undefined;
|
|
52
38
|
});
|
|
53
39
|
}
|
|
40
|
+
function getResultBlockNumber(response) {
|
|
41
|
+
const { result } = response;
|
|
42
|
+
if (!result ||
|
|
43
|
+
typeof result !== 'object' ||
|
|
44
|
+
!hasProperty(result, 'blockNumber')) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
if (typeof result.blockNumber === 'string') {
|
|
48
|
+
return result.blockNumber;
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
54
52
|
//# sourceMappingURL=block-tracker-inspector.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-tracker-inspector.mjs","sourceRoot":"","sources":["../src/block-tracker-inspector.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,kCAAkC;
|
|
1
|
+
{"version":3,"file":"block-tracker-inspector.mjs","sourceRoot":"","sources":["../src/block-tracker-inspector.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,kCAAkC;AAClE,OAAO,EAAE,WAAW,EAAE,wBAAwB;AAO9C,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,4BAAwB;AAEpE,MAAM,GAAG,GAAG,kBAAkB,CAAC,aAAa,EAAE,yBAAyB,CAAC,CAAC;AACzE,MAAM,sBAAsB,GAAsB;IAChD,0BAA0B;IAC1B,2BAA2B;CAC5B,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,qCAAqC,CAAC,EACpD,YAAY,GAGb;IACC,OAAO,qBAAqB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACpD,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YAChD,OAAO,IAAI,EAAE,CAAC;SACf;QACD,MAAM,IAAI,EAAE,CAAC;QAEb,MAAM,mBAAmB,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;QACtD,IAAI,CAAC,mBAAmB,EAAE;YACxB,OAAO,SAAS,CAAC;SAClB;QAED,GAAG,CAAC,qDAAqD,EAAE,GAAG,CAAC,CAAC;QAEhE,mEAAmE;QACnE,MAAM,WAAW,GAAW,MAAM,CAAC,QAAQ,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;QACrE,MAAM,kBAAkB,GAAW,MAAM,CAAC,QAAQ;QAChD,4FAA4F;QAC5F,YAAY,CAAC,eAAe,EAAY,EACxC,EAAE,CACH,CAAC;QACF,IAAI,WAAW,GAAG,kBAAkB,EAAE;YACpC,GAAG,CACD,iGAAiG,CAClG,CAAC;YACF,MAAM,YAAY,CAAC,mBAAmB,EAAE,CAAC;SAC1C;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,oBAAoB,CAC3B,QAAgC;IAEhC,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC;IAC5B,IACE,CAAC,MAAM;QACP,OAAO,MAAM,KAAK,QAAQ;QAC1B,CAAC,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,EACnC;QACA,OAAO,SAAS,CAAC;KAClB;IAED,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,EAAE;QAC1C,OAAO,MAAM,CAAC,WAAW,CAAC;KAC3B;IACD,OAAO,SAAS,CAAC;AACnB,CAAC","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport { hasProperty } from '@metamask/utils';\nimport type {\n Json,\n JsonRpcParams,\n PendingJsonRpcResponse,\n} from '@metamask/utils';\n\nimport { projectLogger, createModuleLogger } from './logging-utils';\n\nconst log = createModuleLogger(projectLogger, 'block-tracker-inspector');\nconst futureBlockRefRequests: readonly string[] = [\n 'eth_getTransactionByHash',\n 'eth_getTransactionReceipt',\n];\n\n/**\n * Creates a middleware that checks whether response block references are higher than the current block.\n * If the block reference is higher, the middleware will make the block tracker check for a new block.\n *\n * @param options - The options for the middleware.\n * @param options.blockTracker - The block tracker to use.\n * @returns The middleware.\n */\nexport function createBlockTrackerInspectorMiddleware({\n blockTracker,\n}: {\n blockTracker: PollingBlockTracker;\n}): JsonRpcMiddleware<JsonRpcParams, Json> {\n return createAsyncMiddleware(async (req, res, next) => {\n if (!futureBlockRefRequests.includes(req.method)) {\n return next();\n }\n await next();\n\n const responseBlockNumber = getResultBlockNumber(res);\n if (!responseBlockNumber) {\n return undefined;\n }\n\n log('res.result.blockNumber exists, proceeding. res = %o', res);\n\n // If number is higher, suggest block-tracker check for a new block\n const blockNumber: number = Number.parseInt(responseBlockNumber, 16);\n const currentBlockNumber: number = Number.parseInt(\n // Typecast: If getCurrentBlock returns null, currentBlockNumber will be NaN, which is fine.\n blockTracker.getCurrentBlock() as string,\n 16,\n );\n if (blockNumber > currentBlockNumber) {\n log(\n 'blockNumber from response is greater than current block number, refreshing current block number',\n );\n await blockTracker.checkForLatestBlock();\n }\n return undefined;\n });\n}\n\nfunction getResultBlockNumber(\n response: PendingJsonRpcResponse,\n): string | undefined {\n const { result } = response;\n if (\n !result ||\n typeof result !== 'object' ||\n !hasProperty(result, 'blockNumber')\n ) {\n return undefined;\n }\n\n if (typeof result.blockNumber === 'string') {\n return result.blockNumber;\n }\n return undefined;\n}\n"]}
|
package/dist/retryOnEmpty.cjs
CHANGED
|
@@ -21,6 +21,14 @@ const emptyValues = [
|
|
|
21
21
|
null,
|
|
22
22
|
'\u003cnil\u003e',
|
|
23
23
|
];
|
|
24
|
+
/**
|
|
25
|
+
* Creates a middleware that retries requests with empty responses.
|
|
26
|
+
*
|
|
27
|
+
* @param options - The options for the middleware.
|
|
28
|
+
* @param options.provider - The provider to use.
|
|
29
|
+
* @param options.blockTracker - The block tracker to use.
|
|
30
|
+
* @returns The middleware.
|
|
31
|
+
*/
|
|
24
32
|
function createRetryOnEmptyMiddleware({ provider, blockTracker, } = {}) {
|
|
25
33
|
if (!provider) {
|
|
26
34
|
throw Error('RetryOnEmptyMiddleware - mandatory "provider" option is missing.');
|
|
@@ -81,6 +89,13 @@ function createRetryOnEmptyMiddleware({ provider, blockTracker, } = {}) {
|
|
|
81
89
|
});
|
|
82
90
|
}
|
|
83
91
|
exports.createRetryOnEmptyMiddleware = createRetryOnEmptyMiddleware;
|
|
92
|
+
/**
|
|
93
|
+
* Retries an asynchronous function up to a maximum number of times.
|
|
94
|
+
*
|
|
95
|
+
* @param maxRetries - The maximum number of retries.
|
|
96
|
+
* @param asyncFn - The asynchronous function to retry.
|
|
97
|
+
* @returns The result of the asynchronous function.
|
|
98
|
+
*/
|
|
84
99
|
async function retry(maxRetries, asyncFn) {
|
|
85
100
|
for (let index = 0; index < maxRetries; index++) {
|
|
86
101
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retryOnEmpty.cjs","sourceRoot":"","sources":["../src/retryOnEmpty.ts"],"names":[],"mappings":";;;AAGA,+DAAkE;AAElE,qCAAmC;AAEnC,uDAAoE;AAEpE,6CAAmD;AACnD,6CAAyD;AACzD,iDAA0C;AAE1C,EAAE;AACF,gFAAgF;AAChF,+EAA+E;AAC/E,8DAA8D;AAC9D,qDAAqD;AACrD,EAAE;AAEF,MAAM,GAAG,GAAG,IAAA,kCAAkB,EAAC,6BAAa,EAAE,gBAAgB,CAAC,CAAC;AAChE,gEAAgE;AAChE,0EAA0E;AAC1E,MAAM,WAAW,GAAkC;IACjD,SAAS;IACT,IAAI;IACJ,iBAAiB;CAClB,CAAC;
|
|
1
|
+
{"version":3,"file":"retryOnEmpty.cjs","sourceRoot":"","sources":["../src/retryOnEmpty.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { SafeEventEmitterProvider } from '@metamask/eth-json-rpc-provider';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport type { Json, JsonRpcParams } from '@metamask/utils';\nimport { klona } from 'klona/full';\n\nimport { projectLogger, createModuleLogger } from './logging-utils';\nimport type { Block } from './types';\nimport { blockTagParamIndex } from './utils/cache';\nimport { isExecutionRevertedError } from './utils/error';\nimport { timeout } from './utils/timeout';\n\n//\n// RetryOnEmptyMiddleware will retry any request with an empty response that has\n// a numbered block reference at or lower than the blockTracker's latest block.\n// Its useful for dealing with load-balanced ethereum JSON RPC\n// nodes that are not always in sync with each other.\n//\n\nconst log = createModuleLogger(projectLogger, 'retry-on-empty');\n// empty values used to determine if a request should be retried\n// `<nil>` comes from https://github.com/ethereum/go-ethereum/issues/16925\nconst emptyValues: (string | null | undefined)[] = [\n undefined,\n null,\n '\\u003cnil\\u003e',\n];\n\n/**\n * Creates a middleware that retries requests with empty responses.\n *\n * @param options - The options for the middleware.\n * @param options.provider - The provider to use.\n * @param options.blockTracker - The block tracker to use.\n * @returns The middleware.\n */\nexport function createRetryOnEmptyMiddleware({\n provider,\n blockTracker,\n}: {\n provider?: SafeEventEmitterProvider;\n blockTracker?: PollingBlockTracker;\n} = {}): JsonRpcMiddleware<JsonRpcParams, Json> {\n if (!provider) {\n throw Error(\n 'RetryOnEmptyMiddleware - mandatory \"provider\" option is missing.',\n );\n }\n\n if (!blockTracker) {\n throw Error(\n 'RetryOnEmptyMiddleware - mandatory \"blockTracker\" option is missing.',\n );\n }\n\n return createAsyncMiddleware(async (req, res, next) => {\n const blockRefIndex: number | undefined = blockTagParamIndex(req.method);\n // skip if method does not include blockRef\n if (blockRefIndex === undefined) {\n return next();\n }\n // skip if not exact block references\n let blockRef: string | undefined =\n Array.isArray(req.params) && req.params[blockRefIndex]\n ? (req.params[blockRefIndex] as string)\n : undefined;\n // omitted blockRef implies \"latest\"\n if (blockRef === undefined) {\n blockRef = 'latest';\n }\n\n // skip if non-number block reference\n if (['latest', 'pending'].includes(blockRef)) {\n return next();\n }\n // skip if block refernce is not a valid number\n const blockRefNumber: number = Number.parseInt(blockRef.slice(2), 16);\n if (Number.isNaN(blockRefNumber)) {\n return next();\n }\n // lookup latest block\n const latestBlockNumberHex: string = await blockTracker.getLatestBlock();\n const latestBlockNumber: number = Number.parseInt(\n latestBlockNumberHex.slice(2),\n 16,\n );\n // skip if request block number is higher than current\n if (blockRefNumber > latestBlockNumber) {\n log(\n 'Requested block number %o is higher than latest block number %o, falling through to original request',\n blockRefNumber,\n latestBlockNumber,\n );\n return next();\n }\n\n log(\n 'Requested block number %o is not higher than latest block number %o, trying request until non-empty response is received',\n blockRefNumber,\n latestBlockNumber,\n );\n\n // create child request with specific block-ref\n const childRequest = klona(req);\n // attempt child request until non-empty response is received\n const childResult = await retry(10, async () => {\n log('Performing request %o', childRequest);\n const attemptResult = await provider.request<JsonRpcParams, Block>(\n childRequest,\n );\n log('Result is %o', attemptResult);\n // verify result\n const allEmptyValues: unknown[] = emptyValues;\n if (allEmptyValues.includes(attemptResult)) {\n throw new Error(\n `RetryOnEmptyMiddleware - empty result \"${JSON.stringify(\n attemptResult,\n )}\" for request \"${JSON.stringify(childRequest)}\"`,\n );\n }\n return attemptResult;\n });\n log('Copying result %o', childResult);\n // copy child result onto original response\n res.result = childResult;\n return undefined;\n });\n}\n\n/**\n * Retries an asynchronous function up to a maximum number of times.\n *\n * @param maxRetries - The maximum number of retries.\n * @param asyncFn - The asynchronous function to retry.\n * @returns The result of the asynchronous function.\n */\nasync function retry<Result>(\n maxRetries: number,\n asyncFn: () => Promise<Result>,\n): Promise<Result> {\n for (let index = 0; index < maxRetries; index++) {\n try {\n return await asyncFn();\n } catch (err: unknown) {\n if (isExecutionRevertedError(err)) {\n throw err as unknown;\n }\n log('(call %i) Request failed, waiting 1s to retry again...', index + 1);\n await timeout(1000);\n }\n }\n log('Retries exhausted');\n throw new Error('RetryOnEmptyMiddleware - retries exhausted');\n}\n"]}
|
package/dist/retryOnEmpty.d.cts
CHANGED
|
@@ -2,10 +2,16 @@ import type { PollingBlockTracker } from "@metamask/eth-block-tracker";
|
|
|
2
2
|
import type { SafeEventEmitterProvider } from "@metamask/eth-json-rpc-provider";
|
|
3
3
|
import type { JsonRpcMiddleware } from "@metamask/json-rpc-engine";
|
|
4
4
|
import type { Json, JsonRpcParams } from "@metamask/utils";
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Creates a middleware that retries requests with empty responses.
|
|
7
|
+
*
|
|
8
|
+
* @param options - The options for the middleware.
|
|
9
|
+
* @param options.provider - The provider to use.
|
|
10
|
+
* @param options.blockTracker - The block tracker to use.
|
|
11
|
+
* @returns The middleware.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createRetryOnEmptyMiddleware({ provider, blockTracker, }?: {
|
|
6
14
|
provider?: SafeEventEmitterProvider;
|
|
7
15
|
blockTracker?: PollingBlockTracker;
|
|
8
|
-
}
|
|
9
|
-
export declare function createRetryOnEmptyMiddleware({ provider, blockTracker, }?: RetryOnEmptyMiddlewareOptions): JsonRpcMiddleware<JsonRpcParams, Json>;
|
|
10
|
-
export {};
|
|
16
|
+
}): JsonRpcMiddleware<JsonRpcParams, Json>;
|
|
11
17
|
//# sourceMappingURL=retryOnEmpty.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retryOnEmpty.d.cts","sourceRoot":"","sources":["../src/retryOnEmpty.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,wBAAwB,EAAE,wCAAwC;AAChF,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,wBAAwB;AAyB3D,
|
|
1
|
+
{"version":3,"file":"retryOnEmpty.d.cts","sourceRoot":"","sources":["../src/retryOnEmpty.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,wBAAwB,EAAE,wCAAwC;AAChF,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,wBAAwB;AAyB3D;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,EAC3C,QAAQ,EACR,YAAY,GACb,GAAE;IACD,QAAQ,CAAC,EAAE,wBAAwB,CAAC;IACpC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CAC/B,GAAG,iBAAiB,CAAC,aAAa,EAAE,IAAI,CAAC,CAqF9C"}
|
package/dist/retryOnEmpty.d.mts
CHANGED
|
@@ -2,10 +2,16 @@ import type { PollingBlockTracker } from "@metamask/eth-block-tracker";
|
|
|
2
2
|
import type { SafeEventEmitterProvider } from "@metamask/eth-json-rpc-provider";
|
|
3
3
|
import type { JsonRpcMiddleware } from "@metamask/json-rpc-engine";
|
|
4
4
|
import type { Json, JsonRpcParams } from "@metamask/utils";
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Creates a middleware that retries requests with empty responses.
|
|
7
|
+
*
|
|
8
|
+
* @param options - The options for the middleware.
|
|
9
|
+
* @param options.provider - The provider to use.
|
|
10
|
+
* @param options.blockTracker - The block tracker to use.
|
|
11
|
+
* @returns The middleware.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createRetryOnEmptyMiddleware({ provider, blockTracker, }?: {
|
|
6
14
|
provider?: SafeEventEmitterProvider;
|
|
7
15
|
blockTracker?: PollingBlockTracker;
|
|
8
|
-
}
|
|
9
|
-
export declare function createRetryOnEmptyMiddleware({ provider, blockTracker, }?: RetryOnEmptyMiddlewareOptions): JsonRpcMiddleware<JsonRpcParams, Json>;
|
|
10
|
-
export {};
|
|
16
|
+
}): JsonRpcMiddleware<JsonRpcParams, Json>;
|
|
11
17
|
//# sourceMappingURL=retryOnEmpty.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retryOnEmpty.d.mts","sourceRoot":"","sources":["../src/retryOnEmpty.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,wBAAwB,EAAE,wCAAwC;AAChF,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,wBAAwB;AAyB3D,
|
|
1
|
+
{"version":3,"file":"retryOnEmpty.d.mts","sourceRoot":"","sources":["../src/retryOnEmpty.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,wBAAwB,EAAE,wCAAwC;AAChF,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,wBAAwB;AAyB3D;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,EAC3C,QAAQ,EACR,YAAY,GACb,GAAE;IACD,QAAQ,CAAC,EAAE,wBAAwB,CAAC;IACpC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CAC/B,GAAG,iBAAiB,CAAC,aAAa,EAAE,IAAI,CAAC,CAqF9C"}
|
package/dist/retryOnEmpty.mjs
CHANGED
|
@@ -18,6 +18,14 @@ const emptyValues = [
|
|
|
18
18
|
null,
|
|
19
19
|
'\u003cnil\u003e',
|
|
20
20
|
];
|
|
21
|
+
/**
|
|
22
|
+
* Creates a middleware that retries requests with empty responses.
|
|
23
|
+
*
|
|
24
|
+
* @param options - The options for the middleware.
|
|
25
|
+
* @param options.provider - The provider to use.
|
|
26
|
+
* @param options.blockTracker - The block tracker to use.
|
|
27
|
+
* @returns The middleware.
|
|
28
|
+
*/
|
|
21
29
|
export function createRetryOnEmptyMiddleware({ provider, blockTracker, } = {}) {
|
|
22
30
|
if (!provider) {
|
|
23
31
|
throw Error('RetryOnEmptyMiddleware - mandatory "provider" option is missing.');
|
|
@@ -77,6 +85,13 @@ export function createRetryOnEmptyMiddleware({ provider, blockTracker, } = {}) {
|
|
|
77
85
|
return undefined;
|
|
78
86
|
});
|
|
79
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Retries an asynchronous function up to a maximum number of times.
|
|
90
|
+
*
|
|
91
|
+
* @param maxRetries - The maximum number of retries.
|
|
92
|
+
* @param asyncFn - The asynchronous function to retry.
|
|
93
|
+
* @returns The result of the asynchronous function.
|
|
94
|
+
*/
|
|
80
95
|
async function retry(maxRetries, asyncFn) {
|
|
81
96
|
for (let index = 0; index < maxRetries; index++) {
|
|
82
97
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retryOnEmpty.mjs","sourceRoot":"","sources":["../src/retryOnEmpty.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,kCAAkC;AAElE,OAAO,EAAE,KAAK,EAAE,mBAAmB;AAEnC,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,4BAAwB;AAEpE,OAAO,EAAE,kBAAkB,EAAE,0BAAsB;AACnD,OAAO,EAAE,wBAAwB,EAAE,0BAAsB;AACzD,OAAO,EAAE,OAAO,EAAE,4BAAwB;AAE1C,EAAE;AACF,gFAAgF;AAChF,+EAA+E;AAC/E,8DAA8D;AAC9D,qDAAqD;AACrD,EAAE;AAEF,MAAM,GAAG,GAAG,kBAAkB,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC;AAChE,gEAAgE;AAChE,0EAA0E;AAC1E,MAAM,WAAW,GAAkC;IACjD,SAAS;IACT,IAAI;IACJ,iBAAiB;CAClB,CAAC;
|
|
1
|
+
{"version":3,"file":"retryOnEmpty.mjs","sourceRoot":"","sources":["../src/retryOnEmpty.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { SafeEventEmitterProvider } from '@metamask/eth-json-rpc-provider';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport type { Json, JsonRpcParams } from '@metamask/utils';\nimport { klona } from 'klona/full';\n\nimport { projectLogger, createModuleLogger } from './logging-utils';\nimport type { Block } from './types';\nimport { blockTagParamIndex } from './utils/cache';\nimport { isExecutionRevertedError } from './utils/error';\nimport { timeout } from './utils/timeout';\n\n//\n// RetryOnEmptyMiddleware will retry any request with an empty response that has\n// a numbered block reference at or lower than the blockTracker's latest block.\n// Its useful for dealing with load-balanced ethereum JSON RPC\n// nodes that are not always in sync with each other.\n//\n\nconst log = createModuleLogger(projectLogger, 'retry-on-empty');\n// empty values used to determine if a request should be retried\n// `<nil>` comes from https://github.com/ethereum/go-ethereum/issues/16925\nconst emptyValues: (string | null | undefined)[] = [\n undefined,\n null,\n '\\u003cnil\\u003e',\n];\n\n/**\n * Creates a middleware that retries requests with empty responses.\n *\n * @param options - The options for the middleware.\n * @param options.provider - The provider to use.\n * @param options.blockTracker - The block tracker to use.\n * @returns The middleware.\n */\nexport function createRetryOnEmptyMiddleware({\n provider,\n blockTracker,\n}: {\n provider?: SafeEventEmitterProvider;\n blockTracker?: PollingBlockTracker;\n} = {}): JsonRpcMiddleware<JsonRpcParams, Json> {\n if (!provider) {\n throw Error(\n 'RetryOnEmptyMiddleware - mandatory \"provider\" option is missing.',\n );\n }\n\n if (!blockTracker) {\n throw Error(\n 'RetryOnEmptyMiddleware - mandatory \"blockTracker\" option is missing.',\n );\n }\n\n return createAsyncMiddleware(async (req, res, next) => {\n const blockRefIndex: number | undefined = blockTagParamIndex(req.method);\n // skip if method does not include blockRef\n if (blockRefIndex === undefined) {\n return next();\n }\n // skip if not exact block references\n let blockRef: string | undefined =\n Array.isArray(req.params) && req.params[blockRefIndex]\n ? (req.params[blockRefIndex] as string)\n : undefined;\n // omitted blockRef implies \"latest\"\n if (blockRef === undefined) {\n blockRef = 'latest';\n }\n\n // skip if non-number block reference\n if (['latest', 'pending'].includes(blockRef)) {\n return next();\n }\n // skip if block refernce is not a valid number\n const blockRefNumber: number = Number.parseInt(blockRef.slice(2), 16);\n if (Number.isNaN(blockRefNumber)) {\n return next();\n }\n // lookup latest block\n const latestBlockNumberHex: string = await blockTracker.getLatestBlock();\n const latestBlockNumber: number = Number.parseInt(\n latestBlockNumberHex.slice(2),\n 16,\n );\n // skip if request block number is higher than current\n if (blockRefNumber > latestBlockNumber) {\n log(\n 'Requested block number %o is higher than latest block number %o, falling through to original request',\n blockRefNumber,\n latestBlockNumber,\n );\n return next();\n }\n\n log(\n 'Requested block number %o is not higher than latest block number %o, trying request until non-empty response is received',\n blockRefNumber,\n latestBlockNumber,\n );\n\n // create child request with specific block-ref\n const childRequest = klona(req);\n // attempt child request until non-empty response is received\n const childResult = await retry(10, async () => {\n log('Performing request %o', childRequest);\n const attemptResult = await provider.request<JsonRpcParams, Block>(\n childRequest,\n );\n log('Result is %o', attemptResult);\n // verify result\n const allEmptyValues: unknown[] = emptyValues;\n if (allEmptyValues.includes(attemptResult)) {\n throw new Error(\n `RetryOnEmptyMiddleware - empty result \"${JSON.stringify(\n attemptResult,\n )}\" for request \"${JSON.stringify(childRequest)}\"`,\n );\n }\n return attemptResult;\n });\n log('Copying result %o', childResult);\n // copy child result onto original response\n res.result = childResult;\n return undefined;\n });\n}\n\n/**\n * Retries an asynchronous function up to a maximum number of times.\n *\n * @param maxRetries - The maximum number of retries.\n * @param asyncFn - The asynchronous function to retry.\n * @returns The result of the asynchronous function.\n */\nasync function retry<Result>(\n maxRetries: number,\n asyncFn: () => Promise<Result>,\n): Promise<Result> {\n for (let index = 0; index < maxRetries; index++) {\n try {\n return await asyncFn();\n } catch (err: unknown) {\n if (isExecutionRevertedError(err)) {\n throw err as unknown;\n }\n log('(call %i) Request failed, waiting 1s to retry again...', index + 1);\n await timeout(1000);\n }\n }\n log('Retries exhausted');\n throw new Error('RetryOnEmptyMiddleware - retries exhausted');\n}\n"]}
|