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

Allow update deployment and mark a deployment latest for a project #284

Merged
merged 5 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
23 changes: 15 additions & 8 deletions contracts/ProjectRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ contract ProjectRegistry is Initializable, OwnableUpgradeable, ERC721Upgradeable
event UpdateProjectMetadata(address indexed owner, uint256 indexed projectId, string metadata);

/// @notice Emitted when the latestDeploymentId of the project updated.
event UpdateProjectDeployment(address indexed owner, uint256 indexed projectId, bytes32 deploymentId, bytes32 metadata);
event UpdateProjectDeployment(address indexed owner, uint256 indexed projectId, bytes32 deploymentId, bytes32 metadata, bool updateLatest);

/// @notice Emitted when service status changed with a specific deploymentId.
event ServiceStatusChanged(address indexed indexer, bytes32 indexed deploymentId, ServiceStatus status);
Expand Down Expand Up @@ -168,16 +168,23 @@ contract ProjectRegistry is Initializable, OwnableUpgradeable, ERC721Upgradeable
}

/**
* @notice update the deployment of a project, if in the restrict mode, only creator allowed call this function
* @notice update or add the deployment of a project, only creator allowed call this function
*/
function updateDeployment(uint256 projectId, bytes32 deploymentId, bytes32 metadata) external {
function addOrUpdateDeployment(uint256 projectId, bytes32 deploymentId, bytes32 metadata, bool updateLatest) external {
mzxyz marked this conversation as resolved.
Show resolved Hide resolved
require(ownerOf(projectId) == msg.sender, 'PR004');
require(deploymentInfos[deploymentId].projectId == 0, 'PR003');

projectInfos[projectId].latestDeploymentId = deploymentId;
deploymentInfos[deploymentId] = DeploymentInfo(projectId, metadata);
require(deploymentInfos[deploymentId].projectId == 0 || deploymentInfos[deploymentId].projectId == projectId, 'PR007');
bool changed = false;
if (deploymentInfos[deploymentId].metadata != metadata) {
deploymentInfos[deploymentId] = DeploymentInfo(projectId, metadata);
changed = true;
}

emit UpdateProjectDeployment(msg.sender, projectId, deploymentId, metadata);
if (updateLatest && projectInfos[projectId].latestDeploymentId != deploymentId) {
mzxyz marked this conversation as resolved.
Show resolved Hide resolved
projectInfos[projectId].latestDeploymentId = deploymentId;
changed = true;
}
require(changed, 'PR008');
emit UpdateProjectDeployment(msg.sender, projectId, deploymentId, metadata, updateLatest);
}

/**
Expand Down
5 changes: 3 additions & 2 deletions contracts/interfaces/IProjectRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ interface IProjectRegistry {

function updateProjectMetadata(uint256 projectId, string memory metadataUri) external;

function updateDeployment(
function addOrUpdateDeployment(
uint256 projectId,
bytes32 deploymentId,
bytes32 metadata
bytes32 metadata,
bool updateLatest
) external;

function startService(bytes32 deploymentId) external;
Expand Down
57 changes: 34 additions & 23 deletions publish/ABI/ProjectRegistry.json
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,12 @@
"internalType": "bytes32",
"name": "metadata",
"type": "bytes32"
},
{
"indexed": false,
"internalType": "bool",
"name": "updateLatest",
"type": "bool"
}
],
"name": "UpdateProjectDeployment",
Expand Down Expand Up @@ -275,6 +281,34 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "projectId",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "deploymentId",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "metadata",
"type": "bytes32"
},
{
"internalType": "bool",
"name": "updateLatest",
"type": "bool"
}
],
"name": "addOrUpdateDeployment",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down Expand Up @@ -898,29 +932,6 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "projectId",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "deploymentId",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "metadata",
"type": "bytes32"
}
],
"name": "updateDeployment",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down
1 change: 1 addition & 0 deletions publish/revertcode.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
"PR005": "can not stop indexing for NOTINDEXING services",
"PR006": "cannot stop indexing with an ongoing service agreement",
"PR007": "Inconsistent project id and deployment id",
"PR008": "deployment metadata not changed",
"RD001": "Waiting Era",
"RD002": "Era expired",
"RD003": "Waiting next era",
Expand Down
91 changes: 81 additions & 10 deletions test/ProjectRegistry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,12 @@ describe('Project Registry Contract', () => {
expect(tokenUri).to.equal(`ipfs://${newProjectMetadata}`);
});

it('update project deploymenet should work', async () => {
it('add new deployment to project should work', async () => {
const projectId = 1;
const [metadata, deploymentId] = [deploymentMetadatas[1], deploymentIds[1]];
await expect(projectRegistry.updateDeployment(1, deploymentId, metadata))
await expect(projectRegistry.addOrUpdateDeployment(1, deploymentId, metadata, true))
.to.be.emit(projectRegistry, 'UpdateProjectDeployment')
.withArgs(wallet_0.address, projectId, deploymentId, metadata);
.withArgs(wallet_0.address, projectId, deploymentId, metadata, true);

// check state changes
const projectInfo = await projectRegistry.projectInfos(projectId);
Expand All @@ -184,7 +184,63 @@ describe('Project Registry Contract', () => {
expect(deploymentInfo.metadata).to.equal(metadata);
});

it('can update project and deployment with new account after owner transferred', async () => {
it('update deployment\'s metadata should work', async () => {
const projectId = 1;
const [metadata, deploymentId] = [deploymentMetadatas[1], deploymentIds[1]];
await expect(projectRegistry.addOrUpdateDeployment(1, deploymentId, metadata, true))
.to.be.emit(projectRegistry, 'UpdateProjectDeployment')
.withArgs(wallet_0.address, projectId, deploymentId, metadata, true);

await expect(projectRegistry.addOrUpdateDeployment(1, deploymentId, deploymentMetadatas[2], false))
.to.be.emit(projectRegistry, 'UpdateProjectDeployment')
.withArgs(wallet_0.address, projectId, deploymentId, deploymentMetadatas[2], false);

// check state changes
const projectInfo = await projectRegistry.projectInfos(projectId);
const deploymentInfo = await projectRegistry.deploymentInfos(deploymentId);
expect(projectInfo.latestDeploymentId).to.equal(deploymentId);
expect(projectInfo.projectType).to.equal(ProjectType.SUBQUERY);
expect(deploymentInfo.projectId).to.equal(projectId);
expect(deploymentInfo.metadata).to.equal(deploymentMetadatas[2]);
});

it('add deployment\'s metadata without marking it as latest should work', async () => {
const projectId = 1;
await projectRegistry.addOrUpdateDeployment(projectId, deploymentIds[1], deploymentMetadatas[1], true)
// check state changes
let projectInfo = await projectRegistry.projectInfos(projectId);
expect(projectInfo.latestDeploymentId).to.equal(deploymentIds[1]);
await expect(projectRegistry.addOrUpdateDeployment(projectId, deploymentIds[2], deploymentMetadatas[2], false))
.to.be.emit(projectRegistry, 'UpdateProjectDeployment')
.withArgs(wallet_0.address, projectId, deploymentIds[2], deploymentMetadatas[2], false);

// check state changes
projectInfo = await projectRegistry.projectInfos(projectId);
expect(projectInfo.latestDeploymentId).to.equal(deploymentIds[1]);
let deploymentInfo = await projectRegistry.deploymentInfos(deploymentIds[1]);
expect(deploymentInfo.projectId).to.equal(projectId);
expect(deploymentInfo.metadata).to.equal(deploymentMetadatas[1]);
deploymentInfo = await projectRegistry.deploymentInfos(deploymentIds[2]);
expect(deploymentInfo.projectId).to.equal(projectId);
expect(deploymentInfo.metadata).to.equal(deploymentMetadatas[2]);
});

it('update old deployment as latest should work', async () => {
const projectId = 1;
await projectRegistry.addOrUpdateDeployment(projectId, deploymentIds[1], deploymentMetadatas[1], true)
// check state changes
let projectInfo = await projectRegistry.projectInfos(projectId);
expect(projectInfo.latestDeploymentId).to.equal(deploymentIds[1]);
await expect(projectRegistry.addOrUpdateDeployment(projectId, deploymentIds[0], deploymentMetadatas[0], true))
.to.be.emit(projectRegistry, 'UpdateProjectDeployment')
.withArgs(wallet_0.address, projectId, deploymentIds[0], deploymentMetadatas[0], true);

// check state changes
projectInfo = await projectRegistry.projectInfos(projectId);
expect(projectInfo.latestDeploymentId).to.equal(deploymentIds[0]);
});

it('can add new deployment to project with new account after owner transferred', async () => {
const projectId = 1;
await projectRegistry.transferFrom(wallet_0.address, wallet_1.address, projectId);
expect(await projectRegistry.ownerOf(projectId)).to.equal(wallet_1.address);
Expand All @@ -195,7 +251,7 @@ describe('Project Registry Contract', () => {
expect(await projectRegistry.ownerOf(projectId)).to.equal(wallet_1.address);
await projectRegistry.connect(wallet_1).updateProjectMetadata(projectId, newProjectMetadata);
const [metadata, deploymentId] = [deploymentMetadatas[1], deploymentIds[1]];
await projectRegistry.connect(wallet_1).updateDeployment(projectId, deploymentId, metadata)
await projectRegistry.connect(wallet_1).addOrUpdateDeployment(projectId, deploymentId, metadata, true)

// check state changes
const tokenUri = await projectRegistry.tokenURI(projectId);
Expand All @@ -213,14 +269,29 @@ describe('Project Registry Contract', () => {
await expect(
projectRegistry.connect(wallet_1).updateProjectMetadata(1, projectMetadata)
).to.be.revertedWith('PR004');
// no permission to update deployment
// no permission to add deployment
await expect(
projectRegistry.connect(wallet_1).updateDeployment(1, deploymentIds[1], deploymentMetadatas[1])
projectRegistry.connect(wallet_1).addOrUpdateDeployment(1, deploymentIds[1], deploymentMetadatas[1],true)
).to.be.revertedWith('PR004');
//
// no changes after the update
await expect(
projectRegistry.addOrUpdateDeployment(1, deploymentIds[0], deploymentMetadatas[0],true)
).to.be.revertedWith('PR008');
await expect(
projectRegistry.addOrUpdateDeployment(1, deploymentIds[0], deploymentMetadatas[0],false)
).to.be.revertedWith('PR008');

// deployment existed
await projectRegistry.addCreator(wallet_1.address);
await projectRegistry.connect(wallet_1).createProject(
projectMetadatas[1],
deploymentMetadatas[1],
deploymentIds[1],
ProjectType.SUBQUERY
);
await expect(
projectRegistry.updateDeployment(1, deploymentId, deploymentMetadatas[1])
).to.be.revertedWith('PR003');
projectRegistry.connect(wallet_1).addOrUpdateDeployment(2, deploymentId, deploymentMetadatas[1], true)
).to.be.revertedWith('PR007');
});
});

Expand Down
4 changes: 3 additions & 1 deletion test/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ export const POI = '0xab3921276c8067fe0c82def3e5ecfd8447f1961bc85768c2a56e6bd26d

export const projectMetadatas = [
'QmZGAZQ7e1oZgfuK4V29Fa5gveYK3G2zEwvUzTZKNvSBsm',
'QmeeqBHdVu7iYnhVE9ZiYEKTWe4jXVUD5pVoGXT6LbCP2t'
'QmeeqBHdVu7iYnhVE9ZiYEKTWe4jXVUD5pVoGXT6LbCP2t',
'QmeHdVHdVuHdVnhVE9ZiYEKTWe4jXVUD5HdVGXT6LbCHdV'
]

export const metadatas = [
Expand All @@ -25,6 +26,7 @@ export const metadatas = [
export const deploymentMetadatas = [
'0xaec921276c8067fe0c82def3e5ecfd8447f1961bc85768c2a56e6bd26d3c0c55',
'0xccc921276c8067fe0c82def3e5ecfd8447f1961bc85768c2a56e6bd26d3c0c55',
'0xccc921276c8067fe0c82def3e5ecfd8447f1961bc85768c2a56e6bd26d3c0c5a',
];

export const deploymentIds = [
Expand Down