diff options
Diffstat (limited to 'common/resolver/resolver.go')
-rw-r--r-- | common/resolver/resolver.go | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/common/resolver/resolver.go b/common/resolver/resolver.go new file mode 100644 index 000000000..1e6d03ffb --- /dev/null +++ b/common/resolver/resolver.go @@ -0,0 +1,128 @@ +package resolver + +import ( + "encoding/binary" + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + xe "github.com/ethereum/go-ethereum/xeth" +) + +/* +Resolver implements the Ethereum DNS mapping +HashReg : Key Hash (hash of domain name or contract code) -> Content Hash +UrlHint : Content Hash -> Url Hint + +The resolver is meant to be called by the roundtripper transport implementation +of a url scheme +*/ + +// contract addresses will be hardcoded after they're created +var URLHintContractAddress string = "0000000000000000000000000000000000000000000000000000000000001234" +var HashRegContractAddress string = "0000000000000000000000000000000000000000000000000000000000005678" + +func CreateContracts(xeth *xe.XEth, addr string) { + var err error + URLHintContractAddress, err = xeth.Transact(addr, "", "100000000000", "1000000", "100000", ContractCodeURLhint) + if err != nil { + panic(err) + } + HashRegContractAddress, err = xeth.Transact(addr, "", "100000000000", "1000000", "100000", ContractCodeHashReg) + if err != nil { + panic(err) + } +} + +type Resolver struct { + backend Backend + urlHintContractAddress string + hashRegContractAddress string +} + +type Backend interface { + StorageAt(string, string) string +} + +func New(eth Backend, uhca, nrca string) *Resolver { + return &Resolver{eth, uhca, nrca} +} + +func (self *Resolver) KeyToContentHash(khash common.Hash) (chash common.Hash, err error) { + // look up in hashReg + key := storageAddress(storageMapping(storageIdx2Addr(1), khash[:])) + hash := self.backend.StorageAt(self.hashRegContractAddress, key) + + if hash == "0x0" || len(hash) < 3 { + err = fmt.Errorf("GetHashReg: content hash not found") + return + } + + copy(chash[:], common.Hex2BytesFixed(hash[2:], 32)) + return +} + +func (self *Resolver) ContentHashToUrl(chash common.Hash) (uri string, err error) { + // look up in URL reg + var str string = " " + var idx uint32 + for len(str) > 0 { + mapaddr := storageMapping(storageIdx2Addr(1), chash[:]) + key := storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(idx))) + hex := self.backend.StorageAt(self.urlHintContractAddress, key) + str = string(common.Hex2Bytes(hex[2:])) + l := len(str) + for (l > 0) && (str[l-1] == 0) { + l-- + } + str = str[:l] + uri = uri + str + idx++ + } + + if len(uri) == 0 { + err = fmt.Errorf("GetURLhint: URL hint not found") + } + return +} + +func (self *Resolver) KeyToUrl(key common.Hash) (uri string, hash common.Hash, err error) { + // look up in urlHint + hash, err = self.KeyToContentHash(key) + if err != nil { + return + } + uri, err = self.ContentHashToUrl(hash) + return +} + +func storageIdx2Addr(varidx uint32) []byte { + data := make([]byte, 32) + binary.BigEndian.PutUint32(data[28:32], varidx) + return data +} + +func storageMapping(addr, key []byte) []byte { + data := make([]byte, 64) + copy(data[0:32], key[0:32]) + copy(data[32:64], addr[0:32]) + return crypto.Sha3(data) +} + +func storageFixedArray(addr, idx []byte) []byte { + var carry byte + for i := 31; i >= 0; i-- { + var b byte = addr[i] + idx[i] + carry + if b < addr[i] { + carry = 1 + } else { + carry = 0 + } + addr[i] = b + } + return addr +} + +func storageAddress(addr []byte) string { + return common.ToHex(addr) +} |