Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
e8f4765
extract and store struct and enum members
frangio Dec 12, 2020
3f03499
implement type id parsing
frangio Dec 15, 2020
2e88710
expand storage layouts before comparing
frangio Dec 15, 2020
8c60e39
add assertion to type id parsing
frangio Dec 15, 2020
eb0b3ab
lay foundation to compare storage fields recursively
frangio Dec 16, 2020
994ecf5
compare struct members recursively
frangio Dec 16, 2020
dd64a36
test type id parser with unknown mapping key from oz cli migration
frangio Dec 16, 2020
aee06bc
implement type compatibility check
frangio Dec 16, 2020
5fe1b8e
explain parameter Type
frangio Dec 16, 2020
4f2968f
add comment explaining ASTDereferencer
frangio Dec 17, 2020
a847daa
typo
frangio Dec 17, 2020
5a4c06b
add note about UserDefinedTypes
frangio Dec 17, 2020
c3890fc
explain implementation decisions and add todo about recursive types
frangio Dec 17, 2020
97126ff
remove unsafeAllowCustomTypes flag
frangio Dec 17, 2020
45e29f9
Merge branch 'master' into extract-structs
frangio Dec 17, 2020
d5c1d9d
fix error message expected in test
frangio Dec 17, 2020
e6b9c05
add note about generic function
frangio Dec 17, 2020
5ea5c09
improve comment
frangio Dec 17, 2020
aeb6414
add documentation for parse-type-id
frangio Dec 17, 2020
09e9b64
remove unused argument to matchStorageField
frangio Dec 17, 2020
22e48e5
rename canGrow -> allowAppend
frangio Dec 17, 2020
8de6555
add more tests for parse-type-id
frangio Dec 17, 2020
9fd620f
grammar
frangio Dec 17, 2020
e99ed1c
limit enum members to 256
frangio Dec 17, 2020
4eec9ae
detect and fail with recursive types
frangio Dec 18, 2020
90f6c56
validate compatibility of array member type
frangio Dec 18, 2020
2eab1cf
add more tests comparing upgraded types
frangio Dec 18, 2020
4898422
improve storage layout tests
frangio Dec 21, 2020
7b19889
add initial support for complex storage layout error reporting
frangio Dec 21, 2020
fb35da6
cache results of comparing two types
frangio Dec 21, 2020
07af28b
return StorageMatchResult instances from compatibleTypes
frangio Dec 21, 2020
4dda814
rename message -> errorMessage
frangio Dec 23, 2020
4ef2b3e
fix regex
frangio Dec 23, 2020
277f271
make ErrorDescriptor.hint a function
frangio Dec 23, 2020
ff629d4
remove unused default value
frangio Dec 23, 2020
7b8a49d
rename operation kinds to past tense
frangio Dec 23, 2020
8be7b72
remove unused default value
frangio Dec 23, 2020
cfa3e26
improve enum incompatibility error message
frangio Dec 24, 2020
036fac6
simplify error message
frangio Dec 24, 2020
20f603e
break up storage.ts into separate files
frangio Dec 24, 2020
935ed03
fix tests
frangio Dec 29, 2020
f944834
use t.like for levenshtein tests
frangio Dec 29, 2020
f70bedf
refactor levenshtein
frangio Dec 29, 2020
a66e07b
add Manifest.loadAll to load all manifests
frangio Dec 31, 2020
7312b91
reorganize validate module
frangio Jan 2, 2021
33d9363
rename RunValidation -> ValidationRunData
frangio Jan 2, 2021
db023c8
define new validation data version
frangio Jan 2, 2021
949d587
add DeepArray utils
frangio Jan 3, 2021
710c051
add a migration of all manifests as a first step
frangio Jan 5, 2021
1689918
improve handling of outdated validations in hardhat
frangio Jan 5, 2021
15007cf
Merge remote-tracking branch 'origin/master' into extract-structs
frangio Jan 5, 2021
cd7e576
fix validations cache errors on hardhat
frangio Jan 5, 2021
a0d7da9
stabilize test snapshot
frangio Jan 5, 2021
02852be
fix Manifest.loadAll
frangio Jan 5, 2021
a98b83f
fix manifest-migrate tests
frangio Jan 5, 2021
096f3fc
fix findVersionWithoutMetadataMatches
frangio Jan 5, 2021
fe53519
refactor storage comparison reporting
frangio Jan 10, 2021
b4f361a
stop extracting struct and enum errors
frangio Jan 10, 2021
415c959
remove unsafeAllowCustomTypes flag tests
frangio Jan 10, 2021
4a4f72d
use unsafeAllowCustomTypes when there are missing members
frangio Jan 10, 2021
3454497
remove more old tests
frangio Jan 10, 2021
55c37bf
rename 'different kinds' error to 'obvious mismatch'
frangio Jan 10, 2021
ed483db
add tests for obvious mismatch errors
frangio Jan 10, 2021
10244d1
add test for changed inner struct member
frangio Jan 10, 2021
8a6a2d5
Merge remote-tracking branch 'origin/master' into extract-structs
frangio Jan 10, 2021
8ce0ded
migrate manifest version earlier in hardhat
frangio Jan 10, 2021
f93c856
fix manifest-migrate validating manifest version before migration
frangio Jan 10, 2021
98bc695
migrate manifest version earlier in truffle
frangio Jan 11, 2021
f729466
add tests for storage layout error reporting and fix found bugs
frangio Jan 11, 2021
9cdd007
pass missing option to approve missing members and add tests
frangio Jan 11, 2021
39ad18f
shorten warning
frangio Jan 11, 2021
e03e40b
add more detail to expected data in test
frangio Jan 11, 2021
2fa7173
improve plugin tests involving structs and enums
frangio Jan 11, 2021
7a97e4f
remove redundant type change detail in struct change description
frangio Jan 11, 2021
3f4888e
add backwards compatible interface for storage module
frangio Jan 19, 2021
dc8972a
simplify deepEqual
frangio Jan 19, 2021
bb563c6
add function to get or update storage layout in manifest
frangio Jan 19, 2021
42f63e9
remove migrateAllManifests
frangio Jan 19, 2021
72f386e
rename manifest-migrate -> manifest-storage-layout
frangio Jan 19, 2021
d10dd2c
revert breaking change to assertStorageUpgradeSafe arguments
frangio Jan 19, 2021
5977eb6
disable color in tests
frangio Jan 19, 2021
cdd906b
Merge remote-tracking branch 'origin/master' into extract-structs
frangio Jan 22, 2021
065d242
tweak wording for storage error
frangio Jan 22, 2021
20ea4a0
print a note when unsafeAllowCustomTypes is not needed
frangio Jan 22, 2021
b9b19e6
lint
frangio Jan 22, 2021
7f10362
detect when dependencies should be updated and notify
frangio Jan 22, 2021
42dbf3e
clean up whitespace around warnings
frangio Jan 22, 2021
a5e180a
update FAQ entry about structs and enums
frangio Jan 22, 2021
84999a7
fix error from merge
frangio Jan 22, 2021
106aecf
update api docs
frangio Jan 22, 2021
6ad37ae
update faq
frangio Jan 22, 2021
335bc1d
improve messaging and formatting of storage layout report
frangio Jan 27, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions packages/core/contracts/test/Storage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,56 @@ contract StorageUpgrade_Delete_V1 {
contract StorageUpgrade_Delete_V2 {
address x2;
}

contract StorageUpgrade_Struct_V1 {
struct Struct {
uint x;
string s1;
string s2;
}
Struct data;
}

contract StorageUpgrade_Struct_V2_Ok {
struct StructRenamed {
uint x;
string s1;
string s2;
}
StructRenamed data;
}

contract StorageUpgrade_Struct_V2_Bad {
struct StructRenamed {
uint x;
string s2;
}
StructRenamed data;
}

contract StorageUpgrade_Enum_V1 {
enum Enum {
A,
B
}
Enum data;
}

contract StorageUpgrade_Enum_V2_Ok {
enum Enum {
A,
B,
C
}
Enum data;
}

contract StorageUpgrade_Enum_V2_Bad {
enum Enum {
A,
C,
B
}
Enum data;
}

4 changes: 2 additions & 2 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"prepare:contracts": "hardhat compile",
"prepublishOnly": "bash scripts/copy-artifacts.sh",
"test": "tsc -b && hardhat compile --force && ava",
"test:watch": "hardhat compile --force && fgbg 'ava --watch' 'tsc -b --watch'",
"test:watch": "hardhat compile --force && fgbg 'ava --watch' 'tsc -b --watch' --",
"version": "node ../../scripts/bump-changelog.js"
},
"devDependencies": {
Expand Down Expand Up @@ -51,6 +51,6 @@
"fp-ts": "^2.7.1",
"io-ts": "^2.2.9",
"proper-lockfile": "^4.1.1",
"solidity-ast": "^0.4.4"
"solidity-ast": "^0.4.15"
}
}
42 changes: 42 additions & 0 deletions packages/core/src/ast-dereferencer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { findAll } from 'solidity-ast/utils';
import type { Node, NodeType, NodeTypeMap } from 'solidity-ast/node';

