github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/common/registrar/ethreg/api.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package ethreg
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"math/big"
    23  	"strconv"
    24  
    25  	"github.com/ethereumproject/go-ethereum/accounts"
    26  	"github.com/ethereumproject/go-ethereum/common"
    27  	"github.com/ethereumproject/go-ethereum/common/compiler"
    28  	"github.com/ethereumproject/go-ethereum/common/registrar"
    29  	"github.com/ethereumproject/go-ethereum/core"
    30  	"github.com/ethereumproject/go-ethereum/core/state"
    31  	"github.com/ethereumproject/go-ethereum/core/types"
    32  	"github.com/ethereumproject/go-ethereum/crypto"
    33  	"github.com/ethereumproject/go-ethereum/ethdb"
    34  	"github.com/ethereumproject/go-ethereum/logger"
    35  	"github.com/ethereumproject/go-ethereum/logger/glog"
    36  )
    37  
    38  // registryAPIBackend is a backend for an Ethereum Registry.
    39  type registryAPIBackend struct {
    40  	config  *core.ChainConfig
    41  	bc      *core.BlockChain
    42  	chainDb ethdb.Database
    43  	txPool  *core.TxPool
    44  	am      *accounts.Manager
    45  }
    46  
    47  // PrivateRegistarAPI offers various functions to access the Ethereum registry.
    48  type PrivateRegistarAPI struct {
    49  	config *core.ChainConfig
    50  	be     *registryAPIBackend
    51  }
    52  
    53  // NewPrivateRegistarAPI creates a new PrivateRegistarAPI instance.
    54  func NewPrivateRegistarAPI(config *core.ChainConfig, bc *core.BlockChain, chainDb ethdb.Database, txPool *core.TxPool, am *accounts.Manager) *PrivateRegistarAPI {
    55  	return &PrivateRegistarAPI{
    56  		config: config,
    57  		be: &registryAPIBackend{
    58  			config:  config,
    59  			bc:      bc,
    60  			chainDb: chainDb,
    61  			txPool:  txPool,
    62  			am:      am,
    63  		},
    64  	}
    65  }
    66  
    67  // SetGlobalRegistrar allows clients to set the global registry for the node.
    68  // This method can be used to deploy a new registry. First zero out the current
    69  // address by calling the method with namereg = '0x0' and then call this method
    70  // again with '' as namereg. This will submit a transaction to the network which
    71  // will deploy a new registry on execution. The TX hash is returned. When called
    72  // with namereg '' and the current address is not zero the current global is
    73  // address is returned..
    74  func (api *PrivateRegistarAPI) SetGlobalRegistrar(namereg string, from common.Address) (string, error) {
    75  	return registrar.New(api.be).SetGlobalRegistrar(namereg, from)
    76  }
    77  
    78  // SetHashReg queries the registry for a hash.
    79  func (api *PrivateRegistarAPI) SetHashReg(hashreg string, from common.Address) (string, error) {
    80  	return registrar.New(api.be).SetHashReg(hashreg, from)
    81  }
    82  
    83  // SetUrlHint queries the registry for an url.
    84  func (api *PrivateRegistarAPI) SetUrlHint(hashreg string, from common.Address) (string, error) {
    85  	return registrar.New(api.be).SetUrlHint(hashreg, from)
    86  }
    87  
    88  // SaveInfo stores contract information on the local file system.
    89  func (api *PrivateRegistarAPI) SaveInfo(info *compiler.ContractInfo, filename string) (contenthash common.Hash, err error) {
    90  	return compiler.SaveInfo(info, filename)
    91  }
    92  
    93  // Register registers a new content hash in the registry.
    94  func (api *PrivateRegistarAPI) Register(sender common.Address, addr common.Address, contentHashHex string) (bool, error) {
    95  	block := api.be.bc.CurrentBlock()
    96  	state, err := state.New(block.Root(), state.NewDatabase(api.be.chainDb))
    97  	if err != nil {
    98  		return false, err
    99  	}
   100  
   101  	codeb := state.GetCode(addr)
   102  	codeHash := common.BytesToHash(crypto.Keccak256(codeb))
   103  	contentHash := common.HexToHash(contentHashHex)
   104  
   105  	_, err = registrar.New(api.be).SetHashToHash(sender, codeHash, contentHash)
   106  	return err == nil, err
   107  }
   108  
   109  // RegisterUrl registers a new url in the registry.
   110  func (api *PrivateRegistarAPI) RegisterUrl(sender common.Address, contentHashHex string, url string) (bool, error) {
   111  	_, err := registrar.New(api.be).SetUrlToHash(sender, common.HexToHash(contentHashHex), url)
   112  	return err == nil, err
   113  }
   114  
   115  // callmsg is the message type used for call transations.
   116  type callmsg struct {
   117  	from          *state.StateObject
   118  	to            *common.Address
   119  	gas, gasPrice *big.Int
   120  	value         *big.Int
   121  	data          []byte
   122  }
   123  
   124  // accessor boilerplate to implement core.Message
   125  func (m callmsg) From() (common.Address, error) {
   126  	return m.from.Address(), nil
   127  }
   128  func (m callmsg) FromFrontier() (common.Address, error) {
   129  	return m.from.Address(), nil
   130  }
   131  func (m callmsg) Nonce() uint64 {
   132  	return m.from.Nonce()
   133  }
   134  func (m callmsg) To() *common.Address {
   135  	return m.to
   136  }
   137  func (m callmsg) GasPrice() *big.Int {
   138  	return m.gasPrice
   139  }
   140  func (m callmsg) Gas() *big.Int {
   141  	return m.gas
   142  }
   143  func (m callmsg) Value() *big.Int {
   144  	return m.value
   145  }
   146  func (m callmsg) Data() []byte {
   147  	return m.data
   148  }
   149  
   150  // Call forms a transaction from the given arguments and tries to execute it on
   151  // a private VM with a copy of the state. Any changes are therefore only temporary
   152  // and not part of the actual state. This allows for local execution/queries.
   153  func (be *registryAPIBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, string, error) {
   154  	value, ok := new(big.Int).SetString(valueStr, 0)
   155  	if !ok {
   156  		return "", "", fmt.Errorf("malformed value %q", valueStr)
   157  	}
   158  
   159  	var gas *big.Int
   160  	if gasStr != "" {
   161  		gas, ok = new(big.Int).SetString(gasStr, 0)
   162  		if !ok {
   163  			return "", "", fmt.Errorf("malformed gas %q", gasStr)
   164  		}
   165  	}
   166  
   167  	var gasPrice *big.Int
   168  	if gasPriceStr != "" {
   169  		gasPrice, ok = new(big.Int).SetString(gasPriceStr, 0)
   170  		if !ok {
   171  			return "", "", fmt.Errorf("malformed gas price %q", gasPriceStr)
   172  		}
   173  	}
   174  
   175  	block := be.bc.CurrentBlock()
   176  	statedb, err := state.New(block.Root(), state.NewDatabase(be.chainDb))
   177  	if err != nil {
   178  		return "", "", err
   179  	}
   180  
   181  	var from *state.StateObject
   182  	if fromStr == "" {
   183  		accounts := be.am.Accounts()
   184  		if len(accounts) == 0 {
   185  			from = statedb.GetOrNewStateObject(common.Address{})
   186  		} else {
   187  			from = statedb.GetOrNewStateObject(accounts[0].Address)
   188  		}
   189  	} else {
   190  		from = statedb.GetOrNewStateObject(common.HexToAddress(fromStr))
   191  	}
   192  
   193  	from.SetBalance(common.MaxBig)
   194  
   195  	msg := callmsg{from: from, gas: gas, gasPrice: gasPrice, value: value, data: common.FromHex(dataStr)}
   196  	if toStr != "" {
   197  		addr := common.HexToAddress(toStr)
   198  		msg.to = &addr
   199  	}
   200  
   201  	if msg.gas.Cmp(big.NewInt(0)) == 0 {
   202  		msg.gas = big.NewInt(50000000)
   203  	}
   204  
   205  	if msg.gasPrice.Cmp(big.NewInt(0)) == 0 {
   206  		msg.gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
   207  	}
   208  
   209  	header := be.bc.CurrentBlock().Header()
   210  	vmenv := core.NewEnv(statedb, be.config, be.bc, msg, header)
   211  	gp := new(core.GasPool).AddGas(common.MaxBig)
   212  	res, gas, _, err := core.ApplyMessage(vmenv, msg, gp)
   213  
   214  	return common.ToHex(res), gas.String(), err
   215  }
   216  
   217  // StorageAt returns the data stores in the state for the given address and location.
   218  func (be *registryAPIBackend) StorageAt(addr string, storageAddr string) string {
   219  	block := be.bc.CurrentBlock()
   220  	state, err := state.New(block.Root(), state.NewDatabase(be.chainDb))
   221  	if err != nil {
   222  		return ""
   223  	}
   224  	return state.GetState(common.HexToAddress(addr), common.HexToHash(storageAddr)).Hex()
   225  }
   226  
   227  // Transact forms a transaction from the given arguments and submits it to the
   228  // transactio pool for execution.
   229  func (be *registryAPIBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
   230  	if len(toStr) > 0 && toStr != "0x" && !common.IsHexAddress(toStr) {
   231  		return "", errors.New("invalid address")
   232  	}
   233  
   234  	var (
   235  		from = common.HexToAddress(fromStr)
   236  		to   = common.HexToAddress(toStr)
   237  	)
   238  
   239  	value, ok := new(big.Int).SetString(valueStr, 0)
   240  	if !ok {
   241  		return "", fmt.Errorf("malformed value %q", valueStr)
   242  	}
   243  
   244  	var gas *big.Int
   245  	if gasStr == "" {
   246  		gas = big.NewInt(90000)
   247  	} else {
   248  		if gas, ok = new(big.Int).SetString(gasStr, 0); !ok {
   249  			return "", fmt.Errorf("malformed gas %q", gasStr)
   250  		}
   251  	}
   252  
   253  	var gasPrice *big.Int
   254  	if gasPriceStr == "" {
   255  		gasPrice = big.NewInt(10000000000000)
   256  	} else {
   257  		if gasPrice, ok = new(big.Int).SetString(gasPriceStr, 0); !ok {
   258  			return "", fmt.Errorf("malformed gas price %q", gasPriceStr)
   259  		}
   260  	}
   261  
   262  	data := common.FromHex(codeStr)
   263  
   264  	nonce := be.txPool.State().GetNonce(from)
   265  	if len(nonceStr) != 0 {
   266  		var err error
   267  		nonce, err = strconv.ParseUint(nonceStr, 0, 64)
   268  		if err != nil {
   269  			return "", fmt.Errorf("malformed nonce %q", nonceStr)
   270  		}
   271  	}
   272  
   273  	var tx *types.Transaction
   274  	if toStr == "" {
   275  		tx = types.NewContractCreation(nonce, value, gas, gasPrice, data)
   276  	} else {
   277  		tx = types.NewTransaction(nonce, to, value, gas, gasPrice, data)
   278  	}
   279  
   280  	sigHash := (types.BasicSigner{}).Hash(tx)
   281  	signature, err := be.am.Sign(from, sigHash.Bytes())
   282  	if err != nil {
   283  		return "", err
   284  	}
   285  	signedTx, err := tx.WithSigner(types.BasicSigner{}).WithSignature(signature)
   286  	if err != nil {
   287  		return "", err
   288  	}
   289  
   290  	be.txPool.SetLocal(signedTx)
   291  	if err := be.txPool.Add(signedTx); err != nil {
   292  		return "", nil
   293  	}
   294  
   295  	if toStr == "" {
   296  		addr := crypto.CreateAddress(from, nonce)
   297  		glog.V(logger.Info).Infof("Tx(%s) created: %s\n", signedTx.Hash().Hex(), addr.Hex())
   298  	} else {
   299  		glog.V(logger.Info).Infof("Tx(%s) to: %s\n", signedTx.Hash().Hex(), tx.To().Hex())
   300  	}
   301  
   302  	return signedTx.Hash().Hex(), nil
   303  }