@metamask-previews/eth-json-rpc-middleware 21.0.0-preview-468843ab
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/CHANGELOG.md +23 -0
- package/LICENSE +15 -0
- package/README.md +23 -0
- package/dist/block-cache.cjs +165 -0
- package/dist/block-cache.cjs.map +1 -0
- package/dist/block-cache.d.cts +9 -0
- package/dist/block-cache.d.cts.map +1 -0
- package/dist/block-cache.d.mts +9 -0
- package/dist/block-cache.d.mts.map +1 -0
- package/dist/block-cache.mjs +161 -0
- package/dist/block-cache.mjs.map +1 -0
- package/dist/block-ref-rewrite.cjs +33 -0
- package/dist/block-ref-rewrite.cjs.map +1 -0
- package/dist/block-ref-rewrite.d.cts +9 -0
- package/dist/block-ref-rewrite.d.cts.map +1 -0
- package/dist/block-ref-rewrite.d.mts +9 -0
- package/dist/block-ref-rewrite.d.mts.map +1 -0
- package/dist/block-ref-rewrite.mjs +29 -0
- package/dist/block-ref-rewrite.mjs.map +1 -0
- package/dist/block-ref.cjs +46 -0
- package/dist/block-ref.cjs.map +1 -0
- package/dist/block-ref.d.cts +11 -0
- package/dist/block-ref.d.cts.map +1 -0
- package/dist/block-ref.d.mts +11 -0
- package/dist/block-ref.d.mts.map +1 -0
- package/dist/block-ref.mjs +42 -0
- package/dist/block-ref.mjs.map +1 -0
- package/dist/block-tracker-inspector.cjs +58 -0
- package/dist/block-tracker-inspector.cjs.map +1 -0
- package/dist/block-tracker-inspector.d.cts +9 -0
- package/dist/block-tracker-inspector.d.cts.map +1 -0
- package/dist/block-tracker-inspector.d.mts +9 -0
- package/dist/block-tracker-inspector.d.mts.map +1 -0
- package/dist/block-tracker-inspector.mjs +54 -0
- package/dist/block-tracker-inspector.mjs.map +1 -0
- package/dist/fetch.cjs +48 -0
- package/dist/fetch.cjs.map +1 -0
- package/dist/fetch.d.cts +22 -0
- package/dist/fetch.d.cts.map +1 -0
- package/dist/fetch.d.mts +22 -0
- package/dist/fetch.d.mts.map +1 -0
- package/dist/fetch.mjs +44 -0
- package/dist/fetch.mjs.map +1 -0
- package/dist/index.cjs +28 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +12 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +12 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +10 -0
- package/dist/index.mjs.map +1 -0
- package/dist/inflight-cache.cjs +80 -0
- package/dist/inflight-cache.cjs.map +1 -0
- package/dist/inflight-cache.d.cts +4 -0
- package/dist/inflight-cache.d.cts.map +1 -0
- package/dist/inflight-cache.d.mts +4 -0
- package/dist/inflight-cache.d.mts.map +1 -0
- package/dist/inflight-cache.mjs +76 -0
- package/dist/inflight-cache.mjs.map +1 -0
- package/dist/logging-utils.cjs +7 -0
- package/dist/logging-utils.cjs.map +1 -0
- package/dist/logging-utils.d.cts +5 -0
- package/dist/logging-utils.d.cts.map +1 -0
- package/dist/logging-utils.d.mts +5 -0
- package/dist/logging-utils.d.mts.map +1 -0
- package/dist/logging-utils.mjs +4 -0
- package/dist/logging-utils.mjs.map +1 -0
- package/dist/methods/wallet-request-execution-permissions.cjs +41 -0
- package/dist/methods/wallet-request-execution-permissions.cjs.map +1 -0
- package/dist/methods/wallet-request-execution-permissions.d.cts +131 -0
- package/dist/methods/wallet-request-execution-permissions.d.cts.map +1 -0
- package/dist/methods/wallet-request-execution-permissions.d.mts +131 -0
- package/dist/methods/wallet-request-execution-permissions.d.mts.map +1 -0
- package/dist/methods/wallet-request-execution-permissions.mjs +37 -0
- package/dist/methods/wallet-request-execution-permissions.mjs.map +1 -0
- package/dist/methods/wallet-revoke-execution-permission.cjs +20 -0
- package/dist/methods/wallet-revoke-execution-permission.cjs.map +1 -0
- package/dist/methods/wallet-revoke-execution-permission.d.cts +13 -0
- package/dist/methods/wallet-revoke-execution-permission.d.cts.map +1 -0
- package/dist/methods/wallet-revoke-execution-permission.d.mts +13 -0
- package/dist/methods/wallet-revoke-execution-permission.d.mts.map +1 -0
- package/dist/methods/wallet-revoke-execution-permission.mjs +16 -0
- package/dist/methods/wallet-revoke-execution-permission.mjs.map +1 -0
- package/dist/providerAsMiddleware.cjs +11 -0
- package/dist/providerAsMiddleware.cjs.map +1 -0
- package/dist/providerAsMiddleware.d.cts +5 -0
- package/dist/providerAsMiddleware.d.cts.map +1 -0
- package/dist/providerAsMiddleware.d.mts +5 -0
- package/dist/providerAsMiddleware.d.mts.map +1 -0
- package/dist/providerAsMiddleware.mjs +7 -0
- package/dist/providerAsMiddleware.mjs.map +1 -0
- package/dist/retryOnEmpty.cjs +100 -0
- package/dist/retryOnEmpty.cjs.map +1 -0
- package/dist/retryOnEmpty.d.cts +11 -0
- package/dist/retryOnEmpty.d.cts.map +1 -0
- package/dist/retryOnEmpty.d.mts +11 -0
- package/dist/retryOnEmpty.d.mts.map +1 -0
- package/dist/retryOnEmpty.mjs +96 -0
- package/dist/retryOnEmpty.mjs.map +1 -0
- package/dist/types.cjs +3 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +25 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.mts +25 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +2 -0
- package/dist/types.mjs.map +1 -0
- package/dist/utils/cache.cjs +186 -0
- package/dist/utils/cache.cjs.map +1 -0
- package/dist/utils/cache.d.cts +68 -0
- package/dist/utils/cache.d.cts.map +1 -0
- package/dist/utils/cache.d.mts +68 -0
- package/dist/utils/cache.d.mts.map +1 -0
- package/dist/utils/cache.mjs +178 -0
- package/dist/utils/cache.mjs.map +1 -0
- package/dist/utils/common.cjs +17 -0
- package/dist/utils/common.cjs.map +1 -0
- package/dist/utils/common.d.cts +8 -0
- package/dist/utils/common.d.cts.map +1 -0
- package/dist/utils/common.d.mts +8 -0
- package/dist/utils/common.d.mts.map +1 -0
- package/dist/utils/common.mjs +13 -0
- package/dist/utils/common.mjs.map +1 -0
- package/dist/utils/error.cjs +12 -0
- package/dist/utils/error.cjs.map +1 -0
- package/dist/utils/error.d.cts +3 -0
- package/dist/utils/error.d.cts.map +1 -0
- package/dist/utils/error.d.mts +3 -0
- package/dist/utils/error.d.mts.map +1 -0
- package/dist/utils/error.mjs +8 -0
- package/dist/utils/error.mjs.map +1 -0
- package/dist/utils/normalize.cjs +52 -0
- package/dist/utils/normalize.cjs.map +1 -0
- package/dist/utils/normalize.d.cts +26 -0
- package/dist/utils/normalize.d.cts.map +1 -0
- package/dist/utils/normalize.d.mts +26 -0
- package/dist/utils/normalize.d.mts.map +1 -0
- package/dist/utils/normalize.mjs +47 -0
- package/dist/utils/normalize.mjs.map +1 -0
- package/dist/utils/timeout.cjs +14 -0
- package/dist/utils/timeout.cjs.map +1 -0
- package/dist/utils/timeout.d.cts +8 -0
- package/dist/utils/timeout.d.cts.map +1 -0
- package/dist/utils/timeout.d.mts +8 -0
- package/dist/utils/timeout.d.mts.map +1 -0
- package/dist/utils/timeout.mjs +10 -0
- package/dist/utils/timeout.mjs.map +1 -0
- package/dist/utils/validation.cjs +43 -0
- package/dist/utils/validation.cjs.map +1 -0
- package/dist/utils/validation.d.cts +8 -0
- package/dist/utils/validation.d.cts.map +1 -0
- package/dist/utils/validation.d.mts +8 -0
- package/dist/utils/validation.d.mts.map +1 -0
- package/dist/utils/validation.mjs +37 -0
- package/dist/utils/validation.mjs.map +1 -0
- package/dist/wallet.cjs +327 -0
- package/dist/wallet.cjs.map +1 -0
- package/dist/wallet.d.cts +33 -0
- package/dist/wallet.d.cts.map +1 -0
- package/dist/wallet.d.mts +33 -0
- package/dist/wallet.d.mts.map +1 -0
- package/dist/wallet.mjs +300 -0
- package/dist/wallet.mjs.map +1 -0
- package/package.json +95 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [21.0.0]
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **BREAKING:** Increase minimum Node.js version from `^18.16` to `^18.18` ([#6866](https://github.com/MetaMask/core/pull/6866))
|
|
15
|
+
- Bump `@metamask/eth-block-tracker` from `^12.2.1` to `^14.0.0` ([#6866](https://github.com/MetaMask/core/pull/6866), [#6883](https://github.com/MetaMask/core/pull/6883))
|
|
16
|
+
- Bump `@metamask/network-controller` from `^24.2.2` to `^24.3.0` ([#6883](https://github.com/MetaMask/core/pull/6883))
|
|
17
|
+
- This package was migrated from `MetaMask/eth-json-rpc-middleware` to the
|
|
18
|
+
`MetaMask/core` monorepo.
|
|
19
|
+
- See [`MetaMask/eth-json-rpc-middleware`](https://github.com/MetaMask/eth-json-rpc-middleware/blob/main/CHANGELOG.md)
|
|
20
|
+
for the original changelog.
|
|
21
|
+
|
|
22
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/eth-json-rpc-middleware@21.0.0...HEAD
|
|
23
|
+
[21.0.0]: https://github.com/MetaMask/core/releases/tag/@metamask/eth-json-rpc-middleware@21.0.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 MetaMask
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# `@metamask/eth-json-rpc-middleware`
|
|
2
|
+
|
|
3
|
+
Ethereum-related middleware for [`json-rpc-engine`](https://github.com/MetaMask/json-rpc-engine).
|
|
4
|
+
|
|
5
|
+
See tests for usage details.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
`yarn add @metamask/eth-json-rpc-middleware`
|
|
10
|
+
|
|
11
|
+
or
|
|
12
|
+
|
|
13
|
+
`npm install @metamask/eth-json-rpc-middleware`
|
|
14
|
+
|
|
15
|
+
## See also
|
|
16
|
+
|
|
17
|
+
- [`@metamask/eth-json-rpc-filters`](https://github.com/MetaMask/eth-json-rpc-filters).
|
|
18
|
+
- [`@metamask/eth-json-rpc-infura`](https://github.com/MetaMask/eth-json-rpc-infura).
|
|
19
|
+
- [`@metamask/json-rpc-engine`](https://github.com/MetaMask/core/tree/main/packages/json-rpc-engine).
|
|
20
|
+
|
|
21
|
+
## Contributing
|
|
22
|
+
|
|
23
|
+
This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createBlockCacheMiddleware = void 0;
|
|
4
|
+
const json_rpc_engine_1 = require("@metamask/json-rpc-engine");
|
|
5
|
+
const logging_utils_1 = require("./logging-utils.cjs");
|
|
6
|
+
const cache_1 = require("./utils/cache.cjs");
|
|
7
|
+
const log = (0, logging_utils_1.createModuleLogger)(logging_utils_1.projectLogger, 'block-cache');
|
|
8
|
+
// `<nil>` comes from https://github.com/ethereum/go-ethereum/issues/16925
|
|
9
|
+
const emptyValues = [undefined, null, '\u003cnil\u003e'];
|
|
10
|
+
//
|
|
11
|
+
// Cache Strategies
|
|
12
|
+
//
|
|
13
|
+
class BlockCacheStrategy {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.cache = {};
|
|
16
|
+
}
|
|
17
|
+
getBlockCache(blockNumberHex) {
|
|
18
|
+
const blockNumber = Number.parseInt(blockNumberHex, 16);
|
|
19
|
+
let blockCache = this.cache[blockNumber];
|
|
20
|
+
// create new cache if necesary
|
|
21
|
+
if (!blockCache) {
|
|
22
|
+
const newCache = {};
|
|
23
|
+
this.cache[blockNumber] = newCache;
|
|
24
|
+
blockCache = newCache;
|
|
25
|
+
}
|
|
26
|
+
return blockCache;
|
|
27
|
+
}
|
|
28
|
+
async get(request, requestedBlockNumber) {
|
|
29
|
+
// lookup block cache
|
|
30
|
+
const blockCache = this.getBlockCache(requestedBlockNumber);
|
|
31
|
+
// lookup payload in block cache
|
|
32
|
+
const identifier = (0, cache_1.cacheIdentifierForRequest)(request, true);
|
|
33
|
+
return identifier ? blockCache[identifier] : undefined;
|
|
34
|
+
}
|
|
35
|
+
async set(request, requestedBlockNumber, result) {
|
|
36
|
+
// check if we can cached this result
|
|
37
|
+
const canCacheResult = this.canCacheResult(request, result);
|
|
38
|
+
if (!canCacheResult) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
// set the value in the cache
|
|
42
|
+
const identifier = (0, cache_1.cacheIdentifierForRequest)(request, true);
|
|
43
|
+
if (!identifier) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const blockCache = this.getBlockCache(requestedBlockNumber);
|
|
47
|
+
blockCache[identifier] = result;
|
|
48
|
+
}
|
|
49
|
+
canCacheRequest(request) {
|
|
50
|
+
// check request method
|
|
51
|
+
if (!(0, cache_1.canCache)(request.method)) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
// check blockTag
|
|
55
|
+
const blockTag = (0, cache_1.blockTagForRequest)(request);
|
|
56
|
+
if (blockTag === 'pending') {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
// can be cached
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
canCacheResult(request, result) {
|
|
63
|
+
// never cache empty values (e.g. undefined)
|
|
64
|
+
if (emptyValues.includes(result)) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
// check if transactions have block reference before caching
|
|
68
|
+
if (request.method &&
|
|
69
|
+
['eth_getTransactionByHash', 'eth_getTransactionReceipt'].includes(request.method)) {
|
|
70
|
+
if (!result?.blockHash ||
|
|
71
|
+
result.blockHash ===
|
|
72
|
+
'0x0000000000000000000000000000000000000000000000000000000000000000') {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// otherwise true
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
// removes all block caches with block number lower than `oldBlockHex`
|
|
80
|
+
clearBefore(oldBlockHex) {
|
|
81
|
+
const oldBlockNumber = Number.parseInt(oldBlockHex, 16);
|
|
82
|
+
// clear old caches
|
|
83
|
+
Object.keys(this.cache)
|
|
84
|
+
.map(Number)
|
|
85
|
+
.filter((num) => num < oldBlockNumber)
|
|
86
|
+
.forEach((num) => delete this.cache[num]);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function createBlockCacheMiddleware({ blockTracker, } = {}) {
|
|
90
|
+
// validate options
|
|
91
|
+
if (!blockTracker) {
|
|
92
|
+
throw new Error('createBlockCacheMiddleware - No PollingBlockTracker specified');
|
|
93
|
+
}
|
|
94
|
+
// create caching strategies
|
|
95
|
+
const blockCache = new BlockCacheStrategy();
|
|
96
|
+
const strategies = {
|
|
97
|
+
[cache_1.CacheStrategy.Permanent]: blockCache,
|
|
98
|
+
[cache_1.CacheStrategy.Block]: blockCache,
|
|
99
|
+
[cache_1.CacheStrategy.Fork]: blockCache,
|
|
100
|
+
[cache_1.CacheStrategy.Never]: undefined,
|
|
101
|
+
};
|
|
102
|
+
return (0, json_rpc_engine_1.createAsyncMiddleware)(async (req, res, next) => {
|
|
103
|
+
// allow cach to be skipped if so specified
|
|
104
|
+
if (req.skipCache) {
|
|
105
|
+
return next();
|
|
106
|
+
}
|
|
107
|
+
// check type and matching strategy
|
|
108
|
+
const type = (0, cache_1.cacheTypeForMethod)(req.method);
|
|
109
|
+
const strategy = strategies[type];
|
|
110
|
+
// If there's no strategy in place, pass it down the chain.
|
|
111
|
+
if (!strategy) {
|
|
112
|
+
return next();
|
|
113
|
+
}
|
|
114
|
+
// If the strategy can't cache this request, ignore it.
|
|
115
|
+
if (!strategy.canCacheRequest(req)) {
|
|
116
|
+
return next();
|
|
117
|
+
}
|
|
118
|
+
// get block reference (number or keyword)
|
|
119
|
+
const requestBlockTag = (0, cache_1.blockTagForRequest)(req);
|
|
120
|
+
const blockTag = requestBlockTag && typeof requestBlockTag === 'string'
|
|
121
|
+
? requestBlockTag
|
|
122
|
+
: 'latest';
|
|
123
|
+
log('blockTag = %o, req = %o', blockTag, req);
|
|
124
|
+
// get exact block number
|
|
125
|
+
let requestedBlockNumber;
|
|
126
|
+
if (blockTag === 'earliest') {
|
|
127
|
+
// this just exists for symmetry with "latest"
|
|
128
|
+
requestedBlockNumber = '0x00';
|
|
129
|
+
}
|
|
130
|
+
else if (blockTag === 'latest') {
|
|
131
|
+
// fetch latest block number
|
|
132
|
+
log('Fetching latest block number to determine cache key');
|
|
133
|
+
const latestBlockNumber = await blockTracker.getLatestBlock();
|
|
134
|
+
// clear all cache before latest block
|
|
135
|
+
log('Clearing values stored under block numbers before %o', latestBlockNumber);
|
|
136
|
+
blockCache.clearBefore(latestBlockNumber);
|
|
137
|
+
requestedBlockNumber = latestBlockNumber;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
// We have a hex number
|
|
141
|
+
requestedBlockNumber = blockTag;
|
|
142
|
+
}
|
|
143
|
+
// end on a hit, continue on a miss
|
|
144
|
+
const cacheResult = await strategy.get(req, requestedBlockNumber);
|
|
145
|
+
if (cacheResult === undefined) {
|
|
146
|
+
// cache miss
|
|
147
|
+
// wait for other middleware to handle request
|
|
148
|
+
log('No cache stored under block number %o, carrying request forward', requestedBlockNumber);
|
|
149
|
+
await next();
|
|
150
|
+
// add result to cache
|
|
151
|
+
// it's safe to cast res.result as Block, due to runtime type checks
|
|
152
|
+
// performed when strategy.set is called
|
|
153
|
+
log('Populating cache with', res);
|
|
154
|
+
await strategy.set(req, requestedBlockNumber, res.result);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
// fill in result from cache
|
|
158
|
+
log('Cache hit, reusing cache result stored under block number %o', requestedBlockNumber);
|
|
159
|
+
res.result = cacheResult;
|
|
160
|
+
}
|
|
161
|
+
return undefined;
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
exports.createBlockCacheMiddleware = createBlockCacheMiddleware;
|
|
165
|
+
//# sourceMappingURL=block-cache.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block-cache.cjs","sourceRoot":"","sources":["../src/block-cache.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport type { Json, JsonRpcParams, JsonRpcRequest } from '@metamask/utils';\n\nimport { projectLogger, createModuleLogger } from './logging-utils';\nimport type {\n Block,\n BlockCache,\n // eslint-disable-next-line @typescript-eslint/no-shadow\n Cache,\n JsonRpcCacheMiddleware,\n JsonRpcRequestToCache,\n} from './types';\nimport {\n cacheIdentifierForRequest,\n blockTagForRequest,\n cacheTypeForMethod,\n canCache,\n CacheStrategy,\n} from './utils/cache';\n\nconst log = createModuleLogger(projectLogger, 'block-cache');\n// `<nil>` comes from https://github.com/ethereum/go-ethereum/issues/16925\nconst emptyValues = [undefined, null, '\\u003cnil\\u003e'];\n\ninterface BlockCacheMiddlewareOptions {\n blockTracker?: PollingBlockTracker;\n}\n\n//\n// Cache Strategies\n//\n\nclass BlockCacheStrategy {\n private cache: Cache;\n\n constructor() {\n this.cache = {};\n }\n\n getBlockCache(blockNumberHex: string): BlockCache {\n const blockNumber: number = Number.parseInt(blockNumberHex, 16);\n let blockCache: BlockCache = this.cache[blockNumber];\n // create new cache if necesary\n if (!blockCache) {\n const newCache: BlockCache = {};\n this.cache[blockNumber] = newCache;\n blockCache = newCache;\n }\n return blockCache;\n }\n\n async get(\n request: JsonRpcRequest,\n requestedBlockNumber: string,\n ): Promise<Block | undefined> {\n // lookup block cache\n const blockCache: BlockCache = this.getBlockCache(requestedBlockNumber);\n // lookup payload in block cache\n const identifier: string | null = cacheIdentifierForRequest(request, true);\n return identifier ? blockCache[identifier] : undefined;\n }\n\n async set(\n request: JsonRpcRequest,\n requestedBlockNumber: string,\n result: Block,\n ): Promise<void> {\n // check if we can cached this result\n const canCacheResult: boolean = this.canCacheResult(request, result);\n if (!canCacheResult) {\n return;\n }\n\n // set the value in the cache\n const identifier: string | null = cacheIdentifierForRequest(request, true);\n if (!identifier) {\n return;\n }\n const blockCache: BlockCache = this.getBlockCache(requestedBlockNumber);\n blockCache[identifier] = result;\n }\n\n canCacheRequest(request: JsonRpcRequest): boolean {\n // check request method\n if (!canCache(request.method)) {\n return false;\n }\n // check blockTag\n const blockTag = blockTagForRequest(request);\n\n if (blockTag === 'pending') {\n return false;\n }\n // can be cached\n return true;\n }\n\n canCacheResult(request: JsonRpcRequest, result: Block): boolean {\n // never cache empty values (e.g. undefined)\n if (emptyValues.includes(result as any)) {\n return false;\n }\n\n // check if transactions have block reference before caching\n if (\n request.method &&\n ['eth_getTransactionByHash', 'eth_getTransactionReceipt'].includes(\n request.method,\n )\n ) {\n if (\n !result?.blockHash ||\n result.blockHash ===\n '0x0000000000000000000000000000000000000000000000000000000000000000'\n ) {\n return false;\n }\n }\n // otherwise true\n return true;\n }\n\n // removes all block caches with block number lower than `oldBlockHex`\n clearBefore(oldBlockHex: string): void {\n const oldBlockNumber: number = Number.parseInt(oldBlockHex, 16);\n // clear old caches\n Object.keys(this.cache)\n .map(Number)\n .filter((num) => num < oldBlockNumber)\n .forEach((num) => delete this.cache[num]);\n }\n}\n\nexport function createBlockCacheMiddleware({\n blockTracker,\n}: BlockCacheMiddlewareOptions = {}): JsonRpcCacheMiddleware<\n JsonRpcParams,\n Json\n> {\n // validate options\n if (!blockTracker) {\n throw new Error(\n 'createBlockCacheMiddleware - No PollingBlockTracker specified',\n );\n }\n\n // create caching strategies\n const blockCache: BlockCacheStrategy = new BlockCacheStrategy();\n const strategies: Record<CacheStrategy, BlockCacheStrategy | undefined> = {\n [CacheStrategy.Permanent]: blockCache,\n [CacheStrategy.Block]: blockCache,\n [CacheStrategy.Fork]: blockCache,\n [CacheStrategy.Never]: undefined,\n };\n\n return createAsyncMiddleware(\n async (req: JsonRpcRequestToCache<JsonRpcParams>, res, next) => {\n // allow cach to be skipped if so specified\n if (req.skipCache) {\n return next();\n }\n // check type and matching strategy\n const type = cacheTypeForMethod(req.method);\n const strategy = strategies[type];\n // If there's no strategy in place, pass it down the chain.\n if (!strategy) {\n return next();\n }\n\n // If the strategy can't cache this request, ignore it.\n if (!strategy.canCacheRequest(req)) {\n return next();\n }\n\n // get block reference (number or keyword)\n const requestBlockTag = blockTagForRequest(req);\n const blockTag =\n requestBlockTag && typeof requestBlockTag === 'string'\n ? requestBlockTag\n : 'latest';\n\n log('blockTag = %o, req = %o', blockTag, req);\n\n // get exact block number\n let requestedBlockNumber: string;\n if (blockTag === 'earliest') {\n // this just exists for symmetry with \"latest\"\n requestedBlockNumber = '0x00';\n } else if (blockTag === 'latest') {\n // fetch latest block number\n log('Fetching latest block number to determine cache key');\n const latestBlockNumber = await blockTracker.getLatestBlock();\n // clear all cache before latest block\n log(\n 'Clearing values stored under block numbers before %o',\n latestBlockNumber,\n );\n blockCache.clearBefore(latestBlockNumber);\n requestedBlockNumber = latestBlockNumber;\n } else {\n // We have a hex number\n requestedBlockNumber = blockTag;\n }\n // end on a hit, continue on a miss\n const cacheResult: Block | undefined = await strategy.get(\n req,\n requestedBlockNumber,\n );\n if (cacheResult === undefined) {\n // cache miss\n // wait for other middleware to handle request\n log(\n 'No cache stored under block number %o, carrying request forward',\n requestedBlockNumber,\n );\n await next();\n\n // add result to cache\n // it's safe to cast res.result as Block, due to runtime type checks\n // performed when strategy.set is called\n log('Populating cache with', res);\n await strategy.set(req, requestedBlockNumber, res.result as Block);\n } else {\n // fill in result from cache\n log(\n 'Cache hit, reusing cache result stored under block number %o',\n requestedBlockNumber,\n );\n res.result = cacheResult;\n }\n return undefined;\n },\n );\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PollingBlockTracker } from "@metamask/eth-block-tracker";
|
|
2
|
+
import type { Json, JsonRpcParams } from "@metamask/utils";
|
|
3
|
+
import type { JsonRpcCacheMiddleware } from "./types.cjs";
|
|
4
|
+
interface BlockCacheMiddlewareOptions {
|
|
5
|
+
blockTracker?: PollingBlockTracker;
|
|
6
|
+
}
|
|
7
|
+
export declare function createBlockCacheMiddleware({ blockTracker, }?: BlockCacheMiddlewareOptions): JsonRpcCacheMiddleware<JsonRpcParams, Json>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=block-cache.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block-cache.d.cts","sourceRoot":"","sources":["../src/block-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AAEvE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAkB,wBAAwB;AAG3E,OAAO,KAAK,EAKV,sBAAsB,EAEvB,oBAAgB;AAajB,UAAU,2BAA2B;IACnC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AA2GD,wBAAgB,0BAA0B,CAAC,EACzC,YAAY,GACb,GAAE,2BAAgC,GAAG,sBAAsB,CAC1D,aAAa,EACb,IAAI,CACL,CA+FA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PollingBlockTracker } from "@metamask/eth-block-tracker";
|
|
2
|
+
import type { Json, JsonRpcParams } from "@metamask/utils";
|
|
3
|
+
import type { JsonRpcCacheMiddleware } from "./types.mjs";
|
|
4
|
+
interface BlockCacheMiddlewareOptions {
|
|
5
|
+
blockTracker?: PollingBlockTracker;
|
|
6
|
+
}
|
|
7
|
+
export declare function createBlockCacheMiddleware({ blockTracker, }?: BlockCacheMiddlewareOptions): JsonRpcCacheMiddleware<JsonRpcParams, Json>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=block-cache.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block-cache.d.mts","sourceRoot":"","sources":["../src/block-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AAEvE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAkB,wBAAwB;AAG3E,OAAO,KAAK,EAKV,sBAAsB,EAEvB,oBAAgB;AAajB,UAAU,2BAA2B;IACnC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AA2GD,wBAAgB,0BAA0B,CAAC,EACzC,YAAY,GACb,GAAE,2BAAgC,GAAG,sBAAsB,CAC1D,aAAa,EACb,IAAI,CACL,CA+FA"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { createAsyncMiddleware } from "@metamask/json-rpc-engine";
|
|
2
|
+
import { projectLogger, createModuleLogger } from "./logging-utils.mjs";
|
|
3
|
+
import { cacheIdentifierForRequest, blockTagForRequest, cacheTypeForMethod, canCache, CacheStrategy } from "./utils/cache.mjs";
|
|
4
|
+
const log = createModuleLogger(projectLogger, 'block-cache');
|
|
5
|
+
// `<nil>` comes from https://github.com/ethereum/go-ethereum/issues/16925
|
|
6
|
+
const emptyValues = [undefined, null, '\u003cnil\u003e'];
|
|
7
|
+
//
|
|
8
|
+
// Cache Strategies
|
|
9
|
+
//
|
|
10
|
+
class BlockCacheStrategy {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.cache = {};
|
|
13
|
+
}
|
|
14
|
+
getBlockCache(blockNumberHex) {
|
|
15
|
+
const blockNumber = Number.parseInt(blockNumberHex, 16);
|
|
16
|
+
let blockCache = this.cache[blockNumber];
|
|
17
|
+
// create new cache if necesary
|
|
18
|
+
if (!blockCache) {
|
|
19
|
+
const newCache = {};
|
|
20
|
+
this.cache[blockNumber] = newCache;
|
|
21
|
+
blockCache = newCache;
|
|
22
|
+
}
|
|
23
|
+
return blockCache;
|
|
24
|
+
}
|
|
25
|
+
async get(request, requestedBlockNumber) {
|
|
26
|
+
// lookup block cache
|
|
27
|
+
const blockCache = this.getBlockCache(requestedBlockNumber);
|
|
28
|
+
// lookup payload in block cache
|
|
29
|
+
const identifier = cacheIdentifierForRequest(request, true);
|
|
30
|
+
return identifier ? blockCache[identifier] : undefined;
|
|
31
|
+
}
|
|
32
|
+
async set(request, requestedBlockNumber, result) {
|
|
33
|
+
// check if we can cached this result
|
|
34
|
+
const canCacheResult = this.canCacheResult(request, result);
|
|
35
|
+
if (!canCacheResult) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// set the value in the cache
|
|
39
|
+
const identifier = cacheIdentifierForRequest(request, true);
|
|
40
|
+
if (!identifier) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const blockCache = this.getBlockCache(requestedBlockNumber);
|
|
44
|
+
blockCache[identifier] = result;
|
|
45
|
+
}
|
|
46
|
+
canCacheRequest(request) {
|
|
47
|
+
// check request method
|
|
48
|
+
if (!canCache(request.method)) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
// check blockTag
|
|
52
|
+
const blockTag = blockTagForRequest(request);
|
|
53
|
+
if (blockTag === 'pending') {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
// can be cached
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
canCacheResult(request, result) {
|
|
60
|
+
// never cache empty values (e.g. undefined)
|
|
61
|
+
if (emptyValues.includes(result)) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
// check if transactions have block reference before caching
|
|
65
|
+
if (request.method &&
|
|
66
|
+
['eth_getTransactionByHash', 'eth_getTransactionReceipt'].includes(request.method)) {
|
|
67
|
+
if (!result?.blockHash ||
|
|
68
|
+
result.blockHash ===
|
|
69
|
+
'0x0000000000000000000000000000000000000000000000000000000000000000') {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// otherwise true
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
// removes all block caches with block number lower than `oldBlockHex`
|
|
77
|
+
clearBefore(oldBlockHex) {
|
|
78
|
+
const oldBlockNumber = Number.parseInt(oldBlockHex, 16);
|
|
79
|
+
// clear old caches
|
|
80
|
+
Object.keys(this.cache)
|
|
81
|
+
.map(Number)
|
|
82
|
+
.filter((num) => num < oldBlockNumber)
|
|
83
|
+
.forEach((num) => delete this.cache[num]);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export function createBlockCacheMiddleware({ blockTracker, } = {}) {
|
|
87
|
+
// validate options
|
|
88
|
+
if (!blockTracker) {
|
|
89
|
+
throw new Error('createBlockCacheMiddleware - No PollingBlockTracker specified');
|
|
90
|
+
}
|
|
91
|
+
// create caching strategies
|
|
92
|
+
const blockCache = new BlockCacheStrategy();
|
|
93
|
+
const strategies = {
|
|
94
|
+
[CacheStrategy.Permanent]: blockCache,
|
|
95
|
+
[CacheStrategy.Block]: blockCache,
|
|
96
|
+
[CacheStrategy.Fork]: blockCache,
|
|
97
|
+
[CacheStrategy.Never]: undefined,
|
|
98
|
+
};
|
|
99
|
+
return createAsyncMiddleware(async (req, res, next) => {
|
|
100
|
+
// allow cach to be skipped if so specified
|
|
101
|
+
if (req.skipCache) {
|
|
102
|
+
return next();
|
|
103
|
+
}
|
|
104
|
+
// check type and matching strategy
|
|
105
|
+
const type = cacheTypeForMethod(req.method);
|
|
106
|
+
const strategy = strategies[type];
|
|
107
|
+
// If there's no strategy in place, pass it down the chain.
|
|
108
|
+
if (!strategy) {
|
|
109
|
+
return next();
|
|
110
|
+
}
|
|
111
|
+
// If the strategy can't cache this request, ignore it.
|
|
112
|
+
if (!strategy.canCacheRequest(req)) {
|
|
113
|
+
return next();
|
|
114
|
+
}
|
|
115
|
+
// get block reference (number or keyword)
|
|
116
|
+
const requestBlockTag = blockTagForRequest(req);
|
|
117
|
+
const blockTag = requestBlockTag && typeof requestBlockTag === 'string'
|
|
118
|
+
? requestBlockTag
|
|
119
|
+
: 'latest';
|
|
120
|
+
log('blockTag = %o, req = %o', blockTag, req);
|
|
121
|
+
// get exact block number
|
|
122
|
+
let requestedBlockNumber;
|
|
123
|
+
if (blockTag === 'earliest') {
|
|
124
|
+
// this just exists for symmetry with "latest"
|
|
125
|
+
requestedBlockNumber = '0x00';
|
|
126
|
+
}
|
|
127
|
+
else if (blockTag === 'latest') {
|
|
128
|
+
// fetch latest block number
|
|
129
|
+
log('Fetching latest block number to determine cache key');
|
|
130
|
+
const latestBlockNumber = await blockTracker.getLatestBlock();
|
|
131
|
+
// clear all cache before latest block
|
|
132
|
+
log('Clearing values stored under block numbers before %o', latestBlockNumber);
|
|
133
|
+
blockCache.clearBefore(latestBlockNumber);
|
|
134
|
+
requestedBlockNumber = latestBlockNumber;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
// We have a hex number
|
|
138
|
+
requestedBlockNumber = blockTag;
|
|
139
|
+
}
|
|
140
|
+
// end on a hit, continue on a miss
|
|
141
|
+
const cacheResult = await strategy.get(req, requestedBlockNumber);
|
|
142
|
+
if (cacheResult === undefined) {
|
|
143
|
+
// cache miss
|
|
144
|
+
// wait for other middleware to handle request
|
|
145
|
+
log('No cache stored under block number %o, carrying request forward', requestedBlockNumber);
|
|
146
|
+
await next();
|
|
147
|
+
// add result to cache
|
|
148
|
+
// it's safe to cast res.result as Block, due to runtime type checks
|
|
149
|
+
// performed when strategy.set is called
|
|
150
|
+
log('Populating cache with', res);
|
|
151
|
+
await strategy.set(req, requestedBlockNumber, res.result);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
// fill in result from cache
|
|
155
|
+
log('Cache hit, reusing cache result stored under block number %o', requestedBlockNumber);
|
|
156
|
+
res.result = cacheResult;
|
|
157
|
+
}
|
|
158
|
+
return undefined;
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=block-cache.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block-cache.mjs","sourceRoot":"","sources":["../src/block-cache.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport type { Json, JsonRpcParams, JsonRpcRequest } from '@metamask/utils';\n\nimport { projectLogger, createModuleLogger } from './logging-utils';\nimport type {\n Block,\n BlockCache,\n // eslint-disable-next-line @typescript-eslint/no-shadow\n Cache,\n JsonRpcCacheMiddleware,\n JsonRpcRequestToCache,\n} from './types';\nimport {\n cacheIdentifierForRequest,\n blockTagForRequest,\n cacheTypeForMethod,\n canCache,\n CacheStrategy,\n} from './utils/cache';\n\nconst log = createModuleLogger(projectLogger, 'block-cache');\n// `<nil>` comes from https://github.com/ethereum/go-ethereum/issues/16925\nconst emptyValues = [undefined, null, '\\u003cnil\\u003e'];\n\ninterface BlockCacheMiddlewareOptions {\n blockTracker?: PollingBlockTracker;\n}\n\n//\n// Cache Strategies\n//\n\nclass BlockCacheStrategy {\n private cache: Cache;\n\n constructor() {\n this.cache = {};\n }\n\n getBlockCache(blockNumberHex: string): BlockCache {\n const blockNumber: number = Number.parseInt(blockNumberHex, 16);\n let blockCache: BlockCache = this.cache[blockNumber];\n // create new cache if necesary\n if (!blockCache) {\n const newCache: BlockCache = {};\n this.cache[blockNumber] = newCache;\n blockCache = newCache;\n }\n return blockCache;\n }\n\n async get(\n request: JsonRpcRequest,\n requestedBlockNumber: string,\n ): Promise<Block | undefined> {\n // lookup block cache\n const blockCache: BlockCache = this.getBlockCache(requestedBlockNumber);\n // lookup payload in block cache\n const identifier: string | null = cacheIdentifierForRequest(request, true);\n return identifier ? blockCache[identifier] : undefined;\n }\n\n async set(\n request: JsonRpcRequest,\n requestedBlockNumber: string,\n result: Block,\n ): Promise<void> {\n // check if we can cached this result\n const canCacheResult: boolean = this.canCacheResult(request, result);\n if (!canCacheResult) {\n return;\n }\n\n // set the value in the cache\n const identifier: string | null = cacheIdentifierForRequest(request, true);\n if (!identifier) {\n return;\n }\n const blockCache: BlockCache = this.getBlockCache(requestedBlockNumber);\n blockCache[identifier] = result;\n }\n\n canCacheRequest(request: JsonRpcRequest): boolean {\n // check request method\n if (!canCache(request.method)) {\n return false;\n }\n // check blockTag\n const blockTag = blockTagForRequest(request);\n\n if (blockTag === 'pending') {\n return false;\n }\n // can be cached\n return true;\n }\n\n canCacheResult(request: JsonRpcRequest, result: Block): boolean {\n // never cache empty values (e.g. undefined)\n if (emptyValues.includes(result as any)) {\n return false;\n }\n\n // check if transactions have block reference before caching\n if (\n request.method &&\n ['eth_getTransactionByHash', 'eth_getTransactionReceipt'].includes(\n request.method,\n )\n ) {\n if (\n !result?.blockHash ||\n result.blockHash ===\n '0x0000000000000000000000000000000000000000000000000000000000000000'\n ) {\n return false;\n }\n }\n // otherwise true\n return true;\n }\n\n // removes all block caches with block number lower than `oldBlockHex`\n clearBefore(oldBlockHex: string): void {\n const oldBlockNumber: number = Number.parseInt(oldBlockHex, 16);\n // clear old caches\n Object.keys(this.cache)\n .map(Number)\n .filter((num) => num < oldBlockNumber)\n .forEach((num) => delete this.cache[num]);\n }\n}\n\nexport function createBlockCacheMiddleware({\n blockTracker,\n}: BlockCacheMiddlewareOptions = {}): JsonRpcCacheMiddleware<\n JsonRpcParams,\n Json\n> {\n // validate options\n if (!blockTracker) {\n throw new Error(\n 'createBlockCacheMiddleware - No PollingBlockTracker specified',\n );\n }\n\n // create caching strategies\n const blockCache: BlockCacheStrategy = new BlockCacheStrategy();\n const strategies: Record<CacheStrategy, BlockCacheStrategy | undefined> = {\n [CacheStrategy.Permanent]: blockCache,\n [CacheStrategy.Block]: blockCache,\n [CacheStrategy.Fork]: blockCache,\n [CacheStrategy.Never]: undefined,\n };\n\n return createAsyncMiddleware(\n async (req: JsonRpcRequestToCache<JsonRpcParams>, res, next) => {\n // allow cach to be skipped if so specified\n if (req.skipCache) {\n return next();\n }\n // check type and matching strategy\n const type = cacheTypeForMethod(req.method);\n const strategy = strategies[type];\n // If there's no strategy in place, pass it down the chain.\n if (!strategy) {\n return next();\n }\n\n // If the strategy can't cache this request, ignore it.\n if (!strategy.canCacheRequest(req)) {\n return next();\n }\n\n // get block reference (number or keyword)\n const requestBlockTag = blockTagForRequest(req);\n const blockTag =\n requestBlockTag && typeof requestBlockTag === 'string'\n ? requestBlockTag\n : 'latest';\n\n log('blockTag = %o, req = %o', blockTag, req);\n\n // get exact block number\n let requestedBlockNumber: string;\n if (blockTag === 'earliest') {\n // this just exists for symmetry with \"latest\"\n requestedBlockNumber = '0x00';\n } else if (blockTag === 'latest') {\n // fetch latest block number\n log('Fetching latest block number to determine cache key');\n const latestBlockNumber = await blockTracker.getLatestBlock();\n // clear all cache before latest block\n log(\n 'Clearing values stored under block numbers before %o',\n latestBlockNumber,\n );\n blockCache.clearBefore(latestBlockNumber);\n requestedBlockNumber = latestBlockNumber;\n } else {\n // We have a hex number\n requestedBlockNumber = blockTag;\n }\n // end on a hit, continue on a miss\n const cacheResult: Block | undefined = await strategy.get(\n req,\n requestedBlockNumber,\n );\n if (cacheResult === undefined) {\n // cache miss\n // wait for other middleware to handle request\n log(\n 'No cache stored under block number %o, carrying request forward',\n requestedBlockNumber,\n );\n await next();\n\n // add result to cache\n // it's safe to cast res.result as Block, due to runtime type checks\n // performed when strategy.set is called\n log('Populating cache with', res);\n await strategy.set(req, requestedBlockNumber, res.result as Block);\n } else {\n // fill in result from cache\n log(\n 'Cache hit, reusing cache result stored under block number %o',\n requestedBlockNumber,\n );\n res.result = cacheResult;\n }\n return undefined;\n },\n );\n}\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createBlockRefRewriteMiddleware = void 0;
|
|
4
|
+
const json_rpc_engine_1 = require("@metamask/json-rpc-engine");
|
|
5
|
+
const cache_1 = require("./utils/cache.cjs");
|
|
6
|
+
function createBlockRefRewriteMiddleware({ blockTracker, } = {}) {
|
|
7
|
+
if (!blockTracker) {
|
|
8
|
+
throw Error('BlockRefRewriteMiddleware - mandatory "blockTracker" option is missing.');
|
|
9
|
+
}
|
|
10
|
+
return (0, json_rpc_engine_1.createAsyncMiddleware)(async (req, _res, next) => {
|
|
11
|
+
const blockRefIndex = (0, cache_1.blockTagParamIndex)(req.method);
|
|
12
|
+
// skip if method does not include blockRef
|
|
13
|
+
if (blockRefIndex === undefined) {
|
|
14
|
+
return next();
|
|
15
|
+
}
|
|
16
|
+
// skip if not "latest"
|
|
17
|
+
const blockRef = Array.isArray(req.params) && req.params[blockRefIndex]
|
|
18
|
+
? req.params[blockRefIndex]
|
|
19
|
+
: // omitted blockRef implies "latest"
|
|
20
|
+
'latest';
|
|
21
|
+
if (blockRef !== 'latest') {
|
|
22
|
+
return next();
|
|
23
|
+
}
|
|
24
|
+
// rewrite blockRef to block-tracker's block number
|
|
25
|
+
const latestBlockNumber = await blockTracker.getLatestBlock();
|
|
26
|
+
if (Array.isArray(req.params)) {
|
|
27
|
+
req.params[blockRefIndex] = latestBlockNumber;
|
|
28
|
+
}
|
|
29
|
+
return next();
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
exports.createBlockRefRewriteMiddleware = createBlockRefRewriteMiddleware;
|
|
33
|
+
//# sourceMappingURL=block-ref-rewrite.cjs.map
|
|
@@ -0,0 +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,2CAA2C;QAC3C,IAAI,aAAa,KAAK,SAAS,EAAE;YAC/B,OAAO,IAAI,EAAE,CAAC;SACf;QACD,uBAAuB;QACvB,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;QACD,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\ninterface BlockRefRewriteMiddlewareOptions {\n blockTracker?: PollingBlockTracker;\n}\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 // skip if method does not include blockRef\n if (blockRefIndex === undefined) {\n return next();\n }\n // skip if not \"latest\"\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 // 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"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PollingBlockTracker } from "@metamask/eth-block-tracker";
|
|
2
|
+
import type { JsonRpcMiddleware } from "@metamask/json-rpc-engine";
|
|
3
|
+
import type { Json, JsonRpcParams } from "@metamask/utils";
|
|
4
|
+
interface BlockRefRewriteMiddlewareOptions {
|
|
5
|
+
blockTracker?: PollingBlockTracker;
|
|
6
|
+
}
|
|
7
|
+
export declare function createBlockRefRewriteMiddleware({ blockTracker, }?: BlockRefRewriteMiddlewareOptions): JsonRpcMiddleware<JsonRpcParams, Json>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=block-ref-rewrite.d.cts.map
|
|
@@ -0,0 +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,UAAU,gCAAgC;IACxC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAED,wBAAgB,+BAA+B,CAAC,EAC9C,YAAY,GACb,GAAE,gCAAqC,GAAG,iBAAiB,CAC1D,aAAa,EACb,IAAI,CACL,CA8BA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PollingBlockTracker } from "@metamask/eth-block-tracker";
|
|
2
|
+
import type { JsonRpcMiddleware } from "@metamask/json-rpc-engine";
|
|
3
|
+
import type { Json, JsonRpcParams } from "@metamask/utils";
|
|
4
|
+
interface BlockRefRewriteMiddlewareOptions {
|
|
5
|
+
blockTracker?: PollingBlockTracker;
|
|
6
|
+
}
|
|
7
|
+
export declare function createBlockRefRewriteMiddleware({ blockTracker, }?: BlockRefRewriteMiddlewareOptions): JsonRpcMiddleware<JsonRpcParams, Json>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=block-ref-rewrite.d.mts.map
|
|
@@ -0,0 +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,UAAU,gCAAgC;IACxC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAED,wBAAgB,+BAA+B,CAAC,EAC9C,YAAY,GACb,GAAE,gCAAqC,GAAG,iBAAiB,CAC1D,aAAa,EACb,IAAI,CACL,CA8BA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createAsyncMiddleware } from "@metamask/json-rpc-engine";
|
|
2
|
+
import { blockTagParamIndex } from "./utils/cache.mjs";
|
|
3
|
+
export function createBlockRefRewriteMiddleware({ blockTracker, } = {}) {
|
|
4
|
+
if (!blockTracker) {
|
|
5
|
+
throw Error('BlockRefRewriteMiddleware - mandatory "blockTracker" option is missing.');
|
|
6
|
+
}
|
|
7
|
+
return createAsyncMiddleware(async (req, _res, next) => {
|
|
8
|
+
const blockRefIndex = blockTagParamIndex(req.method);
|
|
9
|
+
// skip if method does not include blockRef
|
|
10
|
+
if (blockRefIndex === undefined) {
|
|
11
|
+
return next();
|
|
12
|
+
}
|
|
13
|
+
// skip if not "latest"
|
|
14
|
+
const blockRef = Array.isArray(req.params) && req.params[blockRefIndex]
|
|
15
|
+
? req.params[blockRefIndex]
|
|
16
|
+
: // omitted blockRef implies "latest"
|
|
17
|
+
'latest';
|
|
18
|
+
if (blockRef !== 'latest') {
|
|
19
|
+
return next();
|
|
20
|
+
}
|
|
21
|
+
// rewrite blockRef to block-tracker's block number
|
|
22
|
+
const latestBlockNumber = await blockTracker.getLatestBlock();
|
|
23
|
+
if (Array.isArray(req.params)) {
|
|
24
|
+
req.params[blockRefIndex] = latestBlockNumber;
|
|
25
|
+
}
|
|
26
|
+
return next();
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=block-ref-rewrite.mjs.map
|
|
@@ -0,0 +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,2CAA2C;QAC3C,IAAI,aAAa,KAAK,SAAS,EAAE;YAC/B,OAAO,IAAI,EAAE,CAAC;SACf;QACD,uBAAuB;QACvB,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;QACD,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\ninterface BlockRefRewriteMiddlewareOptions {\n blockTracker?: PollingBlockTracker;\n}\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 // skip if method does not include blockRef\n if (blockRefIndex === undefined) {\n return next();\n }\n // skip if not \"latest\"\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 // 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"]}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createBlockRefMiddleware = void 0;
|
|
4
|
+
const json_rpc_engine_1 = require("@metamask/json-rpc-engine");
|
|
5
|
+
const full_1 = require("klona/full");
|
|
6
|
+
const logging_utils_1 = require("./logging-utils.cjs");
|
|
7
|
+
const cache_1 = require("./utils/cache.cjs");
|
|
8
|
+
const log = (0, logging_utils_1.createModuleLogger)(logging_utils_1.projectLogger, 'block-ref');
|
|
9
|
+
function createBlockRefMiddleware({ provider, blockTracker, } = {}) {
|
|
10
|
+
if (!provider) {
|
|
11
|
+
throw Error('BlockRefMiddleware - mandatory "provider" option is missing.');
|
|
12
|
+
}
|
|
13
|
+
if (!blockTracker) {
|
|
14
|
+
throw Error('BlockRefMiddleware - mandatory "blockTracker" option is missing.');
|
|
15
|
+
}
|
|
16
|
+
return (0, json_rpc_engine_1.createAsyncMiddleware)(async (req, res, next) => {
|
|
17
|
+
const blockRefIndex = (0, cache_1.blockTagParamIndex)(req.method);
|
|
18
|
+
// skip if method does not include blockRef
|
|
19
|
+
if (blockRefIndex === undefined) {
|
|
20
|
+
return next();
|
|
21
|
+
}
|
|
22
|
+
const blockRef = Array.isArray(req.params)
|
|
23
|
+
? (req.params[blockRefIndex] ?? 'latest')
|
|
24
|
+
: 'latest';
|
|
25
|
+
// skip if not "latest"
|
|
26
|
+
if (blockRef !== 'latest') {
|
|
27
|
+
log('blockRef is not "latest", carrying request forward');
|
|
28
|
+
return next();
|
|
29
|
+
}
|
|
30
|
+
// lookup latest block
|
|
31
|
+
const latestBlockNumber = await blockTracker.getLatestBlock();
|
|
32
|
+
log(`blockRef is "latest", setting param ${blockRefIndex} to latest block ${latestBlockNumber}`);
|
|
33
|
+
// create child request with specific block-ref
|
|
34
|
+
const childRequest = (0, full_1.klona)(req);
|
|
35
|
+
if (Array.isArray(childRequest.params)) {
|
|
36
|
+
childRequest.params[blockRefIndex] = latestBlockNumber;
|
|
37
|
+
}
|
|
38
|
+
// perform child request
|
|
39
|
+
log('Performing another request %o', childRequest);
|
|
40
|
+
// copy child result onto original response
|
|
41
|
+
res.result = await provider.request(childRequest);
|
|
42
|
+
return undefined;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
exports.createBlockRefMiddleware = createBlockRefMiddleware;
|
|
46
|
+
//# sourceMappingURL=block-ref.cjs.map
|