Skip to content

Commit

Permalink
Merge pull request #11 from ethstorage/hashes
Browse files Browse the repository at this point in the history
Supports batch acquisition of hashes
  • Loading branch information
iteyelmp authored Jan 7, 2025
2 parents 7f446f3 + 6db82d3 commit ac89782
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 75 deletions.
19 changes: 4 additions & 15 deletions contracts/BlobStorageManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,7 @@ contract BlobStorageManager is Ownable {

function _countChunksFromBlob(bytes32 key) internal view returns (uint256) {
uint256 chunkId = 0;
while (true) {
bytes32 chunkKey = keyToChunks[key][chunkId];
if (chunkKey == bytes32(0)) {
break;
}
while (keyToChunks[key][chunkId] != bytes32(0)) {
chunkId++;
}
return chunkId;
Expand Down Expand Up @@ -112,8 +108,7 @@ contract BlobStorageManager is Ownable {
}

function _removeChunkFromBlob(bytes32 key, uint256 chunkId) internal returns (bool) {
bytes32 chunkKey = keyToChunks[key][chunkId];
if (chunkKey == bytes32(0)) {
if (keyToChunks[key][chunkId] == bytes32(0)) {
return false;
}
if (keyToChunks[key][chunkId + 1] != bytes32(0)) {
Expand All @@ -128,12 +123,7 @@ contract BlobStorageManager is Ownable {
}

function _removeFromBlob(bytes32 key, uint256 chunkId) internal returns (uint256) {
while (true) {
bytes32 chunkKey = keyToChunks[key][chunkId];
if (chunkKey == bytes32(0)) {
break;
}

while (keyToChunks[key][chunkId] != bytes32(0)) {
// TODO The current version does not support the delete
// storageContract.remove(keyToChunks[key][chunkId]);
keyToChunks[key][chunkId] = bytes32(0);
Expand All @@ -143,8 +133,7 @@ contract BlobStorageManager is Ownable {
}

function _preparePutFromBlob(bytes32 key, uint256 chunkId) private {
bytes32 chunkKey = keyToChunks[key][chunkId];
if (chunkKey == bytes32(0)) {
if (keyToChunks[key][chunkId] == bytes32(0)) {
require(chunkId == 0 || keyToChunks[key][chunkId - 1] != bytes32(0), "must replace or append");
} else {
// TODO The current version does not support the delete
Expand Down
122 changes: 80 additions & 42 deletions contracts/ERC5018.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ import "./ISemver.sol";

contract ERC5018 is LargeStorageManager, BlobStorageManager, IERC5018, ISemver {

enum StorageMode {
Uninitialized,
OnChain,
Blob
}
mapping(bytes32 => StorageMode) storageModes;

constructor(
Expand All @@ -31,52 +26,49 @@ contract ERC5018 is LargeStorageManager, BlobStorageManager, IERC5018, ISemver {
return storageModes[keccak256(name)];
}

function _setStorageMode(bytes memory name, StorageMode mode) internal {
storageModes[keccak256(name)] = mode;
}

// Large storage methods
function write(bytes memory name, bytes calldata data) public onlyOwner payable virtual override {
// TODO: support multiple chunks
return writeChunk(name, 0, data);
}

function read(bytes memory name) public view virtual override returns (bytes memory, bool) {
StorageMode mode = getStorageMode(name);
(bytes32 key, StorageMode mode) = _getModeAndKey(name);
if (mode == StorageMode.Blob) {
return _getFromBlob(keccak256(name));
return _getFromBlob(key);
} else if (mode == StorageMode.OnChain) {
return _get(keccak256(name));
return _get(key);
}
return (new bytes(0), false);
}

function size(bytes memory name) public view virtual override returns (uint256, uint256) {
StorageMode mode = getStorageMode(name);
(bytes32 key, StorageMode mode) = _getModeAndKey(name);
if (mode == StorageMode.Blob) {
return _sizeFromBlob(keccak256(name));
return _sizeFromBlob(key);
} else if (mode == StorageMode.OnChain) {
return _size(keccak256(name));
return _size(key);
}
return (0, 0);
}

function remove(bytes memory name) public virtual override onlyOwner returns (uint256) {
StorageMode mode = getStorageMode(name);
(bytes32 key, StorageMode mode) = _getModeAndKey(name);
storageModes[key] = StorageMode.Uninitialized;
if (mode == StorageMode.Blob) {
return _removeFromBlob(keccak256(name), 0);
return _removeFromBlob(key, 0);
} else if (mode == StorageMode.OnChain) {
return _remove(keccak256(name), 0);
return _remove(key, 0);
}
return 0;
}

function countChunks(bytes memory name) public view virtual override returns (uint256) {
StorageMode mode = getStorageMode(name);
(bytes32 key, StorageMode mode) = _getModeAndKey(name);
if (mode == StorageMode.Blob) {
return _countChunksFromBlob(keccak256(name));
return _countChunksFromBlob(key);
} else if (mode == StorageMode.OnChain) {
return _countChunks(keccak256(name));
return _countChunks(key);
}
return 0;
}
Expand All @@ -87,12 +79,12 @@ contract ERC5018 is LargeStorageManager, BlobStorageManager, IERC5018, ISemver {
uint256 chunkId,
bytes calldata data
) public payable onlyOwner virtual override {
StorageMode mode = getStorageMode(name);
(bytes32 key, StorageMode mode) = _getModeAndKey(name);
require(mode == StorageMode.Uninitialized || mode == StorageMode.OnChain, "Invalid storage mode");
if (mode == StorageMode.Uninitialized) {
_setStorageMode(name, StorageMode.OnChain);
storageModes[key] = StorageMode.OnChain;
}
_putChunkFromCalldata(keccak256(name), chunkId, data, msg.value);
_putChunkFromCalldata(key, chunkId, data, msg.value);
}

function writeChunks(
Expand All @@ -102,50 +94,50 @@ contract ERC5018 is LargeStorageManager, BlobStorageManager, IERC5018, ISemver {
) public onlyOwner override payable {
require(isSupportBlob(), "The current network does not support blob upload");

StorageMode mode = getStorageMode(name);
(bytes32 key, StorageMode mode) = _getModeAndKey(name);
require(mode == StorageMode.Uninitialized || mode == StorageMode.Blob, "Invalid storage mode");
if (mode == StorageMode.Uninitialized) {
_setStorageMode(name, StorageMode.Blob);
storageModes[key] = StorageMode.Blob;
}
_putChunks(keccak256(name), chunkIds, sizes);
_putChunks(key, chunkIds, sizes);
}

function readChunk(bytes memory name, uint256 chunkId) public view virtual override returns (bytes memory, bool) {
StorageMode mode = getStorageMode(name);
(bytes32 key, StorageMode mode) = _getModeAndKey(name);
if (mode == StorageMode.Blob) {
return _getChunkFromBlob(keccak256(name), chunkId);
return _getChunkFromBlob(key, chunkId);
} else if (mode == StorageMode.OnChain) {
return _getChunk(keccak256(name), chunkId);
return _getChunk(key, chunkId);
}
return (new bytes(0), false);
}

function chunkSize(bytes memory name, uint256 chunkId) public view virtual override returns (uint256, bool) {
StorageMode mode = getStorageMode(name);
(bytes32 key, StorageMode mode) = _getModeAndKey(name);
if (mode == StorageMode.Blob) {
return _chunkSizeFromBlob(keccak256(name), chunkId);
return _chunkSizeFromBlob(key, chunkId);
} else if (mode == StorageMode.OnChain) {
return _chunkSize(keccak256(name), chunkId);
return _chunkSize(key, chunkId);
}
return (0, false);
}

function removeChunk(bytes memory name, uint256 chunkId) public virtual onlyOwner override returns (bool) {
StorageMode mode = getStorageMode(name);
(bytes32 key, StorageMode mode) = _getModeAndKey(name);
if (mode == StorageMode.Blob) {
return _removeChunkFromBlob(keccak256(name), chunkId);
return _removeChunkFromBlob(key, chunkId);
} else if (mode == StorageMode.OnChain) {
return _removeChunk(keccak256(name), chunkId);
return _removeChunk(key, chunkId);
}
return false;
}

function truncate(bytes memory name, uint256 chunkId) public virtual onlyOwner override returns (uint256) {
StorageMode mode = getStorageMode(name);
(bytes32 key, StorageMode mode) = _getModeAndKey(name);
if (mode == StorageMode.Blob) {
return _removeFromBlob(keccak256(name), chunkId);
return _removeFromBlob(key, chunkId);
} else if (mode == StorageMode.OnChain) {
return _remove(keccak256(name), chunkId);
return _remove(key, chunkId);
}
return 0;
}
Expand All @@ -159,13 +151,59 @@ contract ERC5018 is LargeStorageManager, BlobStorageManager, IERC5018, ISemver {
}

function getChunkHash(bytes memory name, uint256 chunkId) public override view returns (bytes32) {
StorageMode mode = getStorageMode(name);
(bytes32 key, StorageMode mode) = _getModeAndKey(name);
if (mode == StorageMode.Blob) {
return _getChunkHashFromBlob(keccak256(name), chunkId);
return _getChunkHashFromBlob(key, chunkId);
} else if (mode == StorageMode.OnChain) {
(bytes memory localData,) = readChunk(name, chunkId);
(bytes memory localData,) = _getChunk(key, chunkId);
return keccak256(localData);
}
return 0;
}

function getChunkHashesBatch(FileChunk[] memory fileChunks) external view returns (bytes32[] memory) {
uint totalChunks = 0;

for (uint i = 0; i < fileChunks.length; i++) {
totalChunks += fileChunks[i].chunkIds.length;
}

bytes32[] memory hashes = new bytes32[](totalChunks);
uint index = 0;
for (uint i = 0; i < fileChunks.length; i++) {
for (uint j = 0; j < fileChunks[i].chunkIds.length; j++) {
hashes[index] = getChunkHash(fileChunks[i].name, fileChunks[i].chunkIds[j]);
index++;
}
}
return hashes;
}

function getChunkCountsBatch(bytes[] memory names) external view returns (uint256[] memory) {
uint256[] memory counts = new uint256[](names.length);
for (uint i = 0; i < names.length; i++) {
counts[i] = countChunks(names[i]);
}
return counts;
}

function getUploadInfo(bytes memory name) public override view returns (StorageMode mode, uint256 chunkCount, uint256 storageCost) {
bytes32 key;
(key, mode) = _getModeAndKey(name);

if (mode == StorageMode.Blob) {
chunkCount = _countChunksFromBlob(key);
} else if (mode == StorageMode.OnChain) {
chunkCount = _countChunks(key);
} else {
chunkCount = 0;
}

storageCost = address(storageContract) != address(0) ? upfrontPayment() : 0;
}

function _getModeAndKey(bytes memory name) private view returns (bytes32 key, StorageMode mode) {
key = keccak256(name);
mode = storageModes[key];
}
}
17 changes: 17 additions & 0 deletions contracts/IERC5018.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@
pragma solidity ^0.8.0;

interface IERC5018 {
enum StorageMode {
Uninitialized,
OnChain,
Blob
}

struct FileChunk {
bytes name;
uint256[] chunkIds;
}

// Large storage methods
function write(bytes memory name, bytes memory data) external payable;

Expand Down Expand Up @@ -36,4 +47,10 @@ interface IERC5018 {
function destruct() external;

function getChunkHash(bytes memory name, uint256 chunkId) external view returns (bytes32);

function getChunkHashesBatch(FileChunk[] memory fileChunks) external view returns (bytes32[] memory);

function getChunkCountsBatch(bytes[] memory names) external view returns (uint256[] memory);

function getUploadInfo(bytes memory name) external view returns (StorageMode mode, uint256 chunkCount, uint256 storageCost);
}
24 changes: 6 additions & 18 deletions contracts/LargeStorageManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,9 @@ contract LargeStorageManager {
bytes32 metadata = keyToMetadata[key][chunkId];

if (metadata.isInSlot()) {
bytes memory res = SlotHelper.getRaw(keyToSlots[key][chunkId], metadata);
return (res, true);
return (SlotHelper.getRaw(keyToSlots[key][chunkId], metadata), true);
} else {
address addr = metadata.bytes32ToAddr();
return StorageHelper.getRaw(addr);
return StorageHelper.getRaw(metadata.bytes32ToAddr());
}
}

Expand All @@ -89,23 +87,16 @@ contract LargeStorageManager {
if (metadata == bytes32(0)) {
return (0, false);
} else if (metadata.isInSlot()) {
uint256 len = metadata.decodeLen();
return (len, true);
return (metadata.decodeLen(), true);
} else {
address addr = metadata.bytes32ToAddr();
return StorageHelper.sizeRaw(addr);
return StorageHelper.sizeRaw(metadata.bytes32ToAddr());
}
}

function _countChunks(bytes32 key) internal view returns (uint256) {
uint256 chunkId = 0;

while (true) {
bytes32 metadata = keyToMetadata[key][chunkId];
if (metadata == bytes32(0x0)) {
break;
}

while (keyToMetadata[key][chunkId] != bytes32(0)) {
chunkId++;
}

Expand Down Expand Up @@ -162,11 +153,8 @@ contract LargeStorageManager {

// Returns # of chunks deleted
function _remove(bytes32 key, uint256 chunkId) internal returns (uint256) {
while (true) {
while (keyToMetadata[key][chunkId] != bytes32(0)) {
bytes32 metadata = keyToMetadata[key][chunkId];
if (metadata == bytes32(0x0)) {
break;
}

if (!metadata.isInSlot()) {
address addr = metadata.bytes32ToAddr();
Expand Down

0 comments on commit ac89782

Please sign in to comment.