api.go 14.9 KB
Newer Older
1
// Copyright 2015 The go-ethereum Authors
2
// This file is part of the go-ethereum library.
3
//
4 5
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
6 7 8
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
9
// The go-ethereum library is distributed in the hope that it will be useful,
10 11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
// GNU Lesser General Public License for more details.
13
//
14 15
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16 17 18 19

package eth

import (
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 36
	"github.com/ethereum/go-ethereum/core/state"
	"github.com/ethereum/go-ethereum/core/types"
37
	"github.com/ethereum/go-ethereum/internal/ethapi"
38
	"github.com/ethereum/go-ethereum/rlp"
39
	"github.com/ethereum/go-ethereum/rpc"
40
	"github.com/ethereum/go-ethereum/trie"
41 42
)

43
// PublicEthereumAPI provides an API to access Ethereum full node-related
44
// information.
45 46
type PublicEthereumAPI struct {
	e *Ethereum
47 48
}

49
// NewPublicEthereumAPI creates a new Ethereum protocol API for full nodes.
50 51
func NewPublicEthereumAPI(e *Ethereum) *PublicEthereumAPI {
	return &PublicEthereumAPI{e}
52 53 54
}

// Etherbase is the address that mining rewards will be send to
55 56
func (api *PublicEthereumAPI) Etherbase() (common.Address, error) {
	return api.e.Etherbase()
57 58
}

59
// Coinbase is the address that mining rewards will be send to (alias for Etherbase)
60 61
func (api *PublicEthereumAPI) Coinbase() (common.Address, error) {
	return api.Etherbase()
62 63 64
}

// Hashrate returns the POW hashrate
65 66
func (api *PublicEthereumAPI) Hashrate() hexutil.Uint64 {
	return hexutil.Uint64(api.e.Miner().HashRate())
67 68
}

69 70 71
// ChainId is the EIP-155 replay-protection chain id for the current ethereum chain config.
func (api *PublicEthereumAPI) ChainId() hexutil.Uint64 {
	chainID := new(big.Int)
72
	if config := api.e.blockchain.Config(); config.IsEIP155(api.e.blockchain.CurrentBlock().Number()) {
73 74 75 76 77
		chainID = config.ChainID
	}
	return (hexutil.Uint64)(chainID.Uint64())
}

78 79 80
// PublicMinerAPI provides an API to control the miner.
// It offers only methods that operate on data that pose no security risk when it is publicly accessible.
type PublicMinerAPI struct {
81
	e *Ethereum
82 83 84
}

// NewPublicMinerAPI create a new PublicMinerAPI instance.
85
func NewPublicMinerAPI(e *Ethereum) *PublicMinerAPI {
86
	return &PublicMinerAPI{e}
87 88 89
}

// Mining returns an indication if this node is currently mining.
90 91
func (api *PublicMinerAPI) Mining() bool {
	return api.e.IsMining()
92 93
}

94 95 96
// PrivateMinerAPI provides private RPC methods to control the miner.
// These methods can be abused by external users and must be considered insecure for use by untrusted users.
type PrivateMinerAPI struct {
97
	e *Ethereum
98 99 100
}

// NewPrivateMinerAPI create a new RPC service which controls the miner of this node.
101
func NewPrivateMinerAPI(e *Ethereum) *PrivateMinerAPI {
102 103 104
	return &PrivateMinerAPI{e: e}
}

105 106 107 108 109
// Start starts the miner with the given number of threads. If threads is nil,
// the number of workers started is equal to the number of logical CPUs that are
// usable by this process. If mining is already running, this method adjust the
// number of threads allowed to use and updates the minimum price required by the
// transaction pool.
110
func (api *PrivateMinerAPI) Start(threads *int) error {
111
	if threads == nil {
112
		return api.e.StartMining(runtime.NumCPU())
113
	}
114
	return api.e.StartMining(*threads)
115 116
}

117 118 119
// Stop terminates the miner, both at the consensus engine level as well as at
// the block creation level.
func (api *PrivateMinerAPI) Stop() {
120
	api.e.StopMining()
121 122 123
}

// SetExtra sets the extra data string that is included when this miner mines a block.
124 125
func (api *PrivateMinerAPI) SetExtra(extra string) (bool, error) {
	if err := api.e.Miner().SetExtra([]byte(extra)); err != nil {
126 127 128 129 130 131
		return false, err
	}
	return true, nil
}

