mirror of https://github.com/ethereum/go-ethereum
Merge pull request #3346 from obscuren/registrar-removal
common/registrar, eth: removed registrar (tech debt)pull/3309/head
commit
9c3ea0d32d
@ -1,124 +0,0 @@ |
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package httpclient |
||||
|
||||
import ( |
||||
"fmt" |
||||
"io/ioutil" |
||||
"net/http" |
||||
"path/filepath" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/crypto" |
||||
) |
||||
|
||||
type HTTPClient struct { |
||||
*http.Transport |
||||
DocRoot string |
||||
schemes []string |
||||
} |
||||
|
||||
func New(docRoot string) (self *HTTPClient) { |
||||
self = &HTTPClient{ |
||||
Transport: &http.Transport{}, |
||||
DocRoot: docRoot, |
||||
schemes: []string{"file"}, |
||||
} |
||||
self.RegisterProtocol("file", http.NewFileTransport(http.Dir(self.DocRoot))) |
||||
return |
||||
} |
||||
|
||||
// Clients should be reused instead of created as needed. Clients are safe for concurrent use by multiple goroutines.
|
||||
|
||||
// A Client is higher-level than a RoundTripper (such as Transport) and additionally handles HTTP details such as cookies and redirects.
|
||||
|
||||
func (self *HTTPClient) Client() *http.Client { |
||||
return &http.Client{ |
||||
Transport: self, |
||||
} |
||||
} |
||||
|
||||
func (self *HTTPClient) RegisterScheme(scheme string, rt http.RoundTripper) { |
||||
self.schemes = append(self.schemes, scheme) |
||||
self.RegisterProtocol(scheme, rt) |
||||
} |
||||
|
||||
func (self *HTTPClient) HasScheme(scheme string) bool { |
||||
for _, s := range self.schemes { |
||||
if s == scheme { |
||||
return true |
||||
} |
||||
} |
||||
return false |
||||
} |
||||
|
||||
func (self *HTTPClient) GetAuthContent(uri string, hash common.Hash) ([]byte, error) { |
||||
// retrieve content
|
||||
content, err := self.Get(uri, "") |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
// check hash to authenticate content
|
||||
chash := crypto.Keccak256Hash(content) |
||||
if chash != hash { |
||||
return nil, fmt.Errorf("content hash mismatch %x != %x (exp)", hash[:], chash[:]) |
||||
} |
||||
|
||||
return content, nil |
||||
|
||||
} |
||||
|
||||
// Get(uri, path) downloads the document at uri, if path is non-empty it
|
||||
// is interpreted as a filepath to which the contents are saved
|
||||
func (self *HTTPClient) Get(uri, path string) ([]byte, error) { |
||||
// retrieve content
|
||||
resp, err := self.Client().Get(uri) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
defer func() { |
||||
if resp != nil { |
||||
resp.Body.Close() |
||||
} |
||||
}() |
||||
|
||||
var content []byte |
||||
content, err = ioutil.ReadAll(resp.Body) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
if resp.StatusCode/100 != 2 { |
||||
return content, fmt.Errorf("HTTP error: %s", resp.Status) |
||||
} |
||||
|
||||
if path != "" { |
||||
var abspath string |
||||
abspath, err = filepath.Abs(path) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
err = ioutil.WriteFile(abspath, content, 0600) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
} |
||||
|
||||
return content, nil |
||||
|
||||
} |
@ -1,77 +0,0 @@ |
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package httpclient |
||||
|
||||
import ( |
||||
"io/ioutil" |
||||
"net/http" |
||||
"os" |
||||
"path" |
||||
"testing" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/crypto" |
||||
) |
||||
|
||||
func TestGetAuthContent(t *testing.T) { |
||||
dir, err := ioutil.TempDir("", "httpclient-test") |
||||
if err != nil { |
||||
t.Fatal("cannot create temporary directory:", err) |
||||
} |
||||
defer os.RemoveAll(dir) |
||||
client := New(dir) |
||||
|
||||
text := "test" |
||||
hash := crypto.Keccak256Hash([]byte(text)) |
||||
if err := ioutil.WriteFile(path.Join(dir, "test.content"), []byte(text), os.ModePerm); err != nil { |
||||
t.Fatal("could not write test file", err) |
||||
} |
||||
content, err := client.GetAuthContent("file:///test.content", hash) |
||||
if err != nil { |
||||
t.Errorf("no error expected, got %v", err) |
||||
} |
||||
if string(content) != text { |
||||
t.Errorf("incorrect content. expected %v, got %v", text, string(content)) |
||||
} |
||||
|
||||
hash = common.Hash{} |
||||
content, err = client.GetAuthContent("file:///test.content", hash) |
||||
expected := "content hash mismatch 0000000000000000000000000000000000000000000000000000000000000000 != 9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658 (exp)" |
||||
if err == nil { |
||||
t.Errorf("expected error, got nothing") |
||||
} else { |
||||
if err.Error() != expected { |
||||
t.Errorf("expected error '%s' got '%v'", expected, err) |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
type rt struct{} |
||||
|
||||
func (rt) RoundTrip(req *http.Request) (resp *http.Response, err error) { return } |
||||
|
||||
func TestRegisterScheme(t *testing.T) { |
||||
client := New("/tmp/") |
||||
if client.HasScheme("scheme") { |
||||
t.Errorf("expected scheme not to be registered") |
||||
} |
||||
client.RegisterScheme("scheme", rt{}) |
||||
if !client.HasScheme("scheme") { |
||||
t.Errorf("expected scheme to be registered") |
||||
} |
||||
} |
File diff suppressed because one or more lines are too long
@ -1,279 +0,0 @@ |
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package ethreg |
||||
|
||||
import ( |
||||
"errors" |
||||
"math/big" |
||||
|
||||
"github.com/ethereum/go-ethereum/accounts" |
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/common/compiler" |
||||
"github.com/ethereum/go-ethereum/common/registrar" |
||||
"github.com/ethereum/go-ethereum/core" |
||||
"github.com/ethereum/go-ethereum/core/state" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/core/vm" |
||||
"github.com/ethereum/go-ethereum/crypto" |
||||
"github.com/ethereum/go-ethereum/ethdb" |
||||
"github.com/ethereum/go-ethereum/logger" |
||||
"github.com/ethereum/go-ethereum/logger/glog" |
||||
"github.com/ethereum/go-ethereum/params" |
||||
) |
||||
|
||||
// registryAPIBackend is a backend for an Ethereum Registry.
|
||||
type registryAPIBackend struct { |
||||
config *params.ChainConfig |
||||
bc *core.BlockChain |
||||
chainDb ethdb.Database |
||||
txPool *core.TxPool |
||||
am *accounts.Manager |
||||
} |
||||
|
||||
// PrivateRegistarAPI offers various functions to access the Ethereum registry.
|
||||
type PrivateRegistarAPI struct { |
||||
config *params.ChainConfig |
||||
be *registryAPIBackend |
||||
} |
||||
|
||||
// NewPrivateRegistarAPI creates a new PrivateRegistarAPI instance.
|
||||
func NewPrivateRegistarAPI(config *params.ChainConfig, bc *core.BlockChain, chainDb ethdb.Database, txPool *core.TxPool, am *accounts.Manager) *PrivateRegistarAPI { |
||||
return &PrivateRegistarAPI{ |
||||
config: config, |
||||
be: ®istryAPIBackend{ |
||||
config: config, |
||||
bc: bc, |
||||
chainDb: chainDb, |
||||
txPool: txPool, |
||||
am: am, |
||||
}, |
||||
} |
||||
} |
||||
|
||||
// SetGlobalRegistrar allows clients to set the global registry for the node.
|
||||
// This method can be used to deploy a new registry. First zero out the current
|
||||
// address by calling the method with namereg = '0x0' and then call this method
|
||||
// again with '' as namereg. This will submit a transaction to the network which
|
||||
// will deploy a new registry on execution. The TX hash is returned. When called
|
||||
// with namereg '' and the current address is not zero the current global is
|
||||
// address is returned..
|
||||
func (api *PrivateRegistarAPI) SetGlobalRegistrar(namereg string, from common.Address) (string, error) { |
||||
return registrar.New(api.be).SetGlobalRegistrar(namereg, from) |
||||
} |
||||
|
||||
// SetHashReg queries the registry for a hash.
|
||||
func (api *PrivateRegistarAPI) SetHashReg(hashreg string, from common.Address) (string, error) { |
||||
return registrar.New(api.be).SetHashReg(hashreg, from) |
||||
} |
||||
|
||||
// SetUrlHint queries the registry for an url.
|
||||
func (api *PrivateRegistarAPI) SetUrlHint(hashreg string, from common.Address) (string, error) { |
||||
return registrar.New(api.be).SetUrlHint(hashreg, from) |
||||
} |
||||
|
||||
// SaveInfo stores contract information on the local file system.
|
||||
func (api *PrivateRegistarAPI) SaveInfo(info *compiler.ContractInfo, filename string) (contenthash common.Hash, err error) { |
||||
return compiler.SaveInfo(info, filename) |
||||
} |
||||
|
||||
// Register registers a new content hash in the registry.
|
||||
func (api *PrivateRegistarAPI) Register(sender common.Address, addr common.Address, contentHashHex string) (bool, error) { |
||||
block := api.be.bc.CurrentBlock() |
||||
state, err := state.New(block.Root(), api.be.chainDb) |
||||
if err != nil { |
||||
return false, err |
||||
} |
||||
|
||||
codeb := state.GetCode(addr) |
||||
codeHash := common.BytesToHash(crypto.Keccak256(codeb)) |
||||
contentHash := common.HexToHash(contentHashHex) |
||||
|
||||
_, err = registrar.New(api.be).SetHashToHash(sender, codeHash, contentHash) |
||||
return err == nil, err |
||||
} |
||||
|
||||
// RegisterUrl registers a new url in the registry.
|
||||
func (api *PrivateRegistarAPI) RegisterUrl(sender common.Address, contentHashHex string, url string) (bool, error) { |
||||
_, err := registrar.New(api.be).SetUrlToHash(sender, common.HexToHash(contentHashHex), url) |
||||
return err == nil, err |
||||
} |
||||
|
||||
// callmsg is the message type used for call transations.
|
||||
type callmsg struct { |
||||
from *state.StateObject |
||||
to *common.Address |
||||
gas, gasPrice *big.Int |
||||
value *big.Int |
||||
data []byte |
||||
} |
||||
|
||||
// accessor boilerplate to implement core.Message
|
||||
func (m callmsg) From() (common.Address, error) { |
||||
return m.from.Address(), nil |
||||
} |
||||
func (m callmsg) FromFrontier() (common.Address, error) { |
||||
return m.from.Address(), nil |
||||
} |
||||
func (m callmsg) Nonce() uint64 { |
||||
return 0 |
||||
} |
||||
func (m callmsg) CheckNonce() bool { |
||||
return false |
||||
} |
||||
func (m callmsg) To() *common.Address { |
||||
return m.to |
||||
} |
||||
func (m callmsg) GasPrice() *big.Int { |
||||
return m.gasPrice |
||||
} |
||||
func (m callmsg) Gas() *big.Int { |
||||
return m.gas |
||||
} |
||||
func (m callmsg) Value() *big.Int { |
||||
return m.value |
||||
} |
||||
func (m callmsg) Data() []byte { |
||||
return m.data |
||||
} |
||||
|
||||
// Call forms a transaction from the given arguments and tries to execute it on
|
||||
// a private VM with a copy of the state. Any changes are therefore only temporary
|
||||
// and not part of the actual state. This allows for local execution/queries.
|
||||
func (be *registryAPIBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, string, error) { |
||||
block := be.bc.CurrentBlock() |
||||
statedb, err := state.New(block.Root(), be.chainDb) |
||||
if err != nil { |
||||
return "", "", err |
||||
} |
||||
|
||||
var from *state.StateObject |
||||
if len(fromStr) == 0 { |
||||
accounts := be.am.Accounts() |
||||
if len(accounts) == 0 { |
||||
from = statedb.GetOrNewStateObject(common.Address{}) |
||||
} else { |
||||
from = statedb.GetOrNewStateObject(accounts[0].Address) |
||||
} |
||||
} else { |
||||
from = statedb.GetOrNewStateObject(common.HexToAddress(fromStr)) |
||||
} |
||||
|
||||
from.SetBalance(common.MaxBig) |
||||
|
||||
var to *common.Address |
||||
if len(toStr) > 0 { |
||||
addr := common.HexToAddress(toStr) |
||||
to = &addr |
||||
} |
||||
gas := common.Big(gasStr) |
||||
if gas.BitLen() == 0 { |
||||
gas = big.NewInt(50000000) |
||||
} |
||||
gasPrice := common.Big(gasPriceStr) |
||||
if gasPrice.BitLen() == 0 { |
||||
gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon) |
||||
} |
||||
msg := types.NewMessage(from.Address(), to, 0, common.Big(valueStr), gas, gasPrice, common.FromHex(dataStr), false) |
||||
|
||||
header := be.bc.CurrentBlock().Header() |
||||
vmenv := core.NewEnv(statedb, be.config, be.bc, msg, header, vm.Config{}) |
||||
gp := new(core.GasPool).AddGas(common.MaxBig) |
||||
res, gas, err := core.ApplyMessage(vmenv, msg, gp) |
||||
|
||||
return common.ToHex(res), gas.String(), err |
||||
} |
||||
|
||||
// StorageAt returns the data stores in the state for the given address and location.
|
||||
func (be *registryAPIBackend) StorageAt(addr string, storageAddr string) string { |
||||
block := be.bc.CurrentBlock() |
||||
state, err := state.New(block.Root(), be.chainDb) |
||||
if err != nil { |
||||
return "" |
||||
} |
||||
return state.GetState(common.HexToAddress(addr), common.HexToHash(storageAddr)).Hex() |
||||
} |
||||
|
||||
// Transact forms a transaction from the given arguments and submits it to the
|
||||
// transactio pool for execution.
|
||||
func (be *registryAPIBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) { |
||||
if len(toStr) > 0 && toStr != "0x" && !common.IsHexAddress(toStr) { |
||||
return "", errors.New("invalid address") |
||||
} |
||||
|
||||
var ( |
||||
from = common.HexToAddress(fromStr) |
||||
to = common.HexToAddress(toStr) |
||||
value = common.Big(valueStr) |
||||
gas *big.Int |
||||
price *big.Int |
||||
data []byte |
||||
contractCreation bool |
||||
) |
||||
|
||||
if len(gasStr) == 0 { |
||||
gas = big.NewInt(90000) |
||||
} else { |
||||
gas = common.Big(gasStr) |
||||
} |
||||
|
||||
if len(gasPriceStr) == 0 { |
||||
price = big.NewInt(10000000000000) |
||||
} else { |
||||
price = common.Big(gasPriceStr) |
||||
} |
||||
|
||||
data = common.FromHex(codeStr) |
||||
if len(toStr) == 0 { |
||||
contractCreation = true |
||||
} |
||||
|
||||
nonce := be.txPool.State().GetNonce(from) |
||||
if len(nonceStr) != 0 { |
||||
nonce = common.Big(nonceStr).Uint64() |
||||
} |
||||
|
||||
var tx *types.Transaction |
||||
if contractCreation { |
||||
tx = types.NewContractCreation(nonce, value, gas, price, data) |
||||
} else { |
||||
tx = types.NewTransaction(nonce, to, value, gas, price, data) |
||||
} |
||||
|
||||
sigHash := (types.HomesteadSigner{}).Hash(tx) |
||||
signature, err := be.am.SignEthereum(from, sigHash.Bytes()) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
signedTx, err := tx.WithSignature(types.HomesteadSigner{}, signature) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
be.txPool.SetLocal(signedTx) |
||||
if err := be.txPool.Add(signedTx); err != nil { |
||||
return "", nil |
||||
} |
||||
|
||||
if contractCreation { |
||||
addr := crypto.CreateAddress(from, nonce) |
||||
glog.V(logger.Info).Infof("Tx(%s) created: %s\n", signedTx.Hash().Hex(), addr.Hex()) |
||||
} else { |
||||
glog.V(logger.Info).Infof("Tx(%s) to: %s\n", signedTx.Hash().Hex(), tx.To().Hex()) |
||||
} |
||||
|
||||
return signedTx.Hash().Hex(), nil |
||||
} |
@ -1,436 +0,0 @@ |
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package registrar |
||||
|
||||
import ( |
||||
"encoding/binary" |
||||
"fmt" |
||||
"math/big" |
||||
"regexp" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/crypto" |
||||
"github.com/ethereum/go-ethereum/logger" |
||||
"github.com/ethereum/go-ethereum/logger/glog" |
||||
) |
||||
|
||||
/* |
||||
Registrar implements the Ethereum name registrar services mapping |
||||
- arbitrary strings to ethereum addresses |
||||
- hashes to hashes |
||||
- hashes to arbitrary strings |
||||
(likely will provide lookup service for all three) |
||||
|
||||
The Registrar is used by |
||||
* the roundtripper transport implementation of |
||||
url schemes to resolve domain names and services that register these names |
||||
* contract info retrieval (NatSpec). |
||||
|
||||
The Registrar uses 3 contracts on the blockchain: |
||||
* GlobalRegistrar: Name (string) -> Address (Owner) |
||||
* HashReg : Key Hash (hash of domain name or contract code) -> Content Hash |
||||
* UrlHint : Content Hash -> Url Hint |
||||
|
||||
These contracts are (currently) not included in the genesis block. |
||||
Each Set<X> needs to be called once on each blockchain/network once. |
||||
|
||||
Contract addresses need to be set the first time any Registrar method is called |
||||
in a client session. |
||||
This is done for frontier by default, otherwise the caller needs to make sure |
||||
the relevant environment initialised the desired contracts |
||||
*/ |
||||
var ( |
||||
// GlobalRegistrarAddr = "0xc6d9d2cd449a754c494264e1809c50e34d64562b" // olympic
|
||||
GlobalRegistrarAddr = "0x33990122638b9132ca29c723bdf037f1a891a70c" // frontier
|
||||
HashRegAddr = "0x23bf622b5a65f6060d855fca401133ded3520620" // frontier
|
||||
UrlHintAddr = "0x73ed5ef6c010727dfd2671dbb70faac19ec18626" // frontier
|
||||
|
||||
zero = regexp.MustCompile("^(0x)?0*$") |
||||
) |
||||
|
||||
const ( |
||||
trueHex = "0000000000000000000000000000000000000000000000000000000000000001" |
||||
falseHex = "0000000000000000000000000000000000000000000000000000000000000000" |
||||
) |
||||
|
||||
func abiSignature(s string) string { |
||||
return common.ToHex(crypto.Keccak256([]byte(s))[:4]) |
||||
} |
||||
|
||||
var ( |
||||
HashRegName = "HashReg" |
||||
UrlHintName = "UrlHint" |
||||
|
||||
registerContentHashAbi = abiSignature("register(uint256,uint256)") |
||||
registerUrlAbi = abiSignature("register(uint256,uint8,uint256)") |
||||
setOwnerAbi = abiSignature("setowner()") |
||||
reserveAbi = abiSignature("reserve(bytes32)") |
||||
resolveAbi = abiSignature("addr(bytes32)") |
||||
registerAbi = abiSignature("setAddress(bytes32,address,bool)") |
||||
addressAbiPrefix = falseHex[:24] |
||||
) |
||||
|
||||
// Registrar's backend is defined as an interface (implemented by xeth, but could be remote)
|
||||
type Backend interface { |
||||
StorageAt(string, string) string |
||||
Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) |
||||
Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, string, error) |
||||
} |
||||
|
||||
// TODO Registrar should also just implement The Resolver and Registry interfaces
|
||||
// Simplify for now.
|
||||
type VersionedRegistrar interface { |
||||
Resolver(*big.Int) *Registrar |
||||
Registry() *Registrar |
||||
} |
||||
|
||||
type Registrar struct { |
||||
backend Backend |
||||
} |
||||
|
||||
func New(b Backend) (res *Registrar) { |
||||
res = &Registrar{b} |
||||
return |
||||
} |
||||
|
||||
func (self *Registrar) SetGlobalRegistrar(namereg string, addr common.Address) (txhash string, err error) { |
||||
if namereg != "" { |
||||
GlobalRegistrarAddr = namereg |
||||
return |
||||
} |
||||
if zero.MatchString(GlobalRegistrarAddr) { |
||||
if (addr == common.Address{}) { |
||||
err = fmt.Errorf("GlobalRegistrar address not found and sender for creation not given") |
||||
return |
||||
} else { |
||||
txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "800000", "", GlobalRegistrarCode) |
||||
if err != nil { |
||||
err = fmt.Errorf("GlobalRegistrar address not found and sender for creation failed: %v", err) |
||||
return |
||||
} |
||||
} |
||||
} |
||||
return |
||||
} |
||||
|
||||
func (self *Registrar) SetHashReg(hashreg string, addr common.Address) (txhash string, err error) { |
||||
if hashreg != "" { |
||||
HashRegAddr = hashreg |
||||
} else { |
||||
if !zero.MatchString(HashRegAddr) { |
||||
return |
||||
} |
||||
nameHex, extra := encodeName(HashRegName, 2) |
||||
hashRegAbi := resolveAbi + nameHex + extra |
||||
glog.V(logger.Detail).Infof("\ncall HashRegAddr %v with %v\n", GlobalRegistrarAddr, hashRegAbi) |
||||
var res string |
||||
res, _, err = self.backend.Call("", GlobalRegistrarAddr, "", "", "", hashRegAbi) |
||||
if len(res) >= 40 { |
||||
HashRegAddr = "0x" + res[len(res)-40:len(res)] |
||||
} |
||||
if err != nil || zero.MatchString(HashRegAddr) { |
||||
if (addr == common.Address{}) { |
||||
err = fmt.Errorf("HashReg address not found and sender for creation not given") |
||||
return |
||||
} |
||||
|
||||
txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "", "", HashRegCode) |
||||
if err != nil { |
||||
err = fmt.Errorf("HashReg address not found and sender for creation failed: %v", err) |
||||
} |
||||
glog.V(logger.Detail).Infof("created HashRegAddr @ txhash %v\n", txhash) |
||||
} else { |
||||
glog.V(logger.Detail).Infof("HashRegAddr found at @ %v\n", HashRegAddr) |
||||
return |
||||
} |
||||
} |
||||
|
||||
return |
||||
} |
||||
|
||||
func (self *Registrar) SetUrlHint(urlhint string, addr common.Address) (txhash string, err error) { |
||||
if urlhint != "" { |
||||
UrlHintAddr = urlhint |
||||
} else { |
||||
if !zero.MatchString(UrlHintAddr) { |
||||
return |
||||
} |
||||
nameHex, extra := encodeName(UrlHintName, 2) |
||||
urlHintAbi := resolveAbi + nameHex + extra |
||||
glog.V(logger.Detail).Infof("UrlHint address query data: %s to %s", urlHintAbi, GlobalRegistrarAddr) |
||||
var res string |
||||
res, _, err = self.backend.Call("", GlobalRegistrarAddr, "", "", "", urlHintAbi) |
||||
if len(res) >= 40 { |
||||
UrlHintAddr = "0x" + res[len(res)-40:len(res)] |
||||
} |
||||
if err != nil || zero.MatchString(UrlHintAddr) { |
||||
if (addr == common.Address{}) { |
||||
err = fmt.Errorf("UrlHint address not found and sender for creation not given") |
||||
return |
||||
} |
||||
txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "210000", "", UrlHintCode) |
||||
if err != nil { |
||||
err = fmt.Errorf("UrlHint address not found and sender for creation failed: %v", err) |
||||
} |
||||
glog.V(logger.Detail).Infof("created UrlHint @ txhash %v\n", txhash) |
||||
} else { |
||||
glog.V(logger.Detail).Infof("UrlHint found @ %v\n", HashRegAddr) |
||||
return |
||||
} |
||||
} |
||||
|
||||
return |
||||
} |
||||
|
||||
// ReserveName(from, name) reserves name for the sender address in the globalRegistrar
|
||||
// the tx needs to be mined to take effect
|
||||
func (self *Registrar) ReserveName(address common.Address, name string) (txh string, err error) { |
||||
if zero.MatchString(GlobalRegistrarAddr) { |
||||
return "", fmt.Errorf("GlobalRegistrar address is not set") |
||||
} |
||||
nameHex, extra := encodeName(name, 2) |
||||
abi := reserveAbi + nameHex + extra |
||||
glog.V(logger.Detail).Infof("Reserve data: %s", abi) |
||||
return self.backend.Transact( |
||||
address.Hex(), |
||||
GlobalRegistrarAddr, |
||||
"", "", "", "", |
||||
abi, |
||||
) |
||||
} |
||||
|
||||
// SetAddressToName(from, name, addr) will set the Address to address for name
|
||||
// in the globalRegistrar using from as the sender of the transaction
|
||||
// the tx needs to be mined to take effect
|
||||
func (self *Registrar) SetAddressToName(from common.Address, name string, address common.Address) (txh string, err error) { |
||||
if zero.MatchString(GlobalRegistrarAddr) { |
||||
return "", fmt.Errorf("GlobalRegistrar address is not set") |
||||
} |
||||
|
||||
nameHex, extra := encodeName(name, 6) |
||||
addrHex := encodeAddress(address) |
||||
|
||||
abi := registerAbi + nameHex + addrHex + trueHex + extra |
||||
glog.V(logger.Detail).Infof("SetAddressToName data: %s to %s ", abi, GlobalRegistrarAddr) |
||||
|
||||
return self.backend.Transact( |
||||
from.Hex(), |
||||
GlobalRegistrarAddr, |
||||
"", "", "", "", |
||||
abi, |
||||
) |
||||
} |
||||
|
||||
// NameToAddr(from, name) queries the registrar for the address on name
|
||||
func (self *Registrar) NameToAddr(from common.Address, name string) (address common.Address, err error) { |
||||
if zero.MatchString(GlobalRegistrarAddr) { |
||||
return address, fmt.Errorf("GlobalRegistrar address is not set") |
||||
} |
||||
|
||||
nameHex, extra := encodeName(name, 2) |
||||
abi := resolveAbi + nameHex + extra |
||||
glog.V(logger.Detail).Infof("NameToAddr data: %s", abi) |
||||
res, _, err := self.backend.Call( |
||||
from.Hex(), |
||||
GlobalRegistrarAddr, |
||||
"", "", "", |
||||
abi, |
||||
) |
||||
if err != nil { |
||||
return |
||||
} |
||||
address = common.HexToAddress(res) |
||||
return |
||||
} |
||||
|
||||
// called as first step in the registration process on HashReg
|
||||
func (self *Registrar) SetOwner(address common.Address) (txh string, err error) { |
||||
if zero.MatchString(HashRegAddr) { |
||||
return "", fmt.Errorf("HashReg address is not set") |
||||
} |
||||
return self.backend.Transact( |
||||
address.Hex(), |
||||
HashRegAddr, |
||||
"", "", "", "", |
||||
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
|
||||
func (self *Registrar) SetHashToHash(address common.Address, codehash, dochash common.Hash) (txh string, err error) { |
||||
if zero.MatchString(HashRegAddr) { |
||||
return "", fmt.Errorf("HashReg address is not set") |
||||
} |
||||
|
||||
_, err = self.SetOwner(address) |
||||
if err != nil { |
||||
return |
||||
} |
||||
codehex := common.Bytes2Hex(codehash[:]) |
||||
dochex := common.Bytes2Hex(dochash[:]) |
||||
|
||||
data := registerContentHashAbi + codehex + dochex |
||||
glog.V(logger.Detail).Infof("SetHashToHash data: %s sent to %v\n", data, HashRegAddr) |
||||
return self.backend.Transact( |
||||
address.Hex(), |
||||
HashRegAddr, |
||||
"", "", "", "", |
||||
data, |
||||
) |
||||
} |
||||
|
||||
// SetUrlToHash(from, hash, url) 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
|
||||
func (self *Registrar) SetUrlToHash(address common.Address, hash common.Hash, url string) (txh string, err error) { |
||||
if zero.MatchString(UrlHintAddr) { |
||||
return "", fmt.Errorf("UrlHint address is not set") |
||||
} |
||||
|
||||
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(), |
||||
UrlHintAddr, |
||||
"", "", "", "", |
||||
data, |
||||
) |
||||
if err != nil { |
||||
return |
||||
} |
||||
cnt++ |
||||
} |
||||
return |
||||
} |
||||
|
||||
// HashToHash(key) resolves contenthash for key (a hash) using HashReg
|
||||
// resolution is costless non-transactional
|
||||
// implemented as direct retrieval from db
|
||||
func (self *Registrar) HashToHash(khash common.Hash) (chash common.Hash, err error) { |
||||
if zero.MatchString(HashRegAddr) { |
||||
return common.Hash{}, fmt.Errorf("HashReg address is not set") |
||||
} |
||||
|
||||
// look up in hashReg
|
||||
at := HashRegAddr[2:] |
||||
key := storageAddress(storageMapping(storageIdx2Addr(1), khash[:])) |
||||
hash := self.backend.StorageAt(at, key) |
||||
|
||||
if hash == "0x0" || len(hash) < 3 || (hash == common.Hash{}.Hex()) { |
||||
err = fmt.Errorf("HashToHash: content hash not found for '%v'", khash.Hex()) |
||||
return |
||||
} |
||||
copy(chash[:], common.Hex2BytesFixed(hash[2:], 32)) |
||||
return |
||||
} |
||||
|
||||
// HashToUrl(contenthash) resolves the url for contenthash using UrlHint
|
||||
// resolution is costless non-transactional
|
||||
// implemented as direct retrieval from db
|
||||
// if we use content addressed storage, this step is no longer necessary
|
||||
func (self *Registrar) HashToUrl(chash common.Hash) (uri string, err error) { |
||||
if zero.MatchString(UrlHintAddr) { |
||||
return "", fmt.Errorf("UrlHint address is not set") |
||||
} |
||||
// 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(UrlHintAddr[2:], key) |
||||
str = string(common.Hex2Bytes(hex[2:])) |
||||
l := 0 |
||||
for (l < len(str)) && (str[l] == 0) { |
||||
l++ |
||||
} |
||||
|
||||
str = str[l:] |
||||
uri = uri + str |
||||
idx++ |
||||
} |
||||
|
||||
if len(uri) == 0 { |
||||
err = fmt.Errorf("HashToUrl: URL hint not found for '%v'", chash.Hex()) |
||||
} |
||||
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]) |
||||
sha := crypto.Keccak256(data) |
||||
return sha |
||||
} |
||||
|
||||
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) |
||||
} |
||||
|
||||
func encodeAddress(address common.Address) string { |
||||
return addressAbiPrefix + address.Hex()[2:] |
||||
} |
||||
|
||||
func encodeName(name string, index uint8) (string, string) { |
||||
extra := common.Bytes2Hex([]byte(name)) |
||||
if len(name) > 32 { |
||||
return fmt.Sprintf("%064x", index), extra |
||||
} |
||||
return extra + falseHex[len(extra):], "" |
||||
} |
@ -1,158 +0,0 @@ |
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package registrar |
||||
|
||||
import ( |
||||
"testing" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/crypto" |
||||
) |
||||
|
||||
type testBackend struct { |
||||
// contracts mock
|
||||
contracts map[string](map[string]string) |
||||
} |
||||
|
||||
var ( |
||||
text = "test" |
||||
codehash = common.StringToHash("1234") |
||||
hash = common.BytesToHash(crypto.Keccak256([]byte(text))) |
||||
url = "bzz://bzzhash/my/path/contr.act" |
||||
) |
||||
|
||||
func NewTestBackend() *testBackend { |
||||
self := &testBackend{} |
||||
self.contracts = make(map[string](map[string]string)) |
||||
return self |
||||
} |
||||
|
||||
func (self *testBackend) initHashReg() { |
||||
self.contracts[HashRegAddr[2:]] = make(map[string]string) |
||||
key := storageAddress(storageMapping(storageIdx2Addr(1), codehash[:])) |
||||
self.contracts[HashRegAddr[2:]][key] = hash.Hex() |
||||
} |
||||
|
||||
func (self *testBackend) initUrlHint() { |
||||
self.contracts[UrlHintAddr[2:]] = make(map[string]string) |
||||
mapaddr := storageMapping(storageIdx2Addr(1), hash[:]) |
||||
|
||||
key := storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(0))) |
||||
self.contracts[UrlHintAddr[2:]][key] = common.ToHex([]byte(url)) |
||||
key = storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(1))) |
||||
self.contracts[UrlHintAddr[2:]][key] = "0x0" |
||||
} |
||||
|
||||
func (self *testBackend) StorageAt(ca, sa string) (res string) { |
||||
c := self.contracts[ca] |
||||
if c == nil { |
||||
return "0x0" |
||||
} |
||||
res = c[sa] |
||||
return |
||||
} |
||||
|
||||
func (self *testBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) { |
||||
return "", nil |
||||
} |
||||
|
||||
func (self *testBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, string, error) { |
||||
return "", "", nil |
||||
} |
||||
|
||||
func TestSetGlobalRegistrar(t *testing.T) { |
||||
b := NewTestBackend() |
||||
res := New(b) |
||||
_, err := res.SetGlobalRegistrar("addresshex", common.BigToAddress(common.Big1)) |
||||
if err != nil { |
||||
t.Errorf("unexpected error: %v'", err) |
||||
} |
||||
} |
||||
|
||||
func TestHashToHash(t *testing.T) { |
||||
b := NewTestBackend() |
||||
res := New(b) |
||||
|
||||
HashRegAddr = "0x0" |
||||
got, err := res.HashToHash(codehash) |
||||
if err == nil { |
||||
t.Errorf("expected error") |
||||
} else { |
||||
exp := "HashReg address is not set" |
||||
if err.Error() != exp { |
||||
t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error()) |
||||
} |
||||
} |
||||
|
||||
HashRegAddr = common.BigToAddress(common.Big1).Hex() //[2:]
|
||||
got, err = res.HashToHash(codehash) |
||||
if err == nil { |
||||
t.Errorf("expected error") |
||||
} else { |
||||
exp := "HashToHash: content hash not found for '" + codehash.Hex() + "'" |
||||
if err.Error() != exp { |
||||
t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error()) |
||||
} |
||||
} |
||||
|
||||
b.initHashReg() |
||||
got, err = res.HashToHash(codehash) |
||||
if err != nil { |
||||
t.Errorf("expected no error, got %v", err) |
||||
} else { |
||||
if got != hash { |
||||
t.Errorf("incorrect result, expected '%v', got '%v'", hash.Hex(), got.Hex()) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func TestHashToUrl(t *testing.T) { |
||||
b := NewTestBackend() |
||||
res := New(b) |
||||
|
||||
UrlHintAddr = "0x0" |
||||
got, err := res.HashToUrl(hash) |
||||
if err == nil { |
||||
t.Errorf("expected error") |
||||
} else { |
||||
exp := "UrlHint address is not set" |
||||
if err.Error() != exp { |
||||
t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error()) |
||||
} |
||||
} |
||||
|
||||
UrlHintAddr = common.BigToAddress(common.Big2).Hex() //[2:]
|
||||
got, err = res.HashToUrl(hash) |
||||
if err == nil { |
||||
t.Errorf("expected error") |
||||
} else { |
||||
exp := "HashToUrl: URL hint not found for '" + hash.Hex() + "'" |
||||
if err.Error() != exp { |
||||
t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error()) |
||||
} |
||||
} |
||||
|
||||
b.initUrlHint() |
||||
got, err = res.HashToUrl(hash) |
||||
if err != nil { |
||||
t.Errorf("expected no error, got %v", err) |
||||
} else { |
||||
if got != url { |
||||
t.Errorf("incorrect result, expected '%v', got '%s'", url, got) |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue