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
17package eth
18
19import (
20	"compress/gzip"
21	"context"
22	"errors"
23	"fmt"
24	"io"
25	"math/big"
26	"os"
27	"runtime"
28	"strings"
29	"time"
30
31	"github.com/ethereum/go-ethereum/common"
32	"github.com/ethereum/go-ethereum/common/hexutil"
33	"github.com/ethereum/go-ethereum/core"
34	"github.com/ethereum/go-ethereum/core/rawdb"
35	"github.com/ethereum/go-ethereum/core/state"
36	"github.com/ethereum/go-ethereum/core/types"
37	"github.com/ethereum/go-ethereum/internal/ethapi"
38	"github.com/ethereum/go-ethereum/log"
39	"github.com/ethereum/go-ethereum/rlp"
40	"github.com/ethereum/go-ethereum/rpc"
41	"github.com/ethereum/go-ethereum/trie"
42)
43
44// PublicEthereumAPI provides an API to access Ethereum full node-related
45// information.
46type PublicEthereumAPI struct {
47	e *Ethereum
48}
49
50// NewPublicEthereumAPI creates a new Ethereum protocol API for full nodes.
51func NewPublicEthereumAPI(e *Ethereum) *PublicEthereumAPI {
52	return &PublicEthereumAPI{e}
53}
54
55// Etherbase is the address that mining rewards will be send to
56func (api *PublicEthereumAPI) Etherbase() (common.Address, error) {
57	return api.e.Etherbase()
58}
59
60// Coinbase is the address that mining rewards will be send to (alias for Etherbase)
61func (api *PublicEthereumAPI) Coinbase() (common.Address, error) {
62	return api.Etherbase()
63}
64
65// Hashrate returns the POW hashrate
66func (api *PublicEthereumAPI) Hashrate() hexutil.Uint64 {
67	return hexutil.Uint64(api.e.Miner().Hashrate())
68}
69
70// PublicMinerAPI provides an API to control the miner.
71// It offers only methods that operate on data that pose no security risk when it is publicly accessible.
72type PublicMinerAPI struct {
73	e *Ethereum
74}
75
76// NewPublicMinerAPI create a new PublicMinerAPI instance.
77func NewPublicMinerAPI(e *Ethereum) *PublicMinerAPI {
78	return &PublicMinerAPI{e}
79}
80
81// Mining returns an indication if this node is currently mining.
82func (api *PublicMinerAPI) Mining() bool {
83	return api.e.IsMining()
84}
85
86// PrivateMinerAPI provides private RPC methods to control the miner.
87// These methods can be abused by external users and must be considered insecure for use by untrusted users.
88type PrivateMinerAPI struct {
89	e *Ethereum
90}
91
92// NewPrivateMinerAPI create a new RPC service which controls the miner of this node.
93func NewPrivateMinerAPI(e *Ethereum) *PrivateMinerAPI {
94	return &PrivateMinerAPI{e: e}
95}
96
97// Start starts the miner with the given number of threads. If threads is nil,
98// the number of workers started is equal to the number of logical CPUs that are
99// usable by this process. If mining is already running, this method adjust the
100// number of threads allowed to use and updates the minimum price required by the
101// transaction pool.
102func (api *PrivateMinerAPI) Start(threads *int) error {
103	if threads == nil {
104		return api.e.StartMining(runtime.NumCPU())
105	}
106	return api.e.StartMining(*threads)
107}
108
109// Stop terminates the miner, both at the consensus engine level as well as at
110// the block creation level.
111func (api *PrivateMinerAPI) Stop() {
112	api.e.StopMining()
113}
114
115// SetExtra sets the extra data string that is included when this miner mines a block.
116func (api *PrivateMinerAPI) SetExtra(extra string) (bool, error) {
117	if err := api.e.Miner().SetExtra([]byte(extra)); err != nil {
118		return false, err
119	}
120	return true, nil
121}
122
123// SetGasPrice sets the minimum accepted gas price for the miner.
124func (api *PrivateMinerAPI) SetGasPrice(gasPrice hexutil.Big) bool {
125	api.e.lock.Lock()
126	api.e.gasPrice = (*big.Int)(&gasPrice)
127	api.e.lock.Unlock()
128
129	api.e.txPool.SetGasPrice((*big.Int)(&gasPrice))
130	return true
131}
132
133// SetGasLimit sets the gaslimit to target towards during mining.
134func (api *PrivateMinerAPI) SetGasLimit(gasLimit hexutil.Uint64) bool {
135	api.e.Miner().SetGasCeil(uint64(gasLimit))
136	return true
137}
138
139// SetEtherbase sets the etherbase of the miner
140func (api *PrivateMinerAPI) SetEtherbase(etherbase common.Address) bool {
141	api.e.SetEtherbase(etherbase)
142	return true
143}
144
145// SetRecommitInterval updates the interval for miner sealing work recommitting.
146func (api *PrivateMinerAPI) SetRecommitInterval(interval int) {
147	api.e.Miner().SetRecommitInterval(time.Duration(interval) * time.Millisecond)
148}
149
150// PrivateAdminAPI is the collection of Ethereum full node-related APIs
151// exposed over the private admin endpoint.
152type PrivateAdminAPI struct {
153	eth *Ethereum
154}
155
156// NewPrivateAdminAPI creates a new API definition for the full node private
157// admin methods of the Ethereum service.
158func NewPrivateAdminAPI(eth *Ethereum) *PrivateAdminAPI {
159	return &PrivateAdminAPI{eth: eth}
160}
161
162// ExportChain exports the current blockchain into a local file,
163// or a range of blocks if first and last are non-nil
164func (api *PrivateAdminAPI) ExportChain(file string, first *uint64, last *uint64) (bool, error) {
165	if first == nil && last != nil {
166		return false, errors.New("last cannot be specified without first")
167	}
168	if first != nil && last == nil {
169		head := api.eth.BlockChain().CurrentHeader().Number.Uint64()
170		last = &head
171	}
172	if _, err := os.Stat(file); err == nil {
173		// File already exists. Allowing overwrite could be a DoS vector,
174		// since the 'file' may point to arbitrary paths on the drive
175		return false, errors.New("location would overwrite an existing file")
176	}
177	// Make sure we can create the file to export into
178	out, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
179	if err != nil {
180		return false, err
181	}
182	defer out.Close()
183
184	var writer io.Writer = out
185	if strings.HasSuffix(file, ".gz") {
186		writer = gzip.NewWriter(writer)
187		defer writer.(*gzip.Writer).Close()
188	}
189
190	// Export the blockchain
191	if first != nil {
192		if err := api.eth.BlockChain().ExportN(writer, *first, *last); err != nil {
193			return false, err
194		}
195	} else if err := api.eth.BlockChain().Export(writer); err != nil {
196		return false, err
197	}
198	return true, nil
199}
200
201func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool {
202	for _, b := range bs {
203		if !chain.HasBlock(b.Hash(), b.NumberU64()) {
204			return false
205		}
206	}
207
208	return true
209}
210
211// ImportChain imports a blockchain from a local file.
212func (api *PrivateAdminAPI) ImportChain(file string) (bool, error) {
213	// Make sure the can access the file to import
214	in, err := os.Open(file)
215	if err != nil {
216		return false, err
217	}
218	defer in.Close()
219
220	var reader io.Reader = in
221	if strings.HasSuffix(file, ".gz") {
222		if reader, err = gzip.NewReader(reader); err != nil {
223			return false, err
224		}
225	}
226
227	// Run actual the import in pre-configured batches
228	stream := rlp.NewStream(reader, 0)
229
230	blocks, index := make([]*types.Block, 0, 2500), 0
231	for batch := 0; ; batch++ {
232		// Load a batch of blocks from the input file
233		for len(blocks) < cap(blocks) {
234			block := new(types.Block)
235			if err := stream.Decode(block); err == io.EOF {
236				break
237			} else if err != nil {
238				return false, fmt.Errorf("block %d: failed to parse: %v", index, err)
239			}
240			blocks = append(blocks, block)
241			index++
242		}
243		if len(blocks) == 0 {
244			break
245		}
246
247		if hasAllBlocks(api.eth.BlockChain(), blocks) {
248			blocks = blocks[:0]
249			continue
250		}
251		// Import the batch and reset the buffer
252		if _, err := api.eth.BlockChain().InsertChain(blocks); err != nil {
253			return false, fmt.Errorf("batch %d: failed to insert: %v", batch, err)
254		}
255		blocks = blocks[:0]
256	}
257	return true, nil
258}
259
260// PublicDebugAPI is the collection of Ethereum full node APIs exposed
261// over the public debugging endpoint.
262type PublicDebugAPI struct {
263	eth *Ethereum
264}
265
266// NewPublicDebugAPI creates a new API definition for the full node-
267// related public debug methods of the Ethereum service.
268func NewPublicDebugAPI(eth *Ethereum) *PublicDebugAPI {
269	return &PublicDebugAPI{eth: eth}
270}
271
272// DumpBlock retrieves the entire state of the database at a given block.
273func (api *PublicDebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) {
274	opts := &state.DumpConfig{
275		OnlyWithAddresses: true,
276		Max:               AccountRangeMaxResults, // Sanity limit over RPC
277	}
278	if blockNr == rpc.PendingBlockNumber {
279		// If we're dumping the pending state, we need to request
280		// both the pending block as well as the pending state from
281		// the miner and operate on those
282		_, stateDb := api.eth.miner.Pending()
283		return stateDb.RawDump(opts), nil
284	}
285	var block *types.Block
286	if blockNr == rpc.LatestBlockNumber {
287		block = api.eth.blockchain.CurrentBlock()
288	} else {
289		block = api.eth.blockchain.GetBlockByNumber(uint64(blockNr))
290	}
291	if block == nil {
292		return state.Dump{}, fmt.Errorf("block #%d not found", blockNr)
293	}
294	stateDb, err := api.eth.BlockChain().StateAt(block.Root())
295	if err != nil {
296		return state.Dump{}, err
297	}
298	return stateDb.RawDump(opts), nil
299}
300
301// PrivateDebugAPI is the collection of Ethereum full node APIs exposed over
302// the private debugging endpoint.
303type PrivateDebugAPI struct {
304	eth *Ethereum
305}
306
307// NewPrivateDebugAPI creates a new API definition for the full node-related
308// private debug methods of the Ethereum service.
309func NewPrivateDebugAPI(eth *Ethereum) *PrivateDebugAPI {
310	return &PrivateDebugAPI{eth: eth}
311}
312
313// Preimage is a debug API function that returns the preimage for a sha3 hash, if known.
314func (api *PrivateDebugAPI) Preimage(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
315	if preimage := rawdb.ReadPreimage(api.eth.ChainDb(), hash); preimage != nil {
316		return preimage, nil
317	}
318	return nil, errors.New("unknown preimage")
319}
320
321// BadBlockArgs represents the entries in the list returned when bad blocks are queried.
322type BadBlockArgs struct {
323	Hash  common.Hash            `json:"hash"`
324	Block map[string]interface{} `json:"block"`
325	RLP   string                 `json:"rlp"`
326}
327
328// GetBadBlocks returns a list of the last 'bad blocks' that the client has seen on the network
329// and returns them as a JSON list of block-hashes
330func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error) {
331	var (
332		err     error
333		blocks  = rawdb.ReadAllBadBlocks(api.eth.chainDb)
334		results = make([]*BadBlockArgs, 0, len(blocks))
335	)
336	for _, block := range blocks {
337		var (
338			blockRlp  string
339			blockJSON map[string]interface{}
340		)
341		if rlpBytes, err := rlp.EncodeToBytes(block); err != nil {
342			blockRlp = err.Error() // Hacky, but hey, it works
343		} else {
344			blockRlp = fmt.Sprintf("0x%x", rlpBytes)
345		}
346		if blockJSON, err = ethapi.RPCMarshalBlock(block, true, true, api.eth.APIBackend.ChainConfig()); err != nil {
347			blockJSON = map[string]interface{}{"error": err.Error()}
348		}
349		results = append(results, &BadBlockArgs{
350			Hash:  block.Hash(),
351			RLP:   blockRlp,
352			Block: blockJSON,
353		})
354	}
355	return results, nil
356}
357
358// AccountRangeMaxResults is the maximum number of results to be returned per call
359const AccountRangeMaxResults = 256
360
361// AccountRange enumerates all accounts in the given block and start point in paging request
362func (api *PublicDebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start []byte, maxResults int, nocode, nostorage, incompletes bool) (state.IteratorDump, error) {
363	var stateDb *state.StateDB
364	var err error
365
366	if number, ok := blockNrOrHash.Number(); ok {
367		if number == rpc.PendingBlockNumber {
368			// If we're dumping the pending state, we need to request
369			// both the pending block as well as the pending state from
370			// the miner and operate on those
371			_, stateDb = api.eth.miner.Pending()
372		} else {
373			var block *types.Block
374			if number == rpc.LatestBlockNumber {
375				block = api.eth.blockchain.CurrentBlock()
376			} else {
377				block = api.eth.blockchain.GetBlockByNumber(uint64(number))
378			}
379			if block == nil {
380				return state.IteratorDump{}, fmt.Errorf("block #%d not found", number)
381			}
382			stateDb, err = api.eth.BlockChain().StateAt(block.Root())
383			if err != nil {
384				return state.IteratorDump{}, err
385			}
386		}
387	} else if hash, ok := blockNrOrHash.Hash(); ok {
388		block := api.eth.blockchain.GetBlockByHash(hash)
389		if block == nil {
390			return state.IteratorDump{}, fmt.Errorf("block %s not found", hash.Hex())
391		}
392		stateDb, err = api.eth.BlockChain().StateAt(block.Root())
393		if err != nil {
394			return state.IteratorDump{}, err
395		}
396	} else {
397		return state.IteratorDump{}, errors.New("either block number or block hash must be specified")
398	}
399
400	opts := &state.DumpConfig{
401		SkipCode:          nocode,
402		SkipStorage:       nostorage,
403		OnlyWithAddresses: !incompletes,
404		Start:             start,
405		Max:               uint64(maxResults),
406	}
407	if maxResults > AccountRangeMaxResults || maxResults <= 0 {
408		opts.Max = AccountRangeMaxResults
409	}
410	return stateDb.IteratorDump(opts), nil
411}
412
413// StorageRangeResult is the result of a debug_storageRangeAt API call.
414type StorageRangeResult struct {
415	Storage storageMap   `json:"storage"`
416	NextKey *common.Hash `json:"nextKey"` // nil if Storage includes the last key in the trie.
417}
418
419type storageMap map[common.Hash]storageEntry
420
421type storageEntry struct {
422	Key   *common.Hash `json:"key"`
423	Value common.Hash  `json:"value"`
424}
425
426// StorageRangeAt returns the storage at the given block height and transaction index.
427func (api *PrivateDebugAPI) StorageRangeAt(blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) {
428	// Retrieve the block
429	block := api.eth.blockchain.GetBlockByHash(blockHash)
430	if block == nil {
431		return StorageRangeResult{}, fmt.Errorf("block %#x not found", blockHash)
432	}
433	_, _, statedb, err := api.eth.stateAtTransaction(block, txIndex, 0)
434	if err != nil {
435		return StorageRangeResult{}, err
436	}
437	st := statedb.StorageTrie(contractAddress)
438	if st == nil {
439		return StorageRangeResult{}, fmt.Errorf("account %x doesn't exist", contractAddress)
440	}
441	return storageRangeAt(st, keyStart, maxResult)
442}
443
444func storageRangeAt(st state.Trie, start []byte, maxResult int) (StorageRangeResult, error) {
445	it := trie.NewIterator(st.NodeIterator(start))
446	result := StorageRangeResult{Storage: storageMap{}}
447	for i := 0; i < maxResult && it.Next(); i++ {
448		_, content, _, err := rlp.Split(it.Value)
449		if err != nil {
450			return StorageRangeResult{}, err
451		}
452		e := storageEntry{Value: common.BytesToHash(content)}
453		if preimage := st.GetKey(it.Key); preimage != nil {
454			preimage := common.BytesToHash(preimage)
455			e.Key = &preimage
456		}
457		result.Storage[common.BytesToHash(it.Key)] = e
458	}
459	// Add the 'next key' so clients can continue downloading.
460	if it.Next() {
461		next := common.BytesToHash(it.Key)
462		result.NextKey = &next
463	}
464	return result, nil
465}
466
467// GetModifiedAccountsByNumber returns all accounts that have changed between the
468// two blocks specified. A change is defined as a difference in nonce, balance,
469// code hash, or storage hash.
470//
471// With one parameter, returns the list of accounts modified in the specified block.
472func (api *PrivateDebugAPI) GetModifiedAccountsByNumber(startNum uint64, endNum *uint64) ([]common.Address, error) {
473	var startBlock, endBlock *types.Block
474
475	startBlock = api.eth.blockchain.GetBlockByNumber(startNum)
476	if startBlock == nil {
477		return nil, fmt.Errorf("start block %x not found", startNum)
478	}
479
480	if endNum == nil {
481		endBlock = startBlock
482		startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash())
483		if startBlock == nil {
484			return nil, fmt.Errorf("block %x has no parent", endBlock.Number())
485		}
486	} else {
487		endBlock = api.eth.blockchain.GetBlockByNumber(*endNum)
488		if endBlock == nil {
489			return nil, fmt.Errorf("end block %d not found", *endNum)
490		}
491	}
492	return api.getModifiedAccounts(startBlock, endBlock)
493}
494
495// GetModifiedAccountsByHash returns all accounts that have changed between the
496// two blocks specified. A change is defined as a difference in nonce, balance,
497// code hash, or storage hash.
498//
499// With one parameter, returns the list of accounts modified in the specified block.
500func (api *PrivateDebugAPI) GetModifiedAccountsByHash(startHash common.Hash, endHash *common.Hash) ([]common.Address, error) {
501	var startBlock, endBlock *types.Block
502	startBlock = api.eth.blockchain.GetBlockByHash(startHash)
503	if startBlock == nil {
504		return nil, fmt.Errorf("start block %x not found", startHash)
505	}
506
507	if endHash == nil {
508		endBlock = startBlock
509		startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash())
510		if startBlock == nil {
511			return nil, fmt.Errorf("block %x has no parent", endBlock.Number())
512		}
513	} else {
514		endBlock = api.eth.blockchain.GetBlockByHash(*endHash)
515		if endBlock == nil {
516			return nil, fmt.Errorf("end block %x not found", *endHash)
517		}
518	}
519	return api.getModifiedAccounts(startBlock, endBlock)
520}
521
522func (api *PrivateDebugAPI) getModifiedAccounts(startBlock, endBlock *types.Block) ([]common.Address, error) {
523	if startBlock.Number().Uint64() >= endBlock.Number().Uint64() {
524		return nil, fmt.Errorf("start block height (%d) must be less than end block height (%d)", startBlock.Number().Uint64(), endBlock.Number().Uint64())
525	}
526	triedb := api.eth.BlockChain().StateCache().TrieDB()
527
528	oldTrie, err := trie.NewSecure(startBlock.Root(), triedb)
529	if err != nil {
530		return nil, err
531	}
532	newTrie, err := trie.NewSecure(endBlock.Root(), triedb)
533	if err != nil {
534		return nil, err
535	}
536	diff, _ := trie.NewDifferenceIterator(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}))
537	iter := trie.NewIterator(diff)
538
539	var dirty []common.Address
540	for iter.Next() {
541		key := newTrie.GetKey(iter.Key)
542		if key == nil {
543			return nil, fmt.Errorf("no preimage found for hash %x", iter.Key)
544		}
545		dirty = append(dirty, common.BytesToAddress(key))
546	}
547	return dirty, nil
548}
549
550// GetAccessibleState returns the first number where the node has accessible
551// state on disk. Note this being the post-state of that block and the pre-state
552// of the next block.
553// The (from, to) parameters are the sequence of blocks to search, which can go
554// either forwards or backwards
555func (api *PrivateDebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64, error) {
556	db := api.eth.ChainDb()
557	var pivot uint64
558	if p := rawdb.ReadLastPivotNumber(db); p != nil {
559		pivot = *p
560		log.Info("Found fast-sync pivot marker", "number", pivot)
561	}
562	var resolveNum = func(num rpc.BlockNumber) (uint64, error) {
563		// We don't have state for pending (-2), so treat it as latest
564		if num.Int64() < 0 {
565			block := api.eth.blockchain.CurrentBlock()
566			if block == nil {
567				return 0, fmt.Errorf("current block missing")
568			}
569			return block.NumberU64(), nil
570		}
571		return uint64(num.Int64()), nil
572	}
573	var (
574		start   uint64
575		end     uint64
576		delta   = int64(1)
577		lastLog time.Time
578		err     error
579	)
580	if start, err = resolveNum(from); err != nil {
581		return 0, err
582	}
583	if end, err = resolveNum(to); err != nil {
584		return 0, err
585	}
586	if start == end {
587		return 0, fmt.Errorf("from and to needs to be different")
588	}
589	if start > end {
590		delta = -1
591	}
592	for i := int64(start); i != int64(end); i += delta {
593		if time.Since(lastLog) > 8*time.Second {
594			log.Info("Finding roots", "from", start, "to", end, "at", i)
595			lastLog = time.Now()
596		}
597		if i < int64(pivot) {
598			continue
599		}
600		h := api.eth.BlockChain().GetHeaderByNumber(uint64(i))
601		if h == nil {
602			return 0, fmt.Errorf("missing header %d", i)
603		}
604		if ok, _ := api.eth.ChainDb().Has(h.Root[:]); ok {
605			return uint64(i), nil
606		}
607	}
608	return 0, fmt.Errorf("No state found")
609}
610