// SetGasPrice sets the minimum accepted gas price for the miner.
132
func (api *PrivateMinerAPI) SetGasPrice(gasPrice hexutil.Big) bool {
133 134 135 136
	api.e.lock.Lock()
	api.e.gasPrice = (*big.Int)(&gasPrice)
	api.e.lock.Unlock()

137
	api.e.txPool.SetGasPrice((*big.Int)(&gasPrice))
138 139 140 141
	return true
}

// SetEtherbase sets the etherbase of the miner
142 143
func (api *PrivateMinerAPI) SetEtherbase(etherbase common.Address) bool {
	api.e.SetEtherbase(etherbase)
144 145 146
	return true
}

147 148 149 150 151
// SetRecommitInterval updates the interval for miner sealing work recommitting.
func (api *PrivateMinerAPI) SetRecommitInterval(interval int) {
	api.e.Miner().SetRecommitInterval(time.Duration(interval) * time.Millisecond)
}

152
// GetHashrate returns the current hashrate of the miner.
153
func (api *PrivateMinerAPI) GetHashrate() uint64 {
154
	return api.e.miner.HashRate()
155 156
}

157
// PrivateAdminAPI is the collection of Ethereum full node-related APIs
158
// exposed over the private admin endpoint.
159 160
type PrivateAdminAPI struct {
	eth *Ethereum
161 162
}

163 164
// NewPrivateAdminAPI creates a new API definition for the full node private
// admin methods of the Ethereum service.
165 166
func NewPrivateAdminAPI(eth *Ethereum) *PrivateAdminAPI {
	return &PrivateAdminAPI{eth: eth}
167 168 169
}

// ExportChain exports the current blockchain into a local file.
170
func (api *PrivateAdminAPI) ExportChain(file string) (bool, error) {
171 172 173 174 175 176 177
	// Make sure we can create the file to export into
	out, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
	if err != nil {
		return false, err
	}
	defer out.Close()

178 179 180 181 182 183
	var writer io.Writer = out
	if strings.HasSuffix(file, ".gz") {
		writer = gzip.NewWriter(writer)
		defer writer.(*gzip.Writer).Close()
	}

184
	// Export the blockchain
185
	if err := api.eth.BlockChain().Export(writer); err != nil {
186 187 188 189 190
		return false, err
	}
	return true, nil
}

191 192
func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool {
	for _, b := range bs {
193
		if !chain.HasBlock(b.Hash(), b.NumberU64()) {
194 195 196 197 198 199 200
			return false
		}
	}

	return true
}

201
// ImportChain imports a blockchain from a local file.
202
func (api *PrivateAdminAPI) ImportChain(file string) (bool, error) {
203 204 205 206 207 208 209
	// Make sure the can access the file to import
	in, err := os.Open(file)
	if err != nil {
		return false, err
	}
	defer in.Close()

210 211 212 213 214 215 216
	var reader io.Reader = in
	if strings.HasSuffix(file, ".gz") {
		if reader, err = gzip.NewReader(reader); err != nil {
			return false, err
		}
	}

217
	// Run actual the import in pre-configured batches
218
	stream := rlp.NewStream(reader, 0)
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

	blocks, index := make([]*types.Block, 0, 2500), 0
	for batch := 0; ; batch++ {
		// Load a batch of blocks from the input file
		for len(blocks) < cap(blocks) {
			block := new(types.Block)
			if err := stream.Decode(block); err == io.EOF {
				break
			} else if err != nil {
				return false, fmt.Errorf("block %d: failed to parse: %v", index, err)
			}
			blocks = append(blocks, block)
			index++
		}
		if len(blocks) == 0 {
			break
		}
236 237 238 239 240

		if hasAllBlocks(api.eth.BlockChain(), blocks) {
			blocks = blocks[:0]
			continue
		}
241 242 243 244 245 246 247 248 249
		// Import the batch and reset the buffer
		if _, err := api.eth.BlockChain().InsertChain(blocks); err != nil {
			return false, fmt.Errorf("batch %d: failed to insert: %v", batch, err)
		}
		blocks = blocks[:0]
	}
	return true, nil
}

250
// PublicDebugAPI is the collection of Ethereum full node APIs exposed
251
// over the public debugging endpoint.
252 253
type PublicDebugAPI struct {
	eth *Ethereum
254 255
}

