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 }