From 5f3ef8842ce6e1e6bc2a3418d411a1770fc9da8c Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Fri, 5 Oct 2018 17:22:36 -0300 Subject: [PATCH] add eraseNode tool --- contracts/registry/UsernameRegistrar.sol | 51 +++++++++++++++++- test/usernameregistrar.spec.js | 68 ++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/contracts/registry/UsernameRegistrar.sol b/contracts/registry/UsernameRegistrar.sol index 9bf1186..b307b6c 100644 --- a/contracts/registry/UsernameRegistrar.sol +++ b/contracts/registry/UsernameRegistrar.sol @@ -274,6 +274,28 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack { slashUsername(username, _reserveSecret); } + /** + * @notice Clear resolver and ownership of unowned subdomians. + * @param _labels Sequence to erase. + */ + function eraseNode( + bytes32[] _labels + ) + external + { + uint len = _labels.length; + require(len != 0, "Nothing to erase"); + bytes32 label = _labels[len - 1]; + bytes32 subnode = keccak256(abi.encodePacked(ensNode, label)); + require(ensRegistry.owner(subnode) == address(0), "First slash/release top level subdomain"); + ensRegistry.setSubnodeOwner(ensNode, label, address(this)); + if(len > 1) { + eraseNodeHierarchy(len - 2, _labels, subnode); + } + ensRegistry.setResolver(subnode, 0); + ensRegistry.setOwner(subnode, 0); + } + /** * @notice Migrate account to new registry, opt-in to new contract. * @param _label Username hash. @@ -697,7 +719,34 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack { state = _state; emit RegistryState(_state); } - + + /** + * @notice recursively erase all _labels in _subnode + * @param _idx recursive position of _labels to erase + * @param _labels list of subnode labes + * @param _subnode subnode being erased + */ + function eraseNodeHierarchy( + uint _idx, + bytes32[] _labels, + bytes32 _subnode + ) + private + { + // Take ownership of the node + ensRegistry.setSubnodeOwner(_subnode, _labels[_idx], address(this)); + bytes32 subnode = keccak256(abi.encodePacked(_subnode, _labels[_idx])); + + // Recurse if there are more labels + if (_idx > 0) { + eraseNodeHierarchy(_idx - 1, _labels, subnode); + } + + // Erase the resolver and owner records + ensRegistry.setResolver(subnode, 0); + ensRegistry.setOwner(subnode, 0); + } + /** * @dev Decodes abi encoded data with selector for "register(bytes32,address,bytes32,bytes32)". * @param _data Abi encoded data. diff --git a/test/usernameregistrar.spec.js b/test/usernameregistrar.spec.js index 7a0ccac..c2330d7 100644 --- a/test/usernameregistrar.spec.js +++ b/test/usernameregistrar.spec.js @@ -986,6 +986,74 @@ contract('UsernameRegistrar', function () { }); }); +describe('eraseNode(bytes32[])', function() { + it('should clear unowned subdomains of users', async () => {; + const registrant = accountsArr[6]; + const anyone = accountsArr[5]; + await TestToken.methods.mint(registry.price).send({from: registrant}); + await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); + const username = "root"; + const usernameHash = namehash.hash(username + '.' + registry.registry); + const label = web3Utils.sha3(username); + const labels = [ + web3Utils.sha3("10"), + web3Utils.sha3("9"), + web3Utils.sha3("8"), + web3Utils.sha3("7"), + web3Utils.sha3("6"), + web3Utils.sha3("5"), + web3Utils.sha3("4"), + web3Utils.sha3("3"), + web3Utils.sha3("2"), + web3Utils.sha3("1"), + web3Utils.sha3("0"), + web3Utils.sha3(username), + ]; + await UsernameRegistrar.methods.register( + label, + utils.zeroAddress, + utils.zeroBytes32, + utils.zeroBytes32 + ).send({from: registrant}); + assert.equal(await ens.methods.owner(usernameHash).call(), registrant); + const releaseDelay = await UsernameRegistrar.methods.releaseDelay().call(); + await utils.increaseTime(releaseDelay) + await utils.increaseTime(1000) + await utils.increaseTime(1000) + let subnode = usernameHash; + for (let index = labels.length - 1; index > 0; index--) { + const label = labels[index - 1]; + await ENSRegistry.methods.setSubnodeOwner(subnode, label, registrant).send({from: registrant}); + subnode = web3Utils.soliditySha3(subnode, label); + assert.equal(await ens.methods.owner(subnode).call(), registrant); + + } + + const resultRelease = await UsernameRegistrar.methods.release(web3Utils.sha3(username)).send({from: registrant}); + + subnode = usernameHash; + for (let index = labels.length - 1; index > 0; index--) { + const label = labels[index - 1]; + subnode = web3Utils.soliditySha3(subnode, label); + assert.equal(await ens.methods.owner(subnode).call(), registrant); + } + + const resultErase = await UsernameRegistrar.methods.eraseNode( + labels + ).send({from: anyone}); + //TODO: check events + + subnode = usernameHash; + for (let index = labels.length - 1; index > 0; index--) { + const label = labels[index - 1]; + subnode = web3Utils.soliditySha3(subnode, label); + assert.equal(await ens.methods.owner(subnode).call(), utils.zeroAddress); + } + }); + + +}); + describe('moveRegistry(address)', function() { it('should move registry to new registry and migrate', async () => { const result = await UsernameRegistrar.methods.moveRegistry(UpdatedUsernameRegistrar.address).send();