@callcium/sdk 0.12.0 → 0.13.0
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/README.md +2 -2
- package/dist/index.d.ts +659 -611
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2285 -2071
- package/dist/index.js.map +1 -1
- package/package.json +13 -10
- package/src/bytes.ts +1 -0
- package/src/calldata-reader.ts +3 -3
- package/src/constants.ts +156 -86
- package/src/constraint.ts +34 -24
- package/src/descriptor-coder.ts +126 -103
- package/src/descriptor.ts +79 -288
- package/src/errors.ts +30 -19
- package/src/hint.ts +237 -0
- package/src/index.ts +29 -10
- package/src/operators.ts +168 -267
- package/src/path.ts +7 -31
- package/src/policy-builder.ts +201 -181
- package/src/policy-coder.ts +1156 -523
- package/src/policy-enforcer.ts +499 -486
- package/src/policy-validator.ts +557 -1046
- package/src/signature.ts +7 -11
- package/src/type-desc.ts +6 -6
- package/src/types.ts +230 -129
- package/src/validation-issue.ts +78 -465
package/src/validation-issue.ts
CHANGED
|
@@ -1,70 +1,58 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { bigintToHex } from "./bytes";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
// Constants
|
|
5
|
-
///////////////////////////////////////////////////////////////////////////
|
|
3
|
+
import type { Hex, Issue, IssueCode, RuleLocation } from "./types";
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
/** The zero word. */
|
|
6
|
+
const ZERO = bigintToHex(0n);
|
|
8
7
|
|
|
9
8
|
///////////////////////////////////////////////////////////////////////////
|
|
10
9
|
// Type mismatch
|
|
11
10
|
///////////////////////////////////////////////////////////////////////////
|
|
12
11
|
|
|
13
|
-
/**
|
|
14
|
-
export function
|
|
15
|
-
code: IssueCode,
|
|
16
|
-
message: string,
|
|
17
|
-
groupIndex: number,
|
|
18
|
-
constraintIndex: number,
|
|
19
|
-
opCode: Hex,
|
|
20
|
-
): Issue {
|
|
12
|
+
/** Issue for a descriptor whose composite node at `offset` disagrees with its children. */
|
|
13
|
+
export function invalidDescriptor(offset: number): Issue {
|
|
21
14
|
return {
|
|
22
15
|
severity: "error",
|
|
23
16
|
category: "typeMismatch",
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
code,
|
|
27
|
-
value1: opCode,
|
|
17
|
+
code: "INVALID_DESCRIPTOR",
|
|
18
|
+
value1: bigintToHex(BigInt(offset)),
|
|
28
19
|
value2: ZERO,
|
|
29
|
-
message,
|
|
20
|
+
message: "Descriptor node metadata disagrees with its children",
|
|
30
21
|
};
|
|
31
22
|
}
|
|
32
23
|
|
|
33
|
-
/** Issue for a
|
|
34
|
-
export function unnavigablePath(
|
|
24
|
+
/** Issue for a path whose step at `stepIndex` breaks `bound`: a parameter, field or element count, or a type code. */
|
|
25
|
+
export function unnavigablePath(location: RuleLocation, stepIndex: number, bound: number): Issue {
|
|
35
26
|
return {
|
|
27
|
+
...location,
|
|
36
28
|
severity: "error",
|
|
37
29
|
category: "typeMismatch",
|
|
38
|
-
groupIndex,
|
|
39
|
-
constraintIndex,
|
|
40
30
|
code: "UNNAVIGABLE_PATH",
|
|
41
|
-
value1:
|
|
42
|
-
value2:
|
|
31
|
+
value1: bigintToHex(BigInt(stepIndex)),
|
|
32
|
+
value2: bigintToHex(BigInt(bound)),
|
|
43
33
|
message: "Path does not navigate the descriptor",
|
|
44
34
|
};
|
|
45
35
|
}
|
|
46
36
|
|
|
47
|
-
/**
|
|
48
|
-
export function
|
|
37
|
+
/** Issue for a loop whose array path ends at a node of `typeCode`, which is not an array. */
|
|
38
|
+
export function quantifierOnNonArray(location: RuleLocation, typeCode: number): Issue {
|
|
49
39
|
return {
|
|
40
|
+
...location,
|
|
50
41
|
severity: "error",
|
|
51
42
|
category: "typeMismatch",
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
code: "NESTED_QUANTIFIER",
|
|
55
|
-
value1: ZERO,
|
|
43
|
+
code: "QUANTIFIER_ON_NON_ARRAY",
|
|
44
|
+
value1: bigintToHex(BigInt(typeCode)),
|
|
56
45
|
value2: ZERO,
|
|
57
|
-
message: "
|
|
46
|
+
message: "Loop path does not end at an array",
|
|
58
47
|
};
|
|
59
48
|
}
|
|
60
49
|
|
|
61
|
-
/** Issue for a hint
|
|
62
|
-
export function hintMismatch(
|
|
50
|
+
/** Issue for a hint other than the compilation of its path. */
|
|
51
|
+
export function hintMismatch(location: RuleLocation): Issue {
|
|
63
52
|
return {
|
|
53
|
+
...location,
|
|
64
54
|
severity: "error",
|
|
65
55
|
category: "typeMismatch",
|
|
66
|
-
groupIndex,
|
|
67
|
-
constraintIndex,
|
|
68
56
|
code: "HINT_MISMATCH",
|
|
69
57
|
value1: ZERO,
|
|
70
58
|
value2: ZERO,
|
|
@@ -72,31 +60,29 @@ export function hintMismatch(groupIndex: number, constraintIndex: number): Issue
|
|
|
72
60
|
};
|
|
73
61
|
}
|
|
74
62
|
|
|
75
|
-
/** Issue for
|
|
76
|
-
export function
|
|
63
|
+
/** Issue for an operator the compatibility matrix does not admit on its target type. */
|
|
64
|
+
export function fromOpRule(code: IssueCode, message: string, location: RuleLocation, opCode: number): Issue {
|
|
77
65
|
return {
|
|
66
|
+
...location,
|
|
78
67
|
severity: "error",
|
|
79
68
|
category: "typeMismatch",
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
value2: typeCode,
|
|
85
|
-
message: "Context property type does not match the target type",
|
|
69
|
+
code,
|
|
70
|
+
value1: bigintToHex(BigInt(opCode)),
|
|
71
|
+
value2: ZERO,
|
|
72
|
+
message,
|
|
86
73
|
};
|
|
87
74
|
}
|
|
88
75
|
|
|
89
|
-
/** Issue for
|
|
90
|
-
export function
|
|
76
|
+
/** Issue for a context operand whose property type does not pair with the target type. */
|
|
77
|
+
export function contextTypeMismatch(location: RuleLocation, contextPropertyId: number, typeCode: number): Issue {
|
|
91
78
|
return {
|
|
79
|
+
...location,
|
|
92
80
|
severity: "error",
|
|
93
81
|
category: "typeMismatch",
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
value2: canonical,
|
|
99
|
-
message: "Operand is not the canonical encoding for the declared type",
|
|
82
|
+
code: "CONTEXT_TYPE_MISMATCH",
|
|
83
|
+
value1: bigintToHex(BigInt(contextPropertyId)),
|
|
84
|
+
value2: bigintToHex(BigInt(typeCode)),
|
|
85
|
+
message: "Context property type does not match the target type",
|
|
100
86
|
};
|
|
101
87
|
}
|
|
102
88
|
|
|
@@ -104,221 +90,29 @@ export function nonCanonicalOperand(groupIndex: number, constraintIndex: number,
|
|
|
104
90
|
// Contradiction
|
|
105
91
|
///////////////////////////////////////////////////////////////////////////
|
|
106
92
|
|
|
107
|
-
/**
|
|
108
|
-
export function
|
|
109
|
-
return {
|
|
110
|
-
severity: "error",
|
|
111
|
-
category: "contradiction",
|
|
112
|
-
groupIndex,
|
|
113
|
-
constraintIndex,
|
|
114
|
-
code: isLength ? "LENGTH_EQ_NEQ_CONTRADICTION" : "EQ_NEQ_CONTRADICTION",
|
|
115
|
-
value1: value,
|
|
116
|
-
value2: ZERO,
|
|
117
|
-
message: isLength ? "lengthEq(v) and lengthNeq(v) on same path" : "eq(v) and neq(v) on same path",
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/** Multiple eq()/lengthEq() operators with different values. */
|
|
122
|
-
export function conflictingEquality(
|
|
123
|
-
isLength: boolean,
|
|
124
|
-
groupIndex: number,
|
|
125
|
-
constraintIndex: number,
|
|
126
|
-
existing: Hex,
|
|
127
|
-
newValue: Hex,
|
|
128
|
-
): Issue {
|
|
129
|
-
return {
|
|
130
|
-
severity: "error",
|
|
131
|
-
category: "contradiction",
|
|
132
|
-
groupIndex,
|
|
133
|
-
constraintIndex,
|
|
134
|
-
code: isLength ? "CONFLICTING_LENGTH" : "CONFLICTING_EQUALITY",
|
|
135
|
-
value1: existing,
|
|
136
|
-
value2: newValue,
|
|
137
|
-
message: isLength
|
|
138
|
-
? "Multiple lengthEq() operators with different values"
|
|
139
|
-
: "Multiple eq() operators with different values",
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/** Value/length is outside the physical range of its type. */
|
|
144
|
-
export function outOfPhysicalBounds(isLength: boolean, groupIndex: number, constraintIndex: number, value: Hex): Issue {
|
|
145
|
-
return {
|
|
146
|
-
severity: "error",
|
|
147
|
-
category: "contradiction",
|
|
148
|
-
groupIndex,
|
|
149
|
-
constraintIndex,
|
|
150
|
-
code: isLength ? "OUT_OF_PHYSICAL_LENGTH_BOUNDS" : "OUT_OF_PHYSICAL_BOUNDS",
|
|
151
|
-
value1: value,
|
|
152
|
-
value2: ZERO,
|
|
153
|
-
message: isLength
|
|
154
|
-
? "Length value is outside the physical range"
|
|
155
|
-
: "Value is outside the physical range of the type",
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/** gt()/lengthGt() on the maximum is impossible. */
|
|
160
|
-
export function impossibleGt(isLength: boolean, groupIndex: number, constraintIndex: number, value: Hex): Issue {
|
|
161
|
-
return {
|
|
162
|
-
severity: "error",
|
|
163
|
-
category: "contradiction",
|
|
164
|
-
groupIndex,
|
|
165
|
-
constraintIndex,
|
|
166
|
-
code: isLength ? "IMPOSSIBLE_LENGTH_GT" : "IMPOSSIBLE_GT",
|
|
167
|
-
value1: value,
|
|
168
|
-
value2: ZERO,
|
|
169
|
-
message: isLength ? "lengthGt() on maximum length is impossible" : "gt() on type maximum is impossible",
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/** lt()/lengthLt() on the minimum is impossible. */
|
|
174
|
-
export function impossibleLt(isLength: boolean, groupIndex: number, constraintIndex: number, value: Hex): Issue {
|
|
175
|
-
return {
|
|
176
|
-
severity: "error",
|
|
177
|
-
category: "contradiction",
|
|
178
|
-
groupIndex,
|
|
179
|
-
constraintIndex,
|
|
180
|
-
code: isLength ? "IMPOSSIBLE_LENGTH_LT" : "IMPOSSIBLE_LT",
|
|
181
|
-
value1: value,
|
|
182
|
-
value2: ZERO,
|
|
183
|
-
message: isLength ? "lengthLt() on minimum length is impossible" : "lt() on type minimum is impossible",
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/** eq()/lengthEq() value is excluded by a bound. */
|
|
188
|
-
export function boundsExcludeEquality(
|
|
189
|
-
isLength: boolean,
|
|
190
|
-
groupIndex: number,
|
|
191
|
-
constraintIndex: number,
|
|
192
|
-
eq: Hex,
|
|
193
|
-
bound: Hex,
|
|
194
|
-
): Issue {
|
|
195
|
-
return {
|
|
196
|
-
severity: "error",
|
|
197
|
-
category: "contradiction",
|
|
198
|
-
groupIndex,
|
|
199
|
-
constraintIndex,
|
|
200
|
-
code: isLength ? "BOUNDS_EXCLUDE_LENGTH" : "BOUNDS_EXCLUDE_EQUALITY",
|
|
201
|
-
value1: eq,
|
|
202
|
-
value2: bound,
|
|
203
|
-
message: isLength ? "lengthEq() value is excluded by bound" : "eq() value is excluded by bound",
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/** Lower bound/length exceeds the upper bound. */
|
|
208
|
-
export function impossibleRange(
|
|
209
|
-
isLength: boolean,
|
|
210
|
-
groupIndex: number,
|
|
211
|
-
constraintIndex: number,
|
|
212
|
-
lower: Hex,
|
|
213
|
-
upper: Hex,
|
|
214
|
-
): Issue {
|
|
215
|
-
return {
|
|
216
|
-
severity: "error",
|
|
217
|
-
category: "contradiction",
|
|
218
|
-
groupIndex,
|
|
219
|
-
constraintIndex,
|
|
220
|
-
code: isLength ? "IMPOSSIBLE_LENGTH_RANGE" : "IMPOSSIBLE_RANGE",
|
|
221
|
-
value1: lower,
|
|
222
|
-
value2: upper,
|
|
223
|
-
message: isLength ? "Lower length bound exceeds upper bound" : "Lower bound exceeds upper bound",
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/** Set operation excludes existing eq() value. */
|
|
228
|
-
export function setExcludesEquality(groupIndex: number, constraintIndex: number, value: Hex): Issue {
|
|
93
|
+
/** Issue for a constant outside its type's values. */
|
|
94
|
+
export function outOfPhysicalBounds(location: RuleLocation, value: Hex): Issue {
|
|
229
95
|
return {
|
|
96
|
+
...location,
|
|
230
97
|
severity: "error",
|
|
231
98
|
category: "contradiction",
|
|
232
|
-
|
|
233
|
-
constraintIndex,
|
|
234
|
-
code: "SET_EXCLUDES_EQUALITY",
|
|
99
|
+
code: "OUT_OF_PHYSICAL_BOUNDS",
|
|
235
100
|
value1: value,
|
|
236
101
|
value2: ZERO,
|
|
237
|
-
message: "
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/** Multiple isIn() sets have no intersection. */
|
|
242
|
-
export function emptySetIntersection(groupIndex: number, constraintIndex: number): Issue {
|
|
243
|
-
return {
|
|
244
|
-
severity: "error",
|
|
245
|
-
category: "contradiction",
|
|
246
|
-
groupIndex,
|
|
247
|
-
constraintIndex,
|
|
248
|
-
code: "EMPTY_SET_INTERSECTION",
|
|
249
|
-
value1: ZERO,
|
|
250
|
-
value2: ZERO,
|
|
251
|
-
message: "Multiple isIn() sets have no intersection",
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/** All values in isIn() set are excluded by neq/notIn. */
|
|
256
|
-
export function setFullyExcluded(groupIndex: number, constraintIndex: number): Issue {
|
|
257
|
-
return {
|
|
258
|
-
severity: "error",
|
|
259
|
-
category: "contradiction",
|
|
260
|
-
groupIndex,
|
|
261
|
-
constraintIndex,
|
|
262
|
-
code: "SET_FULLY_EXCLUDED",
|
|
263
|
-
value1: ZERO,
|
|
264
|
-
value2: ZERO,
|
|
265
|
-
message: "All values in isIn() set are excluded by neq/notIn",
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/** Bitmask operators conflict. */
|
|
270
|
-
export function bitmaskContradiction(groupIndex: number, constraintIndex: number, mask: Hex, conflicting: Hex): Issue {
|
|
271
|
-
return {
|
|
272
|
-
severity: "error",
|
|
273
|
-
category: "contradiction",
|
|
274
|
-
groupIndex,
|
|
275
|
-
constraintIndex,
|
|
276
|
-
code: "BITMASK_CONTRADICTION",
|
|
277
|
-
value1: mask,
|
|
278
|
-
value2: conflicting,
|
|
279
|
-
message: "Bitmask operators conflict",
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/** bitmaskAny is impossible because all bits are forbidden. */
|
|
284
|
-
export function bitmaskAnyImpossible(groupIndex: number, constraintIndex: number, mask: Hex, mustBeZero: Hex): Issue {
|
|
285
|
-
return {
|
|
286
|
-
severity: "error",
|
|
287
|
-
category: "contradiction",
|
|
288
|
-
groupIndex,
|
|
289
|
-
constraintIndex,
|
|
290
|
-
code: "BITMASK_ANY_IMPOSSIBLE",
|
|
291
|
-
value1: mask,
|
|
292
|
-
value2: mustBeZero,
|
|
293
|
-
message: "bitmaskAny is impossible because all bits are forbidden",
|
|
102
|
+
message: "Value is outside the physical range of the type",
|
|
294
103
|
};
|
|
295
104
|
}
|
|
296
105
|
|
|
297
|
-
/**
|
|
298
|
-
export function
|
|
106
|
+
/** Issue for the rule at which the rules on its subject, in order, stop being satisfiable together. */
|
|
107
|
+
export function contradictoryRule(location: RuleLocation): Issue {
|
|
299
108
|
return {
|
|
109
|
+
...location,
|
|
300
110
|
severity: "error",
|
|
301
111
|
category: "contradiction",
|
|
302
|
-
|
|
303
|
-
constraintIndex,
|
|
304
|
-
code: "UNSORTED_IN_SET",
|
|
112
|
+
code: "CONTRADICTORY_RULE",
|
|
305
113
|
value1: ZERO,
|
|
306
114
|
value2: ZERO,
|
|
307
|
-
message: "
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/** Group contains zero constraints. */
|
|
312
|
-
export function emptyGroup(groupIndex: number): Issue {
|
|
313
|
-
return {
|
|
314
|
-
severity: "error",
|
|
315
|
-
category: "vacuity",
|
|
316
|
-
groupIndex,
|
|
317
|
-
constraintIndex: 0,
|
|
318
|
-
code: "EMPTY_GROUP",
|
|
319
|
-
value1: ZERO,
|
|
320
|
-
value2: ZERO,
|
|
321
|
-
message: "Group contains zero constraints",
|
|
115
|
+
message: "Rules on the subject are not satisfiable together",
|
|
322
116
|
};
|
|
323
117
|
}
|
|
324
118
|
|
|
@@ -326,133 +120,31 @@ export function emptyGroup(groupIndex: number): Issue {
|
|
|
326
120
|
// Redundancy
|
|
327
121
|
///////////////////////////////////////////////////////////////////////////
|
|
328
122
|
|
|
329
|
-
/**
|
|
330
|
-
export function
|
|
123
|
+
/** Issue for a rule the other rules on its subject imply. */
|
|
124
|
+
export function redundantRule(location: RuleLocation): Issue {
|
|
331
125
|
return {
|
|
126
|
+
...location,
|
|
332
127
|
severity: "warning",
|
|
333
128
|
category: "redundancy",
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
code: isLength ? "DOMINATED_LENGTH_BOUND" : "DOMINATED_BOUND",
|
|
337
|
-
value1: value,
|
|
129
|
+
code: "REDUNDANT_RULE",
|
|
130
|
+
value1: ZERO,
|
|
338
131
|
value2: ZERO,
|
|
339
|
-
message:
|
|
340
|
-
? "Length bound is dominated by a stricter bound"
|
|
341
|
-
: "Numeric bound is dominated by a stricter bound",
|
|
132
|
+
message: "Rule is implied by the other rules on its subject",
|
|
342
133
|
};
|
|
343
134
|
}
|
|
344
135
|
|
|
345
|
-
/**
|
|
346
|
-
export function
|
|
347
|
-
isLength: boolean,
|
|
348
|
-
groupIndex: number,
|
|
349
|
-
constraintIndex: number,
|
|
350
|
-
bound: Hex,
|
|
351
|
-
eq: Hex,
|
|
352
|
-
): Issue {
|
|
136
|
+
/** Issue for a bound looser than `tightest`, the tightest bound on its side of the subject. */
|
|
137
|
+
export function dominatedBound(isLength: boolean, location: RuleLocation, bound: Hex, tightest: Hex): Issue {
|
|
353
138
|
return {
|
|
139
|
+
...location,
|
|
354
140
|
severity: "warning",
|
|
355
141
|
category: "redundancy",
|
|
356
|
-
|
|
357
|
-
constraintIndex,
|
|
358
|
-
code: isLength ? "REDUNDANT_LENGTH_BOUND" : "REDUNDANT_BOUND",
|
|
142
|
+
code: isLength ? "DOMINATED_LENGTH_BOUND" : "DOMINATED_BOUND",
|
|
359
143
|
value1: bound,
|
|
360
|
-
value2:
|
|
144
|
+
value2: tightest,
|
|
361
145
|
message: isLength
|
|
362
|
-
? "Length bound is
|
|
363
|
-
: "
|
|
364
|
-
};
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
/** notIn() value was present in isIn() set. */
|
|
368
|
-
export function setReduction(groupIndex: number, constraintIndex: number, value: Hex): Issue {
|
|
369
|
-
return {
|
|
370
|
-
severity: "warning",
|
|
371
|
-
category: "redundancy",
|
|
372
|
-
groupIndex,
|
|
373
|
-
constraintIndex,
|
|
374
|
-
code: "SET_REDUCTION",
|
|
375
|
-
value1: value,
|
|
376
|
-
value2: ZERO,
|
|
377
|
-
message: "notIn() value was present in isIn() set",
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/** isIn() sets partially overlap. */
|
|
382
|
-
export function setRedundancy(groupIndex: number, constraintIndex: number, intersectionCount: Hex): Issue {
|
|
383
|
-
return {
|
|
384
|
-
severity: "warning",
|
|
385
|
-
category: "redundancy",
|
|
386
|
-
groupIndex,
|
|
387
|
-
constraintIndex,
|
|
388
|
-
code: "SET_REDUNDANCY",
|
|
389
|
-
value1: intersectionCount,
|
|
390
|
-
value2: ZERO,
|
|
391
|
-
message: "isIn() sets partially overlap",
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
/** Some values in isIn() set are excluded by neq/notIn. */
|
|
396
|
-
export function setPartiallyExcluded(groupIndex: number, constraintIndex: number, excludedCount: Hex): Issue {
|
|
397
|
-
return {
|
|
398
|
-
severity: "warning",
|
|
399
|
-
category: "redundancy",
|
|
400
|
-
groupIndex,
|
|
401
|
-
constraintIndex,
|
|
402
|
-
code: "SET_PARTIALLY_EXCLUDED",
|
|
403
|
-
value1: excludedCount,
|
|
404
|
-
value2: ZERO,
|
|
405
|
-
message: "Some values in isIn() set are excluded by neq/notIn",
|
|
406
|
-
};
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
/** Bitmask operation is redundant. */
|
|
410
|
-
export function redundantBitmask(groupIndex: number, constraintIndex: number, mask: Hex, existing: Hex): Issue {
|
|
411
|
-
return {
|
|
412
|
-
severity: "warning",
|
|
413
|
-
category: "redundancy",
|
|
414
|
-
groupIndex,
|
|
415
|
-
constraintIndex,
|
|
416
|
-
code: "REDUNDANT_BITMASK",
|
|
417
|
-
value1: mask,
|
|
418
|
-
value2: existing,
|
|
419
|
-
message: "Bitmask operation is redundant",
|
|
420
|
-
};
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
/** gte/lte pair fusible into a single range operator. */
|
|
424
|
-
export function fusibleRange(
|
|
425
|
-
isLength: boolean,
|
|
426
|
-
groupIndex: number,
|
|
427
|
-
constraintIndex: number,
|
|
428
|
-
low: Hex,
|
|
429
|
-
high: Hex,
|
|
430
|
-
): Issue {
|
|
431
|
-
return {
|
|
432
|
-
severity: "warning",
|
|
433
|
-
category: "redundancy",
|
|
434
|
-
groupIndex,
|
|
435
|
-
constraintIndex,
|
|
436
|
-
code: isLength ? "FUSIBLE_LENGTH_RANGE" : "FUSIBLE_RANGE",
|
|
437
|
-
value1: low,
|
|
438
|
-
value2: high,
|
|
439
|
-
message: isLength
|
|
440
|
-
? "lengthGte() and lengthLte() fuse into a single lengthBetween()"
|
|
441
|
-
: "gte() and lte() fuse into a single between()",
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
/** Duplicate operator in constraint. */
|
|
446
|
-
export function duplicateConstraint(groupIndex: number, constraintIndex: number): Issue {
|
|
447
|
-
return {
|
|
448
|
-
severity: "warning",
|
|
449
|
-
category: "redundancy",
|
|
450
|
-
groupIndex,
|
|
451
|
-
constraintIndex,
|
|
452
|
-
code: "DUPLICATE_CONSTRAINT",
|
|
453
|
-
value1: ZERO,
|
|
454
|
-
value2: ZERO,
|
|
455
|
-
message: "Duplicate operator in constraint",
|
|
146
|
+
? "Length bound is dominated by a stricter bound"
|
|
147
|
+
: "Numeric bound is dominated by a stricter bound",
|
|
456
148
|
};
|
|
457
149
|
}
|
|
458
150
|
|
|
@@ -460,55 +152,16 @@ export function duplicateConstraint(groupIndex: number, constraintIndex: number)
|
|
|
460
152
|
// Vacuity
|
|
461
153
|
///////////////////////////////////////////////////////////////////////////
|
|
462
154
|
|
|
463
|
-
/**
|
|
464
|
-
export function
|
|
155
|
+
/** Issue for a rule that holds for every value and every context. */
|
|
156
|
+
export function vacuousRule(location: RuleLocation): Issue {
|
|
465
157
|
return {
|
|
158
|
+
...location,
|
|
466
159
|
severity: "info",
|
|
467
160
|
category: "vacuity",
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
code: isLength ? "VACUOUS_LENGTH_GTE" : "VACUOUS_GTE",
|
|
471
|
-
value1: value,
|
|
472
|
-
value2: ZERO,
|
|
473
|
-
message: isLength ? "lengthGte(0) is always true" : "gte() bound equals type minimum (always true)",
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
/** lte(max)/lengthLte(max) is always true. */
|
|
478
|
-
export function vacuousLte(isLength: boolean, groupIndex: number, constraintIndex: number, value: Hex): Issue {
|
|
479
|
-
return {
|
|
480
|
-
severity: "info",
|
|
481
|
-
category: "vacuity",
|
|
482
|
-
groupIndex,
|
|
483
|
-
constraintIndex,
|
|
484
|
-
code: isLength ? "VACUOUS_LENGTH_LTE" : "VACUOUS_LTE",
|
|
485
|
-
value1: value,
|
|
161
|
+
code: "VACUOUS_RULE",
|
|
162
|
+
value1: ZERO,
|
|
486
163
|
value2: ZERO,
|
|
487
|
-
message:
|
|
488
|
-
? "lengthLte() bound equals maximum (always true)"
|
|
489
|
-
: "lte() bound equals type maximum (always true)",
|
|
490
|
-
};
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
/** Negated range with inverted bounds excludes nothing (always true). */
|
|
494
|
-
export function vacuousNegatedRange(
|
|
495
|
-
isLength: boolean,
|
|
496
|
-
groupIndex: number,
|
|
497
|
-
constraintIndex: number,
|
|
498
|
-
low: Hex,
|
|
499
|
-
high: Hex,
|
|
500
|
-
): Issue {
|
|
501
|
-
return {
|
|
502
|
-
severity: "info",
|
|
503
|
-
category: "vacuity",
|
|
504
|
-
groupIndex,
|
|
505
|
-
constraintIndex,
|
|
506
|
-
code: isLength ? "VACUOUS_NEGATED_LENGTH_RANGE" : "VACUOUS_NEGATED_RANGE",
|
|
507
|
-
value1: low,
|
|
508
|
-
value2: high,
|
|
509
|
-
message: isLength
|
|
510
|
-
? "Negated lengthBetween() with low > high excludes nothing (always true)"
|
|
511
|
-
: "Negated between() with low > high excludes nothing (always true)",
|
|
164
|
+
message: "Rule holds for every value",
|
|
512
165
|
};
|
|
513
166
|
}
|
|
514
167
|
|
|
@@ -516,68 +169,28 @@ export function vacuousNegatedRange(
|
|
|
516
169
|
// Compatibility
|
|
517
170
|
///////////////////////////////////////////////////////////////////////////
|
|
518
171
|
|
|
519
|
-
/**
|
|
520
|
-
export function
|
|
521
|
-
return {
|
|
522
|
-
severity: "warning",
|
|
523
|
-
category: "compatibility",
|
|
524
|
-
groupIndex,
|
|
525
|
-
constraintIndex,
|
|
526
|
-
code: "PATH_DEPTH_EXCEEDED",
|
|
527
|
-
value1: depth,
|
|
528
|
-
value2: maxDepth,
|
|
529
|
-
message: "Path depth exceeds the maximum a well-formed policy may declare",
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
/** Quantifier over a static array beyond the iteration cap PV-7 fixes. */
|
|
534
|
-
export function quantifierOverStaticLimit(
|
|
535
|
-
groupIndex: number,
|
|
536
|
-
constraintIndex: number,
|
|
537
|
-
arrayLength: Hex,
|
|
538
|
-
maxLength: Hex,
|
|
539
|
-
): Issue {
|
|
172
|
+
/** Issue for a loop over a static array declared longer than `maxLength`. */
|
|
173
|
+
export function quantifierOverStaticLimit(location: RuleLocation, arrayLength: number, maxLength: number): Issue {
|
|
540
174
|
return {
|
|
175
|
+
...location,
|
|
541
176
|
severity: "error",
|
|
542
177
|
category: "compatibility",
|
|
543
|
-
groupIndex,
|
|
544
|
-
constraintIndex,
|
|
545
178
|
code: "QUANTIFIER_OVER_STATIC_LIMIT",
|
|
546
|
-
value1: arrayLength,
|
|
547
|
-
value2: maxLength,
|
|
179
|
+
value1: bigintToHex(BigInt(arrayLength)),
|
|
180
|
+
value2: bigintToHex(BigInt(maxLength)),
|
|
548
181
|
message: "Quantifier over static array exceeds the maximum quantified length",
|
|
549
182
|
};
|
|
550
183
|
}
|
|
551
184
|
|
|
552
|
-
/**
|
|
553
|
-
export function
|
|
554
|
-
groupIndex: number,
|
|
555
|
-
constraintIndex: number,
|
|
556
|
-
contextId: Hex,
|
|
557
|
-
maxContextId: Hex,
|
|
558
|
-
): Issue {
|
|
185
|
+
/** Issue for a loop body that contains no test of the element. */
|
|
186
|
+
export function contextOnlyBody(location: RuleLocation): Issue {
|
|
559
187
|
return {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
groupIndex,
|
|
563
|
-
constraintIndex,
|
|
564
|
-
code: "UNKNOWN_CONTEXT_PROPERTY",
|
|
565
|
-
value1: contextId,
|
|
566
|
-
value2: maxContextId,
|
|
567
|
-
message: "Unknown context property ID",
|
|
568
|
-
};
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
/** Negated operator under the existential quantifier. */
|
|
572
|
-
export function negationUnderAny(groupIndex: number, constraintIndex: number, opCode: Hex): Issue {
|
|
573
|
-
return {
|
|
574
|
-
severity: "warning",
|
|
188
|
+
...location,
|
|
189
|
+
severity: "error",
|
|
575
190
|
category: "compatibility",
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
code: "NEGATION_UNDER_ANY",
|
|
579
|
-
value1: opCode,
|
|
191
|
+
code: "CONTEXT_ONLY_BODY",
|
|
192
|
+
value1: ZERO,
|
|
580
193
|
value2: ZERO,
|
|
581
|
-
message: "
|
|
194
|
+
message: "Loop body holds no test of the element",
|
|
582
195
|
};
|
|
583
196
|
}
|