diff --git a/contracts/Git3.sol b/contracts/Git3.sol index c3e0d86..cd50ced 100644 --- a/contracts/Git3.sol +++ b/contracts/Git3.sol @@ -21,13 +21,14 @@ contract Git3 is LargeStorageManager { mapping(bytes => address) public repoNameToOwner; mapping(bytes => refInfo) public nameToRefInfo; // dev => {hash: 0x1234..., index: 1 } - bytes[] public refs; // [main, dev, test, staging] + 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 = refs[info.index]; + res.name = repoNameToRefs[repoName][info.index]; } constructor() LargeStorageManager(0) {} @@ -45,20 +46,16 @@ contract Git3 is LargeStorageManager { return _get(keccak256(bytes.concat(repoName, "/", path))); } - function _createRepo(bytes memory repoName) internal { - if (repoNameToOwner[repoName] == address(0)) { - repoNameToOwner[repoName] = msg.sender; - } else { - require(repoNameToOwner[repoName] == msg.sender, "only owner"); - } + function createRepo(bytes memory repoName) external{ + require(repoNameToOwner[repoName] == address(0),"RepoName already exist"); + repoNameToOwner[repoName] = msg.sender; } function upload( bytes memory repoName, bytes memory path, bytes calldata data - ) external payable { - _createRepo(repoName); + ) external payable onlyOwner(repoName){ _putChunkFromCalldata( keccak256(bytes.concat(repoName, "/", path)), 0, @@ -72,8 +69,7 @@ contract Git3 is LargeStorageManager { bytes memory path, uint256 chunkId, bytes calldata data - ) external payable { - _createRepo(repoName); + ) external payable onlyOwner(repoName){ _putChunkFromCalldata( keccak256(bytes.concat(repoName, "/", path)), chunkId, @@ -104,11 +100,10 @@ contract Git3 is LargeStorageManager { return _countChunks(keccak256(bytes.concat(repoName, "/", name))); } - function listRefs() public view returns (refData[] memory list) { - // todo: Differentiate all refs corresponding to a repo - list = new refData[](refs.length); - for (uint index = 0; index < refs.length; index++) { - list[index] = _convertRefInfo(nameToRefInfo[refs[index]]); + function listRefs(bytes memory repoName) public 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]]); } } @@ -116,14 +111,12 @@ contract Git3 is LargeStorageManager { bytes memory repoName, bytes memory name, bytes20 refHash - ) public { + ) public onlyOwner(repoName){ bytes memory fullName = bytes.concat(repoName, "/", name); // only execute `sload` once to reduce gas consumption refInfo memory srs; srs = nameToRefInfo[fullName]; - uint256 refsLen = refs.length; - - _createRepo(repoName); + uint256 refsLen = repoNameToRefs[repoName].length; if (srs.hash == bytes20(0)) { // store refHash for the first time @@ -135,7 +128,7 @@ contract Git3 is LargeStorageManager { nameToRefInfo[fullName].hash = refHash; nameToRefInfo[fullName].index = uint96(refsLen); - refs.push(fullName); + repoNameToRefs[repoName].push(fullName); } else { // only update refHash nameToRefInfo[fullName].hash = refHash; @@ -150,7 +143,7 @@ contract Git3 is LargeStorageManager { // only execute `sload` once to reduce gas consumption refInfo memory srs; srs = nameToRefInfo[fullName]; - uint256 refsLen = refs.length; + uint256 refsLen = repoNameToRefs[repoName].length; require( srs.hash != bytes20(0), @@ -159,10 +152,10 @@ contract Git3 is LargeStorageManager { require(srs.index < refsLen, "System Error: Invalid index"); if (srs.index < refsLen - 1) { - refs[srs.index] = refs[refsLen - 1]; - nameToRefInfo[refs[refsLen - 1]].index = srs.index; + repoNameToRefs[repoName][srs.index] = repoNameToRefs[repoName][refsLen - 1]; + nameToRefInfo[repoNameToRefs[repoName][refsLen - 1]].index = srs.index; } - refs.pop(); + repoNameToRefs[repoName].pop(); delete nameToRefInfo[fullName]; } } diff --git a/test/git3-test.js b/test/git3-test.js index 2167b6a..a60ddb5 100644 --- a/test/git3-test.js +++ b/test/git3-test.js @@ -13,7 +13,8 @@ describe("Git3 Test", function () { let singer; [singer] = await ethers.getSigners(); - console.log("singer", singer.address); + + await git3.createRepo("0x11"); await git3.upload("0x11", "0x616263", "0x112233"); expect(await git3.download("0x11", "0x616263")).to.eql(["0x112233", true]); @@ -39,6 +40,8 @@ describe("Git3 Test", function () { const git3 = await Git3.deploy(); await git3.deployed(); + await git3.createRepo("0x11"); + expect(await git3.countChunks("0x11", "0x616263")).to.eql(ToBig(0)); let data0 = Array.from({ length: 10 }, () => @@ -71,6 +74,8 @@ describe("Git3 Test", function () { await git3.deployed(); let repoName = "0x11"; + await git3.createRepo(repoName); + function concatHexStr(s1, s2) { return s1.concat("2f").concat(s2.slice(2)); } @@ -87,7 +92,7 @@ describe("Git3 Test", function () { let data2 = "0xcccccccccccccccccccccccccccccccccccccccc"; await git3.setRef(repoName, key2, data2); - let refs = await git3.listRefs(); + let refs = await git3.listRefs(repoName); expect(refs[0]).to.eql([data0, concatHexStr(repoName, key0)]); expect(refs[1]).to.eql([data1, concatHexStr(repoName, key1)]); expect(refs[2]).to.eql([data2, concatHexStr(repoName, key2)]); @@ -95,20 +100,43 @@ describe("Git3 Test", function () { // check delRef await git3.delRef(repoName, key0); - refs = await git3.listRefs(); + refs = await git3.listRefs(repoName); expect(refs[0]).to.eql([data2, concatHexStr(repoName, key2)]); expect(refs[1]).to.eql([data1, concatHexStr(repoName, key1)]); expect(refs.length).to.eql(2); await git3.delRef(repoName, key1); - refs = await git3.listRefs(); + refs = await git3.listRefs(repoName); expect(refs[0]).to.eql([data2, concatHexStr(repoName, key2)]); expect(refs.length).to.eql(1); // check update let data3 = "0xdddddddddddddddddddddddddddddddddddddddd"; await git3.setRef(repoName, key2, data3); - refs = await git3.listRefs(); + refs = await git3.listRefs(repoName); expect(refs[0]).to.eql([data3, concatHexStr(repoName, key2)]); }); + + it("Access Control", async function () { + const Git3 = await ethers.getContractFactory("Git3"); + const git3 = await Git3.deploy(); + await git3.deployed(); + + let singer; + let user1; + [singer,user1,] = await ethers.getSigners(); + + await git3.connect(singer).createRepo("0x11"); + + await expect(git3.connect(user1).upload("0x11", "0x616263", "0x112233")).to.be.revertedWith("only owner"); + await expect(git3.connect(user1).uploadChunk("0x11", "0x616263", 0,"0x112233")).to.be.revertedWith("only owner"); + await expect(git3.connect(user1).setRef("0x11", "0x616263", "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")).to.be.revertedWith("only owner"); + + await git3.connect(singer).upload("0x11", "0x616263", "0x112233") + expect(await git3.download("0x11", "0x616263")).to.eql(["0x112233", true]); + await git3.connect(singer).setRef("0x11", "0x616263", "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + + await expect(git3.connect(user1).remove("0x11", "0x616263")).to.be.revertedWith("only owner"); + await expect(git3.connect(user1).delRef("0x11", "0x616263")).to.be.revertedWith("only owner"); + }); });