From 009b2216921b15962f2612687c1460a8342d49d6 Mon Sep 17 00:00:00 2001 From: zelig Date: Wed, 22 Apr 2015 23:11:11 +0100 Subject: solidity compiler and contract metadocs integration * common/compiler: solidity compiler + tests * rpc: eth_compilers, eth_compileSolidity + tests * fix natspec test using keystore API, notice exp dynamically changes addr, cleanup * resolver implements registrars and needs to create reg contract (temp) * xeth: solidity compiler. expose getter Solc() and paths setter SetSolc(solcPath) * ethereumApi: implement compiler related RPC calls using XEth - json struct tests * admin: make use of XEth.SetSolc to allow runtime setting of compiler paths * cli: command line flags solc to set custom solc bin path * js admin api with new features debug and contractInfo modules * wiki is the doc https://github.com/ethereum/go-ethereum/wiki/Contracts-and-Transactions --- common/resolver/resolver.go | 154 ++++++++++++++++++++++++++++++++------- common/resolver/resolver_test.go | 29 +++++--- 2 files changed, 146 insertions(+), 37 deletions(-) (limited to 'common/resolver') diff --git a/common/resolver/resolver.go b/common/resolver/resolver.go index 42348a89c..9016547e1 100644 --- a/common/resolver/resolver.go +++ b/common/resolver/resolver.go @@ -6,7 +6,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - xe "github.com/ethereum/go-ethereum/xeth" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" ) /* @@ -18,50 +19,152 @@ 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" +// // contract addresses will be hardcoded after they're created +var UrlHintContractAddress, HashRegContractAddress string -func CreateContracts(xeth *xe.XEth, addr string) { - var err error - URLHintContractAddress, err = xeth.Transact(addr, "", "", "100000000000", "1000000", "100000", ContractCodeURLhint) +const ( + txValue = "0" + txGas = "100000" + txGasPrice = "1000000000000" +) + +func abi(s string) string { + return common.ToHex(crypto.Sha3([]byte(s))[:4]) +} + +var ( + registerContentHashAbi = abi("register(uint256,uint256)") + registerUrlAbi = abi("register(uint256,uint8,uint256)") + setOwnerAbi = abi("setowner()") +) + +type Backend interface { + StorageAt(string, string) string + Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) +} + +type Resolver struct { + backend Backend +} + +func New(eth Backend) *Resolver { + return &Resolver{eth} +} + +// for testing and play temporarily +// ideally the HashReg and UrlHint contracts should be in the genesis block +// if we got build-in support for natspec/contract info +// there should be only one of these officially endorsed +// addresses as constants +// TODO: could get around this with namereg, check +func (self *Resolver) CreateContracts(addr common.Address) (err error) { + HashRegContractAddress, err = self.backend.Transact(addr.Hex(), "", "", txValue, txGas, txGasPrice, ContractCodeHashReg) if err != nil { - panic(err) + return } - HashRegContractAddress, err = xeth.Transact(addr, "", "", "100000000000", "1000000", "100000", ContractCodeHashReg) + UrlHintContractAddress, err = self.backend.Transact(addr.Hex(), "", "", txValue, txGas, txGasPrice, ContractCodeURLhint) + glog.V(logger.Detail).Infof("HashReg @ %v\nUrlHint @ %v\n", HashRegContractAddress, UrlHintContractAddress) + return +} + +// called as first step in the registration process on HashReg +func (self *Resolver) SetOwner(address common.Address) (txh string, err error) { + return self.backend.Transact( + address.Hex(), + HashRegContractAddress, + "", txValue, txGas, txGasPrice, + setOwnerAbi, + ) +} + +// registers some content hash to a key/code hash +// e.g., the contract Info combined Json Doc's ContentHash +// to CodeHash of a contract or hash of a domain +// kept +func (self *Resolver) RegisterContentHash(address common.Address, codehash, dochash common.Hash) (txh string, err error) { + _, err = self.SetOwner(address) if err != nil { - panic(err) + return } + codehex := common.Bytes2Hex(codehash[:]) + dochex := common.Bytes2Hex(dochash[:]) + + data := registerContentHashAbi + codehex + dochex + return self.backend.Transact( + address.Hex(), + HashRegContractAddress, + "", txValue, txGas, txGasPrice, + data, + ) } -type Resolver struct { - backend Backend - urlHintContractAddress string - hashRegContractAddress string +// registers a url to a content hash so that the content can be fetched +// address is used as sender for the transaction and will be the owner of a new +// registry entry on first time use +// FIXME: silently doing nothing if sender is not the owner +// note that with content addressed storage, this step is no longer necessary +// it could be purely +func (self *Resolver) RegisterUrl(address common.Address, hash common.Hash, url string) (txh string, err error) { + hashHex := common.Bytes2Hex(hash[:]) + var urlHex string + urlb := []byte(url) + var cnt byte + n := len(urlb) + + for n > 0 { + if n > 32 { + n = 32 + } + urlHex = common.Bytes2Hex(urlb[:n]) + urlb = urlb[n:] + n = len(urlb) + bcnt := make([]byte, 32) + bcnt[31] = cnt + data := registerUrlAbi + + hashHex + + common.Bytes2Hex(bcnt) + + common.Bytes2Hex(common.Hex2BytesFixed(urlHex, 32)) + txh, err = self.backend.Transact( + address.Hex(), + UrlHintContractAddress, + "", txValue, txGas, txGasPrice, + data, + ) + if err != nil { + return + } + cnt++ + } + return } -type Backend interface { - StorageAt(string, string) string -} +func (self *Resolver) Register(address common.Address, codehash, dochash common.Hash, url string) (txh string, err error) { -func New(eth Backend, uhca, nrca string) *Resolver { - return &Resolver{eth, uhca, nrca} + _, err = self.RegisterContentHash(address, codehash, dochash) + if err != nil { + return + } + return self.RegisterUrl(address, dochash, url) } +// resolution is costless non-transactional +// implemented as direct retrieval from db func (self *Resolver) KeyToContentHash(khash common.Hash) (chash common.Hash, err error) { // look up in hashReg + at := common.Bytes2Hex(common.FromHex(HashRegContractAddress)) key := storageAddress(storageMapping(storageIdx2Addr(1), khash[:])) - hash := self.backend.StorageAt(self.hashRegContractAddress, key) + hash := self.backend.StorageAt(at, key) if hash == "0x0" || len(hash) < 3 { - err = fmt.Errorf("GetHashReg: content hash not found") + err = fmt.Errorf("content hash not found for '%v'", khash.Hex()) return } - copy(chash[:], common.Hex2BytesFixed(hash[2:], 32)) return } +// retrieves the url-hint for the content hash - +// if we use content addressed storage, this step is no longer necessary func (self *Resolver) ContentHashToUrl(chash common.Hash) (uri string, err error) { // look up in URL reg var str string = " " @@ -69,7 +172,7 @@ func (self *Resolver) ContentHashToUrl(chash common.Hash) (uri string, err error for len(str) > 0 { mapaddr := storageMapping(storageIdx2Addr(1), chash[:]) key := storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(idx))) - hex := self.backend.StorageAt(self.urlHintContractAddress, key) + hex := self.backend.StorageAt(UrlHintContractAddress, key) str = string(common.Hex2Bytes(hex[2:])) l := len(str) for (l > 0) && (str[l-1] == 0) { @@ -81,7 +184,7 @@ func (self *Resolver) ContentHashToUrl(chash common.Hash) (uri string, err error } if len(uri) == 0 { - err = fmt.Errorf("GetURLhint: URL hint not found") + err = fmt.Errorf("GetURLhint: URL hint not found for '%v'", chash.Hex()) } return } @@ -106,7 +209,8 @@ 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) + sha := crypto.Sha3(data) + return sha } func storageFixedArray(addr, idx []byte) []byte { diff --git a/common/resolver/resolver_test.go b/common/resolver/resolver_test.go index f5eb51437..02d12592e 100644 --- a/common/resolver/resolver_test.go +++ b/common/resolver/resolver_test.go @@ -20,6 +20,8 @@ var ( ) func NewTestBackend() *testBackend { + HashRegContractAddress = common.BigToAddress(common.Big0).Hex()[2:] + UrlHintContractAddress = common.BigToAddress(common.Big1).Hex()[2:] self := &testBackend{} self.contracts = make(map[string](map[string]string)) @@ -27,14 +29,13 @@ func NewTestBackend() *testBackend { key := storageAddress(storageMapping(storageIdx2Addr(1), codehash[:])) self.contracts[HashRegContractAddress][key] = hash.Hex() - self.contracts[URLHintContractAddress] = make(map[string]string) + self.contracts[UrlHintContractAddress] = make(map[string]string) mapaddr := storageMapping(storageIdx2Addr(1), hash[:]) key = storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(0))) - self.contracts[URLHintContractAddress][key] = common.ToHex([]byte(url)) + self.contracts[UrlHintContractAddress][key] = common.ToHex([]byte(url)) key = storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(1))) - self.contracts[URLHintContractAddress][key] = "0x00" - + self.contracts[UrlHintContractAddress][key] = "0x00" return self } @@ -47,42 +48,46 @@ func (self *testBackend) StorageAt(ca, sa string) (res string) { return } +func (self *testBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) { + return "", nil +} + func TestKeyToContentHash(t *testing.T) { b := NewTestBackend() - res := New(b, URLHintContractAddress, HashRegContractAddress) + res := New(b) got, err := res.KeyToContentHash(codehash) if err != nil { t.Errorf("expected no error, got %v", err) } else { if got != hash { - t.Errorf("incorrect result, expected %x, got %x: ", hash.Hex(), got.Hex()) + t.Errorf("incorrect result, expected '%v', got '%v'", hash.Hex(), got.Hex()) } } } func TestContentHashToUrl(t *testing.T) { b := NewTestBackend() - res := New(b, URLHintContractAddress, HashRegContractAddress) + res := New(b) got, err := res.ContentHashToUrl(hash) if err != nil { t.Errorf("expected no error, got %v", err) } else { - if string(got) != url { - t.Errorf("incorrect result, expected %v, got %s: ", url, string(got)) + if got != url { + t.Errorf("incorrect result, expected '%v', got '%s'", url, got) } } } func TestKeyToUrl(t *testing.T) { b := NewTestBackend() - res := New(b, URLHintContractAddress, HashRegContractAddress) + res := New(b) got, _, err := res.KeyToUrl(codehash) if err != nil { t.Errorf("expected no error, got %v", err) } else { - if string(got) != url { - t.Errorf("incorrect result, expected %v, got %s: ", url, string(got)) + if got != url { + t.Errorf("incorrect result, expected \n'%s', got \n'%s'", url, got) } } } -- cgit