Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SSTORE2-compatible dependency registry (for scripts) #895

Merged
merged 25 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
036e38b
naming convention
jakerockland Jul 21, 2023
7f1766b
isSupportedCoreContract helper
jakerockland Jul 21, 2023
caf5d0b
additional test coverage
jakerockland Jul 21, 2023
7e31b02
Merge branch 'main' into dependency-registry-v0-updates
jakerockland Jul 21, 2023
771815c
Add backwards compatibility for pointer-writing to DependencyRegistryV0
jakerockland Jul 21, 2023
a79c294
basic test scafolding
jakerockland Jul 24, 2023
bbefb52
additional test coverage
jakerockland Jul 25, 2023
8552c66
Merge branch 'main' into dependency-registry-v0-updates
jakerockland Jul 25, 2023
3d8643e
Merge branch 'dependency-registry-v0-updates' of github.com:ArtBlocks…
jakerockland Jul 25, 2023
0c0b56e
Merge branch 'dependency-registry-v0-updates' into sstore2-compatible…
jakerockland Jul 25, 2023
911bba9
Test coverageeeeeeeee; https://www.youtube.com/watch\?v\=vmgp7MHzmBM
jakerockland Jul 25, 2023
eb4ee33
Merge branch 'main' into dependency-registry-v0-updates
ryley-o Jul 25, 2023
e7b3683
Merge branch 'dependency-registry-v0-updates' into sstore2-compatible…
jakerockland Jul 25, 2023
d2a9ac8
Merge branch 'main' into sstore2-compatible-dependency-registry
jakerockland Jul 25, 2023
551a403
Merge branch 'main' into sstore2-compatible-dependency-registry
jakerockland Jul 25, 2023
dc4c798
Merge branch 'main' into sstore2-compatible-dependency-registry
jakerockland Jul 25, 2023
064dda7
better documentation
jakerockland Jul 25, 2023
b3e2df8
Merge branch 'sstore2-compatible-dependency-registry' of github.com:A…
jakerockland Jul 25, 2023
1a31ce4
return docs
jakerockland Jul 25, 2023
fde83f8
Update pass for consistency in nomenclature and test adjustment in kind
jakerockland Jul 25, 2023
c7b4196
Merge branch 'main' into sstore2-compatible-dependency-registry
jakerockland Jul 25, 2023
518690c
Additional dev note
jakerockland Jul 25, 2023
7e2c01d
Merge branch 'sstore2-compatible-dependency-registry' of github.com:A…
jakerockland Jul 25, 2023
bef3bf5
Merge branch 'main' into sstore2-compatible-dependency-registry
jakerockland Jul 26, 2023
938e343
Named args; rename args
jakerockland Jul 26, 2023
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
154 changes: 118 additions & 36 deletions packages/contracts/contracts/DependencyRegistryV0.sol
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ contract DependencyRegistryV0 is

/**
* @notice Removes a dependency.
* @param _dependencyType Name of dependency type (i.e. "type@version")
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
*/
function removeDependency(bytes32 _dependencyType) external {
_onlyAdminACL(this.removeDependency.selector);
Expand All @@ -169,8 +169,9 @@ contract DependencyRegistryV0 is
}

/**
* @notice Adds a script to dependency `_dependencyType`.
* @param _dependencyType dependency to be updated.
* @notice Adds a script to dependency `_dependencyType`, by way of
* providing a string to write to bytecode storage.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @param _script Script to be added. Required to be a non-empty string,
* but no further validation is performed.
*/
Expand All @@ -191,11 +192,12 @@ contract DependencyRegistryV0 is
}

/**
* @notice Updates script for dependencyType `_dependencyType` at script ID `_scriptId`.
* @param _dependencyType dependency to be updated.
* @notice Updates script for dependencyType `_dependencyType` at script ID `_scriptId`,
* by way of providing a string to write to bytecode storage.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @param _scriptId Script ID to be updated.
* @param _script The updated script value. Required to be a non-empty
* string, but no further validation is performed.
* string, but no further validation is performed.
*/
function updateDependencyScript(
bytes32 _dependencyType,
Expand All @@ -215,9 +217,56 @@ contract DependencyRegistryV0 is
emit DependencyScriptUpdated(_dependencyType);
}

/**
* @notice Adds a script to dependency `_dependencyType`, by way of
* providing an already written chunk of bytecode storage.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @param _scriptPointer Address of script to be added. Required to be a non-zero address,
* but no further validation is performed.
*/
function addDependencyScriptPointer(
bytes32 _dependencyType,
address _scriptPointer
) external {
_onlyAdminACL(this.addDependencyScriptPointer.selector);
_onlyNonZeroAddress(_scriptPointer);
_onlyExistingDependencyType(_dependencyType);
Dependency storage dependency = dependencyDetails[_dependencyType];
// store script in contract bytecode
dependency.scriptBytecodeAddresses[
dependency.scriptCount
] = _scriptPointer;
dependency.scriptCount = dependency.scriptCount + 1;

emit DependencyScriptUpdated(_dependencyType);
}

