/
QueryTest.sol
352 lines (321 loc) · 11.3 KB
/
QueryTest.sol
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.4;
// @dev QueryTest is a library to build Cross Chain Query (CCQ) responses for testing purposes.
library QueryTest {
// Custom errors
error SolanaTooManyPDAs();
error SolanaTooManySeeds();
error SolanaSeedTooLong();
//
// Query Request stuff
//
/// @dev buildOffChainQueryRequestBytes builds an off chain query request from the specified fields.
function buildOffChainQueryRequestBytes(
uint8 _version,
uint32 _nonce,
uint8 _numPerChainQueries,
bytes memory _perChainQueries
) internal pure returns (bytes memory){
return abi.encodePacked(
_version,
_nonce,
_numPerChainQueries,
_perChainQueries // Each created by buildPerChainRequestBytes()
);
}
/// @dev buildPerChainRequestBytes builds a per chain request from the specified fields.
function buildPerChainRequestBytes(
uint16 _chainId,
uint8 _queryType,
bytes memory _queryBytes
) internal pure returns (bytes memory){
return abi.encodePacked(
_chainId,
_queryType,
uint32(_queryBytes.length),
_queryBytes
);
}
/// @dev buildEthCallRequestBytes builds an eth_call query request from the specified fields.
function buildEthCallRequestBytes(
bytes memory _blockId,
uint8 _numCallData,
bytes memory _callData // Created with buildEthCallDataBytes()
) internal pure returns (bytes memory){
return abi.encodePacked(
uint32(_blockId.length),
_blockId,
_numCallData,
_callData
);
}
/// @dev buildEthCallByTimestampRequestBytes builds an eth_call_by_timestamp query request from the specified fields.
function buildEthCallByTimestampRequestBytes(
uint64 _targetTimeUs,
bytes memory _targetBlockHint,
bytes memory _followingBlockHint,
uint8 _numCallData,
bytes memory _callData // Created with buildEthCallDataBytes()
) internal pure returns (bytes memory){
return abi.encodePacked(
_targetTimeUs,
uint32(_targetBlockHint.length),
_targetBlockHint,
uint32(_followingBlockHint.length),
_followingBlockHint,
_numCallData,
_callData
);
}
/// @dev buildEthCallWithFinalityRequestBytes builds an eth_call_with_finality query request from the specified fields.
function buildEthCallWithFinalityRequestBytes(
bytes memory _blockId,
bytes memory _finality,
uint8 _numCallData,
bytes memory _callData // Created with buildEthCallDataBytes()
) internal pure returns (bytes memory){
return abi.encodePacked(
uint32(_blockId.length),
_blockId,
uint32(_finality.length),
_finality,
_numCallData,
_callData
);
}
/// @dev buildEthCallDataBytes builds the call data associated with one of the eth_call family of queries.
function buildEthCallDataBytes(
address _contractAddress,
bytes memory _callData
) internal pure returns (bytes memory){
return abi.encodePacked(
_contractAddress,
uint32(_callData.length),
_callData
);
}
/// @dev buildSolanaAccountRequestBytes builds a sol_account query request from the specified fields.
function buildSolanaAccountRequestBytes(
bytes memory _commitment,
uint64 _minContextSlot,
uint64 _dataSliceOffset,
uint64 _dataSliceLength,
uint8 _numAccounts,
bytes memory _accounts // Each account is 32 bytes.
) internal pure returns (bytes memory){
return abi.encodePacked(
uint32(_commitment.length),
_commitment,
_minContextSlot,
_dataSliceOffset,
_dataSliceLength,
_numAccounts,
_accounts
);
}
/// @dev buildSolanaPdaRequestBytes builds a sol_pda query request from the specified fields.
function buildSolanaPdaRequestBytes(
bytes memory _commitment,
uint64 _minContextSlot,
uint64 _dataSliceOffset,
uint64 _dataSliceLength,
bytes[] memory _pdas // Created with multiple calls to buildSolanaPdaEntry()
) internal pure returns (bytes memory){
uint numPdas = _pdas.length;
if (numPdas > 255) {
revert SolanaTooManyPDAs();
}
bytes memory result = abi.encodePacked(
uint32(_commitment.length),
_commitment,
_minContextSlot,
_dataSliceOffset,
_dataSliceLength,
uint8(numPdas)
);
for (uint idx; idx < numPdas;) {
result = abi.encodePacked(
result,
_pdas[idx]
);
unchecked { ++idx; }
}
return result;
}
/// @dev buildSolanaPdaEntry builds a PDA entry for a sol_pda query.
function buildSolanaPdaEntry(
bytes32 _programId,
uint8 _numSeeds,
bytes memory _seeds // Created with buildSolanaPdaSeedBytes()
) internal pure returns (bytes memory){
if (_numSeeds > SolanaMaxSeeds) {
revert SolanaTooManySeeds();
}
return abi.encodePacked(
_programId,
_numSeeds,
_seeds
);
}
// According to the spec, there may be at most 16 seeds.
// https://github.com/gagliardetto/solana-go/blob/6fe3aea02e3660d620433444df033fc3fe6e64c1/keys.go#L559
uint public constant SolanaMaxSeeds = 16;
// According to the spec, a seed may be at most 32 bytes.
// https://github.com/gagliardetto/solana-go/blob/6fe3aea02e3660d620433444df033fc3fe6e64c1/keys.go#L557
uint public constant SolanaMaxSeedLen = 32;
/// @dev buildSolanaPdaSeedBytes packs the seeds for a PDA entry into an array of bytes.
function buildSolanaPdaSeedBytes(
bytes[] memory _seeds
) internal pure returns (bytes memory, uint8){
uint numSeeds = _seeds.length;
if (numSeeds > SolanaMaxSeeds) {
revert SolanaTooManySeeds();
}
bytes memory result;
for (uint idx; idx < numSeeds;) {
uint seedLen = _seeds[idx].length;
if (seedLen > SolanaMaxSeedLen) {
revert SolanaSeedTooLong();
}
result = abi.encodePacked(
result,
abi.encodePacked(
uint32(seedLen),
_seeds[idx]
)
);
unchecked { ++idx; }
}
return (result, uint8(numSeeds));
}
//
// Query Response stuff
//
/// @dev buildQueryResponseBytes builds a query response from the specified fields.
function buildQueryResponseBytes(
uint8 _version,
uint16 _senderChainId,
bytes memory _signature,
bytes memory _queryRequest,
uint8 _numPerChainResponses,
bytes memory _perChainResponses
) internal pure returns (bytes memory){
return abi.encodePacked(
_version,
_senderChainId,
_signature,
uint32(_queryRequest.length),
_queryRequest,
_numPerChainResponses,
_perChainResponses // Each created by buildPerChainResponseBytes()
);
}
/// @dev buildPerChainResponseBytes builds a per chain response from the specified fields.
function buildPerChainResponseBytes(
uint16 _chainId,
uint8 _queryType,
bytes memory _responseBytes
) internal pure returns (bytes memory){
return abi.encodePacked(
_chainId,
_queryType,
uint32(_responseBytes.length),
_responseBytes
);
}
/// @dev buildEthCallResponseBytes builds an eth_call response from the specified fields.
function buildEthCallResponseBytes(
uint64 _blockNumber,
bytes32 _blockHash,
uint64 _blockTimeUs,
uint8 _numResults,
bytes memory _results // Created with buildEthCallResultBytes()
) internal pure returns (bytes memory){
return abi.encodePacked(
_blockNumber,
_blockHash,
_blockTimeUs,
_numResults,
_results
);
}
/// @dev buildEthCallByTimestampResponseBytes builds an eth_call_by_timestamp response from the specified fields.
function buildEthCallByTimestampResponseBytes(
uint64 _targetBlockNumber,
bytes32 _targetBlockHash,
uint64 _targetBlockTimeUs,
uint64 _followingBlockNumber,
bytes32 _followingBlockHash,
uint64 _followingBlockTimeUs,
uint8 _numResults,
bytes memory _results // Created with buildEthCallResultBytes()
) internal pure returns (bytes memory){
return abi.encodePacked(
_targetBlockNumber,
_targetBlockHash,
_targetBlockTimeUs,
_followingBlockNumber,
_followingBlockHash,
_followingBlockTimeUs,
_numResults,
_results
);
}
/// @dev buildEthCallWithFinalityResponseBytes builds an eth_call_with_finality response from the specified fields. Note that it is currently the same as buildEthCallResponseBytes.
function buildEthCallWithFinalityResponseBytes(
uint64 _blockNumber,
bytes32 _blockHash,
uint64 _blockTimeUs,
uint8 _numResults,
bytes memory _results // Created with buildEthCallResultBytes()
) internal pure returns (bytes memory){
return abi.encodePacked(
_blockNumber,
_blockHash,
_blockTimeUs,
_numResults,
_results
);
}
/// @dev buildEthCallResultBytes builds an eth_call result from the specified fields.
function buildEthCallResultBytes(
bytes memory _result
) internal pure returns (bytes memory){
return abi.encodePacked(
uint32(_result.length),
_result
);
}
/// @dev buildSolanaAccountResponseBytes builds a sol_account response from the specified fields.
function buildSolanaAccountResponseBytes(
uint64 _slotNumber,
uint64 _blockTimeUs,
bytes32 _blockHash,
uint8 _numResults,
bytes memory _results // Created with buildEthCallResultBytes()
) internal pure returns (bytes memory){
return abi.encodePacked(
_slotNumber,
_blockTimeUs,
_blockHash,
_numResults,
_results
);
}
/// @dev buildSolanaPdaResponseBytes builds a sol_pda response from the specified fields.
function buildSolanaPdaResponseBytes(
uint64 _slotNumber,
uint64 _blockTimeUs,
bytes32 _blockHash,
uint8 _numResults,
bytes memory _results // Created with buildEthCallResultBytes()
) internal pure returns (bytes memory){
return abi.encodePacked(
_slotNumber,
_blockTimeUs,
_blockHash,
_numResults,
_results
);
}
}