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