@openzeppelin/upgrades-core 1.13.1 → 1.14.2

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.
Files changed (48) hide show
  1. package/dist/proxy-kind.d.ts +4 -0
  2. package/dist/proxy-kind.d.ts.map +1 -1
  3. package/dist/proxy-kind.js +4 -0
  4. package/dist/proxy-kind.js.map +1 -1
  5. package/dist/standalone.test.js +9 -0
  6. package/dist/standalone.test.js.map +1 -1
  7. package/dist/storage/compare.d.ts +15 -4
  8. package/dist/storage/compare.d.ts.map +1 -1
  9. package/dist/storage/compare.js +49 -4
  10. package/dist/storage/compare.js.map +1 -1
  11. package/dist/storage/extract.d.ts.map +1 -1
  12. package/dist/storage/extract.js +27 -3
  13. package/dist/storage/extract.js.map +1 -1
  14. package/dist/storage/layout.d.ts +14 -0
  15. package/dist/storage/layout.d.ts.map +1 -1
  16. package/dist/storage/layout.js +6 -2
  17. package/dist/storage/layout.js.map +1 -1
  18. package/dist/storage/report-rename-retype.test.d.ts +2 -0
  19. package/dist/storage/report-rename-retype.test.d.ts.map +1 -0
  20. package/dist/storage/report-rename-retype.test.js +93 -0
  21. package/dist/storage/report-rename-retype.test.js.map +1 -0
  22. package/dist/storage/report.d.ts.map +1 -1
  23. package/dist/storage/report.js +32 -2
  24. package/dist/storage/report.js.map +1 -1
  25. package/dist/storage/report.test.js +6 -0
  26. package/dist/storage/report.test.js.map +1 -1
  27. package/dist/storage.test.js +1 -1
  28. package/dist/utils/execall.d.ts +2 -0
  29. package/dist/utils/execall.d.ts.map +1 -0
  30. package/dist/utils/execall.js +17 -0
  31. package/dist/utils/execall.js.map +1 -0
  32. package/package.json +2 -2
  33. package/src/proxy-kind.ts +4 -0
  34. package/src/standalone.test.ts +12 -0
  35. package/src/storage/compare.ts +61 -8
  36. package/src/storage/extract.ts +31 -5
  37. package/src/storage/layout.ts +17 -2
  38. package/src/storage/report-rename-retype.test.ts +106 -0
  39. package/src/storage/report-rename-retype.test.ts.md +44 -0
  40. package/src/storage/report-rename-retype.test.ts.snap +0 -0
  41. package/src/storage/report.test.ts +7 -0
  42. package/src/storage/report.test.ts.md +11 -0
  43. package/src/storage/report.test.ts.snap +0 -0
  44. package/src/storage/report.ts +39 -4
  45. package/src/storage.test.ts +1 -1
  46. package/src/storage.test.ts.md +146 -0
  47. package/src/storage.test.ts.snap +0 -0
  48. package/src/utils/execall.ts +11 -0
@@ -59,6 +59,13 @@ test('obvious mismatch', t => {
59
59
  t.snapshot(report.explain());
60
60
  });
61
61
 
