aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Lange <fjl@twurst.com>2016-11-11 12:18:04 +0800
committerJeffrey Wilcke <jeffrey@ethereum.org>2016-11-25 19:15:28 +0800
commit18d51d1de8e5bb31def0773c95db009ba57e46e8 (patch)
tree70e5fc54e240c0353882f66c6205c4f8a84cd631
parent01d5fc670b3618a82e2242e7b24bef03878a48ba (diff)
downloadgo-tangerine-18d51d1de8e5bb31def0773c95db009ba57e46e8.tar
go-tangerine-18d51d1de8e5bb31def0773c95db009ba57e46e8.tar.gz
go-tangerine-18d51d1de8e5bb31def0773c95db009ba57e46e8.tar.bz2
go-tangerine-18d51d1de8e5bb31def0773c95db009ba57e46e8.tar.lz
go-tangerine-18d51d1de8e5bb31def0773c95db009ba57e46e8.tar.xz
go-tangerine-18d51d1de8e5bb31def0773c95db009ba57e46e8.tar.zst
go-tangerine-18d51d1de8e5bb31def0773c95db009ba57e46e8.zip
common/registrar: delete the old registrar code
The registrar was broken, unmaintained and there is a much better replacement: ENS. (cherry picked from commit 6ca8f57b08d550613175260cab7633adcacbe6ab)
-rw-r--r--common/registrar/contracts.go163
-rw-r--r--common/registrar/ethreg/api.go279
-rw-r--r--common/registrar/registrar.go436
-rw-r--r--common/registrar/registrar_test.go158
-rw-r--r--eth/backend.go7
5 files changed, 0 insertions, 1043 deletions
diff --git a/common/registrar/contracts.go b/common/registrar/contracts.go
deleted file mode 100644
index cd80dfcab..000000000
--- a/common/registrar/contracts.go
+++ /dev/null
@@ -1,163 +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
-
-const ( // built-in contracts address source code and evm code
- UrlHintCode = "0x60c180600c6000396000f30060003560e060020a90048063300a3bbf14601557005b6024600435602435604435602a565b60006000f35b6000600084815260200190815260200160002054600160a060020a0316600014806078575033600160a060020a03166000600085815260200190815260200160002054600160a060020a0316145b607f5760bc565b336000600085815260200190815260200160002081905550806001600085815260200190815260200160002083610100811060b657005b01819055505b50505056"
-
- UrlHintSrc = `
-contract URLhint {
- function register(uint256 _hash, uint8 idx, uint256 _url) {
- if (owner[_hash] == 0 || owner[_hash] == msg.sender) {
- owner[_hash] = msg.sender;
- url[_hash][idx] = _url;
- }
- }
- mapping (uint256 => address) owner;
- (uint256 => uint256[256]) url;
-}
- `
-
- HashRegCode = "0x609880600c6000396000f30060003560e060020a9004806331e12c2014601f578063d66d6c1014602b57005b6025603d565b60006000f35b6037600435602435605d565b60006000f35b600054600160a060020a0316600014605357605b565b336000819055505b565b600054600160a060020a031633600160a060020a031614607b576094565b8060016000848152602001908152602001600020819055505b505056"
-
- HashRegSrc = `
-contract HashReg {
- function setowner() {
- if (owner == 0) {
- owner = msg.sender;
- }
- }
- function register(uint256 _key, uint256 _content) {
- if (msg.sender == owner) {
- content[_key] = _content;
- }
- }
- address owner;
- mapping (uint256 => uint256) content;
-}
-`
-
- GlobalRegistrarSrc = `
-//sol
-
-import "owned";
-
-contract NameRegister {
- function addr(bytes32 _name) constant returns (address o_owner) {}
- function name(address _owner) constant returns (bytes32 o_name) {}
-}
-
-contract Registrar is NameRegister {
- event Changed(bytes32 indexed name);
- event PrimaryChanged(bytes32 indexed name, address indexed addr);
-
- function owner(bytes32 _name) constant returns (address o_owner) {}
- function addr(bytes32 _name) constant returns (address o_address) {}
- function subRegistrar(bytes32 _name) constant returns (address o_subRegistrar) {}
- function content(bytes32 _name) constant returns (bytes32 o_content) {}
-
- function name(address _owner) constant returns (bytes32 o_name) {}
-}
-
-contract GlobalRegistrar is Registrar {
- struct Record {
- address owner;
- address primary;
- address subRegistrar;
- bytes32 content;
- uint value;
- uint renewalDate;
- }
-
- function Registrar() {
- // TODO: Populate with hall-of-fame.
- }
-
- function reserve(bytes32 _name) {
- // Don't allow the same name to be overwritten.
- // TODO: bidding mechanism
- if (m_toRecord[_name].owner == 0) {
- m_toRecord[_name].owner = msg.sender;
- Changed(_name);
- }
- }
-
- /*
- TODO
- > 12 chars: free
- <= 12 chars: auction:
- 1. new names are auctioned
- - 7 day period to collect all bid bytes32es + deposits
- - 1 day period to collect all bids to be considered (validity requires associated deposit to be >10% of bid)
- - all valid bids are burnt except highest - difference between that and second highest is returned to winner
- 2. remember when last auctioned/renewed
- 3. anyone can force renewal process:
- - 7 day period to collect all bid bytes32es + deposits
- - 1 day period to collect all bids & full amounts - bids only uncovered if sufficiently high.
- - 1% of winner burnt; original owner paid rest.
- */
-
- modifier onlyrecordowner(bytes32 _name) { if (m_toRecord[_name].owner == msg.sender) _ }
-
- function transfer(bytes32 _name, address _newOwner) onlyrecordowner(_name) {
- m_toRecord[_name].owner = _newOwner;
- Changed(_name);
- }
-
- function disown(bytes32 _name) onlyrecordowner(_name) {
- if (m_toName[m_toRecord[_name].primary] == _name)
- {
- PrimaryChanged(_name, m_toRecord[_name].primary);
- m_toName[m_toRecord[_name].primary] = "";
- }
- delete m_toRecord[_name];
- Changed(_name);
- }
-
- function setAddress(bytes32 _name, address _a, bool _primary) onlyrecordowner(_name) {
- m_toRecord[_name].primary = _a;
- if (_primary)
- {
- PrimaryChanged(_name, _a);
- m_toName[_a] = _name;
- }
- Changed(_name);
- }
- function setSubRegistrar(bytes32 _name, address _registrar) onlyrecordowner(_name) {
- m_toRecord[_name].subRegistrar = _registrar;
- Changed(_name);
- }
- function setContent(bytes32 _name, bytes32 _content) onlyrecordowner(_name) {
- m_toRecord[_name].content = _content;
- Changed(_name);
- }
-
- function owner(bytes32 _name) constant returns (address) { return m_toRecord[_name].owner; }
- function addr(bytes32 _name) constant returns (address) { return m_toRecord[_name].primary; }
-// function subRegistrar(bytes32 _name) constant returns (address) { return m_toRecord[_name].subRegistrar; } // TODO: bring in on next iteration.
- function register(bytes32 _name) constant returns (address) { return m_toRecord[_name].subRegistrar; } // only possible for now
- function content(bytes32 _name) constant returns (bytes32) { return m_toRecord[_name].content; }
- function name(address _owner) constant returns (bytes32 o_name) { return m_toName[_owner]; }
-
- mapping (address => bytes32) m_toName;
- mapping (bytes32 => Record) m_toRecord;
-}
-`
- GlobalRegistrarAbi = `[{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"name","outputs":[{"name":"o_name","type":"bytes32"}],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"content","outputs":[{"name":"","type":"bytes32"}],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"addr","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserve","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"subRegistrar","outputs":[{"name":"o_subRegistrar","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_newOwner","type":"address"}],"name":"transfer","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_registrar","type":"address"}],"name":"setSubRegistrar","outputs":[],"type":"function"},{"constant":false,"inputs":[],"name":"Registrar","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_a","type":"address"},{"name":"_primary","type":"bool"}],"name":"setAddress","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_content","type":"bytes32"}],"name":"setContent","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"disown","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"register","outputs":[{"name":"","type":"address"}],"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"}],"name":"Changed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"addr","type":"address"}],"name":"PrimaryChanged","type":"event"}]`
-
- GlobalRegistrarCode = `0x610b408061000e6000396000f3006000357c01000000000000000000000000000000000000000000000000000000009004806301984892146100b357806302571be3146100ce5780632dff6941146100ff5780633b3b57de1461011a578063432ced041461014b5780635a3a05bd1461016257806379ce9fac1461019357806389a69c0e146101b0578063b9f37c86146101cd578063be99a980146101de578063c3d014d614610201578063d93e75731461021e578063e1fa8e841461023557005b6100c4600480359060200150610b02565b8060005260206000f35b6100df6004803590602001506109f3565b8073ffffffffffffffffffffffffffffffffffffffff1660005260206000f35b610110600480359060200150610ad4565b8060005260206000f35b61012b600480359060200150610a3e565b8073ffffffffffffffffffffffffffffffffffffffff1660005260206000f35b61015c600480359060200150610271565b60006000f35b610173600480359060200150610266565b8073ffffffffffffffffffffffffffffffffffffffff1660005260206000f35b6101aa600480359060200180359060200150610341565b60006000f35b6101c7600480359060200180359060200150610844565b60006000f35b6101d860045061026e565b60006000f35b6101fb6004803590602001803590602001803590602001506106de565b60006000f35b61021860048035906020018035906020015061092c565b60006000f35b61022f600480359060200150610429565b60006000f35b610246600480359060200150610a89565b8073ffffffffffffffffffffffffffffffffffffffff1660005260206000f35b60005b919050565b5b565b60006001600050600083815260200190815260200160002060005060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561033d57336001600050600083815260200190815260200160002060005060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690830217905550807fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc6040604090036040a25b5b50565b813373ffffffffffffffffffffffffffffffffffffffff166001600050600083815260200190815260200160002060005060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561042357816001600050600085815260200190815260200160002060005060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690830217905550827fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc6040604090036040a25b505b5050565b803373ffffffffffffffffffffffffffffffffffffffff166001600050600083815260200190815260200160002060005060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156106d95781600060005060006001600050600086815260200190815260200160002060005060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000505414156105fd576001600050600083815260200190815260200160002060005060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16827ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a85456040604090036040a36000600060005060006001600050600086815260200190815260200160002060005060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050819055505b6001600050600083815260200190815260200160002060006000820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556003820160005060009055600482016000506000905560058201600050600090555050817fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc6040604090036040a25b505b50565b823373ffffffffffffffffffffffffffffffffffffffff166001600050600083815260200190815260200160002060005060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561083d57826001600050600086815260200190815260200160002060005060010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055508115610811578273ffffffffffffffffffffffffffffffffffffffff16847ff63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a85456040604090036040a383600060005060008573ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050819055505b837fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc6040604090036040a25b505b505050565b813373ffffffffffffffffffffffffffffffffffffffff166001600050600083815260200190815260200160002060005060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561092657816001600050600085815260200190815260200160002060005060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690830217905550827fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc6040604090036040a25b505b5050565b813373ffffffffffffffffffffffffffffffffffffffff166001600050600083815260200190815260200160002060005060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156109ed57816001600050600085815260200190815260200160002060005060030160005081905550827fa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc6040604090036040a25b505b5050565b60006001600050600083815260200190815260200160002060005060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050610a39565b919050565b60006001600050600083815260200190815260200160002060005060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050610a84565b919050565b60006001600050600083815260200190815260200160002060005060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050610acf565b919050565b600060016000506000838152602001908152602001600020600050600301600050549050610afd565b919050565b6000600060005060008373ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050549050610b3b565b91905056`
-)
diff --git a/common/registrar/ethreg/api.go b/common/registrar/ethreg/api.go
deleted file mode 100644
index a32653554..000000000
--- a/common/registrar/ethreg/api.go
+++ /dev/null
@@ -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: &registryAPIBackend{
- 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
-}
diff --git a/common/registrar/registrar.go b/common/registrar/registrar.go
deleted file mode 100644
index 0606f6985..000000000
--- a/common/registrar/registrar.go
+++ /dev/null
@@ -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):], ""
-}
diff --git a/common/registrar/registrar_test.go b/common/registrar/registrar_test.go
deleted file mode 100644
index b2287803c..000000000
--- a/common/registrar/registrar_test.go
+++ /dev/null
@@ -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)
- }
- }
-}
diff --git a/eth/backend.go b/eth/backend.go
index 2351a62c8..7e4941978 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -32,7 +32,6 @@ import (
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/httpclient"
- "github.com/ethereum/go-ethereum/common/registrar/ethreg"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/downloader"
@@ -127,7 +126,6 @@ type Ethereum struct {
eventMux *event.TypeMux
pow *ethash.Ethash
- httpclient *httpclient.HTTPClient
accountManager *accounts.Manager
ApiBackend *EthApiBackend
@@ -173,7 +171,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
pow: pow,
shutdownChan: make(chan bool),
stopDbUpgrade: stopDbUpgrade,
- httpclient: httpclient.New(config.DocRoot),
netVersionId: config.NetworkId,
NatSpec: config.NatSpec,
PowTest: config.PowTest,
@@ -356,10 +353,6 @@ func (s *Ethereum) APIs() []rpc.API {
Version: "1.0",
Service: s.netRPCService,
Public: true,
- }, {
- Namespace: "admin",
- Version: "1.0",
- Service: ethreg.NewPrivateRegistarAPI(s.chainConfig, s.blockchain, s.chainDb, s.txPool, s.accountManager),
},
}...)
}