import { curry2 } from './utils/curry';
import type { SolcOutput } from './solc-api';

// An ASTDereferencer is a function that looks up an AST node given its id, in all of the source files involved in a
// solc run. It will generally be used together with the AST property `referencedDeclaration` (found in Identifier,
// UserDefinedTypeName, etc.) to look up a variable definition or type definition.

export interface ASTDereferencer {
<T extends NodeType>(nodeTypes: T[]): (id: number) => NodeTypeMap[T];
<T extends NodeType>(nodeTypes: T[], id: number): NodeTypeMap[T];
}

export function astDereferencer(solcOutput: SolcOutput): ASTDereferencer {
const asts = Array.from(Object.values(solcOutput.sources), s => s.ast);
const cache = new Map<number, Node>();

function deref<T extends NodeType>(nodeTypes: T[], id: number): NodeTypeMap[T] {
const cached = cache.get(id);

if (cached) {
if ((nodeTypes as NodeType[]).includes(cached.nodeType)) {
return cached as NodeTypeMap[T];
}
}

for (const ast of asts) {
for (const node of findAll(nodeTypes, ast)) {
if (node.id === id) {
cache.set(id, node);
return node;
}
}
}

throw new Error(`No node with id ${id} of type ${nodeTypes}`);
}

return curry2(deref);
}
75 changes: 55 additions & 20 deletions packages/core/src/storage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { findAll } from 'solidity-ast/utils';
import { artifacts } from 'hardhat';

