@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
/// 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.
/// @param target The bootstrapper contract address.
/// @param callData The call data to execute on `_bootstrapper`.
@ -65,11 +65,12 @@ contract Bootstrap is
_bootstrapCaller
));
}
LibBootstrap.delegatecallBootstrapFunction(target, callData);
// Deregister.
LibProxyStorage.getStorage().impls[this.bootstrap.selector] = address(0);
// Self-destruct.
Bootstrap(_implementation).die();
// Call the bootstrapper.
LibBootstrap.delegatecallBootstrapFunction(target, callData);
}
/// @dev Self-destructs this contract.

View File

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

View File

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

View File

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

View File

@ -19,14 +19,12 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "./LibStorage.sol";
/// @dev Storage helpers for the `SimpleFunctionRegistry` feature.
library LibSimpleFunctionRegistryStorage {
/// @dev Globally unique offset for the storage bucket.
bytes32 constant internal STORAGE_ID =
0x9817e79514d088041d4834d6eb535f4fa107927bddb0f3c55c3e6b2bfe43daa5;
/// @dev Storage bucket for this feature.
struct Storage {
// Mapping of function selector -> implementation history.
@ -35,7 +33,9 @@ library LibSimpleFunctionRegistryStorage {
/// @dev Get the storage bucket for this contract.
function getStorage() internal pure returns (Storage storage stor) {
bytes32 storageId = STORAGE_ID;
assembly { stor_slot := storageId }
uint256 storageOffset = LibStorage.getStorageOffset(
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": {
"publicInterfaceContracts": "ZeroEx,IMigrate,IOwnable,ISimpleFunctionRegistry",
"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": {
"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 LibSimpleFunctionRegistryRichErrors from '../test/generated-artifacts/LibSimpleFunctionRegistryRichErrors.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 Ownable from '../test/generated-artifacts/Ownable.json';
import * as SimpleFunctionRegistry from '../test/generated-artifacts/SimpleFunctionRegistry.json';
@ -60,6 +61,7 @@ export const artifacts = {
LibOwnableStorage: LibOwnableStorage as ContractArtifact,
LibProxyStorage: LibProxyStorage as ContractArtifact,
LibSimpleFunctionRegistryStorage: LibSimpleFunctionRegistryStorage as ContractArtifact,
LibStorage: LibStorage as ContractArtifact,
ITestSimpleFunctionRegistryFeature: ITestSimpleFunctionRegistryFeature as ContractArtifact,
TestInitialMigration: TestInitialMigration as ContractArtifact,
TestMigrator: TestMigrator as ContractArtifact,

View File

@ -5,9 +5,10 @@ import { promisify } from 'util';
describe('Storage ID uniqueness test', () => {
const STORAGE_SOURCES_DIR = resolve(__dirname, '../../contracts/src/storage');
async function findStorageIdFromSourceFileAsync(path: string): Promise<string | void> {
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) {
return m[1];
}
@ -17,7 +18,9 @@ describe('Storage ID uniqueness test', () => {
const sourcePaths = (await promisify(readdir)(STORAGE_SOURCES_DIR))
.filter(p => p.endsWith('.sol'))
.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) {
const storageId = storageIds[i];
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_simple_function_registry_rich_errors';
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/ownable';
export * from '../test/generated-wrappers/simple_function_registry';

View File

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