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

Supports batch acquisition of hashes #11

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
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
120 changes: 78 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,53 @@ 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 = keccak256(name);
iteyelmp marked this conversation as resolved.
Show resolved Hide resolved
StorageMode mode = storageModes[key];
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 = keccak256(name);
StorageMode mode = storageModes[key];
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 = keccak256(name);
StorageMode mode = storageModes[key];
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 = keccak256(name);
StorageMode mode = storageModes[key];
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 +83,13 @@ contract ERC5018 is LargeStorageManager, BlobStorageManager, IERC5018, ISemver {
uint256 chunkId,
bytes calldata data
) public payable onlyOwner virtual override {
StorageMode mode = getStorageMode(name);
bytes32 key = keccak256(name);
StorageMode mode = storageModes[key];
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 +99,55 @@ 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 = keccak256(name);
StorageMode mode = storageModes[key];
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 = keccak256(name);
StorageMode mode = storageModes[key];
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 = keccak256(name);
StorageMode mode = storageModes[key];
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 = keccak256(name);
StorageMode mode = storageModes[key];
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 = keccak256(name);
StorageMode mode = storageModes[key];
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 +161,47 @@ 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 = keccak256(name);
StorageMode mode = storageModes[key];
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 getBatchChunkHashes(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 getUploadInfo(bytes memory name) public override view returns (StorageMode mode, uint256 count, uint256 payment) {
bytes32 key = keccak256(name);
mode = storageModes[key];

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

payment = address(storageContract) != address(0) ? upfrontPayment() : 0;
}
}
15 changes: 15 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,8 @@ interface IERC5018 {
function destruct() external;

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

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

function getUploadInfo(bytes memory name) external view returns (StorageMode mode, uint256 count, uint256 payment);
}
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