/**
* @notice Updates script for dependencyType `_dependencyType` at script ID `_scriptId`,
* by way of providing an already written chunk of bytecode storage.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @param _scriptId Script ID to be updated.
* @param _scriptPointer The updated script pointer (address of bytecode storage).
* Required to be a non-zero address, but no further validation is performed.
*/
function updateDependencyScriptPointer(
bytes32 _dependencyType,
uint256 _scriptId,
address _scriptPointer
) external {
_onlyAdminACL(this.updateDependencyScriptPointer.selector);
_onlyNonZeroAddress(_scriptPointer);
_onlyExistingDependencyType(_dependencyType);
Dependency storage dependency = dependencyDetails[_dependencyType];
require(_scriptId < dependency.scriptCount, "scriptId out of range");
dependency.scriptBytecodeAddresses[_scriptId] = _scriptPointer;

emit DependencyScriptUpdated(_dependencyType);
}

/**
* @notice Removes last script from dependency `_dependencyType`.
* @param _dependencyType dependency to be updated.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
*/
function removeDependencyLastScript(bytes32 _dependencyType) external {
_onlyAdminACL(this.removeDependencyLastScript.selector);
Expand All @@ -235,7 +284,7 @@ contract DependencyRegistryV0 is

/**
* @notice Updates preferred CDN for dependency `_dependencyType`.
* @param _dependencyType dependency to be updated.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @param _preferredCDN URL for preferred CDN.
*/
function updateDependencyPreferredCDN(
Expand All @@ -251,7 +300,7 @@ contract DependencyRegistryV0 is

/**
* @notice Updates preferred repository for dependency `_dependencyType`.
* @param _dependencyType dependency to be updated.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @param _preferredRepository URL for preferred repository.
*/
function updateDependencyPreferredRepository(
Expand All @@ -271,7 +320,7 @@ contract DependencyRegistryV0 is

/**
* @notice Updates project website for dependency `_dependencyType`.
* @param _dependencyType dependency to be updated.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @param _referenceWebsite URL for project website.
*/
function updateDependencyReferenceWebsite(
Expand All @@ -290,7 +339,7 @@ contract DependencyRegistryV0 is

/**
* @notice Adds a new CDN url to `_dependencyType`.
* @param _dependencyType dependency to be updated.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @param _additionalCDN CDN URL to be added. Required to be a non-empty string,
* but no further validation is performed.
*/
Expand Down Expand Up @@ -318,7 +367,7 @@ contract DependencyRegistryV0 is
* @notice Removes additional CDN for dependency `_dependencyId` at index `_index`.
* Removal is done by swapping the element to be removed with the last element in the array, then deleting this last element.
* Assets with indices higher than `_index` can have their indices adjusted as a result of this operation.
* @param _dependencyType dependency to be updated.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @param _index Additional CDN index
*/
function removeDependencyAdditionalCDNAtIndex(
Expand Down Expand Up @@ -346,7 +395,7 @@ contract DependencyRegistryV0 is

/**
* @notice Updates additional CDN for dependency `_dependencyType` at `_index`.
* @param _dependencyType dependency to be updated.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @param _index Additional CDN index.
* @param _additionalCDN New CDN URL.
*/
Expand All @@ -373,7 +422,7 @@ contract DependencyRegistryV0 is

/**
* @notice Adds a new repository URL to dependency `_dependencyType`.
* @param _dependencyType dependency to be updated.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @param _additionalRepository Repository URL to be added. Required to be a non-empty string,
* but no further validation is performed.
*/
Expand Down Expand Up @@ -406,7 +455,7 @@ contract DependencyRegistryV0 is
* @notice Removes additional repository for depenency `_dependencyId` at index `_index`.
* Removal is done by swapping the element to be removed with the last element in the array, then deleting this last element.
* Assets with indices higher than `_index` can have their indices adjusted as a result of this operation.
* @param _dependencyType dependency to be updated.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @param _index Additional repository index.
*/
function removeDependencyAdditionalRepositoryAtIndex(
Expand Down Expand Up @@ -437,7 +486,7 @@ contract DependencyRegistryV0 is

/**
* @notice Updates additional repository for dependency `_dependencyType` at `_index`.
* @param _dependencyType dependency to be updated.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @param _index Additional repository index.
* @param _additionalRepository New Repository URL.
*/
Expand Down Expand Up @@ -500,7 +549,7 @@ contract DependencyRegistryV0 is
* type (`_dependencyType`).
* @param _contractAddress Core contract address.
* @param _projectId Project to override script type and version for.
* @param _dependencyType Dependency type to return for project.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
*/
function addProjectDependencyTypeOverride(
address _contractAddress,
Expand Down Expand Up @@ -581,8 +630,8 @@ contract DependencyRegistryV0 is
}

/**
* @notice Returns details for depedency type `_dependencyType`.
* @param _dependencyType Dependency type to be queried.
* @notice Returns details for a given depedency type `_dependencyType`.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @return typeAndVersion String representation of `_dependencyType`.
* (e.g. "p5js(atSymbol)1.0.0")
* @return preferredCDN Preferred CDN URL for dependency
Expand Down Expand Up @@ -682,7 +731,7 @@ contract DependencyRegistryV0 is

/**
* @notice Returns the additional CDN URL at index `_index` for dependency `_dependencyType`.
* @param _dependencyType Dependency type to be queried.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @param _index Index of the additional CDN URL to be returned.
*/
function getDependencyAdditionalCDNAtIndex(
Expand All @@ -694,7 +743,7 @@ contract DependencyRegistryV0 is

/**
* @notice Returns the additional repository URL at index `_index` for dependency `_dependencyType`.
* @param _dependencyType Dependency type to be queried.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @param _index Index of the additional repository URL to be returned.
*/
function getDependencyAdditionalRepositoryAtIndex(
Expand All @@ -707,7 +756,7 @@ contract DependencyRegistryV0 is

/**
* @notice Returns the count of scripts for dependency `_dependencyType`.
* @param _dependencyType Dependency type to be queried.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
*/
function getDependencyScriptCount(
bytes32 _dependencyType
Expand All @@ -717,7 +766,7 @@ contract DependencyRegistryV0 is

/**
* @notice Returns address with bytecode containing script for
* dependency `_dependencyTypes` at script index `_index`.
* dependency `_dependencyTypes` at script index `_index`.
*/
function getDependencyScriptBytecodeAddressAtIndex(
bytes32 _dependencyType,
Expand All @@ -727,10 +776,40 @@ contract DependencyRegistryV0 is
dependencyDetails[_dependencyType].scriptBytecodeAddresses[_index];
}

/**
* @notice Returns the storage library version for
* dependency `_dependencyTypes` at script index `_index`.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @param _index Index of script to be queried in the array of dependency script chunks.
* @return The storage library version for the script at the given index, if it can be determined.
* @dev Note that we only expect this to be determinable if the script was written using a version
* of the Art Blocks `BytecodeStorage` library, and in other cases the fallback will be the
* unknown version string, as defined by the `BytecodeStorage` UNKNOWN_VERSION_STRING – this
* is inclusive of the in the case of `SSTORE2` written data blobs, which are an unknown version
* that can be fallback-read optimistically.
*/
function getDependencyScriptBytecodeStorageVersionAtIndex(
bytes32 _dependencyType,
uint256 _index
ryley-o marked this conversation as resolved.
Show resolved Hide resolved
) external view returns (bytes32) {
return
BytecodeStorageReader.getLibraryVersionForBytecode(
dependencyDetails[_dependencyType].scriptBytecodeAddresses[
_index
jakerockland marked this conversation as resolved.
Show resolved Hide resolved
]
);
}

/**
* @notice Returns script for dependency `_dependencyType` at script index `_index`.
* @param _dependencyType dependency to be queried.
* @param _dependencyType Name of dependency type (i.e. "type@version") used to identify dependency.
* @param _index Index of script to be queried.
* @return A string containing the script content at the given script chunk index for a given dependency.
* @dev This method attempts to introspectively determine which library version of
* `BytecodeStorage` was used to write the stored script string that is being
* read back, in order to use the proper read approach. If the version is
* non-determinate, a fall-back to reading using the assumption that the bytes
* were written with `SSTORE2` is used.
jakerockland marked this conversation as resolved.
Show resolved Hide resolved
*/
function getDependencyScriptAtIndex(
bytes32 _dependencyType,
Expand All @@ -742,7 +821,20 @@ contract DependencyRegistryV0 is
return "";
}

return _readFromBytecode(dependency.scriptBytecodeAddresses[_index]);
address scriptAddress = dependency.scriptBytecodeAddresses[_index];
bytes32 storageVersion = BytecodeStorageReader
.getLibraryVersionForBytecode(scriptAddress);

if (storageVersion == BytecodeStorageReader.UNKNOWN_VERSION_STRING) {
return
ryley-o marked this conversation as resolved.
Show resolved Hide resolved
string(
BytecodeStorageReader.readBytesFromSSTORE2Bytecode(
scriptAddress
)
jakerockland marked this conversation as resolved.
Show resolved Hide resolved
);
} else {
return BytecodeStorageReader.readFromBytecode(scriptAddress);
}
}

/**
Expand All @@ -753,7 +845,7 @@ contract DependencyRegistryV0 is
* an override set, this will revert.
* @param _contractAddress Core contract address.
* @param _projectId Project to return dependency type for.
* @return dependencyType Dependency type used by project.
* @return dependencyType Identifier for the dependency (i.e. "type@version") used by project.
*/
function getDependencyTypeForProject(
address _contractAddress,
Expand Down Expand Up @@ -836,14 +928,4 @@ contract DependencyRegistryV0 is
OwnableUpgradeable._transferOwnership(newOwner);
adminACLContract = IAdminACLV0(newOwner);
}

/**
* Helper for calling `BytecodeStorageReader` external library reader method,
* added for bytecode size reduction purposes.
*/
function _readFromBytecode(
address _address
) internal view returns (string memory) {
return BytecodeStorageReader.readFromBytecode(_address);
}
}
Loading