1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.createBlockCacheMiddleware = void 0;
|
4 | const json_rpc_engine_1 = require("json-rpc-engine");
|
5 | const cache_1 = require("./utils/cache");
|
6 |
|
7 | const emptyValues = [undefined, null, '\u003cnil\u003e'];
|
8 |
|
9 |
|
10 |
|
11 | class BlockCacheStrategy {
|
12 | constructor() {
|
13 | this.cache = {};
|
14 | }
|
15 | getBlockCacheForPayload(_payload, blockNumberHex) {
|
16 | const blockNumber = Number.parseInt(blockNumberHex, 16);
|
17 | let blockCache = this.cache[blockNumber];
|
18 |
|
19 | if (!blockCache) {
|
20 | const newCache = {};
|
21 | this.cache[blockNumber] = newCache;
|
22 | blockCache = newCache;
|
23 | }
|
24 | return blockCache;
|
25 | }
|
26 | async get(payload, requestedBlockNumber) {
|
27 |
|
28 | const blockCache = this.getBlockCacheForPayload(payload, requestedBlockNumber);
|
29 |
|
30 | const identifier = cache_1.cacheIdentifierForPayload(payload, true);
|
31 | return identifier ? blockCache[identifier] : undefined;
|
32 | }
|
33 | async set(payload, requestedBlockNumber, result) {
|
34 |
|
35 | const canCacheResult = this.canCacheResult(payload, result);
|
36 | if (!canCacheResult) {
|
37 | return;
|
38 | }
|
39 |
|
40 | const identifier = cache_1.cacheIdentifierForPayload(payload, true);
|
41 | if (!identifier) {
|
42 | return;
|
43 | }
|
44 | const blockCache = this.getBlockCacheForPayload(payload, requestedBlockNumber);
|
45 | blockCache[identifier] = result;
|
46 | }
|
47 | canCacheRequest(payload) {
|
48 |
|
49 | if (!cache_1.canCache(payload)) {
|
50 | return false;
|
51 | }
|
52 |
|
53 | const blockTag = cache_1.blockTagForPayload(payload);
|
54 | if (blockTag === 'pending') {
|
55 | return false;
|
56 | }
|
57 |
|
58 | return true;
|
59 | }
|
60 | canCacheResult(payload, result) {
|
61 |
|
62 | if (emptyValues.includes(result)) {
|
63 | return false;
|
64 | }
|
65 |
|
66 | if (payload.method &&
|
67 | ['eth_getTransactionByHash', 'eth_getTransactionReceipt'].includes(payload.method)) {
|
68 | if (!result ||
|
69 | !result.blockHash ||
|
70 | result.blockHash ===
|
71 | '0x0000000000000000000000000000000000000000000000000000000000000000') {
|
72 | return false;
|
73 | }
|
74 | }
|
75 |
|
76 | return true;
|
77 | }
|
78 |
|
79 | clearBefore(oldBlockHex) {
|
80 | const oldBlockNumber = Number.parseInt(oldBlockHex, 16);
|
81 |
|
82 | Object.keys(this.cache)
|
83 | .map(Number)
|
84 | .filter((num) => num < oldBlockNumber)
|
85 | .forEach((num) => delete this.cache[num]);
|
86 | }
|
87 | }
|
88 | function createBlockCacheMiddleware({ blockTracker, } = {}) {
|
89 |
|
90 | if (!blockTracker) {
|
91 | throw new Error('createBlockCacheMiddleware - No PollingBlockTracker specified');
|
92 | }
|
93 |
|
94 | const blockCache = new BlockCacheStrategy();
|
95 | const strategies = {
|
96 | perma: blockCache,
|
97 | block: blockCache,
|
98 | fork: blockCache,
|
99 | };
|
100 | return json_rpc_engine_1.createAsyncMiddleware(async (req, res, next) => {
|
101 |
|
102 | if (req.skipCache) {
|
103 | return next();
|
104 | }
|
105 |
|
106 | const type = cache_1.cacheTypeForPayload(req);
|
107 | const strategy = strategies[type];
|
108 |
|
109 | if (!strategy) {
|
110 | return next();
|
111 | }
|
112 |
|
113 | if (!strategy.canCacheRequest(req)) {
|
114 | return next();
|
115 | }
|
116 |
|
117 | let blockTag = cache_1.blockTagForPayload(req);
|
118 | if (!blockTag) {
|
119 | blockTag = 'latest';
|
120 | }
|
121 |
|
122 | let requestedBlockNumber;
|
123 | if (blockTag === 'earliest') {
|
124 |
|
125 | requestedBlockNumber = '0x00';
|
126 | }
|
127 | else if (blockTag === 'latest') {
|
128 |
|
129 | const latestBlockNumber = await blockTracker.getLatestBlock();
|
130 |
|
131 | blockCache.clearBefore(latestBlockNumber);
|
132 | requestedBlockNumber = latestBlockNumber;
|
133 | }
|
134 | else {
|
135 |
|
136 | requestedBlockNumber = blockTag;
|
137 | }
|
138 |
|
139 | const cacheResult = await strategy.get(req, requestedBlockNumber);
|
140 | if (cacheResult === undefined) {
|
141 |
|
142 |
|
143 |
|
144 | await next();
|
145 |
|
146 |
|
147 |
|
148 | await strategy.set(req, requestedBlockNumber, res.result);
|
149 | }
|
150 | else {
|
151 |
|
152 | res.result = cacheResult;
|
153 | }
|
154 | return undefined;
|
155 | });
|
156 | }
|
157 | exports.createBlockCacheMiddleware = createBlockCacheMiddleware;
|
158 |
|
\ | No newline at end of file |