github.com/noirx94/tendermintmp@v0.0.1/rpc/core/env.go (about) 1 package core 2 3 import ( 4 "encoding/base64" 5 "fmt" 6 "time" 7 8 cfg "github.com/tendermint/tendermint/config" 9 "github.com/tendermint/tendermint/consensus" 10 "github.com/tendermint/tendermint/crypto" 11 tmjson "github.com/tendermint/tendermint/libs/json" 12 "github.com/tendermint/tendermint/libs/log" 13 mempl "github.com/tendermint/tendermint/mempool" 14 "github.com/tendermint/tendermint/p2p" 15 "github.com/tendermint/tendermint/proxy" 16 sm "github.com/tendermint/tendermint/state" 17 "github.com/tendermint/tendermint/state/indexer" 18 "github.com/tendermint/tendermint/state/txindex" 19 "github.com/tendermint/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 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 }