github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/neatptc/api.go (about)

     1  package neatptc
     2  
     3  import (
     4  	"compress/gzip"
     5  	"context"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"math/big"
    10  	"os"
    11  	"strings"
    12  
    13  	"github.com/neatlab/neatio/chain/core"
    14  	"github.com/neatlab/neatio/chain/core/datareduction"
    15  	"github.com/neatlab/neatio/chain/core/rawdb"
    16  	"github.com/neatlab/neatio/chain/core/state"
    17  	"github.com/neatlab/neatio/chain/core/types"
    18  	"github.com/neatlab/neatio/chain/log"
    19  	"github.com/neatlab/neatio/chain/trie"
    20  	"github.com/neatlab/neatio/network/rpc"
    21  	"github.com/neatlab/neatio/params"
    22  	"github.com/neatlab/neatio/utilities/common"
    23  	"github.com/neatlab/neatio/utilities/common/hexutil"
    24  	"github.com/neatlab/neatio/utilities/crypto"
    25  	"github.com/neatlab/neatio/utilities/miner"
    26  	"github.com/neatlab/neatio/utilities/rlp"
    27  )
    28  
    29  type PublicEthereumAPI struct {
    30  	e *NeatIO
    31  }
    32  
    33  func NewPublicEthereumAPI(e *NeatIO) *PublicEthereumAPI {
    34  	return &PublicEthereumAPI{e}
    35  }
    36  
    37  func (api *PublicEthereumAPI) Etherbase() (string, error) {
    38  	eb, err := api.e.Coinbase()
    39  	return eb.String(), err
    40  }
    41  
    42  func (api *PublicEthereumAPI) Coinbase() (string, error) {
    43  	return api.Etherbase()
    44  }
    45  
    46  type PublicMinerAPI struct {
    47  	e     *NeatIO
    48  	agent *miner.RemoteAgent
    49  }
    50  
    51  func NewPublicMinerAPI(e *NeatIO) *PublicMinerAPI {
    52  	agent := miner.NewRemoteAgent(e.BlockChain(), e.Engine())
    53  	if e.Miner() != nil {
    54  		e.Miner().Register(agent)
    55  	}
    56  
    57  	return &PublicMinerAPI{e, agent}
    58  }
    59  
    60  func (api *PublicMinerAPI) Mining() bool {
    61  	if api.e.Miner() != nil {
    62  		return api.e.IsMining()
    63  	}
    64  	return false
    65  }
    66  
    67  func (api *PublicMinerAPI) SubmitWork(nonce types.BlockNonce, solution, digest common.Hash) bool {
    68  	return api.agent.SubmitWork(nonce, digest, solution)
    69  }
    70  
    71  func (api *PublicMinerAPI) GetWork() ([3]string, error) {
    72  	if !api.e.IsMining() {
    73  		if err := api.e.StartMining(false); err != nil {
    74  			return [3]string{}, err
    75  		}
    76  	}
    77  	work, err := api.agent.GetWork()
    78  	if err != nil {
    79  		return work, fmt.Errorf("mining not ready: %v", err)
    80  	}
    81  	return work, nil
    82  }
    83  
    84  func (api *PublicMinerAPI) SubmitHashrate(hashrate hexutil.Uint64, id common.Hash) bool {
    85  	api.agent.SubmitHashrate(id, uint64(hashrate))
    86  	return true
    87  }
    88  
    89  type PrivateMinerAPI struct {
    90  	e *NeatIO
    91  }
    92  
    93  func NewPrivateMinerAPI(e *NeatIO) *PrivateMinerAPI {
    94  	return &PrivateMinerAPI{e: e}
    95  }
    96  
    97  func (api *PrivateMinerAPI) Start(threads *int) error {
    98  
    99  	if threads == nil {
   100  		threads = new(int)
   101  	} else if *threads == 0 {
   102  		*threads = -1
   103  	}
   104  	type threaded interface {
   105  		SetThreads(threads int)
   106  	}
   107  	if th, ok := api.e.engine.(threaded); ok {
   108  		log.Info("Updated mining threads", "threads", *threads)
   109  		th.SetThreads(*threads)
   110  	}
   111  
   112  	if !api.e.IsMining() {
   113  
   114  		api.e.lock.RLock()
   115  		price := api.e.gasPrice
   116  		api.e.lock.RUnlock()
   117  
   118  		api.e.txPool.SetGasPrice(price)
   119  		return api.e.StartMining(true)
   120  	}
   121  	return nil
   122  }
   123  
   124  func (api *PrivateMinerAPI) Stop() bool {
   125  	type threaded interface {
   126  		SetThreads(threads int)
   127  	}
   128  	if th, ok := api.e.engine.(threaded); ok {
   129  		th.SetThreads(-1)
   130  	}
   131  	api.e.StopMining()
   132  	return true
   133  }
   134  
   135  func (api *PrivateMinerAPI) SetExtra(extra string) (bool, error) {
   136  	if err := api.e.Miner().SetExtra([]byte(extra)); err != nil {
   137  		return false, err
   138  	}
   139  	return true, nil
   140  }
   141  
   142  func (api *PrivateMinerAPI) SetGasPrice(gasPrice hexutil.Big) bool {
   143  	api.e.lock.Lock()
   144  	api.e.gasPrice = (*big.Int)(&gasPrice)
   145  	api.e.lock.Unlock()
   146  
   147  	api.e.txPool.SetGasPrice((*big.Int)(&gasPrice))
   148  	return true
   149  }
   150  
   151  func (api *PrivateMinerAPI) SetCoinbase(coinbase common.Address) bool {
   152  	api.e.SetCoinbase(coinbase)
   153  	return true
   154  }
   155  
   156  type PrivateAdminAPI struct {
   157  	eth *NeatIO
   158  }
   159  
   160  func NewPrivateAdminAPI(eth *NeatIO) *PrivateAdminAPI {
   161  	return &PrivateAdminAPI{eth: eth}
   162  }
   163  
   164  func (api *PrivateAdminAPI) ExportChain(file string) (bool, error) {
   165  
   166  	out, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
   167  	if err != nil {
   168  		return false, err
   169  	}
   170  	defer out.Close()
   171  
   172  	var writer io.Writer = out
   173  	if strings.HasSuffix(file, ".gz") {
   174  		writer = gzip.NewWriter(writer)
   175  		defer writer.(*gzip.Writer).Close()
   176  	}
   177  
   178  	if err := api.eth.BlockChain().Export(writer); err != nil {
   179  		return false, err
   180  	}
   181  	return true, nil
   182  }
   183  
   184  func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool {
   185  	for _, b := range bs {
   186  		if !chain.HasBlock(b.Hash(), b.NumberU64()) {
   187  			return false
   188  		}
   189  	}
   190  
   191  	return true
   192  }
   193  
   194  func (api *PrivateAdminAPI) ImportChain(file string) (bool, error) {
   195  
   196  	in, err := os.Open(file)
   197  	if err != nil {
   198  		return false, err
   199  	}
   200  	defer in.Close()
   201  
   202  	var reader io.Reader = in
   203  	if strings.HasSuffix(file, ".gz") {
   204  		if reader, err = gzip.NewReader(reader); err != nil {
   205  			return false, err
   206  		}
   207  	}
   208  
   209  	stream := rlp.NewStream(reader, 0)
   210  
   211  	blocks, index := make([]*types.Block, 0, 2500), 0
   212  	for batch := 0; ; batch++ {
   213  
   214  		for len(blocks) < cap(blocks) {
   215  			block := new(types.Block)
   216  			if err := stream.Decode(block); err == io.EOF {
   217  				break
   218  			} else if err != nil {
   219  				return false, fmt.Errorf("block %d: failed to parse: %v", index, err)
   220  			}
   221  			blocks = append(blocks, block)
   222  			index++
   223  		}
   224  		if len(blocks) == 0 {
   225  			break
   226  		}
   227  
   228  		if hasAllBlocks(api.eth.BlockChain(), blocks) {
   229  			blocks = blocks[:0]
   230  			continue
   231  		}
   232  
   233  		if _, err := api.eth.BlockChain().InsertChain(blocks); err != nil {
   234  			return false, fmt.Errorf("batch %d: failed to insert: %v", batch, err)
   235  		}
   236  		blocks = blocks[:0]
   237  	}
   238  	return true, nil
   239  }
   240  
   241  func (api *PrivateAdminAPI) PruneStateData(height *hexutil.Uint64) (bool, error) {
   242  	var blockNumber uint64
   243  	if height != nil && *height > 0 {
   244  		blockNumber = uint64(*height)
   245  	}
   246  
   247  	go api.eth.StartScanAndPrune(blockNumber)
   248  	return true, nil
   249  }
   250  
   251  func (api *PrivateAdminAPI) LatestPruneState() (*datareduction.PruneStatus, error) {
   252  	status := datareduction.GetLatestStatus(api.eth.pruneDb)
   253  	status.LatestBlockNumber = api.eth.blockchain.CurrentHeader().Number.Uint64()
   254  	return status, nil
   255  }
   256  
   257  type PublicDebugAPI struct {
   258  	eth *NeatIO
   259  }
   260  
   261  func NewPublicDebugAPI(eth *NeatIO) *PublicDebugAPI {
   262  	return &PublicDebugAPI{eth: eth}
   263  }
   264  
   265  func (api *PublicDebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) {
   266  	if blockNr == rpc.PendingBlockNumber {
   267  
   268  		_, stateDb := api.eth.miner.Pending()
   269  		return stateDb.RawDump(), nil
   270  	}
   271  	var block *types.Block
   272  	if blockNr == rpc.LatestBlockNumber {
   273  		block = api.eth.blockchain.CurrentBlock()
   274  	} else {
   275  		block = api.eth.blockchain.GetBlockByNumber(uint64(blockNr))
   276  	}
   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  	return stateDb.RawDump(), nil
   285  }
   286  
   287  type PrivateDebugAPI struct {
   288  	config *params.ChainConfig
   289  	eth    *NeatIO
   290  }
   291  
   292  func NewPrivateDebugAPI(config *params.ChainConfig, eth *NeatIO) *PrivateDebugAPI {
   293  	return &PrivateDebugAPI{config: config, eth: eth}
   294  }
   295  
   296  func (api *PrivateDebugAPI) Preimage(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
   297  	if preimage := rawdb.ReadPreimage(api.eth.ChainDb(), hash); preimage != nil {
   298  		return preimage, nil
   299  	}
   300  	return nil, errors.New("unknown preimage")
   301  }
   302  
   303  func (api *PrivateDebugAPI) RemotePreimage(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
   304  	peer := api.eth.protocolManager.peers.BestPeer()
   305  
   306  	hashes := make([]common.Hash, 0)
   307  	return nil, peer.RequestPreimages(append(hashes, hash))
   308  }
   309  
   310  func (api *PrivateDebugAPI) RemovePreimage(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
   311  	rawdb.DeletePreimage(api.eth.ChainDb(), hash)
   312  	return nil, nil
   313  }
   314  
   315  func (api *PrivateDebugAPI) BrokenPreimage(ctx context.Context, hash common.Hash, preimage hexutil.Bytes) (hexutil.Bytes, error) {
   316  
   317  	rawdb.WritePreimages(api.eth.ChainDb(), map[common.Hash][]byte{hash: preimage})
   318  
   319  	if read_preimage := rawdb.ReadPreimage(api.eth.ChainDb(), hash); read_preimage != nil {
   320  		return read_preimage, nil
   321  	}
   322  	return nil, errors.New("broken preimage failed")
   323  }
   324  
   325  func (api *PrivateDebugAPI) FindBadPreimage(ctx context.Context) (interface{}, error) {
   326  
   327  	images := make(map[common.Hash]string)
   328  
   329  	db := api.eth.ChainDb()
   330  	it := db.NewIteratorWithPrefix([]byte("secure-key-"))
   331  	for it.Next() {
   332  		keyHash := common.BytesToHash(it.Key())
   333  		valueHash := crypto.Keccak256Hash(it.Value())
   334  		if keyHash != valueHash {
   335  
   336  			images[keyHash] = common.Bytes2Hex(it.Value())
   337  		}
   338  	}
   339  	it.Release()
   340  
   341  	return images, nil
   342  }
   343  
   344  func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]core.BadBlockArgs, error) {
   345  	return api.eth.BlockChain().BadBlocks()
   346  }
   347  
   348  type StorageRangeResult struct {
   349  	Storage storageMap   `json:"storage"`
   350  	NextKey *common.Hash `json:"nextKey"`
   351  }
   352  
   353  type storageMap map[common.Hash]storageEntry
   354  
   355  type storageEntry struct {
   356  	Key   *common.Hash `json:"key"`
   357  	Value common.Hash  `json:"value"`
   358  }
   359  
   360  func (api *PrivateDebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) {
   361  	_, _, statedb, err := api.computeTxEnv(blockHash, txIndex, 0)
   362  	if err != nil {
   363  		return StorageRangeResult{}, err
   364  	}
   365  	st := statedb.StorageTrie(contractAddress)
   366  	if st == nil {
   367  		return StorageRangeResult{}, fmt.Errorf("account %x doesn't exist", contractAddress)
   368  	}
   369  	return storageRangeAt(st, keyStart, maxResult)
   370  }
   371  
   372  func storageRangeAt(st state.Trie, start []byte, maxResult int) (StorageRangeResult, error) {
   373  	it := trie.NewIterator(st.NodeIterator(start))
   374  	result := StorageRangeResult{Storage: storageMap{}}
   375  	for i := 0; i < maxResult && it.Next(); i++ {
   376  		_, content, _, err := rlp.Split(it.Value)
   377  		if err != nil {
   378  			return StorageRangeResult{}, err
   379  		}
   380  		e := storageEntry{Value: common.BytesToHash(content)}
   381  		if preimage := st.GetKey(it.Key); preimage != nil {
   382  			preimage := common.BytesToHash(preimage)
   383  			e.Key = &preimage
   384  		}
   385  		result.Storage[common.BytesToHash(it.Key)] = e
   386  	}
   387  
   388  	if it.Next() {
   389  		next := common.BytesToHash(it.Key)
   390  		result.NextKey = &next
   391  	}
   392  	return result, nil
   393  }
   394  
   395  func (api *PrivateDebugAPI) GetModifiedAccountsByNumber(startNum uint64, endNum *uint64) ([]common.Address, error) {
   396  	var startBlock, endBlock *types.Block
   397  
   398  	startBlock = api.eth.blockchain.GetBlockByNumber(startNum)
   399  	if startBlock == nil {
   400  		return nil, fmt.Errorf("start block %x not found", startNum)
   401  	}
   402  
   403  	if endNum == nil {
   404  		endBlock = startBlock
   405  		startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash())
   406  		if startBlock == nil {
   407  			return nil, fmt.Errorf("block %x has no parent", endBlock.Number())
   408  		}
   409  	} else {
   410  		endBlock = api.eth.blockchain.GetBlockByNumber(*endNum)
   411  		if endBlock == nil {
   412  			return nil, fmt.Errorf("end block %d not found", *endNum)
   413  		}
   414  	}
   415  	return api.getModifiedAccounts(startBlock, endBlock)
   416  }
   417  
   418  func (api *PrivateDebugAPI) GetModifiedAccountsByHash(startHash common.Hash, endHash *common.Hash) ([]common.Address, error) {
   419  	var startBlock, endBlock *types.Block
   420  	startBlock = api.eth.blockchain.GetBlockByHash(startHash)
   421  	if startBlock == nil {
   422  		return nil, fmt.Errorf("start block %x not found", startHash)
   423  	}
   424  
   425  	if endHash == nil {
   426  		endBlock = startBlock
   427  		startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash())
   428  		if startBlock == nil {
   429  			return nil, fmt.Errorf("block %x has no parent", endBlock.Number())
   430  		}
   431  	} else {
   432  		endBlock = api.eth.blockchain.GetBlockByHash(*endHash)
   433  		if endBlock == nil {
   434  			return nil, fmt.Errorf("end block %x not found", *endHash)
   435  		}
   436  	}
   437  	return api.getModifiedAccounts(startBlock, endBlock)
   438  }
   439  
   440  func (api *PrivateDebugAPI) getModifiedAccounts(startBlock, endBlock *types.Block) ([]common.Address, error) {
   441  	if startBlock.Number().Uint64() >= endBlock.Number().Uint64() {
   442  		return nil, fmt.Errorf("start block height (%d) must be less than end block height (%d)", startBlock.Number().Uint64(), endBlock.Number().Uint64())
   443  	}
   444  	triedb := api.eth.BlockChain().StateCache().TrieDB()
   445  
   446  	oldTrie, err := trie.NewSecure(startBlock.Root(), triedb)
   447  	if err != nil {
   448  		return nil, err
   449  	}
   450  	newTrie, err := trie.NewSecure(endBlock.Root(), triedb)
   451  	if err != nil {
   452  		return nil, err
   453  	}
   454  
   455  	diff, _ := trie.NewDifferenceIterator(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}))
   456  	iter := trie.NewIterator(diff)
   457  
   458  	var dirty []common.Address
   459  	for iter.Next() {
   460  		key := newTrie.GetKey(iter.Key)
   461  		if key == nil {
   462  			return nil, fmt.Errorf("no preimage found for hash %x", iter.Key)
   463  		}
   464  		dirty = append(dirty, common.BytesToAddress(key))
   465  	}
   466  	return dirty, nil
   467  }
   468  
   469  func (api *PrivateDebugAPI) ReadRawDBNode(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
   470  	if exist, _ := api.eth.ChainDb().Has(hash.Bytes()); exist {
   471  		return api.eth.ChainDb().Get(hash.Bytes())
   472  	}
   473  	return nil, errors.New("key not exist")
   474  }
   475  
   476  func (api *PrivateDebugAPI) BroadcastRawDBNode(ctx context.Context, hash common.Hash) (map[string]error, error) {
   477  	result := make(map[string]error)
   478  	if exist, _ := api.eth.ChainDb().Has(hash.Bytes()); exist {
   479  		data, _ := api.eth.chainDb.Get(hash.Bytes())
   480  
   481  		for _, peer := range api.eth.protocolManager.peers.Peers() {
   482  			result[peer.id] = peer.SendTrieNodeData([][]byte{data})
   483  		}
   484  	}
   485  	return result, nil
   486  }
   487  
   488  type resultNode struct {
   489  	Key common.Hash   `json:"hash"`
   490  	Val hexutil.Bytes `json:"value"`
   491  }
   492  
   493  func (api *PrivateDebugAPI) PrintTrieNode(ctx context.Context, root common.Hash) ([]resultNode, error) {
   494  	result := make([]resultNode, 0)
   495  	t, _ := trie.NewSecure(root, trie.NewDatabase(api.eth.chainDb))
   496  	it := t.NodeIterator(nil)
   497  	for it.Next(true) {
   498  		if !it.Leaf() {
   499  			h := it.Hash()
   500  			v, _ := api.eth.chainDb.Get(h.Bytes())
   501  			result = append(result, resultNode{h, v})
   502  		}
   503  	}
   504  	return result, it.Error()
   505  }