Merge pull request #1 from cyl19970726/upgrade

feat: support upgradeable Git3hub
main
Call White 2 years ago committed by GitHub
commit ae64ab5551
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6,33 +6,11 @@ pragma solidity ^0.8.0;
import "./v2/LargeStorageManagerV2.sol"; import "./v2/LargeStorageManagerV2.sol";
contract Git3Hub is LargeStorageManagerV2 { contract Git3Hub is LargeStorageManagerV2 {
struct refInfo {
bytes20 hash;
uint96 index;
}
struct refData {
bytes20 hash;
bytes name;
}
event RepoCreated(bytes repoName, address owner); event RepoCreated(bytes repoName, address owner);
event RepoOwnerTransfer(bytes repoName, address oldOwner, address newOwner); event RepoOwnerTransfer(bytes repoName, address oldOwner, address newOwner);
event PushRef(bytes repoName, bytes ref); event PushRef(bytes repoName, bytes ref);
mapping(bytes => address) public repoNameToOwner; constructor() LargeStorageManagerV2() {}
mapping(bytes => refInfo) public nameToRefInfo; // dev => {hash: 0x1234..., index: 1 }
mapping(bytes => bytes[]) public repoNameToRefs; // [main, dev, test, staging]
function _convertRefInfo(
bytes memory repoName,
refInfo memory info
) internal view returns (refData memory res) {
res.hash = info.hash;
res.name = repoNameToRefs[repoName][info.index];
}
constructor() LargeStorageManagerV2(0) {}
modifier onlyOwner(bytes memory repoName) { modifier onlyOwner(bytes memory repoName) {
require(repoNameToOwner[repoName] == msg.sender, "only owner"); require(repoNameToOwner[repoName] == msg.sender, "only owner");
@ -231,4 +209,12 @@ contract Git3Hub is LargeStorageManagerV2 {
repoNameToRefs[repoName].pop(); repoNameToRefs[repoName].pop();
delete nameToRefInfo[fullName]; 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,23 @@
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
contract Git3HubStorage {
struct refInfo {
bytes20 hash;
uint96 index;
}
struct refData {
bytes20 hash;
bytes name;
}
// LargeStorageManagerV2 Storage Layout
mapping(bytes32 => mapping(uint256 => bytes32)) internal keyToMetadata;
mapping(bytes32 => mapping(uint256 => mapping(uint256 => bytes32)))
internal keyToSlots;
// 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]
}

@ -4,23 +4,16 @@ pragma solidity ^0.8.0;
import "./optimize/SlotHelper.sol"; import "./optimize/SlotHelper.sol";
import "./StorageHelperV2.sol"; import "./StorageHelperV2.sol";
import "./StorageSlotSelfDestructableV2.sol"; import "./StorageSlotSelfDestructableV2.sol";
import "../Git3HubStorage.sol";
// Large storage manager to support arbitrarily-sized data with multiple chunk // Large storage manager to support arbitrarily-sized data with multiple chunk
contract LargeStorageManagerV2 { contract LargeStorageManagerV2 is Git3HubStorage {
using SlotHelper for bytes32; using SlotHelper for bytes32;
using SlotHelper for address; using SlotHelper for address;
uint8 internal immutable SLOT_LIMIT; uint8 internal constant SLOT_LIMIT = 0;
mapping(bytes32 => mapping(uint256 => bytes32)) internal keyToMetadata; function isOptimize() public pure returns (bool) {
mapping(bytes32 => mapping(uint256 => mapping(uint256 => bytes32)))
internal keyToSlots;
constructor(uint8 slotLimit) {
SLOT_LIMIT = slotLimit;
}
function isOptimize() public view returns (bool) {
return SLOT_LIMIT > 0; return SLOT_LIMIT > 0;
} }

@ -4,8 +4,6 @@ pragma solidity ^0.8.0;
import "./LargeStorageManagerV2.sol"; import "./LargeStorageManagerV2.sol";
contract LargeStorageManagerV2Test is LargeStorageManagerV2 { contract LargeStorageManagerV2Test is LargeStorageManagerV2 {
constructor(uint8 slotLimit) LargeStorageManagerV2(slotLimit) {}
function get(bytes32 key) public view returns (bytes memory, bool) { function get(bytes32 key) public view returns (bytes memory, bool) {
(bytes memory data, bool found) = _get(key); (bytes memory data, bool found) = _get(key);
return (data, found); return (data, found);

@ -2,6 +2,8 @@ require("dotenv").config();
import { HardhatUserConfig } from "hardhat/config"; import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox"; import "@nomicfoundation/hardhat-toolbox";
import "@nomiclabs/hardhat-web3";
import "@nomiclabs/hardhat-ethers";
import { NetworkDefinition, EtherscanConfig } from "./local.config"; import { NetworkDefinition, EtherscanConfig } from "./local.config";
const config: HardhatUserConfig = { const config: HardhatUserConfig = {

11119
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -18,6 +18,7 @@
"homepage": "https://github.com/git3protocol/git3-contract#readme", "homepage": "https://github.com/git3protocol/git3-contract#readme",
"devDependencies": { "devDependencies": {
"@nomicfoundation/hardhat-toolbox": "^2.0.1", "@nomicfoundation/hardhat-toolbox": "^2.0.1",
"@nomiclabs/hardhat-web3": "^2.0.0",
"@typechain/ethers-v5": "^10.2.0", "@typechain/ethers-v5": "^10.2.0",
"@typechain/hardhat": "^6.1.5", "@typechain/hardhat": "^6.1.5",
"dotenv": "^16.0.3", "dotenv": "^16.0.3",
@ -35,6 +36,7 @@
"@nomiclabs/hardhat-ethers": "^2.2.2", "@nomiclabs/hardhat-ethers": "^2.2.2",
"@nomiclabs/hardhat-etherscan": "^3.1.5", "@nomiclabs/hardhat-etherscan": "^3.1.5",
"@openzeppelin/contracts": "^4.8.1", "@openzeppelin/contracts": "^4.8.1",
"@openzeppelin/contracts-upgradeable": "^4.8.1",
"chai": "^4.3.7", "chai": "^4.3.7",
"typechain": "^8.1.1" "typechain": "^8.1.1"
} }

@ -3,10 +3,20 @@ import { ethers } from "hardhat";
async function main() { async function main() {
const Git3 = await ethers.getContractFactory("Git3Hub"); const Git3 = await ethers.getContractFactory("Git3Hub");
const git3 = await Git3.deploy(); const git3 = await Git3.deploy();
let receipt = await git3.deployed(); let logicReceipt = await git3.deployed()
console.log(receipt); let factory1 = await ethers.getContractFactory("UpgradeableProxy");
console.log(git3.address); // Proxy don't need to init Git3 contract because the constructor is empty.
let initSelector = "0x";
let [operator,] = await ethers.getSigners();
let proxyInstance = await factory1
.connect(operator)
.deploy(git3.address, operator.address, initSelector);
let proxyReceipt = await proxyInstance.deployed()
// console.log({logicReceipt,proxyReceipt});
console.log("Logic Contract",git3.address);
console.log("Proxy Contract",git3.address);
} }
// We recommend this pattern to be able to use async/await everywhere // We recommend this pattern to be able to use async/await everywhere

@ -0,0 +1,24 @@
import { ethers } from "hardhat";
async function main(proxyAddr:string) {
const Git3 = await ethers.getContractFactory("Git3Hub");
const git3 = await Git3.deploy();
let logicReceipt = await git3.deployed()
let proxyInstance = await ethers.getContractAt("UpgradeableProxy",proxyAddr);
// Proxy don't need to init Git3 contract because the constructor is empty.
let initSelector = "0x";
let [operator,] = await ethers.getSigners();
let receipt = await proxyInstance
.connect(operator)
.upgradeToAndCall(git3.address, initSelector);
await receipt.wait();
console.log("upgradeTxHash:",receipt.hash);
}
main(process.argv0).catch((error) => {
console.error(error);
process.exitCode = 1;
});

@ -8,6 +8,79 @@ var ToBig = (x) => ethers.BigNumber.from(x);
let ETH = ethers.BigNumber.from(10).pow(18); let ETH = ethers.BigNumber.from(10).pow(18);
describe("Git3 Test", function () { describe("Git3 Test", function () {
it("Check Upgradeable", async function () {
let repoName = Buffer.from("test");
let [operator, acc1, acc2] = await ethers.getSigners();
const Git3 = await ethers.getContractFactory("Git3Hub");
const git3 = await Git3.deploy();
await git3.deployed();
let git3Upgraded = await Git3.connect(acc2).deploy();
await git3Upgraded.deployed();
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, acc1.address, initSelector);
await proxyInstance.deployed();
let git3Proxy = await ethers.getContractAt(
"Git3Hub",
proxyInstance.address
);
await git3Proxy.createRepo(repoName);
await git3Proxy.upload(repoName, "0x616263", "0x112233");
expect(await git3Proxy.download(repoName, "0x616263")).to.eql([
"0x112233",
true,
]);
const adminSlot =
"0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103";
let actualAdmin = await web3.eth.getStorageAt(
proxyInstance.address,
adminSlot
);
let actualA = web3.utils.toBN(actualAdmin).toString();
let expectA = web3.utils.toBN(acc1.address).toString();
expect(actualA).to.equal(expectA);
await proxyInstance.connect(acc1).changeAdmin(acc2.address);
actualAdmin = await web3.eth.getStorageAt(proxyInstance.address, adminSlot);
actualA = web3.utils.toBN(actualAdmin).toString();
expectA = web3.utils.toBN(acc2.address).toString();
expect(actualA).to.equal(expectA);
const ImplementationSlot =
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
let actualImplement = await web3.eth.getStorageAt(
proxyInstance.address,
ImplementationSlot
);
let actualI = web3.utils.toBN(actualImplement).toString();
let expectI = web3.utils.toBN(git3.address).toString();
expect(actualI).to.equal(expectI);
//****upgrade contract***//
// await expect(proxyInstance.connect(acc2).upgradeToAndCall(git3Upgraded.address,initSelector)).to.be.revertedWith("Initializable: contract is already initialized")
await proxyInstance.connect(acc2).upgradeTo(git3Upgraded.address);
actualImplement = await web3.eth.getStorageAt(
proxyInstance.address,
ImplementationSlot
);
actualI = web3.utils.toBN(actualImplement).toString();
expectI = web3.utils.toBN(git3Upgraded.address).toString();
expect(actualI).to.equal(expectI);
expect(await git3Proxy.download(repoName, "0x616263")).to.eql([
"0x112233",
true,
]);
});
it("upload/download/remove", async function () { it("upload/download/remove", async function () {
const Git3 = await ethers.getContractFactory("Git3Hub"); const Git3 = await ethers.getContractFactory("Git3Hub");
const git3 = await Git3.deploy(); const git3 = await Git3.deploy();

@ -10,7 +10,7 @@ let ETH = ethers.BigNumber.from("10").pow("18");
describe("FlatDirectory Test", function () { describe("FlatDirectory Test", function () {
it("read/write", async function () { it("read/write", async function () {
const FlatDirectory = await ethers.getContractFactory(contractName); const FlatDirectory = await ethers.getContractFactory(contractName);
const fd = await FlatDirectory.deploy(0); const fd = await FlatDirectory.deploy();
await fd.deployed(); await fd.deployed();
await fd.putChunk(key, 0, "0x112233"); await fd.putChunk(key, 0, "0x112233");
@ -26,7 +26,7 @@ describe("FlatDirectory Test", function () {
it("read/write chunks", async function () { it("read/write chunks", async function () {
const FlatDirectory = await ethers.getContractFactory(contractName); const FlatDirectory = await ethers.getContractFactory(contractName);
const fd = await FlatDirectory.deploy(0); const fd = await FlatDirectory.deploy();
await fd.deployed(); await fd.deployed();
let data0 = Array.from({ length: 1024 }, () => let data0 = Array.from({ length: 1024 }, () =>
@ -51,7 +51,7 @@ describe("FlatDirectory Test", function () {
it("write/remove chunks", async function () { it("write/remove chunks", async function () {
const FlatDirectory = await ethers.getContractFactory(contractName); const FlatDirectory = await ethers.getContractFactory(contractName);
const fd = await FlatDirectory.deploy(0); const fd = await FlatDirectory.deploy();
await fd.deployed(); await fd.deployed();
expect(await fd.countChunks(key)).to.eql(ToBig(0)); expect(await fd.countChunks(key)).to.eql(ToBig(0));
@ -88,7 +88,7 @@ describe("FlatDirectory Test", function () {
it("remove chunks and refund to user", async function () { it("remove chunks and refund to user", async function () {
const FlatDirectory = await ethers.getContractFactory(contractName); const FlatDirectory = await ethers.getContractFactory(contractName);
const fd = await FlatDirectory.deploy(0); const fd = await FlatDirectory.deploy();
await fd.deployed(); await fd.deployed();
let stakeTokenNum = ETH; let stakeTokenNum = ETH;

Loading…
Cancel
Save