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

Curator status #8

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
29 changes: 28 additions & 1 deletion contracts/MetadataRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ contract MetadataRegistry {
bytes32 digest;
uint8 hashFunction;
uint8 size;
bool isValid;
}

mapping (address => Entry) private entries;
mapping (address => uint) private versions;
mapping (address => address) private deployers;

event EntrySet (
address indexed contractAddress,
Expand Down Expand Up @@ -61,6 +63,11 @@ contract MetadataRegistry {
_;
}

modifier onlyValidEntries(address _contract) {
require(entries[_contract].isValid, "Error: contract does not exist");
_;
}

/**
* @dev Initialize association of a multihash with a contract if the deployer sends a tx
* @param _contract address of the associated contract
Expand Down Expand Up @@ -100,6 +107,7 @@ contract MetadataRegistry {
)
public
onlyDelegate(_contract)
onlyValidEntries(_contract)
{
_setEntry(_contract, _digest, _hashFunction, _size, INVALID_NONCE);
}
Expand All @@ -111,6 +119,7 @@ contract MetadataRegistry {
function clearEntry(address _contract)
public
onlyDelegate(_contract)
onlyValidEntries(_contract)
{
require(entries[_contract].digest != 0, "Error: missing entry");
delete entries[_contract];
Expand All @@ -126,6 +135,7 @@ contract MetadataRegistry {
function setDelegate(address _contract, address _delegate)
public
onlyDelegate(_contract)
onlyValidEntries(_contract)
{
require(entries[_contract].delegate != ANY_ADDRESS, "Error: Deployer made all ethereum addresses' delegates");
entries[_contract].delegate = _delegate;
Expand All @@ -139,19 +149,34 @@ contract MetadataRegistry {
function getIPFSMultihash(address _address)
public
view
onlyValidEntries(_address)
returns(bytes32 digest, uint8 hashFunction, uint8 size)
{
Entry storage entry = entries[_address];
return (entry.digest, entry.hashFunction, entry.size);
}

/**
* @dev checks if the latests entry is curated
* @param _contract address of the associated contract
*/
function isCurated(address _contract)
public
view
onlyValidEntries(_contract)
returns(bool)
{
return entries[_contract].delegate == deployers[_contract];
}

/**
* @dev retrieve delegate address associated with a contract
* @param _address address used as key
*/
function getDelegate(address _address)
public
view
onlyValidEntries(_address)
returns(address delegate)
{
Entry storage entry = entries[_address];
Expand Down Expand Up @@ -185,14 +210,16 @@ contract MetadataRegistry {
if (!selfAttested && _nonce != INVALID_NONCE) { // we should never get here with user input
require(isContract(_contract), "Error: address provided is not a contract");
require(isDeployer(msg.sender, _contract, _nonce), "Error: msg.sender is not contract deployer");
deployers[_contract] = msg.sender; // this is so we know if it's curated
}

Entry memory entry = Entry(
selfAttested,
msg.sender,
_digest,
_hashFunction,
_size
_size,
true
);
entries[_contract] = entry;
versions[_contract] += 1;
Expand Down
32 changes: 28 additions & 4 deletions test/MetadataRegistry.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ contract('MetadataRegistry', (accounts) => {
return new BigNumber(await registry.getVersion(registry.address)).toNumber();
}

async function getCurated(contractAddr) {
return Boolean(await registry.isCurated(contractAddr));
}

context('> Publishing with createEntry() && updateEntry()', () => {
context('when the transaction succeds', () => {
it('should get IPFS hash after setting', async () => {
Expand Down Expand Up @@ -92,13 +96,19 @@ contract('MetadataRegistry', (accounts) => {
});

it('should increase the version for that particular contract', async () => {
expect(await getVersion(registry.address)).to.equal(0);
await setInitialIPFSHash(registry.address, accounts[0], ipfsHashes[0]);
const { digest, hashFunction, size } = getBytes32FromMultihash(ipfsHashes[1]);

expect(await getVersion(registry.address)).to.equal(1);

await registry.methods[SET_ENTRY](
registry.address, digest, hashFunction, size, { from: accounts[0] }
);

expect(await getVersion(registry.address)).to.equal(2);
});

it('should get the delegate after setting', async () => {
expect(await getDelegate(registry.address)).to.equal(NULL_ADDRESS);
await setInitialIPFSHash(registry.address, accounts[0], ipfsHashes[0]);
expect(await getDelegate(registry.address)).to.equal(accounts[0]);
});
Expand Down Expand Up @@ -202,7 +212,7 @@ contract('MetadataRegistry', (accounts) => {
expect(await getIPFSHash(registry.address)).to.equal(ipfsHashes[0]);

await registry.clearEntry(registry.address);
expect(await getIPFSHash(registry.address)).to.be.a('null');
await assertRevert(getIPFSHash(registry.address));
});

it('should fire event when entry is cleared', async () => {
Expand All @@ -218,8 +228,14 @@ contract('MetadataRegistry', (accounts) => {
await setInitialIPFSHash(registry.address, accounts[0], ipfsHashes[0]);
expect(await getVersion(registry.address)).to.equal(1);

const { digest, hashFunction, size } = getBytes32FromMultihash(ipfsHashes[1]);

await registry.methods[SET_ENTRY](
registry.address, digest, hashFunction, size, { from: accounts[0] }
);

await registry.clearEntry(registry.address);
expect(await getVersion(registry.address)).to.equal(0);
expect(await getVersion(registry.address)).to.equal(1);
});
});

Expand Down Expand Up @@ -268,6 +284,14 @@ contract('MetadataRegistry', (accounts) => {
});
});

context('> View methods', () => {
it('should revert calling view functions on non-existent entries', async () => {
await assertRevert(getDelegate(registry.address));
await assertRevert(getIPFSHash(registry.address));
await assertRevert(getCurated(registry.address));
});
});

context('Estimate gas cost:', () => {
it('should calculate the gas', async () => {
let gasSetEntryInitial, gasSetEntry, gasClearEntry, gasSetDelegate;
Expand Down