github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/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/ethereumproject/go-ethereum/common" 26 "github.com/ethereumproject/go-ethereum/crypto" 27 "github.com/ethereumproject/go-ethereum/logger" 28 "github.com/ethereumproject/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 the first time any Registrar method is called 52 in a client session. 53 This is done for frontier by default, otherwise the caller needs to make sure 54 the relevant environment initialised the desired contracts 55 */ 56 var ( 57 GlobalRegistrarAddr = "0x33990122638b9132ca29c723bdf037f1a891a70c" // frontier 58 HashRegAddr = "0x23bf622b5a65f6060d855fca401133ded3520620" // frontier 59 UrlHintAddr = "0x73ed5ef6c010727dfd2671dbb70faac19ec18626" // frontier 60 61 zero = regexp.MustCompile("^(0x)?0*$") 62 ) 63 64 const ( 65 trueHex = "0000000000000000000000000000000000000000000000000000000000000001" 66 falseHex = "0000000000000000000000000000000000000000000000000000000000000000" 67 ) 68 69 func abiSignature(s string) string { 70 return common.ToHex(crypto.Keccak256([]byte(s))[:4]) 71 } 72 73 var ( 74 HashRegName = "HashReg" 75 UrlHintName = "UrlHint" 76 77 registerContentHashAbi = abiSignature("register(uint256,uint256)") 78 registerUrlAbi = abiSignature("register(uint256,uint8,uint256)") 79 setOwnerAbi = abiSignature("setowner()") 80 reserveAbi = abiSignature("reserve(bytes32)") 81 resolveAbi = abiSignature("addr(bytes32)") 82 registerAbi = abiSignature("setAddress(bytes32,address,bool)") 83 addressAbiPrefix = falseHex[:24] 84 ) 85 86 // Registrar's backend is defined as an interface (implemented by xeth, but could be remote) 87 type Backend interface { 88 StorageAt(string, string) string 89 Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) 90 Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, string, error) 91 } 92 93 // TODO Registrar should also just implement The Resolver and Registry interfaces 94 // Simplify for now. 95 type VersionedRegistrar interface { 96 Resolver(*big.Int) *Registrar 97 Registry() *Registrar 98 } 99 100 type Registrar struct { 101 backend Backend 102 } 103 104 func New(b Backend) (res *Registrar) { 105 res = &Registrar{b} 106 return 107 } 108 109 func (self *Registrar) SetGlobalRegistrar(namereg string, addr common.Address) (txhash string, err error) { 110 if namereg != "" { 111 GlobalRegistrarAddr = namereg 112 return 113 } 114 if zero.MatchString(GlobalRegistrarAddr) { 115 if addr.IsEmpty() { 116 err = fmt.Errorf("GlobalRegistrar address not found and sender for creation not given") 117 return 118 } else { 119 txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "800000", "", GlobalRegistrarCode) 120 if err != nil { 121 err = fmt.Errorf("GlobalRegistrar address not found and sender for creation failed: %v", err) 122 return 123 } 124 } 125 } 126 return 127 } 128 129 func (self *Registrar) SetHashReg(hashreg string, addr common.Address) (txhash string, err error) { 130 if hashreg != "" { 131 HashRegAddr = hashreg 132 } else { 133 if !zero.MatchString(HashRegAddr) { 134 return 135 } 136 nameHex, extra := encodeName(HashRegName, 2) 137 hashRegAbi := resolveAbi + nameHex + extra 138 glog.V(logger.Detail).Infof("\ncall HashRegAddr %v with %v\n", GlobalRegistrarAddr, hashRegAbi) 139 var res string 140 res, _, err = self.backend.Call("", GlobalRegistrarAddr, "", "", "", hashRegAbi) 141 if len(res) >= 40 { 142 HashRegAddr = "0x" + res[len(res)-40:] 143 } 144 if err != nil || zero.MatchString(HashRegAddr) { 145 if addr.IsEmpty() { 146 err = fmt.Errorf("HashReg address not found and sender for creation not given") 147 return 148 } 149 150 txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "", "", HashRegCode) 151 if err != nil { 152 err = fmt.Errorf("HashReg address not found and sender for creation failed: %v", err) 153 } 154 glog.V(logger.Detail).Infof("created HashRegAddr @ txhash %v\n", txhash) 155 } else { 156 glog.V(logger.Detail).Infof("HashRegAddr found at @ %v\n", HashRegAddr) 157 return 158 } 159 } 160 161 return 162 } 163 164 func (self *Registrar) SetUrlHint(urlhint string, addr common.Address) (txhash string, err error) { 165 if urlhint != "" { 166 UrlHintAddr = urlhint 167 } else { 168 if !zero.MatchString(UrlHintAddr) { 169 return 170 } 171 nameHex, extra := encodeName(UrlHintName, 2) 172 urlHintAbi := resolveAbi + nameHex + extra 173 glog.V(logger.Detail).Infof("UrlHint address query data: %s to %s", urlHintAbi, GlobalRegistrarAddr) 174 var res string 175 res, _, err = self.backend.Call("", GlobalRegistrarAddr, "", "", "", urlHintAbi) 176 if len(res) >= 40 { 177 UrlHintAddr = "0x" + res[len(res)-40:] 178 } 179 if err != nil || zero.MatchString(UrlHintAddr) { 180 if addr.IsEmpty() { 181 err = fmt.Errorf("UrlHint address not found and sender for creation not given") 182 return 183 } 184 txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "210000", "", UrlHintCode) 185 if err != nil { 186 err = fmt.Errorf("UrlHint address not found and sender for creation failed: %v", err) 187 } 188 glog.V(logger.Detail).Infof("created UrlHint @ txhash %v\n", txhash) 189 } else { 190 glog.V(logger.Detail).Infof("UrlHint found @ %v\n", HashRegAddr) 191 return 192 } 193 } 194 195 return 196 } 197 198 // called as first step in the registration process on HashReg 199 func (self *Registrar) SetOwner(address common.Address) (txh string, err error) { 200 if zero.MatchString(HashRegAddr) { 201 return "", fmt.Errorf("HashReg address is not set") 202 } 203 return self.backend.Transact( 204 address.Hex(), 205 HashRegAddr, 206 "", "", "", "", 207 setOwnerAbi, 208 ) 209 } 210 211 // registers some content hash to a key/code hash 212 // e.g., the contract Info combined Json Doc's ContentHash 213 // to CodeHash of a contract or hash of a domain 214 func (self *Registrar) SetHashToHash(address common.Address, codehash, dochash common.Hash) (txh string, err error) { 215 if zero.MatchString(HashRegAddr) { 216 return "", fmt.Errorf("HashReg address is not set") 217 } 218 219 _, err = self.SetOwner(address) 220 if err != nil { 221 return 222 } 223 codehex := common.Bytes2Hex(codehash[:]) 224 dochex := common.Bytes2Hex(dochash[:]) 225 226 data := registerContentHashAbi + codehex + dochex 227 glog.V(logger.Detail).Infof("SetHashToHash data: %s sent to %v\n", data, HashRegAddr) 228 return self.backend.Transact( 229 address.Hex(), 230 HashRegAddr, 231 "", "", "", "", 232 data, 233 ) 234 } 235 236 // SetUrlToHash(from, hash, url) registers a url to a content hash so that the content can be fetched 237 // address is used as sender for the transaction and will be the owner of a new 238 // registry entry on first time use 239 // FIXME: silently doing nothing if sender is not the owner 240 // note that with content addressed storage, this step is no longer necessary 241 func (self *Registrar) SetUrlToHash(address common.Address, hash common.Hash, url string) (txh string, err error) { 242 if zero.MatchString(UrlHintAddr) { 243 return "", fmt.Errorf("UrlHint address is not set") 244 } 245 246 hashHex := common.Bytes2Hex(hash[:]) 247 var urlHex string 248 urlb := []byte(url) 249 var cnt byte 250 n := len(urlb) 251 252 for n > 0 { 253 if n > 32 { 254 n = 32 255 } 256 urlHex = common.Bytes2Hex(urlb[:n]) 257 urlb = urlb[n:] 258 n = len(urlb) 259 bcnt := make([]byte, 32) 260 bcnt[31] = cnt 261 data := registerUrlAbi + 262 hashHex + 263 common.Bytes2Hex(bcnt) + 264 common.Bytes2Hex(common.Hex2BytesFixed(urlHex, 32)) 265 txh, err = self.backend.Transact( 266 address.Hex(), 267 UrlHintAddr, 268 "", "", "", "", 269 data, 270 ) 271 if err != nil { 272 return 273 } 274 cnt++ 275 } 276 return 277 } 278 279 // HashToHash(key) resolves contenthash for key (a hash) using HashReg 280 // resolution is costless non-transactional 281 // implemented as direct retrieval from db 282 func (self *Registrar) HashToHash(khash common.Hash) (chash common.Hash, err error) { 283 if zero.MatchString(HashRegAddr) { 284 return common.Hash{}, fmt.Errorf("HashReg address is not set") 285 } 286 287 // look up in hashReg 288 at := HashRegAddr[2:] 289 key := storageAddress(storageMapping(storageIdx2Addr(1), khash[:])) 290 hash := self.backend.StorageAt(at, key) 291 292 if hash == "0x0" || len(hash) < 3 || (hash == common.Hash{}.Hex()) { 293 err = fmt.Errorf("HashToHash: content hash not found for '%v'", khash.Hex()) 294 return 295 } 296 copy(chash[:], common.Hex2BytesFixed(hash[2:], 32)) 297 return 298 } 299 300 func storageIdx2Addr(varidx uint32) []byte { 301 data := make([]byte, 32) 302 binary.BigEndian.PutUint32(data[28:32], varidx) 303 return data 304 } 305 306 func storageMapping(addr, key []byte) []byte { 307 data := make([]byte, 64) 308 copy(data[0:32], key[0:32]) 309 copy(data[32:64], addr[0:32]) 310 sha := crypto.Keccak256(data) 311 return sha 312 } 313 314 func storageAddress(addr []byte) string { 315 return common.ToHex(addr) 316 } 317 318 func encodeName(name string, index uint8) (string, string) { 319 extra := common.Bytes2Hex([]byte(name)) 320 if len(name) > 32 { 321 return fmt.Sprintf("%064x", index), extra 322 } 323 return extra + falseHex[len(extra):], "" 324 }