github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/rpc/api/admin.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 api 18 19 import ( 20 "fmt" 21 "io" 22 "math/big" 23 "os" 24 "time" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/common/compiler" 28 "github.com/ethereum/go-ethereum/common/docserver" 29 "github.com/ethereum/go-ethereum/common/natspec" 30 "github.com/ethereum/go-ethereum/common/registrar" 31 "github.com/ethereum/go-ethereum/core" 32 "github.com/ethereum/go-ethereum/core/types" 33 "github.com/ethereum/go-ethereum/crypto" 34 "github.com/ethereum/go-ethereum/eth" 35 "github.com/ethereum/go-ethereum/logger/glog" 36 "github.com/ethereum/go-ethereum/rlp" 37 "github.com/ethereum/go-ethereum/rpc/codec" 38 "github.com/ethereum/go-ethereum/rpc/comms" 39 "github.com/ethereum/go-ethereum/rpc/shared" 40 "github.com/ethereum/go-ethereum/rpc/useragent" 41 "github.com/ethereum/go-ethereum/xeth" 42 ) 43 44 const ( 45 AdminApiversion = "1.0" 46 importBatchSize = 2500 47 ) 48 49 var ( 50 // mapping between methods and handlers 51 AdminMapping = map[string]adminhandler{ 52 "admin_addPeer": (*adminApi).AddPeer, 53 "admin_peers": (*adminApi).Peers, 54 "admin_nodeInfo": (*adminApi).NodeInfo, 55 "admin_exportChain": (*adminApi).ExportChain, 56 "admin_importChain": (*adminApi).ImportChain, 57 "admin_verbosity": (*adminApi).Verbosity, 58 "admin_chainSyncStatus": (*adminApi).ChainSyncStatus, 59 "admin_setSolc": (*adminApi).SetSolc, 60 "admin_datadir": (*adminApi).DataDir, 61 "admin_startRPC": (*adminApi).StartRPC, 62 "admin_stopRPC": (*adminApi).StopRPC, 63 "admin_setGlobalRegistrar": (*adminApi).SetGlobalRegistrar, 64 "admin_setHashReg": (*adminApi).SetHashReg, 65 "admin_setUrlHint": (*adminApi).SetUrlHint, 66 "admin_saveInfo": (*adminApi).SaveInfo, 67 "admin_register": (*adminApi).Register, 68 "admin_registerUrl": (*adminApi).RegisterUrl, 69 "admin_startNatSpec": (*adminApi).StartNatSpec, 70 "admin_stopNatSpec": (*adminApi).StopNatSpec, 71 "admin_getContractInfo": (*adminApi).GetContractInfo, 72 "admin_httpGet": (*adminApi).HttpGet, 73 "admin_sleepBlocks": (*adminApi).SleepBlocks, 74 "admin_sleep": (*adminApi).Sleep, 75 "admin_enableUserAgent": (*adminApi).EnableUserAgent, 76 } 77 ) 78 79 // admin callback handler 80 type adminhandler func(*adminApi, *shared.Request) (interface{}, error) 81 82 // admin api provider 83 type adminApi struct { 84 xeth *xeth.XEth 85 ethereum *eth.Ethereum 86 codec codec.Codec 87 coder codec.ApiCoder 88 ds *docserver.DocServer 89 } 90 91 // create a new admin api instance 92 func NewAdminApi(xeth *xeth.XEth, ethereum *eth.Ethereum, codec codec.Codec) *adminApi { 93 return &adminApi{ 94 xeth: xeth, 95 ethereum: ethereum, 96 codec: codec, 97 coder: codec.New(nil), 98 ds: docserver.New("/"), 99 } 100 } 101 102 // collection with supported methods 103 func (self *adminApi) Methods() []string { 104 methods := make([]string, len(AdminMapping)) 105 i := 0 106 for k := range AdminMapping { 107 methods[i] = k 108 i++ 109 } 110 return methods 111 } 112 113 // Execute given request 114 func (self *adminApi) Execute(req *shared.Request) (interface{}, error) { 115 if callback, ok := AdminMapping[req.Method]; ok { 116 return callback(self, req) 117 } 118 119 return nil, &shared.NotImplementedError{req.Method} 120 } 121 122 func (self *adminApi) Name() string { 123 return shared.AdminApiName 124 } 125 126 func (self *adminApi) ApiVersion() string { 127 return AdminApiversion 128 } 129 130 func (self *adminApi) AddPeer(req *shared.Request) (interface{}, error) { 131 args := new(AddPeerArgs) 132 if err := self.coder.Decode(req.Params, &args); err != nil { 133 return nil, shared.NewDecodeParamError(err.Error()) 134 } 135 136 err := self.ethereum.AddPeer(args.Url) 137 if err == nil { 138 return true, nil 139 } 140 return false, err 141 } 142 143 func (self *adminApi) Peers(req *shared.Request) (interface{}, error) { 144 return self.ethereum.PeersInfo(), nil 145 } 146 147 func (self *adminApi) NodeInfo(req *shared.Request) (interface{}, error) { 148 return self.ethereum.NodeInfo(), nil 149 } 150 151 func (self *adminApi) DataDir(req *shared.Request) (interface{}, error) { 152 return self.ethereum.DataDir, nil 153 } 154 155 func hasAllBlocks(chain *core.ChainManager, bs []*types.Block) bool { 156 for _, b := range bs { 157 if !chain.HasBlock(b.Hash()) { 158 return false 159 } 160 } 161 return true 162 } 163 164 func (self *adminApi) ImportChain(req *shared.Request) (interface{}, error) { 165 args := new(ImportExportChainArgs) 166 if err := self.coder.Decode(req.Params, &args); err != nil { 167 return nil, shared.NewDecodeParamError(err.Error()) 168 } 169 170 fh, err := os.Open(args.Filename) 171 if err != nil { 172 return false, err 173 } 174 defer fh.Close() 175 stream := rlp.NewStream(fh, 0) 176 177 // Run actual the import. 178 blocks := make(types.Blocks, importBatchSize) 179 n := 0 180 for batch := 0; ; batch++ { 181 182 i := 0 183 for ; i < importBatchSize; i++ { 184 var b types.Block 185 if err := stream.Decode(&b); err == io.EOF { 186 break 187 } else if err != nil { 188 return false, fmt.Errorf("at block %d: %v", n, err) 189 } 190 blocks[i] = &b 191 n++ 192 } 193 if i == 0 { 194 break 195 } 196 // Import the batch. 197 if hasAllBlocks(self.ethereum.ChainManager(), blocks[:i]) { 198 continue 199 } 200 if _, err := self.ethereum.ChainManager().InsertChain(blocks[:i]); err != nil { 201 return false, fmt.Errorf("invalid block %d: %v", n, err) 202 } 203 } 204 return true, nil 205 } 206 207 func (self *adminApi) ExportChain(req *shared.Request) (interface{}, error) { 208 args := new(ImportExportChainArgs) 209 if err := self.coder.Decode(req.Params, &args); err != nil { 210 return nil, shared.NewDecodeParamError(err.Error()) 211 } 212 213 fh, err := os.OpenFile(args.Filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) 214 if err != nil { 215 return false, err 216 } 217 defer fh.Close() 218 if err := self.ethereum.ChainManager().Export(fh); err != nil { 219 return false, err 220 } 221 222 return true, nil 223 } 224 225 func (self *adminApi) Verbosity(req *shared.Request) (interface{}, error) { 226 args := new(VerbosityArgs) 227 if err := self.coder.Decode(req.Params, &args); err != nil { 228 return nil, shared.NewDecodeParamError(err.Error()) 229 } 230 231 glog.SetV(args.Level) 232 return true, nil 233 } 234 235 func (self *adminApi) ChainSyncStatus(req *shared.Request) (interface{}, error) { 236 pending, cached, importing, estimate := self.ethereum.Downloader().Stats() 237 238 return map[string]interface{}{ 239 "blocksAvailable": pending, 240 "blocksWaitingForImport": cached, 241 "importing": importing, 242 "estimate": estimate.String(), 243 }, nil 244 } 245 246 func (self *adminApi) SetSolc(req *shared.Request) (interface{}, error) { 247 args := new(SetSolcArgs) 248 if err := self.coder.Decode(req.Params, &args); err != nil { 249 return nil, shared.NewDecodeParamError(err.Error()) 250 } 251 252 solc, err := self.xeth.SetSolc(args.Path) 253 if err != nil { 254 return nil, err 255 } 256 return solc.Info(), nil 257 } 258 259 func (self *adminApi) StartRPC(req *shared.Request) (interface{}, error) { 260 args := new(StartRPCArgs) 261 if err := self.coder.Decode(req.Params, &args); err != nil { 262 return nil, shared.NewDecodeParamError(err.Error()) 263 } 264 265 cfg := comms.HttpConfig{ 266 ListenAddress: args.ListenAddress, 267 ListenPort: args.ListenPort, 268 CorsDomain: args.CorsDomain, 269 } 270 271 apis, err := ParseApiString(args.Apis, self.codec, self.xeth, self.ethereum) 272 if err != nil { 273 return false, err 274 } 275 276 err = comms.StartHttp(cfg, self.codec, Merge(apis...)) 277 if err == nil { 278 return true, nil 279 } 280 return false, err 281 } 282 283 func (self *adminApi) StopRPC(req *shared.Request) (interface{}, error) { 284 comms.StopHttp() 285 return true, nil 286 } 287 288 func (self *adminApi) SleepBlocks(req *shared.Request) (interface{}, error) { 289 args := new(SleepBlocksArgs) 290 if err := self.coder.Decode(req.Params, &args); err != nil { 291 return nil, shared.NewDecodeParamError(err.Error()) 292 } 293 var timer <-chan time.Time 294 var height *big.Int 295 var err error 296 if args.Timeout > 0 { 297 timer = time.NewTimer(time.Duration(args.Timeout) * time.Second).C 298 } 299 300 height = new(big.Int).Add(self.xeth.CurrentBlock().Number(), big.NewInt(args.N)) 301 height, err = sleepBlocks(self.xeth.UpdateState(), height, timer) 302 if err != nil { 303 return nil, err 304 } 305 return height.Uint64(), nil 306 } 307 308 func sleepBlocks(wait chan *big.Int, height *big.Int, timer <-chan time.Time) (newHeight *big.Int, err error) { 309 wait <- height 310 select { 311 case <-timer: 312 // if times out make sure the xeth loop does not block 313 go func() { 314 select { 315 case wait <- nil: 316 case <-wait: 317 } 318 }() 319 return nil, fmt.Errorf("timeout") 320 case newHeight = <-wait: 321 } 322 return 323 } 324 325 func (self *adminApi) Sleep(req *shared.Request) (interface{}, error) { 326 args := new(SleepArgs) 327 if err := self.coder.Decode(req.Params, &args); err != nil { 328 return nil, shared.NewDecodeParamError(err.Error()) 329 } 330 time.Sleep(time.Duration(args.S) * time.Second) 331 return nil, nil 332 } 333 334 func (self *adminApi) SetGlobalRegistrar(req *shared.Request) (interface{}, error) { 335 args := new(SetGlobalRegistrarArgs) 336 if err := self.coder.Decode(req.Params, &args); err != nil { 337 return nil, shared.NewDecodeParamError(err.Error()) 338 } 339 340 sender := common.HexToAddress(args.ContractAddress) 341 342 reg := registrar.New(self.xeth) 343 txhash, err := reg.SetGlobalRegistrar(args.NameReg, sender) 344 if err != nil { 345 return false, err 346 } 347 348 return txhash, nil 349 } 350 351 func (self *adminApi) SetHashReg(req *shared.Request) (interface{}, error) { 352 args := new(SetHashRegArgs) 353 if err := self.coder.Decode(req.Params, &args); err != nil { 354 return nil, shared.NewDecodeParamError(err.Error()) 355 } 356 357 reg := registrar.New(self.xeth) 358 sender := common.HexToAddress(args.Sender) 359 txhash, err := reg.SetHashReg(args.HashReg, sender) 360 if err != nil { 361 return false, err 362 } 363 364 return txhash, nil 365 } 366 367 func (self *adminApi) SetUrlHint(req *shared.Request) (interface{}, error) { 368 args := new(SetUrlHintArgs) 369 if err := self.coder.Decode(req.Params, &args); err != nil { 370 return nil, shared.NewDecodeParamError(err.Error()) 371 } 372 373 urlHint := args.UrlHint 374 sender := common.HexToAddress(args.Sender) 375 376 reg := registrar.New(self.xeth) 377 txhash, err := reg.SetUrlHint(urlHint, sender) 378 if err != nil { 379 return nil, err 380 } 381 382 return txhash, nil 383 } 384 385 func (self *adminApi) SaveInfo(req *shared.Request) (interface{}, error) { 386 args := new(SaveInfoArgs) 387 if err := self.coder.Decode(req.Params, &args); err != nil { 388 return nil, shared.NewDecodeParamError(err.Error()) 389 } 390 391 contenthash, err := compiler.SaveInfo(&args.ContractInfo, args.Filename) 392 if err != nil { 393 return nil, err 394 } 395 396 return contenthash.Hex(), nil 397 } 398 399 func (self *adminApi) Register(req *shared.Request) (interface{}, error) { 400 args := new(RegisterArgs) 401 if err := self.coder.Decode(req.Params, &args); err != nil { 402 return nil, shared.NewDecodeParamError(err.Error()) 403 } 404 405 sender := common.HexToAddress(args.Sender) 406 // sender and contract address are passed as hex strings 407 codeb := self.xeth.CodeAtBytes(args.Address) 408 codeHash := common.BytesToHash(crypto.Sha3(codeb)) 409 contentHash := common.HexToHash(args.ContentHashHex) 410 registry := registrar.New(self.xeth) 411 412 _, err := registry.SetHashToHash(sender, codeHash, contentHash) 413 if err != nil { 414 return false, err 415 } 416 417 return true, nil 418 } 419 420 func (self *adminApi) RegisterUrl(req *shared.Request) (interface{}, error) { 421 args := new(RegisterUrlArgs) 422 if err := self.coder.Decode(req.Params, &args); err != nil { 423 return nil, shared.NewDecodeParamError(err.Error()) 424 } 425 426 sender := common.HexToAddress(args.Sender) 427 registry := registrar.New(self.xeth) 428 _, err := registry.SetUrlToHash(sender, common.HexToHash(args.ContentHash), args.Url) 429 if err != nil { 430 return false, err 431 } 432 433 return true, nil 434 } 435 436 func (self *adminApi) StartNatSpec(req *shared.Request) (interface{}, error) { 437 self.ethereum.NatSpec = true 438 return true, nil 439 } 440 441 func (self *adminApi) StopNatSpec(req *shared.Request) (interface{}, error) { 442 self.ethereum.NatSpec = false 443 return true, nil 444 } 445 446 func (self *adminApi) GetContractInfo(req *shared.Request) (interface{}, error) { 447 args := new(GetContractInfoArgs) 448 if err := self.coder.Decode(req.Params, &args); err != nil { 449 return nil, shared.NewDecodeParamError(err.Error()) 450 } 451 452 infoDoc, err := natspec.FetchDocsForContract(args.Contract, self.xeth, self.ds) 453 if err != nil { 454 return nil, err 455 } 456 457 var info interface{} 458 err = self.coder.Decode(infoDoc, &info) 459 if err != nil { 460 return nil, err 461 } 462 463 return info, nil 464 } 465 466 func (self *adminApi) HttpGet(req *shared.Request) (interface{}, error) { 467 args := new(HttpGetArgs) 468 if err := self.coder.Decode(req.Params, &args); err != nil { 469 return nil, shared.NewDecodeParamError(err.Error()) 470 } 471 472 resp, err := self.ds.Get(args.Uri, args.Path) 473 if err != nil { 474 return nil, err 475 } 476 477 return string(resp), nil 478 } 479 480 func (self *adminApi) EnableUserAgent(req *shared.Request) (interface{}, error) { 481 if fe, ok := self.xeth.Frontend().(*useragent.RemoteFrontend); ok { 482 fe.Enable() 483 } 484 return true, nil 485 }