@0x/contracts-zero-ex: Use (scaled) enums for storage IDs

This commit is contained in:
Lawrence Forman 2020-04-20 15:53:21 -04:00
parent 220039ab00
commit 4446ac1ca3
11 changed files with 86 additions and 29 deletions

View File

@ -53,7 +53,7 @@ contract Bootstrap is
} }
/// @dev Bootstrap the initial feature set of this contract by delegatecalling /// @dev Bootstrap the initial feature set of this contract by delegatecalling
/// into `_bootstrapper`. Before exiting the `bootstrap()` function will /// into `target`. Before exiting the `bootstrap()` function will
/// deregister itself from the proxy to prevent being called again. /// deregister itself from the proxy to prevent being called again.
/// @param target The bootstrapper contract address. /// @param target The bootstrapper contract address.
/// @param callData The call data to execute on `_bootstrapper`. /// @param callData The call data to execute on `_bootstrapper`.
@ -65,11 +65,12 @@ contract Bootstrap is
_bootstrapCaller _bootstrapCaller
)); ));
} }
LibBootstrap.delegatecallBootstrapFunction(target, callData);
// Deregister. // Deregister.
LibProxyStorage.getStorage().impls[this.bootstrap.selector] = address(0); LibProxyStorage.getStorage().impls[this.bootstrap.selector] = address(0);
// Self-destruct. // Self-destruct.
Bootstrap(_implementation).die(); Bootstrap(_implementation).die();
// Call the bootstrapper.
LibBootstrap.delegatecallBootstrapFunction(target, callData);
} }
/// @dev Self-destructs this contract. /// @dev Self-destructs this contract.

View File

