gitlab.com/aquachain/aquachain@v1.17.16-rc3.0.20221018032414-e3ddf1e1c055/aqua/api.go (about)

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