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: ®istryAPIBackend{ 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 }