github.com/Finschia/ostracon@v1.1.5/rpc/core/env.go (about)

     1  package core
     2  
     3  import (
     4  	"encoding/base64"
     5  	"fmt"
     6  	"time"
     7  
     8  	cfg "github.com/Finschia/ostracon/config"
     9  	"github.com/Finschia/ostracon/consensus"
    10  	"github.com/Finschia/ostracon/crypto"
    11  	tmjson "github.com/Finschia/ostracon/libs/json"
    12  	"github.com/Finschia/ostracon/libs/log"
    13  	mempl "github.com/Finschia/ostracon/mempool"
    14  	"github.com/Finschia/ostracon/p2p"
    15  	"github.com/Finschia/ostracon/proxy"
    16  	sm "github.com/Finschia/ostracon/state"
    17  	"github.com/Finschia/ostracon/state/indexer"
    18  	"github.com/Finschia/ostracon/state/txindex"
    19  	"github.com/Finschia/ostracon/types"
    20  )
    21  
    22  const (
    23  	// see README
    24  	defaultPerPage = 30
    25  
    26  	// Temporarily set it to a sufficient value to reduce the number of tx search queries during the test.
    27  	// TODO It will be modified later to be configurable. (Also, add a option to get all tx of block)
    28  	maxPerPage = 10000
    29  
    30  	// SubscribeTimeout is the maximum time we wait to subscribe for an event.
    31  	// must be less than the server's write timeout (see rpcserver.DefaultConfig)
    32  	SubscribeTimeout = 5 * time.Second
    33  
    34  	// genesisChunkSize is the maximum size, in bytes, of each
    35  	// chunk in the genesis structure for the chunked API
    36  	genesisChunkSize = 16 * 1024 * 1024 // 16
    37  )
    38  
    39  var (
    40  	// set by Node
    41  	env *Environment
    42  )
    43  
    44  // SetEnvironment sets up the given Environment.
    45  // It will race if multiple Node call SetEnvironment.
    46  func SetEnvironment(e *Environment) {
    47  	env = e
    48  }
    49  
    50  //----------------------------------------------
    51  // These interfaces are used by RPC and must be thread safe
    52  
    53  type Consensus interface {
    54  	GetState() sm.State
    55  	GetValidators() (int64, []*types.Validator)
    56  	GetLastHeight() int64
    57  	GetRoundStateJSON() ([]byte, error)
    58  	GetRoundStateSimpleJSON() ([]byte, error)
    59  }
    60  
    61  type transport interface {
    62  	Listeners() []string
    63  	IsListening() bool
    64  	NodeInfo() p2p.NodeInfo
    65  }
    66  
    67  type peers interface {
    68  	AddPersistentPeers([]string) error
    69  	AddUnconditionalPeerIDs([]string) error
    70  	AddPrivatePeerIDs([]string) error
    71  	DialPeersAsync([]string) error
    72  	Peers() p2p.IPeerSet
    73  }
    74  
    75  // ----------------------------------------------
    76  // Environment contains objects and interfaces used by the RPC. It is expected
    77  // to be setup once during startup.
    78  type Environment struct {
    79  	// external, thread safe interfaces
    80  	ProxyAppQuery   proxy.AppConnQuery
    81  	ProxyAppMempool proxy.AppConnMempool
    82  
    83  	// interfaces defined in types and above
    84  	StateStore     sm.Store
    85  	BlockStore     sm.BlockStore
    86  	EvidencePool   sm.EvidencePool
    87  	ConsensusState Consensus
    88  	P2PPeers       peers
    89  	P2PTransport   transport
    90  
    91  	// objects
    92  	PubKey           crypto.PubKey
    93  	GenDoc           *types.GenesisDoc // cache the genesis structure
    94  	TxIndexer        txindex.TxIndexer
    95  	BlockIndexer     indexer.BlockIndexer
    96  	ConsensusReactor *consensus.Reactor
    97  	EventBus         *types.EventBus // thread safe
    98  	Mempool          mempl.Mempool
    99  
   100  	Logger log.Logger
   101  
   102  	Config cfg.RPCConfig
   103  
   104  	// cache of chunked genesis data.
   105  	genChunks []string
   106  }
   107  
   108  //----------------------------------------------
   109  
   110  func validatePage(pagePtr *int, perPage, totalCount int) (int, error) {
   111  	if perPage < 1 {
   112  		panic(fmt.Sprintf("zero or negative perPage: %d", perPage))
   113  	}
   114  
   115  	if pagePtr == nil { // no page parameter
   116  		return 1, nil
   117  	}
   118  
   119  	pages := ((totalCount - 1) / perPage) + 1
   120  	if pages == 0 {
   121  		pages = 1 // one page (even if it's empty)
   122  	}
   123  	page := *pagePtr
   124  	if page <= 0 || page > pages {
   125  		return 1, fmt.Errorf("page should be within [1, %d] range, given %d", pages, page)
   126  	}
   127  
   128  	return page, nil
   129  }
   130  
   131  func validatePerPage(perPagePtr *int) int {
   132  	if perPagePtr == nil { // no per_page parameter
   133  		return defaultPerPage
   134  	}
   135  
   136  	perPage := *perPagePtr
   137  	if perPage < 1 {
   138  		return defaultPerPage
   139  	} else if perPage > maxPerPage {
   140  		return maxPerPage
   141  	}
   142  	return perPage
   143  }
   144  
   145  // InitGenesisChunks configures the environment and should be called on service
   146  // startup.
   147  func InitGenesisChunks() error {
   148  	if env.genChunks != nil {
   149  		return nil
   150  	}
   151  
   152  	if env.GenDoc == nil {
   153  		return nil
   154  	}
   155  
   156  	data, err := tmjson.Marshal(env.GenDoc)
   157  	if err != nil {
   158  		return err
   159  	}
   160  
   161  	for i := 0; i < len(data); i += genesisChunkSize {
   162  		end := i + genesisChunkSize
   163  
   164  		if end > len(data) {
   165  			end = len(data)
   166  		}
   167  
   168  		env.genChunks = append(env.genChunks, base64.StdEncoding.EncodeToString(data[i:end]))
   169  	}
   170  
   171  	return nil
   172  }
   173  
   174  func validateSkipCount(page, perPage int) int {
   175  	skipCount := (page - 1) * perPage
   176  	if skipCount < 0 {
   177  		return 0
   178  	}
   179  
   180  	return skipCount
   181  }
   182  
   183  // latestHeight can be either latest committed or uncommitted (+1) height.
   184  func getHeight(latestHeight int64, heightPtr *int64) (int64, error) {
   185  	if heightPtr != nil {
   186  		height := *heightPtr
   187  		if height <= 0 {
   188  			return 0, fmt.Errorf("height must be greater than 0, but got %d", height)
   189  		}
   190  		if height > latestHeight {
   191  			return 0, fmt.Errorf("height %d must be less than or equal to the current blockchain height %d",
   192  				height, latestHeight)
   193  		}
   194  		base := env.BlockStore.Base()
   195  		if height < base {
   196  			return 0, fmt.Errorf("height %d is not available, lowest height is %d",
   197  				height, base)
   198  		}
   199  		return height, nil
   200  	}
   201  	return latestHeight, nil
   202  }
   203  
   204  func latestUncommittedHeight() int64 {
   205  	nodeIsSyncing := env.ConsensusReactor.WaitSync()
   206  	if nodeIsSyncing {
   207  		return env.BlockStore.Height()
   208  	}
   209  	return env.BlockStore.Height() + 1
   210  }