github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/common/registrar/registrar.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package registrar 18 19 import ( 20 "encoding/binary" 21 "fmt" 22 "math/big" 23 "regexp" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/crypto" 27 "github.com/ethereum/go-ethereum/logger" 28 "github.com/ethereum/go-ethereum/logger/glog" 29 ) 30 31 /* 32 Registrar implements the Ethereum name registrar services mapping 33 - arbitrary strings to ethereum addresses 34 - hashes to hashes 35 - hashes to arbitrary strings 36 (likely will provide lookup service for all three) 37 38 The Registrar is used by 39 * the roundtripper transport implementation of 40 url schemes to resolve domain names and services that register these names 41 * contract info retrieval (NatSpec). 42 43 The Registrar uses 3 contracts on the blockchain: 44 * GlobalRegistrar: Name (string) -> Address (Owner) 45 * HashReg : Key Hash (hash of domain name or contract code) -> Content Hash 46 * UrlHint : Content Hash -> Url Hint 47 48 These contracts are (currently) not included in the genesis block. 49 Each Set<X> needs to be called once on each blockchain/network once. 50 51 Contract addresses need to be set (HashReg and UrlHint retrieved from the global 52 registrar the first time any Registrar method is called in a client session 53 54 So the caller needs to make sure the relevant environment initialised the desired 55 contracts 56 */ 57 var ( 58 UrlHintAddr = "0x0" 59 HashRegAddr = "0x0" 60 GlobalRegistrarAddr = "0x0" 61 // GlobalRegistrarAddr = "0xc6d9d2cd449a754c494264e1809c50e34d64562b" 62 63 zero = regexp.MustCompile("^(0x)?0*$") 64 ) 65 66 const ( 67 trueHex = "0000000000000000000000000000000000000000000000000000000000000001" 68 falseHex = "0000000000000000000000000000000000000000000000000000000000000000" 69 ) 70 71 func abiSignature(s string) string { 72 return common.ToHex(crypto.Sha3([]byte(s))[:4]) 73 } 74 75 var ( 76 HashRegName = "HashReg" 77 UrlHintName = "UrlHint" 78 79 registerContentHashAbi = abiSignature("register(uint256,uint256)") 80 registerUrlAbi = abiSignature("register(uint256,uint8,uint256)") 81 setOwnerAbi = abiSignature("setowner()") 82 reserveAbi = abiSignature("reserve(bytes32)") 83 resolveAbi = abiSignature("addr(bytes32)") 84 registerAbi = abiSignature("setAddress(bytes32,address,bool)") 85 addressAbiPrefix = falseHex[:24] 86 ) 87 88 // Registrar's backend is defined as an interface (implemented by xeth, but could be remote) 89 type Backend interface { 90 StorageAt(string, string) string 91 Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) 92 Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, string, error) 93 } 94 95 // TODO Registrar should also just implement The Resolver and Registry interfaces 96 // Simplify for now. 97 type VersionedRegistrar interface { 98 Resolver(*big.Int) *Registrar 99 Registry() *Registrar 100 } 101 102 type Registrar struct { 103 backend Backend 104 } 105 106 func New(b Backend) (res *Registrar) { 107 res = &Registrar{b} 108 return 109 } 110 111 func (self *Registrar) SetGlobalRegistrar(namereg string, addr common.Address) (txhash string, err error) { 112 if namereg != "" { 113 GlobalRegistrarAddr = namereg 114 return 115 } 116 if GlobalRegistrarAddr == "0x0" || GlobalRegistrarAddr == "0x" { 117 if (addr == common.Address{}) { 118 err = fmt.Errorf("GlobalRegistrar address not found and sender for creation not given") 119 return 120 } else { 121 txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "800000", "", GlobalRegistrarCode) 122 if err != nil { 123 err = fmt.Errorf("GlobalRegistrar address not found and sender for creation failed: %v", err) 124 return 125 } 126 } 127 } 128 return 129 } 130 131 func (self *Registrar) SetHashReg(hashreg string, addr common.Address) (txhash string, err error) { 132 if hashreg != "" { 133 HashRegAddr = hashreg 134 } else { 135 if !zero.MatchString(HashRegAddr) { 136 return 137 } 138 nameHex, extra := encodeName(HashRegName, 2) 139 hashRegAbi := resolveAbi + nameHex + extra 140 glog.V(logger.Detail).Infof("\ncall HashRegAddr %v with %v\n", GlobalRegistrarAddr, hashRegAbi) 141 var res string 142 res, _, err = self.backend.Call("", GlobalRegistrarAddr, "", "", "", hashRegAbi) 143 if len(res) >= 40 { 144 HashRegAddr = "0x" + res[len(res)-40:len(res)] 145 } 146 if err != nil || zero.MatchString(HashRegAddr) { 147 if (addr == common.Address{}) { 148 err = fmt.Errorf("HashReg address not found and sender for creation not given") 149 return 150 } 151 152 txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "", "", HashRegCode) 153 if err != nil { 154 err = fmt.Errorf("HashReg address not found and sender for creation failed: %v", err) 155 } 156 glog.V(logger.Detail).Infof("created HashRegAddr @ txhash %v\n", txhash) 157 } else { 158 glog.V(logger.Detail).Infof("HashRegAddr found at @ %v\n", HashRegAddr) 159 return 160 } 161 } 162 163 return 164 } 165 166 func (self *Registrar) SetUrlHint(urlhint string, addr common.Address) (txhash string, err error) { 167 if urlhint != "" { 168 UrlHintAddr = urlhint 169 } else { 170 if !zero.MatchString(UrlHintAddr) { 171 return 172 } 173 nameHex, extra := encodeName(UrlHintName, 2) 174 urlHintAbi := resolveAbi + nameHex + extra 175 glog.V(logger.Detail).Infof("UrlHint address query data: %s to %s", urlHintAbi, GlobalRegistrarAddr) 176 var res string 177 res, _, err = self.backend.Call("", GlobalRegistrarAddr, "", "", "", urlHintAbi) 178 if len(res) >= 40 { 179 UrlHintAddr = "0x" + res[len(res)-40:len(res)] 180 } 181 if err != nil || zero.MatchString(UrlHintAddr) { 182 if (addr == common.Address{}) { 183 err = fmt.Errorf("UrlHint address not found and sender for creation not given") 184 return 185 } 186 txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "210000", "", UrlHintCode) 187 if err != nil { 188 err = fmt.Errorf("UrlHint address not found and sender for creation failed: %v", err) 189 } 190 glog.V(logger.Detail).Infof("created UrlHint @ txhash %v\n", txhash) 191 } else { 192 glog.V(logger.Detail).Infof("UrlHint found @ %v\n", HashRegAddr) 193 return 194 } 195 } 196 197 return 198 } 199 200 // ReserveName(from, name) reserves name for the sender address in the globalRegistrar 201 // the tx needs to be mined to take effect 202 func (self *Registrar) ReserveName(address common.Address, name string) (txh string, err error) { 203 nameHex, extra := encodeName(name, 2) 204 abi := reserveAbi + nameHex + extra 205 glog.V(logger.Detail).Infof("Reserve data: %s", abi) 206 return self.backend.Transact( 207 address.Hex(), 208 GlobalRegistrarAddr, 209 "", "", "", "", 210 abi, 211 ) 212 } 213 214 // SetAddressToName(from, name, addr) will set the Address to address for name 215 // in the globalRegistrar using from as the sender of the transaction 216 // the tx needs to be mined to take effect 217 func (self *Registrar) SetAddressToName(from common.Address, name string, address common.Address) (txh string, err error) { 218 nameHex, extra := encodeName(name, 6) 219 addrHex := encodeAddress(address) 220 221 abi := registerAbi + nameHex + addrHex + trueHex + extra 222 glog.V(logger.Detail).Infof("SetAddressToName data: %s to %s ", abi, GlobalRegistrarAddr) 223 224 return self.backend.Transact( 225 from.Hex(), 226 GlobalRegistrarAddr, 227 "", "", "", "", 228 abi, 229 ) 230 } 231 232 // NameToAddr(from, name) queries the registrar for the address on name 233 func (self *Registrar) NameToAddr(from common.Address, name string) (address common.Address, err error) { 234 nameHex, extra := encodeName(name, 2) 235 abi := resolveAbi + nameHex + extra 236 glog.V(logger.Detail).Infof("NameToAddr data: %s", abi) 237 res, _, err := self.backend.Call( 238 from.Hex(), 239 GlobalRegistrarAddr, 240 "", "", "", 241 abi, 242 ) 243 if err != nil { 244 return 245 } 246 address = common.HexToAddress(res) 247 return 248 } 249 250 // called as first step in the registration process on HashReg 251 func (self *Registrar) SetOwner(address common.Address) (txh string, err error) { 252 return self.backend.Transact( 253 address.Hex(), 254 HashRegAddr, 255 "", "", "", "", 256 setOwnerAbi, 257 ) 258 } 259 260 // registers some content hash to a key/code hash 261 // e.g., the contract Info combined Json Doc's ContentHash 262 // to CodeHash of a contract or hash of a domain 263 func (self *Registrar) SetHashToHash(address common.Address, codehash, dochash common.Hash) (txh string, err error) { 264 _, err = self.SetOwner(address) 265 if err != nil { 266 return 267 } 268 codehex := common.Bytes2Hex(codehash[:]) 269 dochex := common.Bytes2Hex(dochash[:]) 270 271 data := registerContentHashAbi + codehex + dochex 272 glog.V(logger.Detail).Infof("SetHashToHash data: %s sent to %v\n", data, HashRegAddr) 273 return self.backend.Transact( 274 address.Hex(), 275 HashRegAddr, 276 "", "", "", "", 277 data, 278 ) 279 } 280 281 // SetUrlToHash(from, hash, url) registers a url to a content hash so that the content can be fetched 282 // address is used as sender for the transaction and will be the owner of a new 283 // registry entry on first time use 284 // FIXME: silently doing nothing if sender is not the owner 285 // note that with content addressed storage, this step is no longer necessary 286 func (self *Registrar) SetUrlToHash(address common.Address, hash common.Hash, url string) (txh string, err error) { 287 hashHex := common.Bytes2Hex(hash[:]) 288 var urlHex string 289 urlb := []byte(url) 290 var cnt byte 291 n := len(urlb) 292 293 for n > 0 { 294 if n > 32 { 295 n = 32 296 } 297 urlHex = common.Bytes2Hex(urlb[:n]) 298 urlb = urlb[n:] 299 n = len(urlb) 300 bcnt := make([]byte, 32) 301 bcnt[31] = cnt 302 data := registerUrlAbi + 303 hashHex + 304 common.Bytes2Hex(bcnt) + 305 common.Bytes2Hex(common.Hex2BytesFixed(urlHex, 32)) 306 txh, err = self.backend.Transact( 307 address.Hex(), 308 UrlHintAddr, 309 "", "", "", "", 310 data, 311 ) 312 if err != nil { 313 return 314 } 315 cnt++ 316 } 317 return 318 } 319 320 // HashToHash(key) resolves contenthash for key (a hash) using HashReg 321 // resolution is costless non-transactional 322 // implemented as direct retrieval from db 323 func (self *Registrar) HashToHash(khash common.Hash) (chash common.Hash, err error) { 324 // look up in hashReg 325 at := HashRegAddr[2:] 326 key := storageAddress(storageMapping(storageIdx2Addr(1), khash[:])) 327 hash := self.backend.StorageAt(at, key) 328 329 if hash == "0x0" || len(hash) < 3 || (hash == common.Hash{}.Hex()) { 330 err = fmt.Errorf("content hash not found for '%v'", khash.Hex()) 331 return 332 } 333 copy(chash[:], common.Hex2BytesFixed(hash[2:], 32)) 334 return 335 } 336 337 // HashToUrl(contenthash) resolves the url for contenthash using UrlHint 338 // resolution is costless non-transactional 339 // implemented as direct retrieval from db 340 // if we use content addressed storage, this step is no longer necessary 341 func (self *Registrar) HashToUrl(chash common.Hash) (uri string, err error) { 342 // look up in URL reg 343 var str string = " " 344 var idx uint32 345 for len(str) > 0 { 346 mapaddr := storageMapping(storageIdx2Addr(1), chash[:]) 347 key := storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(idx))) 348 hex := self.backend.StorageAt(UrlHintAddr[2:], key) 349 str = string(common.Hex2Bytes(hex[2:])) 350 l := 0 351 for (l < len(str)) && (str[l] == 0) { 352 l++ 353 } 354 355 str = str[l:] 356 uri = uri + str 357 idx++ 358 } 359 360 if len(uri) == 0 { 361 err = fmt.Errorf("GetURLhint: URL hint not found for '%v'", chash.Hex()) 362 } 363 return 364 } 365 366 func storageIdx2Addr(varidx uint32) []byte { 367 data := make([]byte, 32) 368 binary.BigEndian.PutUint32(data[28:32], varidx) 369 return data 370 } 371 372 func storageMapping(addr, key []byte) []byte { 373 data := make([]byte, 64) 374 copy(data[0:32], key[0:32]) 375 copy(data[32:64], addr[0:32]) 376 sha := crypto.Sha3(data) 377 return sha 378 } 379 380 func storageFixedArray(addr, idx []byte) []byte { 381 var carry byte 382 for i := 31; i >= 0; i-- { 383 var b byte = addr[i] + idx[i] + carry 384 if b < addr[i] { 385 carry = 1 386 } else { 387 carry = 0 388 } 389 addr[i] = b 390 } 391 return addr 392 } 393 394 func storageAddress(addr []byte) string { 395 return common.ToHex(addr) 396 } 397 398 func encodeAddress(address common.Address) string { 399 return addressAbiPrefix + address.Hex()[2:] 400 } 401 402 func encodeName(name string, index uint8) (string, string) { 403 extra := common.Bytes2Hex([]byte(name)) 404 if len(name) > 32 { 405 return fmt.Sprintf("%064x", index), extra 406 } 407 return extra + falseHex[len(extra):], "" 408 }