diff --git a/contracts/PublicResolver.sol b/contracts/PublicResolver.sol index 1b1bac54..b77ce726 100644 --- a/contracts/PublicResolver.sol +++ b/contracts/PublicResolver.sol @@ -15,6 +15,7 @@ contract PublicResolver { bytes4 constant ABI_INTERFACE_ID = 0x2203ab56; bytes4 constant PUBKEY_INTERFACE_ID = 0xc8690233; bytes4 constant TEXT_INTERFACE_ID = 0x59d1d43c; + bytes4 constant MULTIHASH_INTERFACE_ID = 0xe89401a1; event AddrChanged(bytes32 indexed node, address a); event ContentChanged(bytes32 indexed node, bytes32 hash); @@ -22,6 +23,7 @@ contract PublicResolver { event ABIChanged(bytes32 indexed node, uint256 indexed contentType); event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y); event TextChanged(bytes32 indexed node, string indexedKey, string key); + event MultihashChanged(bytes32 indexed node, bytes hash); struct PublicKey { bytes32 x; @@ -35,6 +37,7 @@ contract PublicResolver { PublicKey pubkey; mapping(string=>string) text; mapping(uint256=>bytes) abis; + bytes multihash; } WNS wns; @@ -77,6 +80,17 @@ contract PublicResolver { records[node].content = hash; ContentChanged(node, hash); } + + /** + * Sets the multihash associated with an WNS node. + * May only be called by the owner of that node in the WNS registry. + * @param node The node to update. + * @param hash The multihash to set + */ + function setMultihash(bytes32 node, bytes hash) public only_owner(node) { + records[node].multihash = hash; + MultihashChanged(node, hash); + } /** * Sets the name associated with an WNS node, for reverse records. @@ -188,6 +202,15 @@ contract PublicResolver { return records[node].content; } + /** + * Returns the multihash associated with an WNS node. + * @param node The WNS node to query. + * @return The associated multihash. + */ + function multihash(bytes32 node) public view returns (bytes) { + return records[node].multihash; + } + /** * Returns the address associated with an WNS node. * @param node The WNS node to query. @@ -209,6 +232,7 @@ contract PublicResolver { interfaceID == ABI_INTERFACE_ID || interfaceID == PUBKEY_INTERFACE_ID || interfaceID == TEXT_INTERFACE_ID || + interfaceID == MULTIHASH_INTERFACE_ID || interfaceID == INTERFACE_META_ID; } } diff --git a/test/TestPublicResolver.js b/test/TestPublicResolver.js index e2d7d777..79706572 100644 --- a/test/TestPublicResolver.js +++ b/test/TestPublicResolver.js @@ -386,4 +386,57 @@ contract('PublicResolver', function (accounts) { }); }); + describe('multihash', async () => { + + it('permits setting multihash by owner', async () => { + await resolver.setMultihash(node, '0x0000000000000000000000000000000000000000000000000000000000000001', {from: accounts[0]}); + assert.equal(await resolver.multihash(node), '0x0000000000000000000000000000000000000000000000000000000000000001'); + }); + + it('can overwrite previously set multihash', async () => { + await resolver.setMultihash(node, '0x0000000000000000000000000000000000000000000000000000000000000001', {from: accounts[0]}); + assert.equal(await resolver.multihash(node), '0x0000000000000000000000000000000000000000000000000000000000000001'); + + await resolver.setMultihash(node, '0x0000000000000000000000000000000000000000000000000000000000000002', {from: accounts[0]}); + assert.equal(await resolver.multihash(node), '0x0000000000000000000000000000000000000000000000000000000000000002'); + }); + + it('can overwrite to same multihash', async () => { + await resolver.setMultihash(node, '0x0000000000000000000000000000000000000000000000000000000000000001', {from: accounts[0]}); + assert.equal(await resolver.multihash(node), '0x0000000000000000000000000000000000000000000000000000000000000001'); + + await resolver.setMultihash(node, '0x0000000000000000000000000000000000000000000000000000000000000002', {from: accounts[0]}); + assert.equal(await resolver.multihash(node), '0x0000000000000000000000000000000000000000000000000000000000000002'); + }); + + it('forbids setting multihash by non-owners', async () => { + try { + await resolver.setMultihash(node, '0x0000000000000000000000000000000000000000000000000000000000000001', {from: accounts[1]}); + } catch (error) { + return utils.ensureException(error); + } + + assert.fail('setting did not fail'); + }); + + it('forbids writing same multihash by non-owners', async () => { + await resolver.setMultihash(node, '0x0000000000000000000000000000000000000000000000000000000000000001', {from: accounts[0]}); + + try { + await resolver.setMultihash(node, '0x0000000000000000000000000000000000000000000000000000000000000001', {from: accounts[1]}); + } catch (error) { + return utils.ensureException(error); + } + + assert.fail('setting did not fail'); + }); + + it('returns empty when fetching nonexistent multihash', async () => { + assert.equal( + await resolver.multihash(node), + '0x' + ); + }); + }); + });