62
+ test('function visibility change', t => {
63
+ const v1 = t.context.extractStorageLayout('StorageUpgrade_FunctionType_Visibility_V1');
64
+ const v2 = t.context.extractStorageLayout('StorageUpgrade_FunctionType_Visibility_V2_Bad');
65
+ const report = getReport(v1, v2);
66
+ t.snapshot(report.explain());
67
+ });
68
+
62
69
  test('array', t => {
63
70
  const v1 = t.context.extractStorageLayout('StorageUpgrade_Array_V1');
64
71
  const v2 = t.context.extractStorageLayout('StorageUpgrade_Array_V2_Bad');
@@ -90,6 +90,17 @@ Generated by [AVA](https://avajs.dev).
90
90
  file.sol:1: Upgraded \`a1\` to an incompatible type␊
91
91
  - Bad upgrade from uint256[] to mapping(uint256 => uint256)`
92
92
 
93
+ ## function visibility change
94
+
95
+ > Snapshot 1
96
+
97
+ `file.sol:1: Upgraded \`s1\` to an incompatible type␊
98
+ - Bad upgrade from struct StorageUpgrade_FunctionType_Visibility_V1.S to struct StorageUpgrade_FunctionType_Visibility_V2_Bad.S␊
99
+ - In struct StorageUpgrade_FunctionType_Visibility_V2_Bad.S␊
100
+ - Upgraded \`m\` to an incompatible type␊
101
+ - Bad upgrade from function () to function () external␊
102
+ Different visibility`
103
+
93
104
  ## array
94
105
 
95
106
  > Snapshot 1
Binary file
@@ -2,7 +2,7 @@ import _chalk from 'chalk';
2
2
 
3
3
  import type { BasicOperation } from '../levenshtein';
4
4
  import type { ParsedTypeDetailed } from './layout';
5
- import type { StorageOperation, StorageItem, StorageField, TypeChange, EnumOperation } from './compare';
5
+ import type { StorageOperation, StorageItem, StorageField, TypeChange, EnumOperation, LayoutChange } from './compare';
6
6
  import { itemize, itemizeWith } from '../utils/itemize';
7
7
  import { indent } from '../utils/indent';
8
8
  import { assert } from '../utils/assert';
@@ -22,8 +22,12 @@ export class LayoutCompatibilityReport {
22
22
  const chalk = new _chalk.Instance({ level: color && _chalk.supportsColor ? _chalk.supportsColor.level : 0 });
23
23
  const res = [];
24
24
 
25
- for (const op of this.ops) {
25
+ for (const [i, op] of this.ops.entries()) {
26
26
  const src = 'updated' in op ? op.updated.src : op.original.contract;
27
+ // Only print layoutchange if it's the first op, otherwise we assume it will be explained by previous ops.
28
+ if (op.kind === 'layoutchange' && i !== 0) {
29
+ continue;
30
+ }
27
31
  res.push(
28
32
  chalk.bold(src) + ':' + indent(explainStorageOperation(op, { kind: 'layout', allowAppend: true }), 2, 1),
29
33
  );
@@ -52,13 +56,20 @@ function explainStorageOperation(op: StorageOperation<StorageField>, ctx: Storag
52
56
  : [];
53
57
  return `Upgraded ${label(op.updated)} to an incompatible type\n` + itemize(basic, ...details);
54
58
  }
55
-
56
59
  case 'rename':
57
60
  return `Renamed ${label(op.original)} to ${label(op.updated)}`;
58
61
 
59
62
  case 'replace':
60
63
  return `Replaced ${label(op.original)} with ${label(op.updated)} of incompatible type`;
61
64
 
65
+ case 'layoutchange': {
66
+ return (
67
+ `Layout ${op.change.uncertain ? 'could have changed' : 'changed'} for ${label(op.updated)} ` +
68
+ `(${op.original.type.item.label} -> ${op.updated.type.item.label})\n` +
69
+ describeLayoutTransition(op.change)
70
+ ).trimEnd();
71
+ }
72
+
62
73
  default: {
63
74
  const title = explainBasicOperation(op, t => t.label);
64
75
  const hints = [];
@@ -90,6 +101,9 @@ function explainStorageOperation(op: StorageOperation<StorageField>, ctx: Storag
90
101
 
91
102
  function explainTypeChange(ch: TypeChange): string {
92
103
  switch (ch.kind) {
104
+ case 'visibility change':
105
+ return `Bad upgrade ${describeTransition(ch.original, ch.updated)}\nDifferent visibility`;
106
+
93
107
  case 'obvious mismatch':
94
108
  case 'struct members':
95
109
  case 'enum members':
@@ -172,7 +186,16 @@ function explainTypeChangeDetails(ch: TypeChange): string | undefined {
172
186
  const { allowAppend } = ch;
173
187
  return (
174
188
  `In ${ch.updated.item.label}\n` +
175
- itemize(...ch.ops.map(op => explainStorageOperation(op, { kind: 'struct', allowAppend })))
189
+ itemize(
190
+ ...ch.ops.flatMap((op, i) => {
191
+ if (op.kind === 'layoutchange' && i !== 0) {
192
+ // Only print layoutchange if it's the first op, otherwise we assume it will be explained by previous ops.
193
+ return [];
194
+ } else {
195
+ return [explainStorageOperation(op, { kind: 'struct', allowAppend })];
196
+ }
197
+ }),
198
+ )
176
199
  );
177
200
  }
178
201
 
@@ -215,6 +238,18 @@ function describeTransition(original: ParsedTypeDetailed, updated: ParsedTypeDet
215
238
  }
216
239
  }
217
240
 
241
+ function describeLayoutTransition(change: LayoutChange): string {
242
+ const res = [];
243
+ for (const k of ['slot', 'offset', 'bytes'] as const) {
244
+ const ch = change[k];
245
+ if (ch) {
246
+ const label = (k === 'bytes' ? 'number of bytes' : k).replace(/^./, c => c.toUpperCase());
247
+ res.push(`${label} changed from ${ch.from} to ${ch.to}`);
248
+ }
249
+ }
250
+ return itemize(...res);
251
+ }
252
+
218
253
  function label(variable: { label: string }): string {
219
254
  return '`' + variable.label + '`';
220
255
  }
@@ -179,7 +179,7 @@ test('storage upgrade with structs', t => {
179
179
  change: {
180
180
  kind: 'struct members',
181
181
  ops: {
182
- length: 1,
182
+ length: 2,
183
183
  0: { kind: 'delete' },
184
184
  },
185
185
  },