github.com/vipernet-xyz/tm@v0.34.24/rpc/core/env.go (about)

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