github.com/murrekatt/go-ethereum@v1.5.8-0.20170123175102-fc52f2c007fb/eth/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 eth 18 19 import ( 20 "bytes" 21 "compress/gzip" 22 "errors" 23 "fmt" 24 "io" 25 "io/ioutil" 26 "math/big" 27 "os" 28 "runtime" 29 "strings" 30 "time" 31 32 "github.com/ethereum/ethash" 33 "github.com/ethereum/go-ethereum/common" 34 "github.com/ethereum/go-ethereum/common/hexutil" 35 "github.com/ethereum/go-ethereum/core" 36 "github.com/ethereum/go-ethereum/core/state" 37 "github.com/ethereum/go-ethereum/core/types" 38 "github.com/ethereum/go-ethereum/core/vm" 39 "github.com/ethereum/go-ethereum/internal/ethapi" 40 "github.com/ethereum/go-ethereum/logger" 41 "github.com/ethereum/go-ethereum/logger/glog" 42 "github.com/ethereum/go-ethereum/miner" 43 "github.com/ethereum/go-ethereum/params" 44 "github.com/ethereum/go-ethereum/rlp" 45 "github.com/ethereum/go-ethereum/rpc" 46 "golang.org/x/net/context" 47 ) 48 49 const defaultTraceTimeout = 5 * time.Second 50 51 // PublicEthereumAPI provides an API to access Ethereum full node-related 52 // information. 53 type PublicEthereumAPI struct { 54 e *Ethereum 55 } 56 57 // NewPublicEthereumAPI creates a new Etheruem protocol API for full nodes. 58 func NewPublicEthereumAPI(e *Ethereum) *PublicEthereumAPI { 59 return &PublicEthereumAPI{e} 60 } 61 62 // Etherbase is the address that mining rewards will be send to 63 func (s *PublicEthereumAPI) Etherbase() (common.Address, error) { 64 return s.e.Etherbase() 65 } 66 67 // Coinbase is the address that mining rewards will be send to (alias for Etherbase) 68 func (s *PublicEthereumAPI) Coinbase() (common.Address, error) { 69 return s.Etherbase() 70 } 71 72 // Hashrate returns the POW hashrate 73 func (s *PublicEthereumAPI) Hashrate() hexutil.Uint64 { 74 return hexutil.Uint64(s.e.Miner().HashRate()) 75 } 76 77 // PublicMinerAPI provides an API to control the miner. 78 // It offers only methods that operate on data that pose no security risk when it is publicly accessible. 79 type PublicMinerAPI struct { 80 e *Ethereum 81 agent *miner.RemoteAgent 82 } 83 84 // NewPublicMinerAPI create a new PublicMinerAPI instance. 85 func NewPublicMinerAPI(e *Ethereum) *PublicMinerAPI { 86 agent := miner.NewRemoteAgent(e.Pow()) 87 e.Miner().Register(agent) 88 89 return &PublicMinerAPI{e, agent} 90 } 91 92 // Mining returns an indication if this node is currently mining. 93 func (s *PublicMinerAPI) Mining() bool { 94 return s.e.IsMining() 95 } 96 97 // SubmitWork can be used by external miner to submit their POW solution. It returns an indication if the work was 98 // accepted. Note, this is not an indication if the provided work was valid! 99 func (s *PublicMinerAPI) SubmitWork(nonce types.BlockNonce, solution, digest common.Hash) bool { 100 return s.agent.SubmitWork(nonce, digest, solution) 101 } 102 103 // GetWork returns a work package for external miner. The work package consists of 3 strings 104 // result[0], 32 bytes hex encoded current block header pow-hash 105 // result[1], 32 bytes hex encoded seed hash used for DAG 106 // result[2], 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty 107 func (s *PublicMinerAPI) GetWork() (work [3]string, err error) { 108 if !s.e.IsMining() { 109 if err := s.e.StartMining(0); err != nil { 110 return work, err 111 } 112 } 113 if work, err = s.agent.GetWork(); err == nil { 114 return 115 } 116 glog.V(logger.Debug).Infof("%v", err) 117 return work, fmt.Errorf("mining not ready") 118 } 119 120 // SubmitHashrate can be used for remote miners to submit their hash rate. This enables the node to report the combined 121 // hash rate of all miners which submit work through this node. It accepts the miner hash rate and an identifier which 122 // must be unique between nodes. 123 func (s *PublicMinerAPI) SubmitHashrate(hashrate hexutil.Uint64, id common.Hash) bool { 124 s.agent.SubmitHashrate(id, uint64(hashrate)) 125 return true 126 } 127 128 // PrivateMinerAPI provides private RPC methods to control the miner. 129 // These methods can be abused by external users and must be considered insecure for use by untrusted users. 130 type PrivateMinerAPI struct { 131 e *Ethereum 132 } 133 134 // NewPrivateMinerAPI create a new RPC service which controls the miner of this node. 135 func NewPrivateMinerAPI(e *Ethereum) *PrivateMinerAPI { 136 return &PrivateMinerAPI{e: e} 137 } 138 139 // Start the miner with the given number of threads. If threads is nil the number of 140 // workers started is equal to the number of logical CPU's that are usable by this process. 141 func (s *PrivateMinerAPI) Start(threads *int) (bool, error) { 142 s.e.StartAutoDAG() 143 var err error 144 if threads == nil { 145 err = s.e.StartMining(runtime.NumCPU()) 146 } else { 147 err = s.e.StartMining(*threads) 148 } 149 return err == nil, err 150 } 151 152 // Stop the miner 153 func (s *PrivateMinerAPI) Stop() bool { 154 s.e.StopMining() 155 return true 156 } 157 158 // SetExtra sets the extra data string that is included when this miner mines a block. 159 func (s *PrivateMinerAPI) SetExtra(extra string) (bool, error) { 160 if err := s.e.Miner().SetExtra([]byte(extra)); err != nil { 161 return false, err 162 } 163 return true, nil 164 } 165 166 // SetGasPrice sets the minimum accepted gas price for the miner. 167 func (s *PrivateMinerAPI) SetGasPrice(gasPrice hexutil.Big) bool { 168 s.e.Miner().SetGasPrice((*big.Int)(&gasPrice)) 169 return true 170 } 171 172 // SetEtherbase sets the etherbase of the miner 173 func (s *PrivateMinerAPI) SetEtherbase(etherbase common.Address) bool { 174 s.e.SetEtherbase(etherbase) 175 return true 176 } 177 178 // StartAutoDAG starts auto DAG generation. This will prevent the DAG generating on epoch change 179 // which will cause the node to stop mining during the generation process. 180 func (s *PrivateMinerAPI) StartAutoDAG() bool { 181 s.e.StartAutoDAG() 182 return true 183 } 184 185 // StopAutoDAG stops auto DAG generation 186 func (s *PrivateMinerAPI) StopAutoDAG() bool { 187 s.e.StopAutoDAG() 188 return true 189 } 190 191 // MakeDAG creates the new DAG for the given block number 192 func (s *PrivateMinerAPI) MakeDAG(blockNr rpc.BlockNumber) (bool, error) { 193 if err := ethash.MakeDAG(uint64(blockNr.Int64()), ""); err != nil { 194 return false, err 195 } 196 return true, nil 197 } 198 199 // PrivateAdminAPI is the collection of Etheruem full node-related APIs 200 // exposed over the private admin endpoint. 201 type PrivateAdminAPI struct { 202 eth *Ethereum 203 } 204 205 // NewPrivateAdminAPI creates a new API definition for the full node private 206 // admin methods of the Ethereum service. 207 func NewPrivateAdminAPI(eth *Ethereum) *PrivateAdminAPI { 208 return &PrivateAdminAPI{eth: eth} 209 } 210 211 // ExportChain exports the current blockchain into a local file. 212 func (api *PrivateAdminAPI) ExportChain(file string) (bool, error) { 213 // Make sure we can create the file to export into 214 out, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) 215 if err != nil { 216 return false, err 217 } 218 defer out.Close() 219 220 var writer io.Writer = out 221 if strings.HasSuffix(file, ".gz") { 222 writer = gzip.NewWriter(writer) 223 defer writer.(*gzip.Writer).Close() 224 } 225 226 // Export the blockchain 227 if err := api.eth.BlockChain().Export(writer); err != nil { 228 return false, err 229 } 230 return true, nil 231 } 232 233 func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool { 234 for _, b := range bs { 235 if !chain.HasBlock(b.Hash()) { 236 return false 237 } 238 } 239 240 return true 241 } 242 243 // ImportChain imports a blockchain from a local file. 244 func (api *PrivateAdminAPI) ImportChain(file string) (bool, error) { 245 // Make sure the can access the file to import 246 in, err := os.Open(file) 247 if err != nil { 248 return false, err 249 } 250 defer in.Close() 251 252 var reader io.Reader = in 253 if strings.HasSuffix(file, ".gz") { 254 if reader, err = gzip.NewReader(reader); err != nil { 255 return false, err 256 } 257 } 258 259 // Run actual the import in pre-configured batches 260 stream := rlp.NewStream(reader, 0) 261 262 blocks, index := make([]*types.Block, 0, 2500), 0 263 for batch := 0; ; batch++ { 264 // Load a batch of blocks from the input file 265 for len(blocks) < cap(blocks) { 266 block := new(types.Block) 267 if err := stream.Decode(block); err == io.EOF { 268 break 269 } else if err != nil { 270 return false, fmt.Errorf("block %d: failed to parse: %v", index, err) 271 } 272 blocks = append(blocks, block) 273 index++ 274 } 275 if len(blocks) == 0 { 276 break 277 } 278 279 if hasAllBlocks(api.eth.BlockChain(), blocks) { 280 blocks = blocks[:0] 281 continue 282 } 283 // Import the batch and reset the buffer 284 if _, err := api.eth.BlockChain().InsertChain(blocks); err != nil { 285 return false, fmt.Errorf("batch %d: failed to insert: %v", batch, err) 286 } 287 blocks = blocks[:0] 288 } 289 return true, nil 290 } 291 292 // PublicDebugAPI is the collection of Etheruem full node APIs exposed 293 // over the public debugging endpoint. 294 type PublicDebugAPI struct { 295 eth *Ethereum 296 } 297 298 // NewPublicDebugAPI creates a new API definition for the full node- 299 // related public debug methods of the Ethereum service. 300 func NewPublicDebugAPI(eth *Ethereum) *PublicDebugAPI { 301 return &PublicDebugAPI{eth: eth} 302 } 303 304 // DumpBlock retrieves the entire state of the database at a given block. 305 func (api *PublicDebugAPI) DumpBlock(number uint64) (state.Dump, error) { 306 block := api.eth.BlockChain().GetBlockByNumber(number) 307 if block == nil { 308 return state.Dump{}, fmt.Errorf("block #%d not found", number) 309 } 310 stateDb, err := api.eth.BlockChain().StateAt(block.Root()) 311 if err != nil { 312 return state.Dump{}, err 313 } 314 return stateDb.RawDump(), nil 315 } 316 317 // PrivateDebugAPI is the collection of Etheruem full node APIs exposed over 318 // the private debugging endpoint. 319 type PrivateDebugAPI struct { 320 config *params.ChainConfig 321 eth *Ethereum 322 } 323 324 // NewPrivateDebugAPI creates a new API definition for the full node-related 325 // private debug methods of the Ethereum service. 326 func NewPrivateDebugAPI(config *params.ChainConfig, eth *Ethereum) *PrivateDebugAPI { 327 return &PrivateDebugAPI{config: config, eth: eth} 328 } 329 330 // BlockTraceResult is the returned value when replaying a block to check for 331 // consensus results and full VM trace logs for all included transactions. 332 type BlockTraceResult struct { 333 Validated bool `json:"validated"` 334 StructLogs []ethapi.StructLogRes `json:"structLogs"` 335 Error string `json:"error"` 336 } 337 338 // TraceArgs holds extra parameters to trace functions 339 type TraceArgs struct { 340 *vm.LogConfig 341 Tracer *string 342 Timeout *string 343 } 344 345 // TraceBlock processes the given block's RLP but does not import the block in to 346 // the chain. 347 func (api *PrivateDebugAPI) TraceBlock(blockRlp []byte, config *vm.LogConfig) BlockTraceResult { 348 var block types.Block 349 err := rlp.Decode(bytes.NewReader(blockRlp), &block) 350 if err != nil { 351 return BlockTraceResult{Error: fmt.Sprintf("could not decode block: %v", err)} 352 } 353 354 validated, logs, err := api.traceBlock(&block, config) 355 return BlockTraceResult{ 356 Validated: validated, 357 StructLogs: ethapi.FormatLogs(logs), 358 Error: formatError(err), 359 } 360 } 361 362 // TraceBlockFromFile loads the block's RLP from the given file name and attempts to 363 // process it but does not import the block in to the chain. 364 func (api *PrivateDebugAPI) TraceBlockFromFile(file string, config *vm.LogConfig) BlockTraceResult { 365 blockRlp, err := ioutil.ReadFile(file) 366 if err != nil { 367 return BlockTraceResult{Error: fmt.Sprintf("could not read file: %v", err)} 368 } 369 return api.TraceBlock(blockRlp, config) 370 } 371 372 // TraceBlockByNumber processes the block by canonical block number. 373 func (api *PrivateDebugAPI) TraceBlockByNumber(number uint64, config *vm.LogConfig) BlockTraceResult { 374 // Fetch the block that we aim to reprocess 375 block := api.eth.BlockChain().GetBlockByNumber(number) 376 if block == nil { 377 return BlockTraceResult{Error: fmt.Sprintf("block #%d not found", number)} 378 } 379 380 validated, logs, err := api.traceBlock(block, config) 381 return BlockTraceResult{ 382 Validated: validated, 383 StructLogs: ethapi.FormatLogs(logs), 384 Error: formatError(err), 385 } 386 } 387 388 // TraceBlockByHash processes the block by hash. 389 func (api *PrivateDebugAPI) TraceBlockByHash(hash common.Hash, config *vm.LogConfig) BlockTraceResult { 390 // Fetch the block that we aim to reprocess 391 block := api.eth.BlockChain().GetBlockByHash(hash) 392 if block == nil { 393 return BlockTraceResult{Error: fmt.Sprintf("block #%x not found", hash)} 394 } 395 396 validated, logs, err := api.traceBlock(block, config) 397 return BlockTraceResult{ 398 Validated: validated, 399 StructLogs: ethapi.FormatLogs(logs), 400 Error: formatError(err), 401 } 402 } 403 404 // traceBlock processes the given block but does not save the state. 405 func (api *PrivateDebugAPI) traceBlock(block *types.Block, logConfig *vm.LogConfig) (bool, []vm.StructLog, error) { 406 // Validate and reprocess the block 407 var ( 408 blockchain = api.eth.BlockChain() 409 validator = blockchain.Validator() 410 processor = blockchain.Processor() 411 ) 412 413 structLogger := vm.NewStructLogger(logConfig) 414 415 config := vm.Config{ 416 Debug: true, 417 Tracer: structLogger, 418 } 419 420 if err := core.ValidateHeader(api.config, blockchain.AuxValidator(), block.Header(), blockchain.GetHeader(block.ParentHash(), block.NumberU64()-1), true, false); err != nil { 421 return false, structLogger.StructLogs(), err 422 } 423 statedb, err := blockchain.StateAt(blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1).Root()) 424 if err != nil { 425 return false, structLogger.StructLogs(), err 426 } 427 428 receipts, _, usedGas, err := processor.Process(block, statedb, config) 429 if err != nil { 430 return false, structLogger.StructLogs(), err 431 } 432 if err := validator.ValidateState(block, blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1), statedb, receipts, usedGas); err != nil { 433 return false, structLogger.StructLogs(), err 434 } 435 return true, structLogger.StructLogs(), nil 436 } 437 438 // callmsg is the message type used for call transitions. 439 type callmsg struct { 440 addr common.Address 441 to *common.Address 442 gas, gasPrice *big.Int 443 value *big.Int 444 data []byte 445 } 446 447 // accessor boilerplate to implement core.Message 448 func (m callmsg) From() (common.Address, error) { return m.addr, nil } 449 func (m callmsg) FromFrontier() (common.Address, error) { return m.addr, nil } 450 func (m callmsg) Nonce() uint64 { return 0 } 451 func (m callmsg) CheckNonce() bool { return false } 452 func (m callmsg) To() *common.Address { return m.to } 453 func (m callmsg) GasPrice() *big.Int { return m.gasPrice } 454 func (m callmsg) Gas() *big.Int { return m.gas } 455 func (m callmsg) Value() *big.Int { return m.value } 456 func (m callmsg) Data() []byte { return m.data } 457 458 // formatError formats a Go error into either an empty string or the data content 459 // of the error itself. 460 func formatError(err error) string { 461 if err == nil { 462 return "" 463 } 464 return err.Error() 465 } 466 467 type timeoutError struct{} 468 469 func (t *timeoutError) Error() string { 470 return "Execution time exceeded" 471 } 472 473 // TraceTransaction returns the structured logs created during the execution of EVM 474 // and returns them as a JSON object. 475 func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common.Hash, config *TraceArgs) (interface{}, error) { 476 var tracer vm.Tracer 477 if config != nil && config.Tracer != nil { 478 timeout := defaultTraceTimeout 479 if config.Timeout != nil { 480 var err error 481 if timeout, err = time.ParseDuration(*config.Timeout); err != nil { 482 return nil, err 483 } 484 } 485 486 var err error 487 if tracer, err = ethapi.NewJavascriptTracer(*config.Tracer); err != nil { 488 return nil, err 489 } 490 491 // Handle timeouts and RPC cancellations 492 deadlineCtx, cancel := context.WithTimeout(ctx, timeout) 493 go func() { 494 <-deadlineCtx.Done() 495 tracer.(*ethapi.JavascriptTracer).Stop(&timeoutError{}) 496 }() 497 defer cancel() 498 } else if config == nil { 499 tracer = vm.NewStructLogger(nil) 500 } else { 501 tracer = vm.NewStructLogger(config.LogConfig) 502 } 503 504 // Retrieve the tx from the chain and the containing block 505 tx, blockHash, _, txIndex := core.GetTransaction(api.eth.ChainDb(), txHash) 506 if tx == nil { 507 return nil, fmt.Errorf("transaction %x not found", txHash) 508 } 509 block := api.eth.BlockChain().GetBlockByHash(blockHash) 510 if block == nil { 511 return nil, fmt.Errorf("block %x not found", blockHash) 512 } 513 // Create the state database to mutate and eventually trace 514 parent := api.eth.BlockChain().GetBlock(block.ParentHash(), block.NumberU64()-1) 515 if parent == nil { 516 return nil, fmt.Errorf("block parent %x not found", block.ParentHash()) 517 } 518 stateDb, err := api.eth.BlockChain().StateAt(parent.Root()) 519 if err != nil { 520 return nil, err 521 } 522 523 signer := types.MakeSigner(api.config, block.Number()) 524 // Mutate the state and trace the selected transaction 525 for idx, tx := range block.Transactions() { 526 // Assemble the transaction call message 527 msg, err := tx.AsMessage(signer) 528 if err != nil { 529 return nil, fmt.Errorf("sender retrieval failed: %v", err) 530 } 531 context := core.NewEVMContext(msg, block.Header(), api.eth.BlockChain()) 532 533 // Mutate the state if we haven't reached the tracing transaction yet 534 if uint64(idx) < txIndex { 535 vmenv := vm.NewEVM(context, stateDb, api.config, vm.Config{}) 536 _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())) 537 if err != nil { 538 return nil, fmt.Errorf("mutation failed: %v", err) 539 } 540 stateDb.DeleteSuicides() 541 continue 542 } 543 544 vmenv := vm.NewEVM(context, stateDb, api.config, vm.Config{Debug: true, Tracer: tracer}) 545 ret, gas, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())) 546 if err != nil { 547 return nil, fmt.Errorf("tracing failed: %v", err) 548 } 549 550 switch tracer := tracer.(type) { 551 case *vm.StructLogger: 552 return ðapi.ExecutionResult{ 553 Gas: gas, 554 ReturnValue: fmt.Sprintf("%x", ret), 555 StructLogs: ethapi.FormatLogs(tracer.StructLogs()), 556 }, nil 557 case *ethapi.JavascriptTracer: 558 return tracer.GetResult() 559 } 560 } 561 return nil, errors.New("database inconsistency") 562 } 563 564 // Preimage is a debug API function that returns the preimage for a sha3 hash, if known. 565 func (api *PrivateDebugAPI) Preimage(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { 566 db := core.PreimageTable(api.eth.ChainDb()) 567 return db.Get(hash.Bytes()) 568 }