import { SolcOutput } from './solc-api';
import { astDereferencer } from './ast-dereferencer';
import { extractStorageLayout, getStorageUpgradeErrors, stabilizeTypeIdentifier, StorageLayout } from './storage';

interface Context {
contracts: Record<string, ContractDefinition>;
extractStorageLayout: (contract: string) => ReturnType<typeof extractStorageLayout>;
}

const test = _test as TestInterface<Context>;
Expand All @@ -18,57 +19,91 @@ test.before(async t => {
throw new Error('Build info not found');
}
const solcOutput: SolcOutput = buildInfo.output;
t.context.contracts = {};
const contracts: Record<string, ContractDefinition> = {};
for (const def of findAll('ContractDefinition', solcOutput.sources['contracts/test/Storage.sol'].ast)) {
t.context.contracts[def.name] = def;
contracts[def.name] = def;
}
const deref = astDereferencer(solcOutput);
t.context.extractStorageLayout = name => extractStorageLayout(contracts[name], dummyDecodeSrc, deref);
});

const dummyDecodeSrc = () => 'file.sol:1';

test('Storage1', t => {
const contract = 'Storage1';
const def = t.context.contracts[contract];
const layout = extractStorageLayout(def, dummyDecodeSrc);
const layout = t.context.extractStorageLayout('Storage1');
t.snapshot(stabilizeStorageLayout(layout));
});

