-
Notifications
You must be signed in to change notification settings - Fork 239
/
Copy pathnet-access-fixture.js
197 lines (190 loc) · 4.67 KB
/
net-access-fixture.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
const { stringify: jq } = JSON;
/**
* @file to regenerate
* 1. set RECORDING=true in interpose-net-access.test.js
* 2. run: yarn test test/interpose-net-access.test.js --update-snapshots
* 3. for each map in interpose-net-access.test.js.md, copy it and
* 4. replace all occurences of => with : and paste as args to Object.fromEntries()
* 5. change RECORDING back to false
*/
export const web1 = new Map([
[
jq([
'https://emerynet.rpc.agoric.net/',
{
method: 'POST',
body: jq({
id: 1208387614,
method: 'no-such-method',
params: [],
jsonrpc: '2.0',
}),
headers: { 'Content-Type': 'application/json' },
},
]),
{
error: {
code: -32601,
message: 'Method not found',
},
id: 1208387614,
jsonrpc: '2.0',
},
],
[
jq([
'https://emerynet.rpc.agoric.net/',
{
method: 'POST',
body: jq({
jsonrpc: '2.0',
id: 797030719,
method: 'abci_query',
params: {
path: '/cosmos.bank.v1beta1.Query/Balance',
data: '0a2d61676f726963313430646d6b727a326534326572676a6a37677976656a687a6d6a7a7572767165713832616e67120475697374',
prove: false,
},
}),
headers: { 'Content-Type': 'application/json' },
},
]),
{
id: 797030719,
jsonrpc: '2.0',
result: {
response: {
code: 0,
codespace: '',
height: '123985',
index: '0',
info: '',
key: null,
log: '',
proofOps: null,
value: 'ChAKBHVpc3QSCDI1MDUwMDAw',
},
},
},
],
]);
export const web2 = new Map([
[
jq([
'https://emerynet.rpc.agoric.net/',
{
method: 'POST',
body: jq({
jsonrpc: '2.0',
id: 1757612624,
method: 'abci_query',
params: {
path: '/agoric.vstorage.Query/Children',
data: '',
prove: false,
},
}),
headers: { 'Content-Type': 'application/json' },
},
]),
{
id: 1757612624,
jsonrpc: '2.0',
result: {
response: {
code: 0,
codespace: '',
height: '123985',
index: '0',
info: '',
key: null,
log: '',
proofOps: null,
value:
'CgxhY3Rpdml0eWhhc2gKCmJlYW5zT3dpbmcKBmVncmVzcwoTaGlnaFByaW9yaXR5U2VuZGVycwoJcHVibGlzaGVkCgpzd2luZ1N0b3Jl',
},
},
},
],
]);
/**
* @param {string} str
* ack: https://stackoverflow.com/a/7616484
*/
const hashCode = str => {
let hash = 0;
let i;
let chr;
if (str.length === 0) return hash;
for (i = 0; i < str.length; i += 1) {
chr = str.charCodeAt(i);
// eslint-disable-next-line no-bitwise
hash = (hash << 5) - hash + chr;
// eslint-disable-next-line no-bitwise
hash |= 0; // Convert to 32bit integer
}
return hash;
};
/**
* Normalize JSON RPC request ID
*
* tendermint-rpc generates ids using ambient access to Math.random()
* So we normalize them to a hash of the rest of the JSON.
*
* Earlier, we tried a sequence number, but it was non-deterministic
* with multiple interleaved requests.
*
* @param {string} argsKey
*/
const normalizeID = argsKey => {
// arbitrary string unlikely to occur in a request. from `pwgen 16 -1`
const placeholder = 'Ajaz1chei7ohnguv';
const noid = argsKey.replace(/\\"id\\":\d+/, `\\"id\\":${placeholder}`);
const id = Math.abs(hashCode(noid));
return noid.replace(placeholder, `${id}`);
};
/**
* Wrap `fetch` to capture JSON RPC IO traffic.
*
* @param {typeof window.fetch} fetch
* returns wraped fetch along with a .web map for use with {@link replayIO}
*/
export const captureIO = fetch => {
const web = new Map();
/** @type {typeof window.fetch} */
// @ts-expect-error mock
const f = async (...args) => {
const key = normalizeID(JSON.stringify(args));
const resp = await fetch(...args);
return {
ok: resp.ok,
json: async () => {
const data = await resp.json();
web.set(key, data);
return data;
},
};
};
return { fetch: f, web };
};
/**
* Replay captured JSON RPC IO.
*
* @param {Map<string, any>} web map from
* JSON-stringified fetch args to fetched JSON data.
*/
export const replayIO = web => {
/** @type {typeof window.fetch} */
// @ts-expect-error mock
const f = async (...args) => {
const key = normalizeID(JSON.stringify(args));
const data = web.get(key);
if (!data) {
throw Error(`no data for ${key}`);
}
return {
json: async () => data,
};
};
return f;
};