parent
7e9084de37
commit
31dc57a57b
@ -0,0 +1,399 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
|
||||||
|
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
|
||||||
|
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Library for managing
|
||||||
|
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
|
||||||
|
* types.
|
||||||
|
*
|
||||||
|
* Sets have the following properties:
|
||||||
|
*
|
||||||
|
* - Elements are added, removed, and checked for existence in constant time
|
||||||
|
* (O(1)).
|
||||||
|
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* contract Example {
|
||||||
|
* // Add the library methods
|
||||||
|
* using EnumerableSet for EnumerableSet.AddressSet;
|
||||||
|
*
|
||||||
|
* // Declare a set state variable
|
||||||
|
* EnumerableSet.AddressSet private mySet;
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
|
||||||
|
* and `uint256` (`UintSet`) are supported.
|
||||||
|
*
|
||||||
|
* [WARNING]
|
||||||
|
* ====
|
||||||
|
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
|
||||||
|
* unusable.
|
||||||
|
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
|
||||||
|
*
|
||||||
|
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
|
||||||
|
* array of EnumerableSet.
|
||||||
|
* ====
|
||||||
|
*/
|
||||||
|
library EnumerableSet {
|
||||||
|
// To implement this library for multiple types with as little code
|
||||||
|
// repetition as possible, we write it in terms of a generic Set type with
|
||||||
|
// bytes32 values.
|
||||||
|
// The Set implementation uses private functions, and user-facing
|
||||||
|
// implementations (such as AddressSet) are just wrappers around the
|
||||||
|
// underlying Set.
|
||||||
|
// This means that we can only create new EnumerableSets for types that fit
|
||||||
|
// in bytes32.
|
||||||
|
|
||||||
|
struct Set {
|
||||||
|
// Storage of set values
|
||||||
|
bytes32[] _values;
|
||||||
|
// Position of the value in the `values` array, plus 1 because index 0
|
||||||
|
// means a value is not in the set.
|
||||||
|
mapping(bytes32 => uint256) _indexes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Add a value to a set. O(1).
|
||||||
|
*
|
||||||
|
* Returns true if the value was added to the set, that is if it was not
|
||||||
|
* already present.
|
||||||
|
*/
|
||||||
|
function _add(Set storage set, bytes32 value) private returns (bool) {
|
||||||
|
if (!_contains(set, value)) {
|
||||||
|
set._values.push(value);
|
||||||
|
// The value is stored at length-1, but we add 1 to all indexes
|
||||||
|
// and use 0 as a sentinel value
|
||||||
|
set._indexes[value] = set._values.length;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev replace a value to a set. O(1).
|
||||||
|
*
|
||||||
|
* Returns true if the value was added to the set, that is if it was not
|
||||||
|
* already present.
|
||||||
|
*/
|
||||||
|
function _replace(Set storage set, uint256 index, bytes32 oldValue , bytes32 newValue) private returns (bool) {
|
||||||
|
if (set._values[index-1] != oldValue){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
set._indexes[oldValue] = 0;
|
||||||
|
// 0 represents the value is empty
|
||||||
|
set._indexes[newValue] = index;
|
||||||
|
set._values[index-1] = newValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes a value from a set. O(1).
|
||||||
|
*
|
||||||
|
* Returns true if the value was removed from the set, that is if it was
|
||||||
|
* present.
|
||||||
|
*/
|
||||||
|
function _remove(Set storage set, bytes32 value) private returns (bool) {
|
||||||
|
// We read and store the value's index to prevent multiple reads from the same storage slot
|
||||||
|
uint256 valueIndex = set._indexes[value];
|
||||||
|
|
||||||
|
if (valueIndex != 0) {
|
||||||
|
// Equivalent to contains(set, value)
|
||||||
|
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
|
||||||
|
// the array, and then remove the last element (sometimes called as 'swap and pop').
|
||||||
|
// This modifies the order of the array, as noted in {at}.
|
||||||
|
|
||||||
|
uint256 toDeleteIndex = valueIndex - 1;
|
||||||
|
uint256 lastIndex = set._values.length - 1;
|
||||||
|
|
||||||
|
if (lastIndex != toDeleteIndex) {
|
||||||
|
bytes32 lastValue = set._values[lastIndex];
|
||||||
|
|
||||||
|
// Move the last value to the index where the value to delete is
|
||||||
|
set._values[toDeleteIndex] = lastValue;
|
||||||
|
// Update the index for the moved value
|
||||||
|
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the slot where the moved value was stored
|
||||||
|
set._values.pop();
|
||||||
|
|
||||||
|
// Delete the index for the deleted slot
|
||||||
|
delete set._indexes[value];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Returns true if the value is in the set. O(1).
|
||||||
|
*/
|
||||||
|
function _contains(Set storage set, bytes32 value) private view returns (bool) {
|
||||||
|
return set._indexes[value] != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Returns the number of values on the set. O(1).
|
||||||
|
*/
|
||||||
|
function _length(Set storage set) private view returns (uint256) {
|
||||||
|
return set._values.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Returns the value stored at position `index` in the set. O(1).
|
||||||
|
*
|
||||||
|
* Note that there are no guarantees on the ordering of values inside the
|
||||||
|
* array, and it may change when more values are added or removed.
|
||||||
|
*
|
||||||
|
* Requirements:
|
||||||
|
*
|
||||||
|
* - `index` must be strictly less than {length}.
|
||||||
|
*/
|
||||||
|
function _at(Set storage set, uint256 index) private view returns (bytes32) {
|
||||||
|
return set._values[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Return the entire set in an array
|
||||||
|
*
|
||||||
|
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
|
||||||
|
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
|
||||||
|
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
|
||||||
|
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function _values(Set storage set) private view returns (bytes32[] memory) {
|
||||||
|
return set._values;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes32Set
|
||||||
|
|
||||||
|
struct Bytes32Set {
|
||||||
|
Set _inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Add a value to a set. O(1).
|
||||||
|
*
|
||||||
|
* Returns true if the value was added to the set, that is if it was not
|
||||||
|
* already present.
|
||||||
|
*/
|
||||||
|
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
|
||||||
|
return _add(set._inner, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes a value from a set. O(1).
|
||||||
|
*
|
||||||
|
* Returns true if the value was removed from the set, that is if it was
|
||||||
|
* present.
|
||||||
|
*/
|
||||||
|
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
|
||||||
|
return _remove(set._inner, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Returns true if the value is in the set. O(1).
|
||||||
|
*/
|
||||||
|
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
|
||||||
|
return _contains(set._inner, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Returns the number of values in the set. O(1).
|
||||||
|
*/
|
||||||
|
function length(Bytes32Set storage set) internal view returns (uint256) {
|
||||||
|
return _length(set._inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Returns the value stored at position `index` in the set. O(1).
|
||||||
|
*
|
||||||
|
* Note that there are no guarantees on the ordering of values inside the
|
||||||
|
* array, and it may change when more values are added or removed.
|
||||||
|
*
|
||||||
|
* Requirements:
|
||||||
|
*
|
||||||
|
* - `index` must be strictly less than {length}.
|
||||||
|
*/
|
||||||
|
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
|
||||||
|
return _at(set._inner, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Return the entire set in an array
|
||||||
|
*
|
||||||
|
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
|
||||||
|
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
|
||||||
|
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
|
||||||
|
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
|
||||||
|
bytes32[] memory store = _values(set._inner);
|
||||||
|
bytes32[] memory result;
|
||||||
|
|
||||||
|
/// @solidity memory-safe-assembly
|
||||||
|
assembly {
|
||||||
|
result := store
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddressSet
|
||||||
|
|
||||||
|
struct AddressSet {
|
||||||
|
Set _inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Add a value to a set. O(1).
|
||||||
|
*
|
||||||
|
* Returns true if the value was added to the set, that is if it was not
|
||||||
|
* already present.
|
||||||
|
*/
|
||||||
|
function add(AddressSet storage set, address value) internal returns (bool) {
|
||||||
|
return _add(set._inner, bytes32(uint256(uint160(value))));
|
||||||
|
}
|
||||||
|
|
||||||
|
function replace(AddressSet storage set,uint256 index, address oldValue, address newValue) internal returns (bool) {
|
||||||
|
return _replace(set._inner, index ,bytes32(uint256(uint160(oldValue))), bytes32(uint256(uint160(newValue))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes a value from a set. O(1).
|
||||||
|
*
|
||||||
|
* Returns true if the value was removed from the set, that is if it was
|
||||||
|
* present.
|
||||||
|
*/
|
||||||
|
function remove(AddressSet storage set, address value) internal returns (bool) {
|
||||||
|
return _remove(set._inner, bytes32(uint256(uint160(value))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Returns true if the value is in the set. O(1).
|
||||||
|
*/
|
||||||
|
function contains(AddressSet storage set, address value) internal view returns (bool) {
|
||||||
|
return _contains(set._inner, bytes32(uint256(uint160(value))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Returns the number of values in the set. O(1).
|
||||||
|
*/
|
||||||
|
function length(AddressSet storage set) internal view returns (uint256) {
|
||||||
|
return _length(set._inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Returns the value stored at position `index` in the set. O(1).
|
||||||
|
*
|
||||||
|
* Note that there are no guarantees on the ordering of values inside the
|
||||||
|
* array, and it may change when more values are added or removed.
|
||||||
|
*
|
||||||
|
* Requirements:
|
||||||
|
*
|
||||||
|
* - `index` must be strictly less than {length}.
|
||||||
|
*/
|
||||||
|
function at(AddressSet storage set, uint256 index) internal view returns (address) {
|
||||||
|
return address(uint160(uint256(_at(set._inner, index))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Return the entire set in an array
|
||||||
|
*
|
||||||
|
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
|
||||||
|
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
|
||||||
|
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
|
||||||
|
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function values(AddressSet storage set) internal view returns (address[] memory) {
|
||||||
|
bytes32[] memory store = _values(set._inner);
|
||||||
|
address[] memory result;
|
||||||
|
|
||||||
|
/// @solidity memory-safe-assembly
|
||||||
|
assembly {
|
||||||
|
result := store
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintSet
|
||||||
|
|
||||||
|
struct UintSet {
|
||||||
|
Set _inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Add a value to a set. O(1).
|
||||||
|
*
|
||||||
|
* Returns true if the value was added to the set, that is if it was not
|
||||||
|
* already present.
|
||||||
|
*/
|
||||||
|
function add(UintSet storage set, uint256 value) internal returns (bool) {
|
||||||
|
return _add(set._inner, bytes32(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes a value from a set. O(1).
|
||||||
|
*
|
||||||
|
* Returns true if the value was removed from the set, that is if it was
|
||||||
|
* present.
|
||||||
|
*/
|
||||||
|
function remove(UintSet storage set, uint256 value) internal returns (bool) {
|
||||||
|
return _remove(set._inner, bytes32(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Returns true if the value is in the set. O(1).
|
||||||
|
*/
|
||||||
|
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
|
||||||
|
return _contains(set._inner, bytes32(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Returns the number of values in the set. O(1).
|
||||||
|
*/
|
||||||
|
function length(UintSet storage set) internal view returns (uint256) {
|
||||||
|
return _length(set._inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Returns the value stored at position `index` in the set. O(1).
|
||||||
|
*
|
||||||
|
* Note that there are no guarantees on the ordering of values inside the
|
||||||
|
* array, and it may change when more values are added or removed.
|
||||||
|
*
|
||||||
|
* Requirements:
|
||||||
|
*
|
||||||
|
* - `index` must be strictly less than {length}.
|
||||||
|
*/
|
||||||
|
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
|
||||||
|
return uint256(_at(set._inner, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Return the entire set in an array
|
||||||
|
*
|
||||||
|
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
|
||||||
|
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
|
||||||
|
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
|
||||||
|
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function values(UintSet storage set) internal view returns (uint256[] memory) {
|
||||||
|
bytes32[] memory store = _values(set._inner);
|
||||||
|
uint256[] memory result;
|
||||||
|
|
||||||
|
/// @solidity memory-safe-assembly
|
||||||
|
assembly {
|
||||||
|
result := store
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +0,0 @@
|
|||||||
pragma solidity ^0.8.0;
|
|
||||||
|
|
||||||
// import "hardhat/console.sol";
|
|
||||||
// import "@openzeppelin/contracts/access/Ownable.sol";
|
|
||||||
import "./Hub.sol";
|
|
||||||
|
|
||||||
contract HubFactory {
|
|
||||||
function createHub() public returns(Hub){
|
|
||||||
Hub hub = new Hub();
|
|
||||||
return hub;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,111 +0,0 @@
|
|||||||
pragma solidity ^0.8.0;
|
|
||||||
|
|
||||||
import "./storage/IStorageLayer.sol";
|
|
||||||
import "./RepositoryAccess.sol";
|
|
||||||
|
|
||||||
contract Repository is RepositoryAccess{
|
|
||||||
|
|
||||||
struct refInfo {
|
|
||||||
bytes20 hash;
|
|
||||||
uint96 index;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct refData {
|
|
||||||
bytes20 hash;
|
|
||||||
bytes name;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes repositoryName;
|
|
||||||
address creator;
|
|
||||||
address[] public contributorList;
|
|
||||||
|
|
||||||
mapping(bytes => refInfo) public branchToRefInfo; // dev => {hash: 0x1234..., index: 1 }
|
|
||||||
bytes[] public branchs; // 有几条branch,就有几个reference
|
|
||||||
|
|
||||||
IStorageLayer public storageManager;
|
|
||||||
bytes32 constant public ETHSTORAGEID_LAYER = bytes32(keccak256("ETHSTORAGE"));
|
|
||||||
bytes32 constant public NFTSTORAGE_LAYER = bytes32(keccak256("NFTSTORAGE"));
|
|
||||||
constructor(bytes memory repoName){
|
|
||||||
creator = msg.sender;
|
|
||||||
repositoryName = repoName;
|
|
||||||
}
|
|
||||||
|
|
||||||
modifier onlyCreator() {
|
|
||||||
require(address(storageManager) == msg.sender, "only creator");
|
|
||||||
_;
|
|
||||||
}
|
|
||||||
|
|
||||||
function listBranchs() external view returns (refData[] memory list) {
|
|
||||||
list = new refData[](branchs.length);
|
|
||||||
for (uint index = 0; index < branchs.length; index++) {
|
|
||||||
list[index] = _convertToRefData(
|
|
||||||
branchToRefInfo[branchs[index]]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createBranch(bytes memory branch,bytes20 refHash) public onlyCreator {
|
|
||||||
bytes memory fullname = bytes.concat(repositoryName,"/",branch);
|
|
||||||
require(refHash!=bytes20(0),"reference hash don't allow to set 0x0" );
|
|
||||||
require(branchToRefInfo[fullname].hash == bytes20(0),"branch already exists");
|
|
||||||
branchToRefInfo[fullname].hash = refHash;
|
|
||||||
branchToRefInfo[fullname].index = uint96(branchs.length);
|
|
||||||
branchs.push(fullname);
|
|
||||||
|
|
||||||
// add branch owner
|
|
||||||
this.addBranchOperator(fullname,msg.sender);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function updateBranch(
|
|
||||||
bytes memory branch,
|
|
||||||
bytes20 refHash
|
|
||||||
)external onlyBranchOperator(branch){
|
|
||||||
bytes memory fullname = bytes.concat(repositoryName,"/",branch);
|
|
||||||
require(refHash!=bytes20(0),"reference hash don't allow to set 0x0" );
|
|
||||||
require(branchToRefInfo[fullname].hash != bytes20(0),"branch do not exist");
|
|
||||||
branchToRefInfo[fullname].hash = refHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeBranch(
|
|
||||||
bytes memory branch
|
|
||||||
) external {
|
|
||||||
bytes memory fullname = bytes.concat(repositoryName,"/",branch);
|
|
||||||
refInfo memory refI = branchToRefInfo[fullname];
|
|
||||||
require(
|
|
||||||
refI.hash != bytes20(0),
|
|
||||||
"Reference of this name does not exist"
|
|
||||||
);
|
|
||||||
uint256 lastIndex = branchs.length -1 ;
|
|
||||||
if (refI.index < lastIndex){
|
|
||||||
branchToRefInfo[branchs[lastIndex]].index = refI.index;
|
|
||||||
branchs[refI.index] = branchs[lastIndex];
|
|
||||||
}
|
|
||||||
branchs.pop();
|
|
||||||
delete branchToRefInfo[fullname];
|
|
||||||
}
|
|
||||||
|
|
||||||
function _convertToRefData(
|
|
||||||
refInfo memory info
|
|
||||||
) internal view returns (refData memory res) {
|
|
||||||
res.hash = info.hash;
|
|
||||||
res.name = branchs[info.index];
|
|
||||||
}
|
|
||||||
|
|
||||||
// data storage module
|
|
||||||
|
|
||||||
function setStorageLayer(IStorageLayer addr) external onlyCreator {
|
|
||||||
storageManager = addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
function upload(
|
|
||||||
bytes20 refHash,
|
|
||||||
bytes calldata data
|
|
||||||
) external payable {
|
|
||||||
storageManager.upload(refHash, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
function download(bytes20 refHash) external view returns(bytes32 storageLayerId , bytes memory data){
|
|
||||||
return storageManager.download(refHash);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
pragma solidity ^0.8.0;
|
|
||||||
|
|
||||||
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
|
|
||||||
|
|
||||||
contract RepositoryAccess{
|
|
||||||
using EnumerableSet for EnumerableSet.AddressSet;
|
|
||||||
mapping(bytes => EnumerableSet.AddressSet) BranchOperators;
|
|
||||||
|
|
||||||
modifier onlyBranchOperator(bytes memory branch) {
|
|
||||||
require(BranchOperators[branch].contains(msg.sender),"only branch Operator");
|
|
||||||
_;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _getBranchOwner(bytes memory branch) internal view returns(address){
|
|
||||||
return BranchOperators[branch].at(0) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
function addBranchOperator(bytes memory branch, address member) external virtual{
|
|
||||||
require(_getBranchOwner(branch) == msg.sender,"only branch owner");
|
|
||||||
BranchOperators[branch].add(member);
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeBranchOperator(bytes memory branch , address member) external virtual{
|
|
||||||
require(_getBranchOwner(branch) == msg.sender,"only branch owner");
|
|
||||||
BranchOperators[branch].remove(member);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,77 @@
|
|||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
library RepositoryLib {
|
||||||
|
|
||||||
|
struct refInfo {
|
||||||
|
bytes20 hash;
|
||||||
|
uint96 index;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct refData {
|
||||||
|
bytes20 hash;
|
||||||
|
bytes name;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BranchInfo{
|
||||||
|
mapping(bytes => refInfo) branchToRefInfo; // dev => {hash: 0x1234..., index: 1 }
|
||||||
|
bytes[] branchs; // 有几条branch,就有几个reference
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function listBranchs(BranchInfo storage info) external view returns (refData[] memory list) {
|
||||||
|
list = new refData[](info.branchs.length);
|
||||||
|
for (uint index = 0; index < info.branchs.length; index++) {
|
||||||
|
list[index] = _convertToRefData(
|
||||||
|
info,
|
||||||
|
info.branchToRefInfo[info.branchs[index]]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateBranch(
|
||||||
|
BranchInfo storage info,
|
||||||
|
bytes memory repositoryName,
|
||||||
|
bytes memory branch,
|
||||||
|
bytes20 refHash
|
||||||
|
) external {
|
||||||
|
bytes memory fullname = bytes.concat(repositoryName,"/",branch);
|
||||||
|
require(refHash!=bytes20(0),"reference hash don't allow to set 0x0" );
|
||||||
|
if (info.branchToRefInfo[fullname].hash==bytes20(0)) {
|
||||||
|
info.branchToRefInfo[fullname].hash = refHash;
|
||||||
|
info.branchToRefInfo[fullname].index = uint96(info.branchs.length);
|
||||||
|
info.branchs.push(fullname);
|
||||||
|
}else {
|
||||||
|
info.branchToRefInfo[fullname].hash = refHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeBranch(
|
||||||
|
BranchInfo storage info,
|
||||||
|
bytes memory repositoryName,
|
||||||
|
bytes memory branch
|
||||||
|
) external {
|
||||||
|
bytes memory fullname = bytes.concat(repositoryName,"/",branch);
|
||||||
|
refInfo memory refI = info.branchToRefInfo[fullname];
|
||||||
|
require(
|
||||||
|
refI.hash != bytes20(0),
|
||||||
|
"Reference of this name does not exist"
|
||||||
|
);
|
||||||
|
uint256 lastIndex = info.branchs.length -1 ;
|
||||||
|
if (refI.index < lastIndex){
|
||||||
|
info.branchToRefInfo[info.branchs[lastIndex]].index = refI.index;
|
||||||
|
info.branchs[refI.index] = info.branchs[lastIndex];
|
||||||
|
}
|
||||||
|
info.branchs.pop();
|
||||||
|
delete info.branchToRefInfo[fullname];
|
||||||
|
}
|
||||||
|
|
||||||
|
function _convertToRefData(
|
||||||
|
BranchInfo storage info,
|
||||||
|
refInfo memory rInfo
|
||||||
|
) internal view returns (refData memory res) {
|
||||||
|
res.hash = rInfo.hash;
|
||||||
|
res.name = info.branchs[rInfo.index];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,273 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "./optimize/SlotHelper.sol";
|
||||||
|
import "./StorageHelperV2.sol";
|
||||||
|
import "./StorageSlotSelfDestructableV2.sol";
|
||||||
|
|
||||||
|
// Large storage manager to support arbitrarily-sized data with multiple chunk
|
||||||
|
contract LargeStorageManagerV2 {
|
||||||
|
using SlotHelper for bytes32;
|
||||||
|
using SlotHelper for address;
|
||||||
|
|
||||||
|
uint8 internal constant SLOT_LIMIT = 0;
|
||||||
|
mapping(bytes32 => mapping(uint256 => bytes32)) internal keyToMetadata;
|
||||||
|
mapping(bytes32 => mapping(uint256 => mapping(uint256 => bytes32)))
|
||||||
|
internal keyToSlots;
|
||||||
|
|
||||||
|
function isOptimize() public pure returns (bool) {
|
||||||
|
return SLOT_LIMIT > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _preparePut(bytes32 key, uint256 chunkId) private {
|
||||||
|
bytes32 metadata = keyToMetadata[key][chunkId];
|
||||||
|
|
||||||
|
if (metadata == bytes32(0)) {
|
||||||
|
require(
|
||||||
|
chunkId == 0 || keyToMetadata[key][chunkId - 1] != bytes32(0x0),
|
||||||
|
"must replace or append"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!metadata.isInSlot()) {
|
||||||
|
address addr = metadata.bytes32ToAddr();
|
||||||
|
if (addr != address(0x0)) {
|
||||||
|
// remove the KV first if it exists
|
||||||
|
StorageSlotSelfDestructableV2(addr).destruct();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _putChunkFromCalldata(
|
||||||
|
bytes32 key,
|
||||||
|
uint256 chunkId,
|
||||||
|
bytes calldata data,
|
||||||
|
uint256 value
|
||||||
|
) internal {
|
||||||
|
_preparePut(key, chunkId);
|
||||||
|
|
||||||
|
// store data and rewrite metadata
|
||||||
|
if (data.length > SLOT_LIMIT) {
|
||||||
|
keyToMetadata[key][chunkId] = StorageHelperV2
|
||||||
|
.putRawFromCalldata(data, value)
|
||||||
|
.addrToBytes32();
|
||||||
|
} else {
|
||||||
|
keyToMetadata[key][chunkId] = SlotHelper.putRaw(
|
||||||
|
keyToSlots[key][chunkId],
|
||||||
|
data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _putChunk(
|
||||||
|
bytes32 key,
|
||||||
|
uint256 chunkId,
|
||||||
|
bytes memory data,
|
||||||
|
uint256 value
|
||||||
|
) internal {
|
||||||
|
_preparePut(key, chunkId);
|
||||||
|
|
||||||
|
// store data and rewrite metadata
|
||||||
|
if (data.length > SLOT_LIMIT) {
|
||||||
|
keyToMetadata[key][chunkId] = StorageHelperV2
|
||||||
|
.putRaw(data, value)
|
||||||
|
.addrToBytes32();
|
||||||
|
} else {
|
||||||
|
keyToMetadata[key][chunkId] = SlotHelper.putRaw(
|
||||||
|
keyToSlots[key][chunkId],
|
||||||
|
data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getChunkAddr(
|
||||||
|
bytes32 key,
|
||||||
|
uint256 chunkId
|
||||||
|
) internal view returns (address) {
|
||||||
|
bytes32 metadata = keyToMetadata[key][chunkId];
|
||||||
|
address addr = metadata.bytes32ToAddr();
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getChunk(
|
||||||
|
bytes32 key,
|
||||||
|
uint256 chunkId
|
||||||
|
) internal view returns (bytes memory, bool) {
|
||||||
|
bytes32 metadata = keyToMetadata[key][chunkId];
|
||||||
|
|
||||||
|
if (metadata.isInSlot()) {
|
||||||
|
bytes memory res = SlotHelper.getRaw(
|
||||||
|
keyToSlots[key][chunkId],
|
||||||
|
metadata
|
||||||
|
);
|
||||||
|
return (res, true);
|
||||||
|
} else {
|
||||||
|
address addr = metadata.bytes32ToAddr();
|
||||||
|
return StorageHelperV2.getRaw(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _stakeTokens(
|
||||||
|
bytes32 key,
|
||||||
|
uint256 chunkId
|
||||||
|
) internal view returns (uint256) {
|
||||||
|
uint256 stakeNum = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
(uint256 count, bool found) = _chunkStakeTokens(key, chunkId);
|
||||||
|
if (!found) {
|
||||||
|
return stakeNum;
|
||||||
|
}
|
||||||
|
stakeNum += count;
|
||||||
|
chunkId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stakeNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _chunkStakeTokens(
|
||||||
|
bytes32 key,
|
||||||
|
uint256 chunkId
|
||||||
|
) internal view returns (uint256, bool) {
|
||||||
|
bytes32 metadata = keyToMetadata[key][chunkId];
|
||||||
|
if (metadata == bytes32(0)) {
|
||||||
|
return (0, false);
|
||||||
|
} else if (metadata.isInSlot()) {
|
||||||
|
return (0, true);
|
||||||
|
} else {
|
||||||
|
address addr = metadata.bytes32ToAddr();
|
||||||
|
return (addr.balance, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _chunkSize(
|
||||||
|
bytes32 key,
|
||||||
|
uint256 chunkId
|
||||||
|
) internal view returns (uint256, bool) {
|
||||||
|
bytes32 metadata = keyToMetadata[key][chunkId];
|
||||||
|
|
||||||
|
if (metadata == bytes32(0)) {
|
||||||
|
return (0, false);
|
||||||
|
} else if (metadata.isInSlot()) {
|
||||||
|
uint256 len = metadata.decodeLen();
|
||||||
|
return (len, true);
|
||||||
|
} else {
|
||||||
|
address addr = metadata.bytes32ToAddr();
|
||||||
|
return StorageHelperV2.sizeRaw(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _countChunks(bytes32 key) internal view returns (uint256) {
|
||||||
|
uint256 chunkId = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
bytes32 metadata = keyToMetadata[key][chunkId];
|
||||||
|
if (metadata == bytes32(0x0)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunkId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunkId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns (size, # of chunks).
|
||||||
|
function _size(bytes32 key) internal view returns (uint256, uint256) {
|
||||||
|
uint256 size = 0;
|
||||||
|
uint256 chunkId = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
(uint256 chunkSize, bool found) = _chunkSize(key, chunkId);
|
||||||
|
if (!found) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
size += chunkSize;
|
||||||
|
chunkId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (size, chunkId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _get(bytes32 key) internal view returns (bytes memory, bool) {
|
||||||
|
(uint256 size, uint256 chunkNum) = _size(key);
|
||||||
|
if (chunkNum == 0) {
|
||||||
|
return (new bytes(0), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes memory data = new bytes(size); // solidity should auto-align the memory-size to 32
|
||||||
|
uint256 dataPtr;
|
||||||
|
assembly {
|
||||||
|
dataPtr := add(data, 0x20)
|
||||||
|
}
|
||||||
|
for (uint256 chunkId = 0; chunkId < chunkNum; chunkId++) {
|
||||||
|
bytes32 metadata = keyToMetadata[key][chunkId];
|
||||||
|
|
||||||
|
uint256 chunkSize = 0;
|
||||||
|
if (metadata.isInSlot()) {
|
||||||
|
chunkSize = metadata.decodeLen();
|
||||||
|
SlotHelper.getRawAt(
|
||||||
|
keyToSlots[key][chunkId],
|
||||||
|
metadata,
|
||||||
|
dataPtr
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
address addr = metadata.bytes32ToAddr();
|
||||||
|
(chunkSize, ) = StorageHelperV2.sizeRaw(addr);
|
||||||
|
StorageHelperV2.getRawAt(addr, dataPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
dataPtr += chunkSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (data, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns # of chunks deleted
|
||||||
|
function _remove(bytes32 key, uint256 chunkId) internal returns (uint256) {
|
||||||
|
while (true) {
|
||||||
|
bytes32 metadata = keyToMetadata[key][chunkId];
|
||||||
|
if (metadata == bytes32(0x0)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!metadata.isInSlot()) {
|
||||||
|
address addr = metadata.bytes32ToAddr();
|
||||||
|
// remove new contract
|
||||||
|
StorageSlotSelfDestructableV2(addr).destruct();
|
||||||
|
}
|
||||||
|
|
||||||
|
keyToMetadata[key][chunkId] = bytes32(0x0);
|
||||||
|
|
||||||
|
chunkId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunkId;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _removeChunk(
|
||||||
|
bytes32 key,
|
||||||
|
uint256 chunkId
|
||||||
|
) internal returns (bool) {
|
||||||
|
bytes32 metadata = keyToMetadata[key][chunkId];
|
||||||
|
if (metadata == bytes32(0x0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyToMetadata[key][chunkId + 1] != bytes32(0x0)) {
|
||||||
|
// only the last chunk can be removed
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!metadata.isInSlot()) {
|
||||||
|
address addr = metadata.bytes32ToAddr();
|
||||||
|
// remove new contract
|
||||||
|
StorageSlotSelfDestructableV2(addr).destruct();
|
||||||
|
}
|
||||||
|
|
||||||
|
keyToMetadata[key][chunkId] = bytes32(0x0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "./LargeStorageManagerV2.sol";
|
||||||
|
|
||||||
|
contract LargeStorageManagerV2Test is LargeStorageManagerV2 {
|
||||||
|
function get(bytes32 key) public view returns (bytes memory, bool) {
|
||||||
|
(bytes memory data, bool found) = _get(key);
|
||||||
|
return (data, found);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getChunk(
|
||||||
|
bytes32 key,
|
||||||
|
uint256 chunkId
|
||||||
|
) public view returns (bytes memory, bool) {
|
||||||
|
(bytes memory data, bool found) = _getChunk(key, chunkId);
|
||||||
|
return (data, found);
|
||||||
|
}
|
||||||
|
|
||||||
|
function putChunk(
|
||||||
|
bytes32 key,
|
||||||
|
uint256 chunkId,
|
||||||
|
bytes memory data
|
||||||
|
) public payable {
|
||||||
|
_putChunk(key, chunkId, data, msg.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function putChunkFromCalldata(
|
||||||
|
bytes32 key,
|
||||||
|
uint256 chunkId,
|
||||||
|
bytes calldata data
|
||||||
|
) public payable {
|
||||||
|
_putChunkFromCalldata(key, chunkId, data, msg.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function size(bytes32 key) public view returns (uint256, uint256) {
|
||||||
|
return _size(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function chunkSize(
|
||||||
|
bytes32 key,
|
||||||
|
uint256 chunkId
|
||||||
|
) public view returns (uint256, bool) {
|
||||||
|
return _chunkSize(key, chunkId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function countChunks(bytes32 key) public view returns (uint256) {
|
||||||
|
return _countChunks(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function remove(bytes32 key) public {
|
||||||
|
_remove(key, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeChunk(bytes32 key, uint256 chunkId) public {
|
||||||
|
_removeChunk(key, chunkId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBalance() public view returns (uint256 balance) {
|
||||||
|
return address(this).balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
function stakeTokens(
|
||||||
|
bytes32 key,
|
||||||
|
uint256 chunkId
|
||||||
|
) public view returns (uint256) {
|
||||||
|
return _stakeTokens(key, chunkId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function chunkStakeTokens(
|
||||||
|
bytes32 key,
|
||||||
|
uint256 chunkId
|
||||||
|
) public view returns (uint256, bool) {
|
||||||
|
return _chunkStakeTokens(key, chunkId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getChunkAddr(
|
||||||
|
bytes32 key,
|
||||||
|
uint256 chunkId
|
||||||
|
) public view returns (address) {
|
||||||
|
return _getChunkAddr(key, chunkId);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,187 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
library Memory {
|
||||||
|
// Size of a word, in bytes.
|
||||||
|
uint256 internal constant WORD_SIZE = 32;
|
||||||
|
// Size of the header of a 'bytes' array.
|
||||||
|
uint256 internal constant BYTES_HEADER_SIZE = 32;
|
||||||
|
// Address of the free memory pointer.
|
||||||
|
uint256 internal constant FREE_MEM_PTR = 0x40;
|
||||||
|
|
||||||
|
// Compares the 'len' bytes starting at address 'addr' in memory with the 'len'
|
||||||
|
// bytes starting at 'addr2'.
|
||||||
|
// Returns 'true' if the bytes are the same, otherwise 'false'.
|
||||||
|
function equals(
|
||||||
|
uint256 addr,
|
||||||
|
uint256 addr2,
|
||||||
|
uint256 len
|
||||||
|
) internal pure returns (bool equal) {
|
||||||
|
assembly {
|
||||||
|
equal := eq(keccak256(addr, len), keccak256(addr2, len))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compares the 'len' bytes starting at address 'addr' in memory with the bytes stored in
|
||||||
|
// 'bts'. It is allowed to set 'len' to a lower value then 'bts.length', in which case only
|
||||||
|
// the first 'len' bytes will be compared.
|
||||||
|
// Requires that 'bts.length >= len'
|
||||||
|
function equals(
|
||||||
|
uint256 addr,
|
||||||
|
uint256 len,
|
||||||
|
bytes memory bts
|
||||||
|
) internal pure returns (bool equal) {
|
||||||
|
require(bts.length >= len);
|
||||||
|
uint256 addr2;
|
||||||
|
assembly {
|
||||||
|
addr2 := add(
|
||||||
|
bts,
|
||||||
|
/*BYTES_HEADER_SIZE*/
|
||||||
|
32
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return equals(addr, addr2, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocates 'numBytes' bytes in memory. This will prevent the Solidity compiler
|
||||||
|
// from using this area of memory. It will also initialize the area by setting
|
||||||
|
// each byte to '0'.
|
||||||
|
function allocate(uint256 numBytes) internal pure returns (uint256 addr) {
|
||||||
|
// Take the current value of the free memory pointer, and update.
|
||||||
|
assembly {
|
||||||
|
addr := mload(
|
||||||
|
/*FREE_MEM_PTR*/
|
||||||
|
0x40
|
||||||
|
)
|
||||||
|
mstore(
|
||||||
|
/*FREE_MEM_PTR*/
|
||||||
|
0x40,
|
||||||
|
add(addr, numBytes)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
uint256 words = (numBytes + WORD_SIZE - 1) / WORD_SIZE;
|
||||||
|
for (uint256 i = 0; i < words; i++) {
|
||||||
|
assembly {
|
||||||
|
mstore(
|
||||||
|
add(
|
||||||
|
addr,
|
||||||
|
mul(
|
||||||
|
i,
|
||||||
|
/*WORD_SIZE*/
|
||||||
|
32
|
||||||
|
)
|
||||||
|
),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy 'len' bytes from memory address 'src', to address 'dest'.
|
||||||
|
// This function does not check the or destination, it only copies
|
||||||
|
// the bytes.
|
||||||
|
function copy(uint256 src, uint256 dest, uint256 len) internal pure {
|
||||||
|
// Copy word-length chunks while possible
|
||||||
|
// Reverse copy to prevent out of memory bound error
|
||||||
|
src = src + len;
|
||||||
|
dest = dest + len;
|
||||||
|
for (; len >= WORD_SIZE; len -= WORD_SIZE) {
|
||||||
|
dest -= WORD_SIZE;
|
||||||
|
src -= WORD_SIZE;
|
||||||
|
|
||||||
|
assembly {
|
||||||
|
mstore(dest, mload(src))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy remaining bytes
|
||||||
|
src = src - len;
|
||||||
|
dest = dest - len;
|
||||||
|
assembly {
|
||||||
|
mstore(dest, mload(src))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a memory pointer to the provided bytes array.
|
||||||
|
function ptr(bytes memory bts) internal pure returns (uint256 addr) {
|
||||||
|
assembly {
|
||||||
|
addr := bts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a memory pointer to the data portion of the provided bytes array.
|
||||||
|
function dataPtr(bytes memory bts) internal pure returns (uint256 addr) {
|
||||||
|
assembly {
|
||||||
|
addr := add(
|
||||||
|
bts,
|
||||||
|
/*BYTES_HEADER_SIZE*/
|
||||||
|
32
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function does the same as 'dataPtr(bytes memory)', but will also return the
|
||||||
|
// length of the provided bytes array.
|
||||||
|
function fromBytes(
|
||||||
|
bytes memory bts
|
||||||
|
) internal pure returns (uint256 addr, uint256 len) {
|
||||||
|
len = bts.length;
|
||||||
|
assembly {
|
||||||
|
addr := add(
|
||||||
|
bts,
|
||||||
|
/*BYTES_HEADER_SIZE*/
|
||||||
|
32
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a 'bytes memory' variable from the memory address 'addr', with the
|
||||||
|
// length 'len'. The function will allocate new memory for the bytes array, and
|
||||||
|
// the 'len bytes starting at 'addr' will be copied into that new memory.
|
||||||
|
function toBytes(
|
||||||
|
uint256 addr,
|
||||||
|
uint256 len
|
||||||
|
) internal pure returns (bytes memory bts) {
|
||||||
|
bts = new bytes(len);
|
||||||
|
uint256 btsptr;
|
||||||
|
assembly {
|
||||||
|
btsptr := add(
|
||||||
|
bts,
|
||||||
|
/*BYTES_HEADER_SIZE*/
|
||||||
|
32
|
||||||
|
)
|
||||||
|
}
|
||||||
|
copy(addr, btsptr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the word stored at memory address 'addr' as a 'uint'.
|
||||||
|
function toUint(uint256 addr) internal pure returns (uint256 n) {
|
||||||
|
assembly {
|
||||||
|
n := mload(addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the word stored at memory address 'addr' as a 'bytes32'.
|
||||||
|
function toBytes32(uint256 addr) internal pure returns (bytes32 bts) {
|
||||||
|
assembly {
|
||||||
|
bts := mload(addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Get the byte stored at memory address 'addr' as a 'byte'.
|
||||||
|
function toByte(uint addr, uint8 index) internal pure returns (byte b) {
|
||||||
|
require(index < WORD_SIZE);
|
||||||
|
uint8 n;
|
||||||
|
assembly {
|
||||||
|
n := byte(index, mload(addr))
|
||||||
|
}
|
||||||
|
b = byte(n);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
@ -0,0 +1,224 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "./Memory.sol";
|
||||||
|
import "./StorageSlotFactory.sol";
|
||||||
|
|
||||||
|
library StorageHelperV2 {
|
||||||
|
// StorageSlotSelfDestructableV2 compiled via solc 0.8.7 optimized 200
|
||||||
|
bytes internal constant STORAGE_SLOT_CODE_V2 =
|
||||||
|
hex"6080604052348015600f57600080fd5b506004361060285760003560e01c80632b68b9c614602d575b600080fd5b60336035565b005b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161460965760405162461bcd60e51b81526020600482015260036024820152624e464f60e81b604482015260640160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316fffea2646970667358221220154417754813d1989858c876ab2ded2ba1aa380679fff7a4c8faea076ba020e664736f6c63430008070033";
|
||||||
|
uint256 internal constant OWNER_ADDR_OFF = 64;
|
||||||
|
uint256 internal constant USER_ADDR_OFF = 152;
|
||||||
|
|
||||||
|
// StorageSlotFactoryFromInput compiled via solc 0.8.7 optimized 200 + STORAGE_SLOT_CODE
|
||||||
|
bytes internal constant FACTORY_CODE =
|
||||||
|
hex"60806040526040516101113803806101118339810160408190526100229161002b565b80518060208301f35b6000602080838503121561003e57600080fd5b82516001600160401b038082111561005557600080fd5b818501915085601f83011261006957600080fd5b81518181111561007b5761007b6100fa565b604051601f8201601f19908116603f011681019083821181831017156100a3576100a36100fa565b8160405282815288868487010111156100bb57600080fd5b600093505b828410156100dd57848401860151818501870152928501926100c0565b828411156100ee5760008684830101525b98975050505050505050565b634e487b7160e01b600052604160045260246000fdfe000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000006080604052348015600f57600080fd5b506004361060325760003560e01c80632b68b9c61460375780638da5cb5b14603f575b600080fd5b603d6081565b005b60657f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161460ed5760405162461bcd60e51b815260206004820152600e60248201526d3737ba10333937b69037bbb732b960911b604482015260640160405180910390fd5b33fffea2646970667358221220fc66c9afb7cb2f6209ae28167cf26c6c06f86a82cbe3c56de99027979389a1be64736f6c63430008070033";
|
||||||
|
uint256 internal constant FACTORY_SIZE_OFF = 305;
|
||||||
|
uint256 internal constant FACTORY_ADDR_OFF0 = 305 + 32 + OWNER_ADDR_OFF;
|
||||||
|
uint256 internal constant FACTORY_ADDR_OFF1 = 305 + 32 + USER_ADDR_OFF;
|
||||||
|
|
||||||
|
function putRawFromCalldata(
|
||||||
|
bytes calldata data,
|
||||||
|
uint256 value
|
||||||
|
) internal returns (address) {
|
||||||
|
bytes memory bytecode = bytes.concat(STORAGE_SLOT_CODE_V2, data);
|
||||||
|
address userAddr = msg.sender;
|
||||||
|
{
|
||||||
|
// revise the owner to the contract (so that it is destructable)
|
||||||
|
uint256 off = OWNER_ADDR_OFF + 0x20;
|
||||||
|
assembly {
|
||||||
|
mstore(add(bytecode, off), address())
|
||||||
|
}
|
||||||
|
off = USER_ADDR_OFF + 0x20;
|
||||||
|
assembly {
|
||||||
|
mstore(add(bytecode, off), userAddr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageSlotFactoryFromInput c = new StorageSlotFactoryFromInput{
|
||||||
|
value: value
|
||||||
|
}(bytecode);
|
||||||
|
return address(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
function putRaw(
|
||||||
|
bytes memory data,
|
||||||
|
uint256 value
|
||||||
|
) internal returns (address) {
|
||||||
|
// create the new contract code with the data
|
||||||
|
bytes memory bytecode = STORAGE_SLOT_CODE_V2;
|
||||||
|
uint256 bytecodeLen = bytecode.length;
|
||||||
|
uint256 newSize = bytecode.length + data.length;
|
||||||
|
assembly {
|
||||||
|
// in-place resize of bytecode bytes
|
||||||
|
// note that this must be done when bytecode is the last allocated object by solidity.
|
||||||
|
mstore(bytecode, newSize)
|
||||||
|
// notify solidity about the memory size increase, must be 32-bytes aligned
|
||||||
|
mstore(
|
||||||
|
0x40,
|
||||||
|
add(bytecode, and(add(add(newSize, 0x20), 0x1f), not(0x1f)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// append data to self-destruct byte code
|
||||||
|
Memory.copy(
|
||||||
|
Memory.dataPtr(data),
|
||||||
|
Memory.dataPtr(bytecode) + bytecodeLen,
|
||||||
|
data.length
|
||||||
|
);
|
||||||
|
address userAddr = msg.sender;
|
||||||
|
{
|
||||||
|
// revise the owner to the contract (so that it is destructable)
|
||||||
|
uint256 off = OWNER_ADDR_OFF + 0x20;
|
||||||
|
assembly {
|
||||||
|
mstore(add(bytecode, off), address())
|
||||||
|
}
|
||||||
|
off = USER_ADDR_OFF + 0x20;
|
||||||
|
assembly {
|
||||||
|
mstore(add(bytecode, off), userAddr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageSlotFactoryFromInput c = new StorageSlotFactoryFromInput{
|
||||||
|
value: value
|
||||||
|
}(bytecode);
|
||||||
|
return address(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
function putRaw2(
|
||||||
|
bytes32 key,
|
||||||
|
bytes memory data,
|
||||||
|
uint256 value
|
||||||
|
) internal returns (address) {
|
||||||
|
// create the new contract code with the data
|
||||||
|
bytes memory bytecode = FACTORY_CODE;
|
||||||
|
uint256 bytecodeLen = bytecode.length;
|
||||||
|
uint256 newSize = bytecode.length + data.length;
|
||||||
|
assembly {
|
||||||
|
// in-place resize of bytecode bytes
|
||||||
|
// note that this must be done when bytecode is the last allocated object by solidity.
|
||||||
|
mstore(bytecode, newSize)
|
||||||
|
// notify solidity about the memory size increase, must be 32-bytes aligned
|
||||||
|
mstore(
|
||||||
|
0x40,
|
||||||
|
add(bytecode, and(add(add(newSize, 0x20), 0x1f), not(0x1f)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// append data to self-destruct byte code
|
||||||
|
Memory.copy(
|
||||||
|
Memory.dataPtr(data),
|
||||||
|
Memory.dataPtr(bytecode) + bytecodeLen,
|
||||||
|
data.length
|
||||||
|
);
|
||||||
|
{
|
||||||
|
// revise the size of calldata
|
||||||
|
uint256 calldataSize = STORAGE_SLOT_CODE_V2.length + data.length;
|
||||||
|
uint256 off = FACTORY_SIZE_OFF + 0x20;
|
||||||
|
assembly {
|
||||||
|
mstore(add(bytecode, off), calldataSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// revise the owner to the contract (so that it is destructable)
|
||||||
|
uint256 off = FACTORY_ADDR_OFF0 + 0x20;
|
||||||
|
assembly {
|
||||||
|
mstore(add(bytecode, off), address())
|
||||||
|
}
|
||||||
|
off = FACTORY_ADDR_OFF1 + 0x20;
|
||||||
|
assembly {
|
||||||
|
mstore(add(bytecode, off), address())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
address addr;
|
||||||
|
assembly {
|
||||||
|
addr := create2(
|
||||||
|
value,
|
||||||
|
add(bytecode, 0x20), // data offset
|
||||||
|
mload(bytecode), // size
|
||||||
|
key
|
||||||
|
)
|
||||||
|
|
||||||
|
if iszero(extcodesize(addr)) {
|
||||||
|
revert(0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sizeRaw(address addr) internal view returns (uint256, bool) {
|
||||||
|
if (addr == address(0x0)) {
|
||||||
|
return (0, false);
|
||||||
|
}
|
||||||
|
uint256 codeSize;
|
||||||
|
uint256 off = STORAGE_SLOT_CODE_V2.length;
|
||||||
|
assembly {
|
||||||
|
codeSize := extcodesize(addr)
|
||||||
|
}
|
||||||
|
if (codeSize < off) {
|
||||||
|
return (0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (codeSize - off, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRaw(address addr) internal view returns (bytes memory, bool) {
|
||||||
|
(uint256 dataSize, bool found) = sizeRaw(addr);
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
return (new bytes(0), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy the data without the "code"
|
||||||
|
bytes memory data = new bytes(dataSize);
|
||||||
|
uint256 off = STORAGE_SLOT_CODE_V2.length;
|
||||||
|
assembly {
|
||||||
|
// retrieve data size
|
||||||
|
extcodecopy(addr, add(data, 0x20), off, dataSize)
|
||||||
|
}
|
||||||
|
return (data, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRawAt(
|
||||||
|
address addr,
|
||||||
|
uint256 memoryPtr
|
||||||
|
) internal view returns (uint256, bool) {
|
||||||
|
(uint256 dataSize, bool found) = sizeRaw(addr);
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
return (0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint256 off = STORAGE_SLOT_CODE_V2.length;
|
||||||
|
assembly {
|
||||||
|
// retrieve data size
|
||||||
|
extcodecopy(addr, memoryPtr, off, dataSize)
|
||||||
|
}
|
||||||
|
return (dataSize, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function returnBytesInplace(bytes memory content) internal pure {
|
||||||
|
// equal to return abi.encode(content)
|
||||||
|
uint256 size = content.length + 0x40; // pointer + size
|
||||||
|
size = (size + 0x20 + 0x1f) & ~uint256(0x1f);
|
||||||
|
assembly {
|
||||||
|
// (DATA CORRUPTION): the caller method must be "external returns (bytes)", cannot be public!
|
||||||
|
mstore(sub(content, 0x20), 0x20)
|
||||||
|
return(sub(content, 0x20), size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateValueForData(
|
||||||
|
uint256 datalen,
|
||||||
|
uint256 chunkSize,
|
||||||
|
uint256 codeStakingPerChunk
|
||||||
|
) internal pure returns (uint256) {
|
||||||
|
return
|
||||||
|
((datalen + STORAGE_SLOT_CODE_V2.length - 1) / chunkSize) *
|
||||||
|
codeStakingPerChunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
function storageSlotCodeLength() internal pure returns (uint256) {
|
||||||
|
return STORAGE_SLOT_CODE_V2.length;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "./Memory.sol";
|
||||||
|
|
||||||
|
// Create a storage slot by appending data to the end
|
||||||
|
contract StorageSlotFromContract {
|
||||||
|
constructor(address contractAddr, bytes memory data) payable {
|
||||||
|
uint256 codeSize;
|
||||||
|
assembly {
|
||||||
|
// retrieve the size of the code, this needs assembly
|
||||||
|
codeSize := extcodesize(contractAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
uint256 totalSize = codeSize + data.length + 32;
|
||||||
|
bytes memory deployCode = new bytes(totalSize);
|
||||||
|
|
||||||
|
// Copy contract code
|
||||||
|
assembly {
|
||||||
|
// actually retrieve the code, this needs assembly
|
||||||
|
extcodecopy(contractAddr, add(deployCode, 0x20), 0, codeSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy data
|
||||||
|
uint256 off = Memory.dataPtr(deployCode) + codeSize;
|
||||||
|
Memory.copy(Memory.dataPtr(data), off, data.length);
|
||||||
|
|
||||||
|
off += data.length;
|
||||||
|
uint256 len = data.length;
|
||||||
|
// Set data size
|
||||||
|
assembly {
|
||||||
|
mstore(off, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the contract manually
|
||||||
|
assembly {
|
||||||
|
return(add(deployCode, 0x20), totalSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a storage slot
|
||||||
|
contract StorageSlotFactoryFromInput {
|
||||||
|
constructor(bytes memory codeAndData) payable {
|
||||||
|
uint256 size = codeAndData.length;
|
||||||
|
// Return the contract manually
|
||||||
|
assembly {
|
||||||
|
return(add(codeAndData, 0x20), size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
contract StorageSlotSelfDestructableV2 {
|
||||||
|
address immutable owner;
|
||||||
|
address immutable userToRefund;
|
||||||
|
|
||||||
|
constructor(address user) payable {
|
||||||
|
owner = msg.sender;
|
||||||
|
userToRefund = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
function destruct() public {
|
||||||
|
require(msg.sender == owner, "NFO");
|
||||||
|
selfdestruct(payable(userToRefund));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract StorageSlotSelfDestructableV2_DEBUG {
|
||||||
|
address public immutable owner;
|
||||||
|
address public immutable userToRefund;
|
||||||
|
|
||||||
|
constructor(address user) payable {
|
||||||
|
owner = msg.sender;
|
||||||
|
userToRefund = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
function destruct() public {
|
||||||
|
require(msg.sender == owner, "NFO");
|
||||||
|
selfdestruct(payable(userToRefund));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,151 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
library SlotHelper {
|
||||||
|
uint256 internal constant SLOTDATA_RIGHT_SHIFT = 32;
|
||||||
|
uint256 internal constant LEN_OFFSET = 224;
|
||||||
|
uint256 internal constant FIRST_SLOT_DATA_SIZE = 28;
|
||||||
|
|
||||||
|
function putRaw(
|
||||||
|
mapping(uint256 => bytes32) storage slots,
|
||||||
|
bytes memory datas
|
||||||
|
) internal returns (bytes32 mdata) {
|
||||||
|
uint256 len = datas.length;
|
||||||
|
mdata = encodeMetadata(datas);
|
||||||
|
if (len > FIRST_SLOT_DATA_SIZE) {
|
||||||
|
bytes32 value;
|
||||||
|
uint256 ptr;
|
||||||
|
assembly {
|
||||||
|
ptr := add(datas, add(0x20, FIRST_SLOT_DATA_SIZE))
|
||||||
|
}
|
||||||
|
for (
|
||||||
|
uint256 i = 0;
|
||||||
|
i < (len - FIRST_SLOT_DATA_SIZE + 32 - 1) / 32;
|
||||||
|
i++
|
||||||
|
) {
|
||||||
|
assembly {
|
||||||
|
value := mload(ptr)
|
||||||
|
}
|
||||||
|
ptr = ptr + 32;
|
||||||
|
slots[i] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeMetadata(
|
||||||
|
bytes memory data
|
||||||
|
) internal pure returns (bytes32 medata) {
|
||||||
|
uint256 datLen = data.length;
|
||||||
|
uint256 value;
|
||||||
|
assembly {
|
||||||
|
value := mload(add(data, 0x20))
|
||||||
|
}
|
||||||
|
|
||||||
|
datLen = datLen << LEN_OFFSET;
|
||||||
|
value = value >> SLOTDATA_RIGHT_SHIFT;
|
||||||
|
|
||||||
|
medata = bytes32(value | datLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeMetadata(
|
||||||
|
bytes32 mdata
|
||||||
|
) internal pure returns (uint256 len, bytes32 data) {
|
||||||
|
len = decodeLen(mdata);
|
||||||
|
data = mdata << SLOTDATA_RIGHT_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeMetadataToData(
|
||||||
|
bytes32 mdata
|
||||||
|
) internal pure returns (uint256 len, bytes memory data) {
|
||||||
|
len = decodeLen(mdata);
|
||||||
|
mdata = mdata << SLOTDATA_RIGHT_SHIFT;
|
||||||
|
data = new bytes(len);
|
||||||
|
assembly {
|
||||||
|
mstore(add(data, 0x20), mdata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRaw(
|
||||||
|
mapping(uint256 => bytes32) storage slots,
|
||||||
|
bytes32 mdata
|
||||||
|
) internal view returns (bytes memory data) {
|
||||||
|
uint256 datalen;
|
||||||
|
(datalen, data) = decodeMetadataToData(mdata);
|
||||||
|
|
||||||
|
if (datalen > FIRST_SLOT_DATA_SIZE) {
|
||||||
|
uint256 ptr = 0;
|
||||||
|
bytes32 value = 0;
|
||||||
|
assembly {
|
||||||
|
ptr := add(data, add(0x20, FIRST_SLOT_DATA_SIZE))
|
||||||
|
}
|
||||||
|
for (
|
||||||
|
uint256 i = 0;
|
||||||
|
i < (datalen - FIRST_SLOT_DATA_SIZE + 32 - 1) / 32;
|
||||||
|
i++
|
||||||
|
) {
|
||||||
|
value = slots[i];
|
||||||
|
assembly {
|
||||||
|
mstore(ptr, value)
|
||||||
|
}
|
||||||
|
ptr = ptr + 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRawAt(
|
||||||
|
mapping(uint256 => bytes32) storage slots,
|
||||||
|
bytes32 mdata,
|
||||||
|
uint256 memoryPtr
|
||||||
|
) internal view returns (uint256 datalen, bool found) {
|
||||||
|
bytes32 datapart;
|
||||||
|
(datalen, datapart) = decodeMetadata(mdata);
|
||||||
|
|
||||||
|
// memoryPtr:memoryPtr+32 is allocated for the data
|
||||||
|
uint256 dataPtr = memoryPtr;
|
||||||
|
assembly {
|
||||||
|
mstore(dataPtr, datapart)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (datalen > FIRST_SLOT_DATA_SIZE) {
|
||||||
|
uint256 ptr = 0;
|
||||||
|
bytes32 value = 0;
|
||||||
|
|
||||||
|
assembly {
|
||||||
|
ptr := add(dataPtr, FIRST_SLOT_DATA_SIZE)
|
||||||
|
}
|
||||||
|
for (
|
||||||
|
uint256 i = 0;
|
||||||
|
i < (datalen - FIRST_SLOT_DATA_SIZE + 32 - 1) / 32;
|
||||||
|
i++
|
||||||
|
) {
|
||||||
|
value = slots[i];
|
||||||
|
assembly {
|
||||||
|
mstore(ptr, value)
|
||||||
|
}
|
||||||
|
ptr = ptr + 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInSlot(bytes32 mdata) internal pure returns (bool succeed) {
|
||||||
|
return decodeLen(mdata) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeLen(uint256 datalen) internal pure returns (bytes32 res) {
|
||||||
|
res = bytes32(datalen << LEN_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeLen(bytes32 mdata) internal pure returns (uint256 res) {
|
||||||
|
res = uint256(mdata) >> LEN_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addrToBytes32(address addr) internal pure returns (bytes32) {
|
||||||
|
return bytes32(uint256(uint160(addr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function bytes32ToAddr(bytes32 bt) internal pure returns (address) {
|
||||||
|
return address(uint160(uint256(bt)));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "./SlotHelper.sol";
|
||||||
|
|
||||||
|
contract SlotHelperTest {
|
||||||
|
mapping(bytes32 => bytes32) public metadatas;
|
||||||
|
mapping(bytes32 => mapping(uint256 => bytes32)) public slots;
|
||||||
|
|
||||||
|
function put(bytes32 key, bytes memory data) public {
|
||||||
|
metadatas[key] = SlotHelper.putRaw(slots[key], data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(bytes32 key) public view returns (bytes memory res) {
|
||||||
|
bytes32 md = metadatas[key];
|
||||||
|
res = SlotHelper.getRaw(slots[key], md);
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeMetadata(bytes memory data) public pure returns (bytes32) {
|
||||||
|
return SlotHelper.encodeMetadata(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeMetadata(
|
||||||
|
bytes32 mdata
|
||||||
|
) public pure returns (uint256, bytes32) {
|
||||||
|
return SlotHelper.decodeMetadata(mdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeMetadata1(
|
||||||
|
bytes32 mdata
|
||||||
|
) public pure returns (uint256, bytes memory) {
|
||||||
|
return SlotHelper.decodeMetadataToData(mdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeLen(uint256 datalen) public pure returns (bytes32) {
|
||||||
|
return SlotHelper.encodeLen(datalen);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeLen(bytes32 mdata) public pure returns (uint256 res) {
|
||||||
|
res = SlotHelper.decodeLen(mdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLen(bytes32 key) public view returns (uint256 resLen) {
|
||||||
|
bytes32 mdata = metadatas[key];
|
||||||
|
resLen = SlotHelper.decodeLen(mdata);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
interface database {
|
||||||
|
|
||||||
|
function download(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory path
|
||||||
|
) external view returns (bytes memory, bool) ;
|
||||||
|
|
||||||
|
function upload(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory path,
|
||||||
|
bytes calldata data
|
||||||
|
) external payable;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
pragma solidity ^0.8.0;
|
||||||
|
import "./EthStorage/LargeStorageManagerV2.sol";
|
||||||
|
contract EthStorage is LargeStorageManagerV2{
|
||||||
|
function stakeTokens(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory path
|
||||||
|
) external view returns (uint256) {
|
||||||
|
bytes memory fullPath = bytes.concat(repoName, "/", path);
|
||||||
|
return _stakeTokens(keccak256(fullPath), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function chunkStakeTokens(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory path,
|
||||||
|
uint256 chunkId
|
||||||
|
) external view returns (uint256) {
|
||||||
|
bytes memory fullPath = bytes.concat(repoName, "/", path);
|
||||||
|
(uint256 sTokens, ) = _chunkStakeTokens(keccak256(fullPath), chunkId);
|
||||||
|
return sTokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getChunkAddr(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory path,
|
||||||
|
uint256 chunkId
|
||||||
|
) external view returns (address) {
|
||||||
|
bytes memory fullPath = bytes.concat(repoName, "/", path);
|
||||||
|
return _getChunkAddr(keccak256(fullPath), chunkId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function download(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory path
|
||||||
|
) external view returns (bytes memory, bool) {
|
||||||
|
// call flat directory(FD)
|
||||||
|
return _get(keccak256(bytes.concat(repoName, "/", path)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function upload(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory path,
|
||||||
|
bytes calldata data
|
||||||
|
) external payable {
|
||||||
|
_putChunkFromCalldata(
|
||||||
|
keccak256(bytes.concat(repoName, "/", path)),
|
||||||
|
0,
|
||||||
|
data,
|
||||||
|
msg.value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function uploadChunk(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory path,
|
||||||
|
uint256 chunkId,
|
||||||
|
bytes calldata data
|
||||||
|
) external payable{
|
||||||
|
_putChunkFromCalldata(
|
||||||
|
keccak256(bytes.concat(repoName, "/", path)),
|
||||||
|
chunkId,
|
||||||
|
data,
|
||||||
|
msg.value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function remove(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory path
|
||||||
|
) external {
|
||||||
|
// The actually process of remove will remove all the chunks
|
||||||
|
_remove(keccak256(bytes.concat(repoName, "/", path)), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeChunk(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory path,
|
||||||
|
uint256 chunkId
|
||||||
|
) external {
|
||||||
|
_removeChunk(keccak256(bytes.concat(repoName, "/", path)), chunkId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function size(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory name
|
||||||
|
) external view returns (uint256, uint256) {
|
||||||
|
return _size(keccak256(bytes.concat(repoName, "/", name)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function countChunks(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory name
|
||||||
|
) external view returns (uint256) {
|
||||||
|
return _countChunks(keccak256(bytes.concat(repoName, "/", name)));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
contract filecoin{
|
||||||
|
|
||||||
|
mapping(bytes32 => bytes) public pathToHash;
|
||||||
|
|
||||||
|
function download(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory path
|
||||||
|
) external view returns (bytes memory, bool) {
|
||||||
|
|
||||||
|
bytes32 fullName = keccak256(bytes.concat(repoName, "/", path));
|
||||||
|
// call flat directory(FD)
|
||||||
|
return (pathToHash[fullName],true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function upload(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory path,
|
||||||
|
bytes calldata data
|
||||||
|
) external payable {
|
||||||
|
bytes32 fullName = keccak256(bytes.concat(repoName, "/", path));
|
||||||
|
pathToHash[fullName] = data;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,12 +0,0 @@
|
|||||||
pragma solidity ^0.8.0;
|
|
||||||
|
|
||||||
|
|
||||||
interface IStorageLayer{
|
|
||||||
|
|
||||||
function upload(
|
|
||||||
bytes20 refHash,
|
|
||||||
bytes calldata data
|
|
||||||
) external payable ;
|
|
||||||
|
|
||||||
function download(bytes20 refHash) external view returns(bytes32 storageLayerId,bytes memory data);
|
|
||||||
}
|
|
Loading…
Reference in new issue