256
// NewPublicDebugAPI creates a new API definition for the full node-
257
// related public debug methods of the Ethereum service.
258 259
func NewPublicDebugAPI(eth *Ethereum) *PublicDebugAPI {
	return &PublicDebugAPI{eth: eth}
260 261 262
}

// DumpBlock retrieves the entire state of the database at a given block.
263 264 265 266 267 268 269 270 271 272 273 274 275 276
func (api *PublicDebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) {
	if blockNr == rpc.PendingBlockNumber {
		// If we're dumping the pending state, we need to request
		// both the pending block as well as the pending state from
		// the miner and operate on those
		_, stateDb := api.eth.miner.Pending()
		return stateDb.RawDump(), nil
	}
	var block *types.Block
	if blockNr == rpc.LatestBlockNumber {
		block = api.eth.blockchain.CurrentBlock()
	} else {
		block = api.eth.blockchain.GetBlockByNumber(uint64(blockNr))
	}
277
	if block == nil {
278
		return state.Dump{}, fmt.Errorf("block #%d not found", blockNr)
279
	}
280
	stateDb, err := api.eth.BlockChain().StateAt(block.Root())
281
	if err != nil {
282
		return state.Dump{}, err
283 284 285 286
	}
	return stateDb.RawDump(), nil
}

287
// PrivateDebugAPI is the collection of Ethereum full node APIs exposed over
288
// the private debugging endpoint.
289
type PrivateDebugAPI struct {
290
	eth *Ethereum
291 292
}

293
// NewPrivateDebugAPI creates a new API definition for the full node-related
294
// private debug methods of the Ethereum service.
295 296
func NewPrivateDebugAPI(eth *Ethereum) *PrivateDebugAPI {
	return &PrivateDebugAPI{eth: eth}
297 298
}

299 300
// Preimage is a debug API function that returns the preimage for a sha3 hash, if known.
func (api *PrivateDebugAPI) Preimage(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
301 302 303 304
	if preimage := rawdb.ReadPreimage(api.eth.ChainDb(), hash); preimage != nil {
		return preimage, nil
	}
	return nil, errors.New("unknown preimage")
305
}
306

307 308 309 310 311 312 313
// BadBlockArgs represents the entries in the list returned when bad blocks are queried.
type BadBlockArgs struct {
	Hash  common.Hash            `json:"hash"`
	Block map[string]interface{} `json:"block"`
	RLP   string                 `json:"rlp"`
}

314
// GetBadBlocks returns a list of the last 'bad blocks' that the client has seen on the network
315
// and returns them as a JSON list of block-hashes
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error) {
	blocks := api.eth.BlockChain().BadBlocks()
	results := make([]*BadBlockArgs, len(blocks))

	var err error
	for i, block := range blocks {
		results[i] = &BadBlockArgs{
			Hash: block.Hash(),
		}
		if rlpBytes, err := rlp.EncodeToBytes(block); err != nil {
			results[i].RLP = err.Error() // Hacky, but hey, it works
		} else {
			results[i].RLP = fmt.Sprintf("0x%x", rlpBytes)
		}
		if results[i].Block, err = ethapi.RPCMarshalBlock(block, true, true); err != nil {
			results[i].Block = map[string]interface{}{"error": err.Error()}
		}
	}
	return results, nil
335
}
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351

// StorageRangeResult is the result of a debug_storageRangeAt API call.
type StorageRangeResult struct {
	Storage storageMap   `json:"storage"`
	NextKey *common.Hash `json:"nextKey"` // nil if Storage includes the last key in the trie.
}

type storageMap map[common.Hash]storageEntry

type storageEntry struct {
	Key   *common.Hash `json:"key"`
	Value common.Hash  `json:"value"`
}

// StorageRangeAt returns the storage at the given block height and transaction index.
func (api *PrivateDebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) {
352
	_, _, statedb, err := api.computeTxEnv(blockHash, txIndex, 0)
353 354 355 356 357 358 359
	if err != nil {
		return StorageRangeResult{}, err
	}
	st := statedb.StorageTrie(contractAddress)
	if st == nil {
		return StorageRangeResult{}, fmt.Errorf("account %x doesn't exist", contractAddress)
	}
360
	return storageRangeAt(st, keyStart, maxResult)
361 362
}

