github.com/number571/tendermint@v0.34.11-gost/rpc/core/env.go (about)

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