did:cow, a proposal for an ID resolution method with most of the convenience of did:plc/did:web and the robustness of a public blockchain
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

drop the prefix business

+82 -123
-19
script/Counter.s.sol
··· 1 - // SPDX-License-Identifier: UNLICENSED 2 - pragma solidity ^0.8.13; 3 - 4 - import {Script} from "forge-std/Script.sol"; 5 - import {Counter} from "../src/Counter.sol"; 6 - 7 - contract CounterScript is Script { 8 - Counter public counter; 9 - 10 - function setUp() public {} 11 - 12 - function run() public { 13 - vm.startBroadcast(); 14 - 15 - counter = new Counter(); 16 - 17 - vm.stopBroadcast(); 18 - } 19 - }
+30 -40
src/CowRegistry.sol
··· 5 5 6 6 struct Cow { 7 7 address controller; 8 - bytes12 prefix; // set to "did::" to deactivate 9 8 string wrappedDID; 10 9 } 10 + 11 + string constant DEACTIVATED = "did::"; 11 12 12 13 mapping(bytes32 => Cow) public cows; 13 14 14 - event CowInitialized(bytes32 indexed cowHash, address controller, bytes12 prefix, string wrappedDID); 15 + event CowInitialized(bytes32 indexed cowHash, address controller, string wrappedDID); 15 16 event CowDeactivated(bytes32 indexed cowHash); 16 17 event ControllerUpdated(bytes32 indexed cowHash, address controller); 17 - event WrappedDIDUpdated(bytes32 indexed cowHash, bytes12 prefix, string wrappedDID); 18 + event WrappedDIDUpdated(bytes32 indexed cowHash, string wrappedDID); 18 19 19 - function updateWrappedDIDByHash( 20 - bytes32 cowHash, 21 - bytes12 prefix, 22 - string memory wrappedDID 23 - ) public { 24 - require(cows[cowHash].prefix != bytes12("did::")); 20 + function _isDeactivated(bytes32 cowHash) internal view returns (bool) { 21 + return keccak256(bytes(cows[cowHash].wrappedDID)) == keccak256(bytes(DEACTIVATED)); 22 + } 23 + 24 + function updateWrappedDIDByHash(bytes32 cowHash, string memory wrappedDID) public { 25 + require(!_isDeactivated(cowHash)); 25 26 require(msg.sender == cows[cowHash].controller); 27 + require(keccak256(bytes(wrappedDID)) != keccak256(bytes(DEACTIVATED)), "Use deactivate() to deactivate"); 26 28 27 - require(prefix != bytes12("did::"), "Use deactivate() to deactivate"); 28 - 29 - cows[cowHash].prefix = prefix; 30 29 cows[cowHash].wrappedDID = wrappedDID; 31 - emit WrappedDIDUpdated(cowHash, prefix, wrappedDID); 30 + emit WrappedDIDUpdated(cowHash, wrappedDID); 32 31 } 33 32 34 - function updateControllerByHash( 35 - bytes32 cowHash, 36 - address controller 37 - ) public { 38 - require(cows[cowHash].prefix != bytes12("did::")); 33 + function updateControllerByHash(bytes32 cowHash, address controller) public { 34 + require(!_isDeactivated(cowHash)); 39 35 require(msg.sender == cows[cowHash].controller); 40 36 41 37 cows[cowHash].controller = controller; 42 38 emit ControllerUpdated(cowHash, controller); 43 39 } 44 40 45 - function calculateCowHash(address controller, bytes12 prefix, string memory wrappedDID) public pure returns (bytes32) { 46 - return keccak256(abi.encodePacked(controller, prefix, wrappedDID)); 41 + function calculateCowHash(address controller, string memory wrappedDID) public pure returns (bytes32) { 42 + return keccak256(abi.encodePacked(controller, wrappedDID)); 47 43 } 48 44 49 - // Return a cow hash for the settings, storing the cow if it was not already there 50 - function _ensureCowInitialized(address controller, bytes12 prefix, string memory wrappedDID) internal returns (bytes32 cowHash) { 51 - cowHash = calculateCowHash(controller, prefix, wrappedDID); 52 - if (cows[cowHash].prefix == bytes12(0)) { // unregistered 53 - cows[cowHash] = Cow( 54 - controller, 55 - prefix, 56 - wrappedDID 57 - ); 58 - emit CowInitialized(cowHash, controller, prefix, wrappedDID); 45 + function _ensureCowInitialized(address controller, string memory wrappedDID) internal returns (bytes32 cowHash) { 46 + cowHash = calculateCowHash(controller, wrappedDID); 47 + if (bytes(cows[cowHash].wrappedDID).length == 0) { 48 + cows[cowHash] = Cow(controller, wrappedDID); 49 + emit CowInitialized(cowHash, controller, wrappedDID); 59 50 } 60 51 return cowHash; 61 52 } 62 53 63 54 // You don't particularly need to call this, you can leave it until you make an update 64 - function initializeCow(address controller, bytes12 prefix, string memory wrappedDID) external { 65 - _ensureCowInitialized(controller, prefix, wrappedDID); 55 + function initializeCow(address controller, string memory wrappedDID) external { 56 + _ensureCowInitialized(controller, wrappedDID); 66 57 } 67 58 68 - function updateWrappedDID(address controller, bytes12 prefix, string memory wrappedDID, bytes12 newPrefix, string memory newWrappedDID) public { 69 - bytes32 cowHash = _ensureCowInitialized(controller, prefix, wrappedDID); 70 - updateWrappedDIDByHash(cowHash, newPrefix, newWrappedDID); 59 + function updateWrappedDID(address controller, string memory wrappedDID, string memory newWrappedDID) public { 60 + bytes32 cowHash = _ensureCowInitialized(controller, wrappedDID); 61 + updateWrappedDIDByHash(cowHash, newWrappedDID); 71 62 } 72 63 73 - function updateController(address controller, bytes12 prefix, string memory wrappedDID, address newController) public { 74 - bytes32 cowHash = _ensureCowInitialized(controller, prefix, wrappedDID); 64 + function updateController(address controller, string memory wrappedDID, address newController) public { 65 + bytes32 cowHash = _ensureCowInitialized(controller, wrappedDID); 75 66 updateControllerByHash(cowHash, newController); 76 67 } 77 68 78 69 function deactivate(bytes32 cowHash) external { 79 - require(cows[cowHash].prefix != bytes12("did::")); 70 + require(!_isDeactivated(cowHash)); 80 71 require(msg.sender == cows[cowHash].controller); 81 72 82 - cows[cowHash].prefix = bytes12("did::"); 73 + cows[cowHash].wrappedDID = DEACTIVATED; 83 74 cows[cowHash].controller = address(0); 84 75 85 76 emit CowDeactivated(cowHash); 86 77 } 87 - 88 78 }
+52 -64
test/CowRegistry.t.sol
··· 11 11 address controller2 = address(0x2222); 12 12 13 13 // Two did:plc addresses 14 - bytes12 plcPrefix = bytes12("did:plc:"); 15 - string plcDID1 = "7qqsrnkn4moc2jgd"; // did:plc:7qqsrnkn4moc2jgd 16 - string plcDID2 = "abcdefghijklmnop"; // did:plc:abcdefghijklmnop 14 + string plcDID1 = "did:plc:7qqsrnkn4moc2jgd"; 15 + string plcDID2 = "did:plc:abcdefghijklmnop"; 17 16 18 17 // did:web addresses of varying lengths 19 - bytes12 webPrefix = bytes12("did:web:"); 20 - string webDIDShort = "a.io"; // did:web:a.io 21 - string webDIDMedium = "example.com"; // did:web:example.com 22 - string webDIDLong = "subdomain.very-long-hostname.example.co.uk"; // did:web:subdomain... 23 - string webDIDVeryLong = "deep.nested.subdomain.with-a-quite-long-hostname.enterprise.example.com"; // did:web:... 18 + string webDIDShort = "did:web:a.io"; 19 + string webDIDMedium = "did:web:example.com"; 20 + string webDIDLong = "did:web:subdomain.very-long-hostname.example.co.uk"; 21 + string webDIDVeryLong = "did:web:deep.nested.subdomain.with-a-quite-long-hostname.enterprise.example.com"; 24 22 25 23 function setUp() public { 26 24 registry = new CowRegistry(); 27 25 } 28 26 29 - // ------------------------------------------------------------------------- 30 - // Helpers 31 - // ------------------------------------------------------------------------- 32 - 33 - function _hashFor(address ctrl, bytes12 pfx, string memory did) internal view returns (bytes32) { 34 - return registry.calculateCowHash(ctrl, pfx, did); 35 - } 36 - 37 - function _init(address ctrl, bytes12 pfx, string memory did) internal returns (bytes32) { 38 - registry.initializeCow(ctrl, pfx, did); 39 - return _hashFor(ctrl, pfx, did); 27 + function _init(address ctrl, string memory did) internal returns (bytes32) { 28 + registry.initializeCow(ctrl, did); 29 + return registry.calculateCowHash(ctrl, did); 40 30 } 41 31 42 32 // ------------------------------------------------------------------------- ··· 44 34 // ------------------------------------------------------------------------- 45 35 46 36 function test_updateWrappedDID_plc1_to_plc2() public { 47 - bytes32 cowHash = _init(controller1, plcPrefix, plcDID1); 37 + bytes32 cowHash = _init(controller1, plcDID1); 48 38 49 39 vm.prank(controller1); 50 40 uint256 gasBefore = gasleft(); 51 - registry.updateWrappedDIDByHash(cowHash, plcPrefix, plcDID2); 41 + registry.updateWrappedDIDByHash(cowHash, plcDID2); 52 42 uint256 gasUsed = gasBefore - gasleft(); 53 43 54 - (, bytes12 pfx, string memory did) = registry.cows(cowHash); 55 - assertEq(pfx, plcPrefix); 44 + (, string memory did) = registry.cows(cowHash); 56 45 assertEq(did, plcDID2); 57 46 emit log_named_uint("gas updateWrappedDID plc1->plc2", gasUsed); 58 47 } 59 48 60 49 function test_updateWrappedDID_plc2_to_plc1() public { 61 - bytes32 cowHash = _init(controller2, plcPrefix, plcDID2); 50 + bytes32 cowHash = _init(controller2, plcDID2); 62 51 63 52 vm.prank(controller2); 64 53 uint256 gasBefore = gasleft(); 65 - registry.updateWrappedDIDByHash(cowHash, plcPrefix, plcDID1); 54 + registry.updateWrappedDIDByHash(cowHash, plcDID1); 66 55 uint256 gasUsed = gasBefore - gasleft(); 67 56 68 - (, , string memory did) = registry.cows(cowHash); 57 + (, string memory did) = registry.cows(cowHash); 69 58 assertEq(did, plcDID1); 70 59 emit log_named_uint("gas updateWrappedDID plc2->plc1", gasUsed); 71 60 } ··· 75 64 // ------------------------------------------------------------------------- 76 65 77 66 function test_updateWrappedDID_web_short() public { 78 - bytes32 cowHash = _init(controller1, plcPrefix, plcDID1); 67 + bytes32 cowHash = _init(controller1, plcDID1); 79 68 80 69 vm.prank(controller1); 81 70 uint256 gasBefore = gasleft(); 82 - registry.updateWrappedDIDByHash(cowHash, webPrefix, webDIDShort); 71 + registry.updateWrappedDIDByHash(cowHash, webDIDShort); 83 72 uint256 gasUsed = gasBefore - gasleft(); 84 73 85 - (, bytes12 pfx, string memory did) = registry.cows(cowHash); 86 - assertEq(pfx, webPrefix); 74 + (, string memory did) = registry.cows(cowHash); 87 75 assertEq(did, webDIDShort); 88 - emit log_named_uint("gas updateWrappedDID web short (4 chars)", gasUsed); 76 + emit log_named_uint("gas updateWrappedDID web short (12 chars)", gasUsed); 89 77 } 90 78 91 79 function test_updateWrappedDID_web_medium() public { 92 - bytes32 cowHash = _init(controller1, plcPrefix, plcDID1); 80 + bytes32 cowHash = _init(controller1, plcDID1); 93 81 94 82 vm.prank(controller1); 95 83 uint256 gasBefore = gasleft(); 96 - registry.updateWrappedDIDByHash(cowHash, webPrefix, webDIDMedium); 84 + registry.updateWrappedDIDByHash(cowHash, webDIDMedium); 97 85 uint256 gasUsed = gasBefore - gasleft(); 98 86 99 - (, , string memory did) = registry.cows(cowHash); 87 + (, string memory did) = registry.cows(cowHash); 100 88 assertEq(did, webDIDMedium); 101 - emit log_named_uint("gas updateWrappedDID web medium (11 chars)", gasUsed); 89 + emit log_named_uint("gas updateWrappedDID web medium (19 chars)", gasUsed); 102 90 } 103 91 104 92 function test_updateWrappedDID_web_long() public { 105 - bytes32 cowHash = _init(controller1, plcPrefix, plcDID1); 93 + bytes32 cowHash = _init(controller1, plcDID1); 106 94 107 95 vm.prank(controller1); 108 96 uint256 gasBefore = gasleft(); 109 - registry.updateWrappedDIDByHash(cowHash, webPrefix, webDIDLong); 97 + registry.updateWrappedDIDByHash(cowHash, webDIDLong); 110 98 uint256 gasUsed = gasBefore - gasleft(); 111 99 112 - (, , string memory did) = registry.cows(cowHash); 100 + (, string memory did) = registry.cows(cowHash); 113 101 assertEq(did, webDIDLong); 114 - emit log_named_uint("gas updateWrappedDID web long (42 chars)", gasUsed); 102 + emit log_named_uint("gas updateWrappedDID web long (50 chars)", gasUsed); 115 103 } 116 104 117 105 function test_updateWrappedDID_web_verylong() public { 118 - bytes32 cowHash = _init(controller1, plcPrefix, plcDID1); 106 + bytes32 cowHash = _init(controller1, plcDID1); 119 107 120 108 vm.prank(controller1); 121 109 uint256 gasBefore = gasleft(); 122 - registry.updateWrappedDIDByHash(cowHash, webPrefix, webDIDVeryLong); 110 + registry.updateWrappedDIDByHash(cowHash, webDIDVeryLong); 123 111 uint256 gasUsed = gasBefore - gasleft(); 124 112 125 - (, , string memory did) = registry.cows(cowHash); 113 + (, string memory did) = registry.cows(cowHash); 126 114 assertEq(did, webDIDVeryLong); 127 - emit log_named_uint("gas updateWrappedDID web very long (71 chars)", gasUsed); 115 + emit log_named_uint("gas updateWrappedDID web very long (79 chars)", gasUsed); 128 116 } 129 117 130 118 // ------------------------------------------------------------------------- ··· 132 120 // ------------------------------------------------------------------------- 133 121 134 122 function test_updateController_plc1() public { 135 - bytes32 cowHash = _init(controller1, plcPrefix, plcDID1); 123 + bytes32 cowHash = _init(controller1, plcDID1); 136 124 137 125 vm.prank(controller1); 138 126 uint256 gasBefore = gasleft(); 139 127 registry.updateControllerByHash(cowHash, controller2); 140 128 uint256 gasUsed = gasBefore - gasleft(); 141 129 142 - (address ctrl, , ) = registry.cows(cowHash); 130 + (address ctrl, ) = registry.cows(cowHash); 143 131 assertEq(ctrl, controller2); 144 132 emit log_named_uint("gas updateController plc1 ctrl1->ctrl2", gasUsed); 145 133 } 146 134 147 135 function test_updateController_plc2() public { 148 - bytes32 cowHash = _init(controller2, plcPrefix, plcDID2); 136 + bytes32 cowHash = _init(controller2, plcDID2); 149 137 150 138 vm.prank(controller2); 151 139 uint256 gasBefore = gasleft(); 152 140 registry.updateControllerByHash(cowHash, controller1); 153 141 uint256 gasUsed = gasBefore - gasleft(); 154 142 155 - (address ctrl, , ) = registry.cows(cowHash); 143 + (address ctrl, ) = registry.cows(cowHash); 156 144 assertEq(ctrl, controller1); 157 145 emit log_named_uint("gas updateController plc2 ctrl2->ctrl1", gasUsed); 158 146 } ··· 162 150 // ------------------------------------------------------------------------- 163 151 164 152 function test_updateController_web_short() public { 165 - bytes32 cowHash = _init(controller1, webPrefix, webDIDShort); 153 + bytes32 cowHash = _init(controller1, webDIDShort); 166 154 167 155 vm.prank(controller1); 168 156 uint256 gasBefore = gasleft(); 169 157 registry.updateControllerByHash(cowHash, controller2); 170 158 uint256 gasUsed = gasBefore - gasleft(); 171 159 172 - (address ctrl, , ) = registry.cows(cowHash); 160 + (address ctrl, ) = registry.cows(cowHash); 173 161 assertEq(ctrl, controller2); 174 - emit log_named_uint("gas updateController web short (4 chars)", gasUsed); 162 + emit log_named_uint("gas updateController web short (12 chars)", gasUsed); 175 163 } 176 164 177 165 function test_updateController_web_medium() public { 178 - bytes32 cowHash = _init(controller1, webPrefix, webDIDMedium); 166 + bytes32 cowHash = _init(controller1, webDIDMedium); 179 167 180 168 vm.prank(controller1); 181 169 uint256 gasBefore = gasleft(); 182 170 registry.updateControllerByHash(cowHash, controller2); 183 171 uint256 gasUsed = gasBefore - gasleft(); 184 172 185 - (address ctrl, , ) = registry.cows(cowHash); 173 + (address ctrl, ) = registry.cows(cowHash); 186 174 assertEq(ctrl, controller2); 187 - emit log_named_uint("gas updateController web medium (11 chars)", gasUsed); 175 + emit log_named_uint("gas updateController web medium (19 chars)", gasUsed); 188 176 } 189 177 190 178 function test_updateController_web_long() public { 191 - bytes32 cowHash = _init(controller1, webPrefix, webDIDLong); 179 + bytes32 cowHash = _init(controller1, webDIDLong); 192 180 193 181 vm.prank(controller1); 194 182 uint256 gasBefore = gasleft(); 195 183 registry.updateControllerByHash(cowHash, controller2); 196 184 uint256 gasUsed = gasBefore - gasleft(); 197 185 198 - (address ctrl, , ) = registry.cows(cowHash); 186 + (address ctrl, ) = registry.cows(cowHash); 199 187 assertEq(ctrl, controller2); 200 - emit log_named_uint("gas updateController web long (42 chars)", gasUsed); 188 + emit log_named_uint("gas updateController web long (50 chars)", gasUsed); 201 189 } 202 190 203 191 function test_updateController_web_verylong() public { 204 - bytes32 cowHash = _init(controller1, webPrefix, webDIDVeryLong); 192 + bytes32 cowHash = _init(controller1, webDIDVeryLong); 205 193 206 194 vm.prank(controller1); 207 195 uint256 gasBefore = gasleft(); 208 196 registry.updateControllerByHash(cowHash, controller2); 209 197 uint256 gasUsed = gasBefore - gasleft(); 210 198 211 - (address ctrl, , ) = registry.cows(cowHash); 199 + (address ctrl, ) = registry.cows(cowHash); 212 200 assertEq(ctrl, controller2); 213 - emit log_named_uint("gas updateController web very long (71 chars)", gasUsed); 201 + emit log_named_uint("gas updateController web very long (79 chars)", gasUsed); 214 202 } 215 203 216 204 // ------------------------------------------------------------------------- ··· 218 206 // ------------------------------------------------------------------------- 219 207 220 208 function test_updateWrappedDID_rejectsNonController() public { 221 - bytes32 cowHash = _init(controller1, plcPrefix, plcDID1); 209 + bytes32 cowHash = _init(controller1, plcDID1); 222 210 223 211 vm.prank(controller2); 224 212 vm.expectRevert(); 225 - registry.updateWrappedDIDByHash(cowHash, plcPrefix, plcDID2); 213 + registry.updateWrappedDIDByHash(cowHash, plcDID2); 226 214 } 227 215 228 216 function test_updateController_rejectsNonController() public { 229 - bytes32 cowHash = _init(controller1, plcPrefix, plcDID1); 217 + bytes32 cowHash = _init(controller1, plcDID1); 230 218 231 219 vm.prank(controller2); 232 220 vm.expectRevert(); ··· 234 222 } 235 223 236 224 function test_updateWrappedDID_rejectsAfterDeactivation() public { 237 - bytes32 cowHash = _init(controller1, plcPrefix, plcDID1); 225 + bytes32 cowHash = _init(controller1, plcDID1); 238 226 239 227 vm.prank(controller1); 240 228 registry.deactivate(cowHash); 241 229 242 230 vm.prank(address(0)); 243 231 vm.expectRevert(); 244 - registry.updateWrappedDIDByHash(cowHash, plcPrefix, plcDID2); 232 + registry.updateWrappedDIDByHash(cowHash, plcDID2); 245 233 } 246 234 }