You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
4.8 KiB
Solidity
151 lines
4.8 KiB
Solidity
2 years ago
|
//SPDX-License-Identifier: Unlicense
|
||
|
pragma solidity ^0.8.0;
|
||
|
|
||
2 years ago
|
// import "hardhat/console.sol";
|
||
2 years ago
|
import "./Git3HubStorage.sol";
|
||
2 years ago
|
|
||
2 years ago
|
contract Git3Hub_SLI is Git3HubStorage_SLI {
|
||
2 years ago
|
event RepoCreated(bytes repoName, address owner);
|
||
|
event RepoOwnerTransfer(bytes repoName, address oldOwner, address newOwner);
|
||
|
event PushRef(bytes repoName, bytes ref);
|
||
2 years ago
|
|
||
2 years ago
|
constructor() Git3HubStorage_SLI() {}
|
||
2 years ago
|
|
||
2 years ago
|
modifier onlyOwner(bytes memory repoName) {
|
||
2 years ago
|
require(repoNameToOwner[repoName] == msg.sender, "only owner");
|
||
2 years ago
|
_;
|
||
|
}
|
||
|
|
||
2 years ago
|
function createRepo(bytes memory repoName) external {
|
||
|
require(
|
||
|
repoName.length > 0 && repoName.length <= 100,
|
||
|
"RepoName length must be 1-100"
|
||
|
);
|
||
|
for (uint i; i < repoName.length; i++) {
|
||
|
bytes1 char = repoName[i];
|
||
|
require(
|
||
|
(char >= 0x61 && char <= 0x7A) || //a-z
|
||
|
(char >= 0x41 && char <= 0x5A) || //A-Z
|
||
|
(char >= 0x30 && char <= 0x39) || //0-9
|
||
|
(char == 0x2D || char == 0x2E || char == 0x5F), //-._
|
||
|
"RepoName must be alphanumeric or -._"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
require(
|
||
|
repoNameToOwner[repoName] == address(0),
|
||
|
"RepoName already exist"
|
||
|
);
|
||
|
repoNameToOwner[repoName] = msg.sender;
|
||
2 years ago
|
emit RepoCreated(repoName, msg.sender);
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
function transferOwnership(
|
||
|
bytes memory repoName,
|
||
|
address newOwner
|
||
|
) external onlyOwner(repoName) {
|
||
2 years ago
|
require(newOwner != address(0), "newOwner must not be zero address");
|
||
|
repoNameToOwner[repoName] = newOwner;
|
||
2 years ago
|
emit RepoOwnerTransfer(repoName, msg.sender, newOwner);
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
function download(
|
||
2 years ago
|
bytes memory repoName,
|
||
2 years ago
|
bytes memory path
|
||
2 years ago
|
) external view returns (bytes memory) {
|
||
|
return pathToHash[keccak256(bytes.concat(repoName, "/", path))];
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
function upload(
|
||
|
bytes memory repoName,
|
||
|
bytes memory path,
|
||
|
bytes calldata data
|
||
2 years ago
|
) external payable onlyOwner(repoName) {
|
||
2 years ago
|
pathToHash[keccak256(bytes.concat(repoName, "/", path))] = data;
|
||
2 years ago
|
}
|
||
2 years ago
|
|
||
2 years ago
|
function remove(
|
||
|
bytes memory repoName,
|
||
|
bytes memory path
|
||
|
) external onlyOwner(repoName) {
|
||
2 years ago
|
// The actually process of remove will remove all the chunks
|
||
2 years ago
|
pathToHash[keccak256(bytes.concat(repoName, "/", path))] = "";
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
function listRefs(
|
||
|
bytes memory repoName
|
||
2 years ago
|
) external view returns (refData[] memory list) {
|
||
2 years ago
|
list = new refData[](repoNameToRefs[repoName].length);
|
||
|
for (uint index = 0; index < repoNameToRefs[repoName].length; index++) {
|
||
2 years ago
|
list[index] = _convertRefInfo(
|
||
|
repoName,
|
||
|
nameToRefInfo[repoNameToRefs[repoName][index]]
|
||
|
);
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
|
||
2 years ago
|
function setRef(
|
||
|
bytes memory repoName,
|
||
2 years ago
|
bytes memory ref,
|
||
2 years ago
|
bytes20 refHash
|
||
2 years ago
|
) external onlyOwner(repoName) {
|
||
2 years ago
|
bytes memory fullName = bytes.concat(repoName, "/", ref);
|
||
2 years ago
|
// only execute `sload` once to reduce gas consumption
|
||
|
refInfo memory srs;
|
||
2 years ago
|
srs = nameToRefInfo[fullName];
|
||
2 years ago
|
uint256 refsLen = repoNameToRefs[repoName].length;
|
||
2 years ago
|
|
||
2 years ago
|
if (srs.hash == bytes20(0)) {
|
||
|
// store refHash for the first time
|
||
|
require(
|
||
|
refsLen <= uint256(uint96(int96(-1))),
|
||
|
"Refs exceed valid length"
|
||
|
);
|
||
|
|
||
2 years ago
|
nameToRefInfo[fullName].hash = refHash;
|
||
|
nameToRefInfo[fullName].index = uint96(refsLen);
|
||
2 years ago
|
|
||
2 years ago
|
repoNameToRefs[repoName].push(fullName);
|
||
2 years ago
|
} else {
|
||
|
// only update refHash
|
||
2 years ago
|
nameToRefInfo[fullName].hash = refHash;
|
||
2 years ago
|
}
|
||
2 years ago
|
emit PushRef(repoName, ref);
|
||
2 years ago
|
}
|
||
2 years ago
|
|
||
2 years ago
|
function delRef(
|
||
|
bytes memory repoName,
|
||
2 years ago
|
bytes memory ref
|
||
2 years ago
|
) external onlyOwner(repoName) {
|
||
2 years ago
|
bytes memory fullName = bytes.concat(repoName, "/", ref);
|
||
2 years ago
|
// only execute `sload` once to reduce gas consumption
|
||
|
refInfo memory srs;
|
||
2 years ago
|
srs = nameToRefInfo[fullName];
|
||
2 years ago
|
uint256 refsLen = repoNameToRefs[repoName].length;
|
||
2 years ago
|
|
||
2 years ago
|
require(
|
||
|
srs.hash != bytes20(0),
|
||
|
"Reference of this name does not exist"
|
||
|
);
|
||
2 years ago
|
require(srs.index < refsLen, "System Error: Invalid index");
|
||
|
|
||
|
if (srs.index < refsLen - 1) {
|
||
2 years ago
|
repoNameToRefs[repoName][srs.index] = repoNameToRefs[repoName][
|
||
|
refsLen - 1
|
||
|
];
|
||
|
nameToRefInfo[repoNameToRefs[repoName][refsLen - 1]].index = srs
|
||
|
.index;
|
||
2 years ago
|
}
|
||
2 years ago
|
repoNameToRefs[repoName].pop();
|
||
2 years ago
|
delete nameToRefInfo[fullName];
|
||
2 years ago
|
}
|
||
2 years ago
|
|
||
|
function _convertRefInfo(
|
||
|
bytes memory repoName,
|
||
|
refInfo memory info
|
||
|
) internal view returns (refData memory res) {
|
||
|
res.hash = info.hash;
|
||
|
res.name = repoNameToRefs[repoName][info.index];
|
||
|
}
|
||
2 years ago
|
}
|