363
func storageRangeAt(st state.Trie, start []byte, maxResult int) (StorageRangeResult, error) {
364 365 366
	it := trie.NewIterator(st.NodeIterator(start))
	result := StorageRangeResult{Storage: storageMap{}}
	for i := 0; i < maxResult && it.Next(); i++ {
367 368 369 370 371
		_, content, _, err := rlp.Split(it.Value)
		if err != nil {
			return StorageRangeResult{}, err
		}
		e := storageEntry{Value: common.BytesToHash(content)}
372 373 374 375 376 377 378 379 380 381 382
		if preimage := st.GetKey(it.Key); preimage != nil {
			preimage := common.BytesToHash(preimage)
			e.Key = &preimage
		}
		result.Storage[common.BytesToHash(it.Key)] = e
	}
	// Add the 'next key' so clients can continue downloading.
	if it.Next() {
		next := common.BytesToHash(it.Key)
		result.NextKey = &next
	}
383
	return result, nil
384
}
385

386
// GetModifiedAccountsByNumber returns all accounts that have changed between the
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
// two blocks specified. A change is defined as a difference in nonce, balance,
// code hash, or storage hash.
//
// With one parameter, returns the list of accounts modified in the specified block.
func (api *PrivateDebugAPI) GetModifiedAccountsByNumber(startNum uint64, endNum *uint64) ([]common.Address, error) {
	var startBlock, endBlock *types.Block

	startBlock = api.eth.blockchain.GetBlockByNumber(startNum)
	if startBlock == nil {
		return nil, fmt.Errorf("start block %x not found", startNum)
	}

	if endNum == nil {
		endBlock = startBlock
		startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash())
		if startBlock == nil {
			return nil, fmt.Errorf("block %x has no parent", endBlock.Number())
		}
	} else {
		endBlock = api.eth.blockchain.GetBlockByNumber(*endNum)
		if endBlock == nil {
			return nil, fmt.Errorf("end block %d not found", *endNum)
		}
	}
	return api.getModifiedAccounts(startBlock, endBlock)
}

// GetModifiedAccountsByHash returns all accounts that have changed between the
// two blocks specified. A change is defined as a difference in nonce, balance,
// code hash, or storage hash.
//
// With one parameter, returns the list of accounts modified in the specified block.
func (api *PrivateDebugAPI) GetModifiedAccountsByHash(startHash common.Hash, endHash *common.Hash) ([]common.Address, error) {
	var startBlock, endBlock *types.Block
	startBlock = api.eth.blockchain.GetBlockByHash(startHash)
	if startBlock == nil {
		return nil, fmt.Errorf("start block %x not found", startHash)
	}

	if endHash == nil {
		endBlock = startBlock
		startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash())
		if startBlock == nil {
			return nil, fmt.Errorf("block %x has no parent", endBlock.Number())
		}
	} else {
		endBlock = api.eth.blockchain.GetBlockByHash(*endHash)
		if endBlock == nil {
			return nil, fmt.Errorf("end block %x not found", *endHash)
		}
	}
	return api.getModifiedAccounts(startBlock, endBlock)
}

func (api *PrivateDebugAPI) getModifiedAccounts(startBlock, endBlock *types.Block) ([]common.Address, error) {
	if startBlock.Number().Uint64() >= endBlock.Number().Uint64() {
		return nil, fmt.Errorf("start block height (%d) must be less than end block height (%d)", startBlock.Number().Uint64(), endBlock.Number().Uint64())
	}
445
	triedb := api.eth.BlockChain().StateCache().TrieDB()
446

447
	oldTrie, err := trie.NewSecure(startBlock.Root(), triedb)
448 449 450
	if err != nil {
		return nil, err
	}
451
	newTrie, err := trie.NewSecure(endBlock.Root(), triedb)
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
	if err != nil {
		return nil, err
	}
	diff, _ := trie.NewDifferenceIterator(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}))
	iter := trie.NewIterator(diff)

	var dirty []common.Address
	for iter.Next() {
		key := newTrie.GetKey(iter.Key)
		if key == nil {
			return nil, fmt.Errorf("no preimage found for hash %x", iter.Key)
		}
		dirty = append(dirty, common.BytesToAddress(key))
	}
	return dirty, nil
}