parent
480d10da6e
commit
7b498b35c1
@ -0,0 +1,150 @@
|
|||||||
|
//SPDX-License-Identifier: Unlicense
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
// import "hardhat/console.sol";
|
||||||
|
import "./Git3HubStorage.sol";
|
||||||
|
|
||||||
|
contract Git3Hub_SLI is Git3HubStorage_SLI {
|
||||||
|
event RepoCreated(bytes repoName, address owner);
|
||||||
|
event RepoOwnerTransfer(bytes repoName, address oldOwner, address newOwner);
|
||||||
|
event PushRef(bytes repoName, bytes ref);
|
||||||
|
|
||||||
|
constructor() Git3HubStorage_SLI() {}
|
||||||
|
|
||||||
|
modifier onlyOwner(bytes memory repoName) {
|
||||||
|
require(repoNameToOwner[repoName] == msg.sender, "only owner");
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
emit RepoCreated(repoName, msg.sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
function transferOwnership(
|
||||||
|
bytes memory repoName,
|
||||||
|
address newOwner
|
||||||
|
) external onlyOwner(repoName) {
|
||||||
|
require(newOwner != address(0), "newOwner must not be zero address");
|
||||||
|
repoNameToOwner[repoName] = newOwner;
|
||||||
|
emit RepoOwnerTransfer(repoName, msg.sender, newOwner);
|
||||||
|
}
|
||||||
|
|
||||||
|
function download(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory path
|
||||||
|
) external view returns (bytes memory) {
|
||||||
|
return pathToHash[keccak256(bytes.concat(repoName, "/", path))];
|
||||||
|
}
|
||||||
|
|
||||||
|
function upload(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory path,
|
||||||
|
bytes calldata data
|
||||||
|
) external payable onlyOwner(repoName) {
|
||||||
|
pathToHash[keccak256(bytes.concat(repoName, "/", path))] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function remove(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory path
|
||||||
|
) external onlyOwner(repoName) {
|
||||||
|
// The actually process of remove will remove all the chunks
|
||||||
|
pathToHash[keccak256(bytes.concat(repoName, "/", path))] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function listRefs(
|
||||||
|
bytes memory repoName
|
||||||
|
) external view returns (refData[] memory list) {
|
||||||
|
list = new refData[](repoNameToRefs[repoName].length);
|
||||||
|
for (uint index = 0; index < repoNameToRefs[repoName].length; index++) {
|
||||||
|
list[index] = _convertRefInfo(
|
||||||
|
repoName,
|
||||||
|
nameToRefInfo[repoNameToRefs[repoName][index]]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setRef(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory ref,
|
||||||
|
bytes20 refHash
|
||||||
|
) external onlyOwner(repoName) {
|
||||||
|
bytes memory fullName = bytes.concat(repoName, "/", ref);
|
||||||
|
// only execute `sload` once to reduce gas consumption
|
||||||
|
refInfo memory srs;
|
||||||
|
srs = nameToRefInfo[fullName];
|
||||||
|
uint256 refsLen = repoNameToRefs[repoName].length;
|
||||||
|
|
||||||
|
if (srs.hash == bytes20(0)) {
|
||||||
|
// store refHash for the first time
|
||||||
|
require(
|
||||||
|
refsLen <= uint256(uint96(int96(-1))),
|
||||||
|
"Refs exceed valid length"
|
||||||
|
);
|
||||||
|
|
||||||
|
nameToRefInfo[fullName].hash = refHash;
|
||||||
|
nameToRefInfo[fullName].index = uint96(refsLen);
|
||||||
|
|
||||||
|
repoNameToRefs[repoName].push(fullName);
|
||||||
|
} else {
|
||||||
|
// only update refHash
|
||||||
|
nameToRefInfo[fullName].hash = refHash;
|
||||||
|
}
|
||||||
|
emit PushRef(repoName, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
function delRef(
|
||||||
|
bytes memory repoName,
|
||||||
|
bytes memory ref
|
||||||
|
) external onlyOwner(repoName) {
|
||||||
|
bytes memory fullName = bytes.concat(repoName, "/", ref);
|
||||||
|
// only execute `sload` once to reduce gas consumption
|
||||||
|
refInfo memory srs;
|
||||||
|
srs = nameToRefInfo[fullName];
|
||||||
|
uint256 refsLen = repoNameToRefs[repoName].length;
|
||||||
|
|
||||||
|
require(
|
||||||
|
srs.hash != bytes20(0),
|
||||||
|
"Reference of this name does not exist"
|
||||||
|
);
|
||||||
|
require(srs.index < refsLen, "System Error: Invalid index");
|
||||||
|
|
||||||
|
if (srs.index < refsLen - 1) {
|
||||||
|
repoNameToRefs[repoName][srs.index] = repoNameToRefs[repoName][
|
||||||
|
refsLen - 1
|
||||||
|
];
|
||||||
|
nameToRefInfo[repoNameToRefs[repoName][refsLen - 1]].index = srs
|
||||||
|
.index;
|
||||||
|
}
|
||||||
|
repoNameToRefs[repoName].pop();
|
||||||
|
delete nameToRefInfo[fullName];
|
||||||
|
}
|
||||||
|
|
||||||
|
function _convertRefInfo(
|
||||||
|
bytes memory repoName,
|
||||||
|
refInfo memory info
|
||||||
|
) internal view returns (refData memory res) {
|
||||||
|
res.hash = info.hash;
|
||||||
|
res.name = repoNameToRefs[repoName][info.index];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
//SPDX-License-Identifier: Unlicense
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
contract Git3HubStorage_SLI {
|
||||||
|
struct refInfo {
|
||||||
|
bytes20 hash;
|
||||||
|
uint96 index;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct refData {
|
||||||
|
bytes20 hash;
|
||||||
|
bytes name;
|
||||||
|
}
|
||||||
|
// FileStorage Storage Layout
|
||||||
|
mapping(bytes32 => bytes) public pathToHash;
|
||||||
|
|
||||||
|
|
||||||
|
// Git3Hub Storage Layout
|
||||||
|
mapping(bytes => address) public repoNameToOwner;
|
||||||
|
mapping(bytes => refInfo) public nameToRefInfo; // dev => {hash: 0x1234..., index: 1 }
|
||||||
|
mapping(bytes => bytes[]) public repoNameToRefs; // [main, dev, test, staging]
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
//SPDX-License-Identifier: Unlicense
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
contract Hello{
|
||||||
|
string public abc;
|
||||||
|
|
||||||
|
constructor(){
|
||||||
|
abc="Hello World";
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
//SPDX-License-Identifier: Unlicense
|
//SPDX-License-Identifier: Unlicense
|
||||||
pragma solidity ^0.8.0;
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
contract Git3HubStorage {
|
contract Git3HubStorage_ES {
|
||||||
struct refInfo {
|
struct refInfo {
|
||||||
bytes20 hash;
|
bytes20 hash;
|
||||||
uint96 index;
|
uint96 index;
|
@ -0,0 +1,51 @@
|
|||||||
|
import { ethers } from "hardhat";
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
let provider = ethers.provider;
|
||||||
|
let [operator] = await ethers.getSigners();
|
||||||
|
let nonce = await operator.getTransactionCount();
|
||||||
|
console.log(operator.address, nonce, await operator.getBalance());
|
||||||
|
|
||||||
|
let price = await provider.getFeeData();
|
||||||
|
let net = await provider.getNetwork();
|
||||||
|
console.log(price, net.chainId);
|
||||||
|
|
||||||
|
const Git3 = await ethers.getContractFactory("Git3Hub_SLI");
|
||||||
|
const git3 = await Git3.deploy({
|
||||||
|
nonce: nonce,
|
||||||
|
type: 2,
|
||||||
|
maxFeePerGas: price.maxFeePerGas!,
|
||||||
|
maxPriorityFeePerGas: price.maxPriorityFeePerGas!,
|
||||||
|
gasLimit: 3000000,
|
||||||
|
});
|
||||||
|
|
||||||
|
let logicReceipt = await git3.deployed();
|
||||||
|
console.log(logicReceipt.deployTransaction.hash);
|
||||||
|
nonce++;
|
||||||
|
|
||||||
|
let factory1 = await ethers.getContractFactory("UpgradeableProxy");
|
||||||
|
// Proxy don't need to init Git3 contract because the constructor is empty.
|
||||||
|
let initSelector = "0x";
|
||||||
|
|
||||||
|
let proxyInstance = await factory1
|
||||||
|
.connect(operator)
|
||||||
|
.deploy(git3.address, operator.address, initSelector, {
|
||||||
|
nonce: nonce,
|
||||||
|
type: 2,
|
||||||
|
maxFeePerGas: price.maxFeePerGas,
|
||||||
|
maxPriorityFeePerGas: price.maxPriorityFeePerGas,
|
||||||
|
});
|
||||||
|
let proxyReceipt = await proxyInstance.deployed();
|
||||||
|
console.log(proxyReceipt.deployTransaction.hash);
|
||||||
|
|
||||||
|
// console.log({logicReceipt,proxyReceipt});
|
||||||
|
console.log("Logic Contract", git3.address);
|
||||||
|
console.log("Proxy Contract", proxyInstance.address);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We recommend this pattern to be able to use async/await everywhere
|
||||||
|
// and properly handle errors.
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
process.exitCode = 1;
|
||||||
|
});
|
@ -0,0 +1,24 @@
|
|||||||
|
import hre from "hardhat";
|
||||||
|
const { ethers } = hre;
|
||||||
|
import fs from "fs";
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const accounts = await ethers.getSigners();
|
||||||
|
console.log(accounts[0].address);
|
||||||
|
|
||||||
|
const Git3 = await hre.ethers.getContractAt(
|
||||||
|
"Git3Hub_SLI",
|
||||||
|
"0xF56A1dd941667911896B9B872AC79E56cfc6a3dB"
|
||||||
|
);
|
||||||
|
|
||||||
|
let res = await Git3.download(
|
||||||
|
Buffer.from("h1"),
|
||||||
|
Buffer.from("objects/9f/2781f252bddce27d26a4e9ae4acf965f09ba9f")
|
||||||
|
);
|
||||||
|
console.log(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
Loading…
Reference in new issue