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 }