github.com/aquanetwork/aquachain@v1.7.8/aqua/api.go (about)

     1  // Copyright 2015 The aquachain Authors
     2  // This file is part of the aquachain library.
     3  //
     4  // The aquachain 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 aquachain 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 aquachain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package aqua
    18  
    19  import (
    20  	"compress/gzip"
    21  	"context"
    22  	"fmt"
    23  	"io"
    24  	"math/big"
    25  	"os"
    26  	"sort"
    27  	"strings"
    28  
    29  	"gitlab.com/aquachain/aquachain/common"
    30  	"gitlab.com/aquachain/aquachain/common/hexutil"
    31  	"gitlab.com/aquachain/aquachain/common/log"
    32  	"gitlab.com/aquachain/aquachain/core"
    33  	"gitlab.com/aquachain/aquachain/core/state"
    34  	"gitlab.com/aquachain/aquachain/core/types"
    35  	"gitlab.com/aquachain/aquachain/opt/miner"
    36  	"gitlab.com/aquachain/aquachain/params"
    37  	"gitlab.com/aquachain/aquachain/rlp"
    38  	"gitlab.com/aquachain/aquachain/rpc"
    39  )
    40  
    41  // PublicTestingAPI provides an API to access new features
    42  type PublicTestingAPI struct {
    43  	cfg   *params.ChainConfig
    44  	agent *miner.RemoteAgent
    45  	e     *AquaChain
    46  }
    47  
    48  // NewPublicAquaChainAPI creates a new AquaChain protocol API for full nodes.
    49  func NewPublicTestingAPI(cfg *params.ChainConfig, e *AquaChain) *PublicTestingAPI {
    50  	agent := miner.NewRemoteAgent(e.BlockChain(), e.Engine())
    51  	e.Miner().Register(agent)
    52  	return &PublicTestingAPI{cfg, agent, e}
    53  }
    54  
    55  // PublicAquaChainAPI provides an API to access AquaChain full node-related
    56  // information.
    57  type PublicAquaChainAPI struct {
    58  	e *AquaChain
    59  }
    60  
    61  // NewPublicAquaChainAPI creates a new AquaChain protocol API for full nodes.
    62  func NewPublicAquaChainAPI(e *AquaChain) *PublicAquaChainAPI {
    63  	return &PublicAquaChainAPI{e}
    64  }
    65  
    66  // Aquabase is the address that mining rewards will be send to
    67  func (api *PublicAquaChainAPI) Aquabase() (common.Address, error) {
    68  	return api.e.Aquabase()
    69  }
    70  
    71  // Coinbase is the address that mining rewards will be send to (alias for Aquabase)
    72  func (api *PublicAquaChainAPI) Coinbase() (common.Address, error) {
    73  	return api.Aquabase()
    74  }
    75  
    76  // Hashrate returns the POW hashrate
    77  func (api *PublicAquaChainAPI) Hashrate() hexutil.Uint64 {
    78  	return hexutil.Uint64(api.e.Miner().HashRate())
    79  }
    80  
    81  // PublicMinerAPI provides an API to control the miner.
    82  // It offers only methods that operate on data that pose no security risk when it is publicly accessible.
    83  type PublicMinerAPI struct {
    84  	e     *AquaChain
    85  	agent *miner.RemoteAgent
    86  }
    87  
    88  // NewPublicMinerAPI create a new PublicMinerAPI instance.
    89  func NewPublicMinerAPI(e *AquaChain) *PublicMinerAPI {
    90  	agent := miner.NewRemoteAgent(e.BlockChain(), e.Engine())
    91  	e.Miner().Register(agent)
    92  
    93  	return &PublicMinerAPI{e, agent}
    94  }
    95  
    96  // Mining returns an indication if this node is currently mining.
    97  func (api *PublicMinerAPI) Mining() bool {
    98  	return api.e.IsMining()
    99  }
   100  
   101  // SubmitWork can be used by external miner to submit their POW solution. It returns an indication if the work was
   102  // accepted. Note, this is not an indication if the provided work was valid!
   103  func (api *PublicMinerAPI) SubmitWork(nonce types.BlockNonce, solution, digest common.Hash) bool {
   104  	return api.agent.SubmitWork(nonce, digest, solution)
   105  }
   106  
   107  // SubmitBlock can be used by external miner to submit their POW solution. It returns an indication if the work was
   108  // accepted. Note, this is not an indication if the provided work was valid!
   109  func (api *PublicTestingAPI) SubmitBlock(encodedBlock []byte) bool {
   110  	var block types.Block
   111  	if encodedBlock == nil {
   112  		log.Warn("submitblock rlp got nil")
   113  		return false
   114  	}
   115  	if err := rlp.DecodeBytes(encodedBlock, &block); err != nil {
   116  		log.Warn("submitblock rlp decode error", "err", err)
   117  		return false
   118  	}
   119  	if block.Nonce() == 0 {
   120  		log.Warn("submitblock got 0 nonce")
   121  		return false
   122  	}
   123  	block.SetVersion(api.e.chainConfig.GetBlockVersion(block.Number()))
   124  	log.Debug("RPC client submitted block:", "block", block.Header())
   125  	return api.agent.SubmitBlock(&block)
   126  }
   127  
   128  func (api *PublicTestingAPI) GetBlockTemplate(addr common.Address) ([]byte, error) {
   129  	log.Debug("Got block template request:", "coinbase", addr)
   130  	if !api.e.IsMining() {
   131  		if err := api.e.StartMining(false); err != nil {
   132  			return nil, err
   133  		}
   134  	}
   135  	return api.agent.GetBlockTemplate(addr)
   136  }
   137  
   138  // GetWork returns a work package for external miner. The work package consists of 3 strings
   139  // result[0], 32 bytes hex encoded current block header pow-hash
   140  // result[1], 32 bytes hex encoded auxiliary chunk (pre hf5: dag seed, hf5: zeros, hf8: header version)
   141  // result[2], 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty
   142  func (api *PublicMinerAPI) GetWork() ([3]string, error) {
   143  	if !api.e.IsMining() {
   144  		if err := api.e.StartMining(false); err != nil {
   145  			return [3]string{}, err
   146  		}
   147  	}
   148  	work, err := api.agent.GetWork()
   149  	if err != nil {
   150  		return work, fmt.Errorf("mining not ready: %v", err)
   151  	}
   152  	return work, nil
   153  }
   154  
   155  // SubmitHashrate can be used for remote miners to submit their hash rate. This enables the node to report the combined
   156  // hash rate of all miners which submit work through this node. It accepts the miner hash rate and an identifier which
   157  // must be unique between nodes.
   158  func (api *PublicMinerAPI) SubmitHashrate(hashrate hexutil.Uint64, id common.Hash) bool {
   159  	// api.agent.SubmitHashrate(id, uint64(hashrate))
   160  	return true
   161  }
   162  
   163  // PrivateMinerAPI provides private RPC methods to control the miner.
   164  // These methods can be abused by external users and must be considered insecure for use by untrusted users.
   165  type PrivateMinerAPI struct {
   166  	e *AquaChain
   167  }
   168  
   169  // NewPrivateMinerAPI create a new RPC service which controls the miner of this node.
   170  func NewPrivateMinerAPI(e *AquaChain) *PrivateMinerAPI {
   171  	return &PrivateMinerAPI{e: e}
   172  }
   173  
   174  // Start the miner with the given number of threads. If threads is nil the number
   175  // of workers started is equal to the number of logical CPUs that are usable by
   176  // this process. If mining is already running, this method adjust the number of
   177  // threads allowed to use.
   178  func (api *PrivateMinerAPI) Start(threads *int) error {
   179  	// Set the number of threads if the seal engine supports it
   180  	if threads == nil {
   181  		threads = new(int)
   182  	} else if *threads == 0 {
   183  		*threads = -1 // Disable the miner from within
   184  	}
   185  	type threaded interface {
   186  		SetThreads(threads int)
   187  	}
   188  	if th, ok := api.e.engine.(threaded); ok {
   189  		log.Info("Updated mining threads", "threads", *threads)
   190  		th.SetThreads(*threads)
   191  	}
   192  	// Start the miner and return
   193  	if !api.e.IsMining() {
   194  		// Propagate the initial price point to the transaction pool
   195  		api.e.lock.RLock()
   196  		price := api.e.gasPrice
   197  		api.e.lock.RUnlock()
   198  
   199  		api.e.txPool.SetGasPrice(price)
   200  		return api.e.StartMining(true)
   201  	}
   202  	return nil
   203  }
   204  
   205  // Stop the miner
   206  func (api *PrivateMinerAPI) Stop() bool {
   207  	type threaded interface {
   208  		SetThreads(threads int)
   209  	}
   210  	if th, ok := api.e.engine.(threaded); ok {
   211  		th.SetThreads(-1)
   212  	}
   213  	api.e.StopMining()
   214  	return true
   215  }
   216  
   217  // SetExtra sets the extra data string that is included when this miner mines a block.
   218  func (api *PrivateMinerAPI) SetExtra(extra string) (bool, error) {
   219  	if err := api.e.Miner().SetExtra([]byte(extra)); err != nil {
   220  		return false, err
   221  	}
   222  	return true, nil
   223  }
   224  
   225  // SetGasPrice sets the minimum accepted gas price for the miner.
   226  func (api *PrivateMinerAPI) SetGasPrice(gasPrice hexutil.Big) bool {
   227  	api.e.lock.Lock()
   228  	api.e.gasPrice = (*big.Int)(&gasPrice)
   229  	api.e.lock.Unlock()
   230  
   231  	api.e.txPool.SetGasPrice((*big.Int)(&gasPrice))
   232  	return true
   233  }
   234  
   235  // SetAquabase sets the aquabase of the miner
   236  func (api *PrivateMinerAPI) SetAquabase(aquabase common.Address) bool {
   237  	api.e.SetAquabase(aquabase)
   238  	return true
   239  }
   240  
   241  // GetHashrate returns the current hashrate of the miner.
   242  func (api *PrivateMinerAPI) GetHashrate() uint64 {
   243  	return uint64(api.e.miner.HashRate())
   244  }
   245  
   246  // PrivateAdminAPI is the collection of AquaChain full node-related APIs
   247  // exposed over the private admin endpoint.
   248  type PrivateAdminAPI struct {
   249  	aqua *AquaChain
   250  }
   251  
   252  // NewPrivateAdminAPI creates a new API definition for the full node private
   253  // admin methods of the AquaChain service.
   254  func NewPrivateAdminAPI(aqua *AquaChain) *PrivateAdminAPI {
   255  	return &PrivateAdminAPI{aqua: aqua}
   256  }
   257  
   258  // ExportState exports the current state database into a simplified json file.
   259  func (api *PrivateAdminAPI) ExportState(file string) (bool, error) {
   260  	// Make sure we can create the file to export into
   261  	out, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
   262  	if err != nil {
   263  		return false, err
   264  	}
   265  	defer out.Close()
   266  	statedb, err := api.aqua.BlockChain().State()
   267  	if err != nil {
   268  		return false, err
   269  	}
   270  	var writer io.Writer = out
   271  	if strings.HasSuffix(file, ".gz") {
   272  		writer = gzip.NewWriter(writer)
   273  		defer writer.(*gzip.Writer).Close()
   274  	}
   275  	// Export the state
   276  	if err := statedb.TakeSnapshot(writer); err != nil {
   277  		return false, err
   278  	}
   279  	return true, nil
   280  }
   281  
   282  // GetDistribution returns a map of address->balance
   283  func (api *PrivateAdminAPI) GetDistribution() (map[string]state.DumpAccount, error) {
   284  	statedb, err := api.aqua.BlockChain().State()
   285  	if err != nil {
   286  		return nil, err
   287  	}
   288  	// Export the state
   289  	dump := statedb.RawDump()
   290  	return dump.Accounts, nil
   291  }
   292  
   293  var BigAqua = new(big.Float).SetFloat64(params.Aqua)
   294  
   295  func (api *PrivateAdminAPI) GetRichlist(n int) ([]string, error) {
   296  	if n == 0 {
   297  		n = 100
   298  	}
   299  	dist, err := api.GetDistribution()
   300  	if err != nil {
   301  		return nil, err
   302  	}
   303  	type distribResult struct {
   304  		a  string
   305  		ss state.DumpAccount
   306  	}
   307  	var results = []distribResult{}
   308  	for addr, bal := range dist {
   309  		results = append(results, distribResult{addr, bal})
   310  	}
   311  	sort.Slice(results, func(i, j int) bool {
   312  		ii, _ := new(big.Int).SetString(results[i].ss.Balance, 10)
   313  		jj, _ := new(big.Int).SetString(results[j].ss.Balance, 10)
   314  		return ii.Cmp(jj) > 0
   315  	})
   316  	var balances []string
   317  	for i, v := range results {
   318  		if v.ss.Balance != "0" {
   319  			f, _ := new(big.Float).SetString(v.ss.Balance)
   320  			f = f.Quo(f, BigAqua)
   321  			balances = append(balances, fmt.Sprintf("%s: %2.8f", v.a, f))
   322  			if i >= n-1 {
   323  				break
   324  			}
   325  		}
   326  	}
   327  	return balances, nil
   328  }
   329  
   330  // Supply returns a map of address->balance
   331  func (api *PrivateAdminAPI) Supply() (*big.Int, error) {
   332  	dump, err := api.GetDistribution()
   333  	if err != nil {
   334  		return nil, err
   335  	}
   336  	total := new(big.Int)
   337  
   338  	if len(dump) > 100000 {
   339  		return nil, fmt.Errorf("number of accounts over 100000, bailing")
   340  	}
   341  
   342  	bal := make([]string, len(dump))
   343  	n := 0
   344  	for i := range dump {
   345  		bal[n] = dump[i].Balance
   346  		n++
   347  	}
   348  
   349  	for i := range bal {
   350  		if bal[i] == "" || bal[i] == "0" {
   351  			continue
   352  		}
   353  		balance, _ := new(big.Int).SetString(bal[i], 10)
   354  		total.Add(total, balance)
   355  	}
   356  	return total, nil
   357  }
   358  
   359  // ExportRealloc exports the current state database into a ready to import json file
   360  func (api *PrivateAdminAPI) ExportRealloc(file string) (bool, error) {
   361  	// Make sure we can create the file to export into
   362  	out, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
   363  	if err != nil {
   364  		return false, err
   365  	}
   366  	defer out.Close()
   367  	statedb, err := api.aqua.BlockChain().State()
   368  	if err != nil {
   369  		return false, err
   370  	}
   371  	var writer io.Writer = out
   372  	if strings.HasSuffix(file, ".gz") {
   373  		writer = gzip.NewWriter(writer)
   374  		defer writer.(*gzip.Writer).Close()
   375  	}
   376  	writer.Write([]byte(`` +
   377  		`{
   378  "config":{
   379    "chainId":61717561,
   380    "homesteadBlock":0,
   381    "eip150Block":0,
   382    "eip150Hash":"0x0000000000000000000000000000000000000000000000000000000000000000"
   383  },
   384    "nonce":"0x2a",
   385    "timestamp":"0x0",
   386    "extraData":"0x",
   387    "gasLimit":"0x401640",
   388    "difficulty":"0x5f5e0ff",
   389    "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
   390    "coinbase":"0x0000000000000000000000000000000000000000",
   391         "alloc":
   392  `))
   393  	// Export the state
   394  	if err := statedb.TakeSnapshot(writer); err != nil {
   395  		return false, err
   396  	}
   397  	writer.Write([]byte("}"))
   398  	return true, nil
   399  }
   400  
   401  // ExportChain exports the current blockchain into a local file.
   402  func (api *PrivateAdminAPI) ExportChain(file string) (bool, error) {
   403  	// Make sure we can create the file to export into
   404  	out, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
   405  	if err != nil {
   406  		return false, err
   407  	}
   408  	defer out.Close()
   409  
   410  	var writer io.Writer = out
   411  	if strings.HasSuffix(file, ".gz") {
   412  		writer = gzip.NewWriter(writer)
   413  		defer writer.(*gzip.Writer).Close()
   414  	}
   415  
   416  	// Export the blockchain
   417  	if err := api.aqua.BlockChain().Export(writer); err != nil {
   418  		return false, err
   419  	}
   420  	return true, nil
   421  }
   422  
   423  func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool {
   424  	for _, b := range bs {
   425  		if !chain.HasBlock(b.Hash(), b.NumberU64()) {
   426  			return false
   427  		}
   428  	}
   429  
   430  	return true
   431  }
   432  
   433  // ImportChain imports a blockchain from a local file.
   434  func (api *PrivateAdminAPI) ImportChain(file string) (bool, error) {
   435  	// Make sure the can access the file to import
   436  	in, err := os.Open(file)
   437  	if err != nil {
   438  		return false, err
   439  	}
   440  	defer in.Close()
   441  
   442  	var reader io.Reader = in
   443  	if strings.HasSuffix(file, ".gz") {
   444  		if reader, err = gzip.NewReader(reader); err != nil {
   445  			return false, err
   446  		}
   447  	}
   448  
   449  	// Run actual the import in pre-configured batches
   450  	stream := rlp.NewStream(reader, 0)
   451  
   452  	blocks, index := make([]*types.Block, 0, 2500), 0
   453  	for batch := 0; ; batch++ {
   454  		// Load a batch of blocks from the input file
   455  		for len(blocks) < cap(blocks) {
   456  			block := new(types.Block)
   457  			if err := stream.Decode(block); err == io.EOF {
   458  				break
   459  			} else if err != nil {
   460  				return false, fmt.Errorf("block %d: failed to parse: %v", index, err)
   461  			}
   462  			blocks = append(blocks, block)
   463  			index++
   464  		}
   465  		if len(blocks) == 0 {
   466  			break
   467  		}
   468  
   469  		if hasAllBlocks(api.aqua.BlockChain(), blocks) {
   470  			blocks = blocks[:0]
   471  			continue
   472  		}
   473  		// Import the batch and reset the buffer
   474  		if _, err := api.aqua.BlockChain().InsertChain(blocks); err != nil {
   475  			return false, fmt.Errorf("batch %d: failed to insert: %v", batch, err)
   476  		}
   477  		blocks = blocks[:0]
   478  	}
   479  	return true, nil
   480  }
   481  
   482  // PublicDebugAPI is the collection of AquaChain full node APIs exposed
   483  // over the public debugging endpoint.
   484  type PublicDebugAPI struct {
   485  	aqua *AquaChain
   486  }
   487  
   488  // NewPublicDebugAPI creates a new API definition for the full node-
   489  // related public debug methods of the AquaChain service.
   490  func NewPublicDebugAPI(aqua *AquaChain) *PublicDebugAPI {
   491  	return &PublicDebugAPI{aqua: aqua}
   492  }
   493  
   494  // DumpBlock retrieves the entire state of the database at a given block.
   495  func (api *PublicDebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) {
   496  	if blockNr == rpc.PendingBlockNumber {
   497  		// If we're dumping the pending state, we need to request
   498  		// both the pending block as well as the pending state from
   499  		// the miner and operate on those
   500  		_, stateDb := api.aqua.miner.Pending()
   501  		return stateDb.RawDump(), nil
   502  	}
   503  	var block *types.Block
   504  	if blockNr == rpc.LatestBlockNumber {
   505  		block = api.aqua.blockchain.CurrentBlock()
   506  	} else {
   507  		block = api.aqua.blockchain.GetBlockByNumber(uint64(blockNr))
   508  	}
   509  	if block == nil {
   510  		return state.Dump{}, fmt.Errorf("block #%d not found", blockNr)
   511  	}
   512  	stateDb, err := api.aqua.BlockChain().StateAt(block.Root())
   513  	if err != nil {
   514  		return state.Dump{}, err
   515  	}
   516  	return stateDb.RawDump(), nil
   517  }
   518  
   519  // PrivateDebugAPI is the collection of AquaChain full node APIs exposed over
   520  // the private debugging endpoint.
   521  type PrivateDebugAPI struct {
   522  	config *params.ChainConfig
   523  	aqua   *AquaChain
   524  }
   525  
   526  // NewPrivateDebugAPI creates a new API definition for the full node-related
   527  // private debug methods of the AquaChain service.
   528  func NewPrivateDebugAPI(config *params.ChainConfig, aqua *AquaChain) *PrivateDebugAPI {
   529  	return &PrivateDebugAPI{config: config, aqua: aqua}
   530  }
   531  
   532  // Preimage is a debug API function that returns the preimage for a sha3 hash, if known.
   533  func (api *PrivateDebugAPI) Preimage(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
   534  	db := core.PreimageTable(api.aqua.ChainDb())
   535  	return db.Get(hash.Bytes())
   536  }
   537  
   538  // GetBadBlocks returns a list of the last 'bad blocks' that the client has seen on the network
   539  // and returns them as a JSON list of block-hashes
   540  func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]core.BadBlockArgs, error) {
   541  	return api.aqua.BlockChain().BadBlocks()
   542  }
   543  
   544  // StorageRangeResult is the result of a debug_storageRangeAt API call.
   545  type StorageRangeResult struct {
   546  	Storage storageMap   `json:"storage"`
   547  	NextKey *common.Hash `json:"nextKey"` // nil if Storage includes the last key in the trie.
   548  }
   549  
   550  type storageMap map[common.Hash]storageEntry
   551  
   552  type storageEntry struct {
   553  	Key   *common.Hash `json:"key"`
   554  	Value common.Hash  `json:"value"`
   555  }