Skip to content

Commit

Permalink
Add tests, fix checking duplicates
Browse files Browse the repository at this point in the history
  • Loading branch information
ericglau committed Sep 11, 2023
1 parent 077fe1e commit 01c4c8e
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 20 deletions.
12 changes: 0 additions & 12 deletions packages/core/contracts/test/Namespaced.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,6 @@ contract Example {
}
}

contract DuplicateNamespace {
/// @custom:storage-location erc7201:conflicting
struct Conflicting1 {
uint256 b;
}

/// @custom:storage-location erc7201:conflicting
struct Conflicting2 {
uint256 c;
}
}

contract MultipleNamespaces {
/// @custom:storage-location erc7201:one
struct S1 {
Expand Down
24 changes: 24 additions & 0 deletions packages/core/contracts/test/NamespacedConflicts.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract DuplicateNamespace {
/// @custom:storage-location erc7201:conflicting
struct Conflicting1 {
uint256 b;
}

/// @custom:storage-location erc7201:conflicting
struct Conflicting2 {
uint256 c;
}
}

contract ConflictsWithParent is DuplicateNamespace {
/// @custom:storage-location erc7201:conflicting
struct Conflicting {
uint256 a;
}
}

contract ConflictsInBothParents is DuplicateNamespace, ConflictsWithParent {
}
1 change: 1 addition & 0 deletions packages/core/hardhat.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ module.exports = {
],
overrides: {
'contracts/test/Namespaced.sol': { version: '0.8.20', settings },
'contracts/test/NamespacedConflicts.sol': { version: '0.8.20', settings },
},
},
etherscan: {
Expand Down
49 changes: 49 additions & 0 deletions packages/core/src/storage-namespaced-conflicts.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import _test, { TestFn } from 'ava';
import { ContractDefinition } from 'solidity-ast';
import { findAll, astDereferencer } from 'solidity-ast/utils';
import { artifacts } from 'hardhat';

import { SolcOutput } from './solc-api';
import { StorageLayout } from './storage/layout';
import { extractStorageLayout } from './storage/extract';
import { solcInputOutputDecoder } from './src-decoder';

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

const test = _test as TestFn<Context>;

test.before(async t => {
const buildInfo = await artifacts.getBuildInfo('contracts/test/NamespacedConflicts.sol:DuplicateNamespace');
if (buildInfo === undefined) {
throw new Error('Build info not found');
}
const solcOutput: SolcOutput = buildInfo.output;
const contracts: Record<string, ContractDefinition> = {};
const storageLayouts: Record<string, StorageLayout> = {};
for (const def of findAll('ContractDefinition', solcOutput.sources['contracts/test/NamespacedConflicts.sol'].ast)) {
contracts[def.name] = def;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
storageLayouts[def.name] = solcOutput.contracts['contracts/test/NamespacedConflicts.sol'][def.name].storageLayout!;
}
const deref = astDereferencer(solcOutput);
const decodeSrc = solcInputOutputDecoder(buildInfo.input, solcOutput);
t.context.extractStorageLayout = name =>
extractStorageLayout(contracts[name], decodeSrc, deref, storageLayouts[name]);
});

test('duplicate namespace', t => {
const error = t.throws(() => t.context.extractStorageLayout('DuplicateNamespace'));
t.snapshot(error?.message);
});

test('conflicts with parent', t => {
const error = t.throws(() => t.context.extractStorageLayout('ConflictsWithParent'));
t.snapshot(error?.message);
});

test('conflicts in both parents', t => {
const error = t.throws(() => t.context.extractStorageLayout('ConflictsInBothParents'));
t.snapshot(error?.message);
});

Check warning on line 49 in packages/core/src/storage-namespaced-conflicts.test.ts

View workflow job for this annotation

GitHub Actions / lint

Insert `⏎`
43 changes: 43 additions & 0 deletions packages/core/src/storage-namespaced-conflicts.test.ts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Snapshot report for `src/storage-namespaced-conflicts.test.ts`

The actual snapshot is saved in `storage-namespaced-conflicts.test.ts.snap`.

Generated by [AVA](https://avajs.dev).

## duplicate namespace

> Snapshot 1
`Namespace erc7201:conflicting is defined multiple times for contract DuplicateNamespace␊
The namespace erc7201:conflicting was found in structs at the following locations:␊
- contracts/test/NamespacedConflicts.sol:6␊
- contracts/test/NamespacedConflicts.sol:11␊
Use a unique namespace id for each struct annotated with '@custom:storage-location erc7201:<NAMESPACE_ID>' in your contract and its inherited contracts.`

## conflicts with parent

> Snapshot 1
`Namespace erc7201:conflicting is defined multiple times for contract ConflictsWithParent␊
The namespace erc7201:conflicting was found in structs at the following locations:␊
- contracts/test/NamespacedConflicts.sol:18␊
- contracts/test/NamespacedConflicts.sol:6␊
- contracts/test/NamespacedConflicts.sol:11␊
Use a unique namespace id for each struct annotated with '@custom:storage-location erc7201:<NAMESPACE_ID>' in your contract and its inherited contracts.`

## conflicts in both parents

> Snapshot 1
`Namespace erc7201:conflicting is defined multiple times for contract ConflictsInBothParents␊
The namespace erc7201:conflicting was found in structs at the following locations:␊
- contracts/test/NamespacedConflicts.sol:18␊
- contracts/test/NamespacedConflicts.sol:6␊
- contracts/test/NamespacedConflicts.sol:11␊
Use a unique namespace id for each struct annotated with '@custom:storage-location erc7201:<NAMESPACE_ID>' in your contract and its inherited contracts.`
Binary file not shown.
5 changes: 0 additions & 5 deletions packages/core/src/storage-namespaced.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,6 @@ test('layout', t => {
t.snapshot(stabilizeStorageLayout(layout));
});

test('duplicate namespace', t => {
const layout = t.context.extractStorageLayout('DuplicateNamespace');
t.snapshot(stabilizeStorageLayout(layout));
});

test('multiple namespaces', t => {
const layout = t.context.extractStorageLayout('MultipleNamespaces');
t.snapshot(stabilizeStorageLayout(layout));
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/storage/namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class DuplicateNamespaceError extends UpgradesError {
super(
`Namespace ${id} is defined multiple times for contract ${contractName}`,
() => `\
The namespace ${id} was found in:
The namespace ${id} was found in structs at the following locations:
- ${srcs.join('\n- ')}
Use a unique namespace id for each struct annotated with '@custom:storage-location erc7201:<NAMESPACE_ID>' in your contract and its inherited contracts.`,
Expand Down Expand Up @@ -111,7 +111,7 @@ function pushInheritedNamespaces(
if (namespacedContext === undefined) {
for (let i = 0; i < origInheritIds.length; i++) {
const origInherit = origContext.deref(['ContractDefinition'], origInheritIds[i]);
pushDirectNamespaces(namespaces, decodeSrc, layout, origContext, origInherit);
pushDirectNamespaces(namespaces, decodeSrc, layout, { ...origContext, contractDef: origInherit }, origInherit);
}
} else {
const namespacedInheritIds = namespacedContext.contractDef.linearizedBaseContracts.slice(1);
Expand Down Expand Up @@ -215,7 +215,7 @@ function getOriginalStruct(structCanonicalName: string, origContractDef: Contrac
}
}
}
throw new Error(`Could not find original source location for namespace struct with name ${structCanonicalName}`);
throw new Error(`Could not find original source location for namespace struct with name ${structCanonicalName} from contract ${origContractDef.name}`);

Check warning on line 218 in packages/core/src/storage/namespace.ts

View workflow job for this annotation

GitHub Actions / lint

Replace ``Could·not·find·original·source·location·for·namespace·struct·with·name·${structCanonicalName}·from·contract·${origContractDef.name}`` with `⏎····`Could·not·find·original·source·location·for·namespace·struct·with·name·${structCanonicalName}·from·contract·${origContractDef.name}`,⏎··`
}

function getOriginalMemberSrc(structCanonicalName: string, memberLabel: string, origContractDef: ContractDefinition) {
Expand Down

0 comments on commit 01c4c8e

Please sign in to comment.