test('Storage2', t => {
const contract = 'Storage2';
const def = t.context.contracts[contract];
const layout = extractStorageLayout(def, dummyDecodeSrc);
const layout = t.context.extractStorageLayout('Storage2');
t.snapshot(stabilizeStorageLayout(layout));
});

test('storage upgrade equal', t => {
const v1 = extractStorageLayout(t.context.contracts['StorageUpgrade_Equal_V1'], dummyDecodeSrc);
const v2 = extractStorageLayout(t.context.contracts['StorageUpgrade_Equal_V2'], dummyDecodeSrc);
const v1 = t.context.extractStorageLayout('StorageUpgrade_Equal_V1');
const v2 = t.context.extractStorageLayout('StorageUpgrade_Equal_V2');
const comparison = getStorageUpgradeErrors(v1, v2);
t.deepEqual(comparison, []);
});

test('storage upgrade append', t => {
const v1 = extractStorageLayout(t.context.contracts['StorageUpgrade_Append_V1'], dummyDecodeSrc);
const v2 = extractStorageLayout(t.context.contracts['StorageUpgrade_Append_V2'], dummyDecodeSrc);
const v1 = t.context.extractStorageLayout('StorageUpgrade_Append_V1');
const v2 = t.context.extractStorageLayout('StorageUpgrade_Append_V2');
const comparison = getStorageUpgradeErrors(v1, v2);
t.deepEqual(comparison, []);
});

test('storage upgrade delete', t => {
const v1 = extractStorageLayout(t.context.contracts['StorageUpgrade_Delete_V1'], dummyDecodeSrc);
const v2 = extractStorageLayout(t.context.contracts['StorageUpgrade_Delete_V2'], dummyDecodeSrc);
const v1 = t.context.extractStorageLayout('StorageUpgrade_Delete_V1');
const v2 = t.context.extractStorageLayout('StorageUpgrade_Delete_V2');
const comparison = getStorageUpgradeErrors(v1, v2);
t.deepEqual(comparison, [
{
t.like(comparison, {
length: 1,
0: {
kind: 'delete',
original: {
contract: 'StorageUpgrade_Delete_V1',
label: 'x1',
type: 't_uint256',
src: 'file.sol:1',
type: {
id: 't_uint256',
},
},
},
]);
});
});

test('storage upgrade with structs', t => {
const v1 = t.context.extractStorageLayout('StorageUpgrade_Struct_V1');

const v2_Ok = t.context.extractStorageLayout('StorageUpgrade_Struct_V2_Ok');
t.deepEqual(getStorageUpgradeErrors(v1, v2_Ok), []);

const v2_Bad = t.context.extractStorageLayout('StorageUpgrade_Struct_V2_Bad');
t.like(getStorageUpgradeErrors(v1, v2_Bad), {
length: 1,
0: {
kind: 'typechange',
original: { label: 'data' },
updated: { label: 'data' },
},
});
});

test('storage upgrade with enums', t => {
const v1 = t.context.extractStorageLayout('StorageUpgrade_Enum_V1');

const v2_Ok = t.context.extractStorageLayout('StorageUpgrade_Enum_V2_Ok');
t.deepEqual(getStorageUpgradeErrors(v1, v2_Ok), []);

const v2_Bad = t.context.extractStorageLayout('StorageUpgrade_Enum_V2_Bad');
t.like(getStorageUpgradeErrors(v1, v2_Bad), {
length: 1,
0: {
kind: 'typechange',
original: { label: 'data' },
updated: { label: 'data' },
},
});
});

function stabilizeStorageLayout(layout: StorageLayout) {
Expand Down
Loading