@ -19,14 +19,12 @@
pragma solidity ^0.6.5; pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "./LibStorage.sol";
/// @dev Storage helpers for the `Migrate` feature. /// @dev Storage helpers for the `Migrate` feature.
library LibMigrateStorage { library LibMigrateStorage {
/// @dev Globally unique offset for the storage bucket.
bytes32 constant internal STORAGE_ID =
0x0ed67b719caa0e9bebb7147a4de9fdb6f1c82a984b2297d741a9888432214d5c;
/// @dev Storage bucket for this feature. /// @dev Storage bucket for this feature.
struct Storage { struct Storage {
// The owner of this contract prior to the `migrate()` call. // The owner of this contract prior to the `migrate()` call.
@ -35,7 +33,9 @@ library LibMigrateStorage {
/// @dev Get the storage bucket for this contract. /// @dev Get the storage bucket for this contract.
function getStorage() internal pure returns (Storage storage stor) { function getStorage() internal pure returns (Storage storage stor) {
bytes32 storageId = STORAGE_ID; uint256 storageOffset = LibStorage.getStorageOffset(
assembly { stor_slot := storageId } LibStorage.StorageId.Migrate
);
assembly { stor_slot := storageOffset }
} }
} }

View File

@ -19,14 +19,12 @@
pragma solidity ^0.6.5; pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "./LibStorage.sol";
/// @dev Storage helpers for the `Ownable` feature. /// @dev Storage helpers for the `Ownable` feature.
library LibOwnableStorage { library LibOwnableStorage {
/// @dev Globally unique offset for the storage bucket.
bytes32 constant internal STORAGE_ID =
0xeef73acb590dd70cb88ccc8e9832ea7f198de2f3c87ff92d610497d647795b3c;
/// @dev Storage bucket for this feature. /// @dev Storage bucket for this feature.
struct Storage { struct Storage {
// The owner of this contract. // The owner of this contract.
@ -35,7 +33,9 @@ library LibOwnableStorage {
/// @dev Get the storage bucket for this contract. /// @dev Get the storage bucket for this contract.
function getStorage() internal pure returns (Storage storage stor) { function getStorage() internal pure returns (Storage storage stor) {
bytes32 storageId = STORAGE_ID; uint256 storageOffset = LibStorage.getStorageOffset(
assembly { stor_slot := storageId } LibStorage.StorageId.Ownable
);
assembly { stor_slot := storageOffset }
} }
} }

View File

@ -19,14 +19,12 @@
pragma solidity ^0.6.5; pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "./LibStorage.sol";
/// @dev Storage helpers for the proxy contract. /// @dev Storage helpers for the proxy contract.
library LibProxyStorage { library LibProxyStorage {
/// @dev Globally unique offset for the storage bucket.
bytes32 constant internal STORAGE_ID =
0xd7434ab6df6fb6431870c66fc3fc3d21ddd20b029595942d9e0ffc950ce32f66;
/// @dev Storage bucket for proxy contract. /// @dev Storage bucket for proxy contract.
struct Storage { struct Storage {
// Mapping of function selector -> function implementation // Mapping of function selector -> function implementation
@ -35,7 +33,9 @@ library LibProxyStorage {
/// @dev Get the storage bucket for this contract. /// @dev Get the storage bucket for this contract.
function getStorage() internal pure returns (Storage storage stor) { function getStorage() internal pure returns (Storage storage stor) {
bytes32 storageId = STORAGE_ID; uint256 storageOffset = LibStorage.getStorageOffset(
assembly { stor_slot := storageId } LibStorage.StorageId.Proxy
);
assembly { stor_slot := storageOffset }
} }
} }

View File

@ -19,14 +19,12 @@
pragma solidity ^0.6.5; pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "./LibStorage.sol";
/// @dev Storage helpers for the `SimpleFunctionRegistry` feature. /// @dev Storage helpers for the `SimpleFunctionRegistry` feature.
library LibSimpleFunctionRegistryStorage { library LibSimpleFunctionRegistryStorage {
/// @dev Globally unique offset for the storage bucket.
bytes32 constant internal STORAGE_ID =
0x9817e79514d088041d4834d6eb535f4fa107927bddb0f3c55c3e6b2bfe43daa5;
/// @dev Storage bucket for this feature. /// @dev Storage bucket for this feature.
struct Storage { struct Storage {
// Mapping of function selector -> implementation history. // Mapping of function selector -> implementation history.
@ -35,7 +33,9 @@ library LibSimpleFunctionRegistryStorage {
/// @dev Get the storage bucket for this contract. /// @dev Get the storage bucket for this contract.
function getStorage() internal pure returns (Storage storage stor) { function getStorage() internal pure returns (Storage storage stor) {
bytes32 storageId = STORAGE_ID; uint256 storageOffset = LibStorage.getStorageOffset(
assembly { stor_slot := storageId } LibStorage.StorageId.SimpleFunctionRegistry
);
assembly { stor_slot := storageOffset }
} }
} }

View File

@ -0,0 +1,49 @@
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
/// @dev Common storage helpers
library LibStorage {
/// @dev What to multiply a storage ID by to get its offset.
/// This is also the maximum number of fields inside a storage
/// bucket.
uint256 internal constant STORAGE_OFFSET_MULTIPLIER = 1e18;
/// @dev Storage IDs for feature storage buckets.
enum StorageId {
Proxy,
SimpleFunctionRegistry,
Ownable,
Migrate
}
/// @dev Get the storage offset given a storage ID.
/// @param storageId An entry in `StorageId`
/// @return offset The storage offset.
function getStorageOffset(StorageId storageId)
internal
pure
returns (uint256 offset)
{
return uint256(storageId) * STORAGE_OFFSET_MULTIPLIER;
}
}

View File

@ -40,7 +40,7 @@
"config": { "config": {
"publicInterfaceContracts": "ZeroEx,IMigrate,IOwnable,ISimpleFunctionRegistry", "publicInterfaceContracts": "ZeroEx,IMigrate,IOwnable,ISimpleFunctionRegistry",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(Bootstrap|FixinCommon|FixinOwnable|IBootstrap|IFeature|IMigrate|IOwnable|ISimpleFunctionRegistry|ITestSimpleFunctionRegistryFeature|InitialMigration|LibBootstrap|LibCommonRichErrors|LibMigrate|LibMigrateRichErrors|LibMigrateStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|Migrate|Ownable|SimpleFunctionRegistry|TestInitialMigration|TestMigrator|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestZeroExFeature|ZeroEx).json" "abis": "./test/generated-artifacts/@(Bootstrap|FixinCommon|FixinOwnable|IBootstrap|IFeature|IMigrate|IOwnable|ISimpleFunctionRegistry|ITestSimpleFunctionRegistryFeature|InitialMigration|LibBootstrap|LibCommonRichErrors|LibMigrate|LibMigrateRichErrors|LibMigrateStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|Migrate|Ownable|SimpleFunctionRegistry|TestInitialMigration|TestMigrator|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestZeroExFeature|ZeroEx).json"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -26,6 +26,7 @@ import * as LibProxyRichErrors from '../test/generated-artifacts/LibProxyRichErr
import * as LibProxyStorage from '../test/generated-artifacts/LibProxyStorage.json'; import * as LibProxyStorage from '../test/generated-artifacts/LibProxyStorage.json';
import * as LibSimpleFunctionRegistryRichErrors from '../test/generated-artifacts/LibSimpleFunctionRegistryRichErrors.json'; import * as LibSimpleFunctionRegistryRichErrors from '../test/generated-artifacts/LibSimpleFunctionRegistryRichErrors.json';
import * as LibSimpleFunctionRegistryStorage from '../test/generated-artifacts/LibSimpleFunctionRegistryStorage.json'; import * as LibSimpleFunctionRegistryStorage from '../test/generated-artifacts/LibSimpleFunctionRegistryStorage.json';
import * as LibStorage from '../test/generated-artifacts/LibStorage.json';
import * as Migrate from '../test/generated-artifacts/Migrate.json'; import * as Migrate from '../test/generated-artifacts/Migrate.json';
import * as Ownable from '../test/generated-artifacts/Ownable.json'; import * as Ownable from '../test/generated-artifacts/Ownable.json';
import * as SimpleFunctionRegistry from '../test/generated-artifacts/SimpleFunctionRegistry.json'; import * as SimpleFunctionRegistry from '../test/generated-artifacts/SimpleFunctionRegistry.json';
@ -60,6 +61,7 @@ export const artifacts = {
LibOwnableStorage: LibOwnableStorage as ContractArtifact, LibOwnableStorage: LibOwnableStorage as ContractArtifact,
LibProxyStorage: LibProxyStorage as ContractArtifact, LibProxyStorage: LibProxyStorage as ContractArtifact,
LibSimpleFunctionRegistryStorage: LibSimpleFunctionRegistryStorage as ContractArtifact, LibSimpleFunctionRegistryStorage: LibSimpleFunctionRegistryStorage as ContractArtifact,
LibStorage: LibStorage as ContractArtifact,
ITestSimpleFunctionRegistryFeature: ITestSimpleFunctionRegistryFeature as ContractArtifact, ITestSimpleFunctionRegistryFeature: ITestSimpleFunctionRegistryFeature as ContractArtifact,
TestInitialMigration: TestInitialMigration as ContractArtifact, TestInitialMigration: TestInitialMigration as ContractArtifact,
TestMigrator: TestMigrator as ContractArtifact, TestMigrator: TestMigrator as ContractArtifact,

View File

@ -5,9 +5,10 @@ import { promisify } from 'util';
describe('Storage ID uniqueness test', () => { describe('Storage ID uniqueness test', () => {
const STORAGE_SOURCES_DIR = resolve(__dirname, '../../contracts/src/storage'); const STORAGE_SOURCES_DIR = resolve(__dirname, '../../contracts/src/storage');
async function findStorageIdFromSourceFileAsync(path: string): Promise<string | void> { async function findStorageIdFromSourceFileAsync(path: string): Promise<string | void> {
const contents = await promisify(readFile)(path, { encoding: 'utf-8' }); const contents = await promisify(readFile)(path, { encoding: 'utf-8' });
const m = /STORAGE_ID\s*=\s*(0x[a-fA-F0-9]{64})/m.exec(contents); const m = /LibStorage\.\s*getStorageOffset\(\s*LibStorage\.\s*StorageId\.\s*(\w+)\s*\)/m.exec(contents);
if (m) { if (m) {
return m[1]; return m[1];
} }
@ -17,7 +18,9 @@ describe('Storage ID uniqueness test', () => {
const sourcePaths = (await promisify(readdir)(STORAGE_SOURCES_DIR)) const sourcePaths = (await promisify(readdir)(STORAGE_SOURCES_DIR))
.filter(p => p.endsWith('.sol')) .filter(p => p.endsWith('.sol'))
.map(p => resolve(STORAGE_SOURCES_DIR, p)); .map(p => resolve(STORAGE_SOURCES_DIR, p));
const storageIds = await Promise.all(sourcePaths.map(async p => findStorageIdFromSourceFileAsync(p))); const storageIds = (await Promise.all(sourcePaths.map(async p => findStorageIdFromSourceFileAsync(p)))).filter(
id => !!id,
);
for (let i = 0; i < storageIds.length; ++i) { for (let i = 0; i < storageIds.length; ++i) {
const storageId = storageIds[i]; const storageId = storageIds[i];
for (let j = 0; j < storageIds.length; ++j) { for (let j = 0; j < storageIds.length; ++j) {

View File

@ -24,6 +24,7 @@ export * from '../test/generated-wrappers/lib_proxy_rich_errors';
export * from '../test/generated-wrappers/lib_proxy_storage'; export * from '../test/generated-wrappers/lib_proxy_storage';
export * from '../test/generated-wrappers/lib_simple_function_registry_rich_errors'; export * from '../test/generated-wrappers/lib_simple_function_registry_rich_errors';
export * from '../test/generated-wrappers/lib_simple_function_registry_storage'; export * from '../test/generated-wrappers/lib_simple_function_registry_storage';
export * from '../test/generated-wrappers/lib_storage';
export * from '../test/generated-wrappers/migrate'; export * from '../test/generated-wrappers/migrate';
export * from '../test/generated-wrappers/ownable'; export * from '../test/generated-wrappers/ownable';
export * from '../test/generated-wrappers/simple_function_registry'; export * from '../test/generated-wrappers/simple_function_registry';

View File

@ -28,6 +28,7 @@
"test/generated-artifacts/LibProxyStorage.json", "test/generated-artifacts/LibProxyStorage.json",
"test/generated-artifacts/LibSimpleFunctionRegistryRichErrors.json", "test/generated-artifacts/LibSimpleFunctionRegistryRichErrors.json",
"test/generated-artifacts/LibSimpleFunctionRegistryStorage.json", "test/generated-artifacts/LibSimpleFunctionRegistryStorage.json",
"test/generated-artifacts/LibStorage.json",
"test/generated-artifacts/Migrate.json", "test/generated-artifacts/Migrate.json",
"test/generated-artifacts/Ownable.json", "test/generated-artifacts/Ownable.json",
"test/generated-artifacts/SimpleFunctionRegistry.json", "test/generated-artifacts/SimpleFunctionRegistry.json",