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 &ethapi.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  }