github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/blockchain/rpcserver/rpcserver.go (about) 1 // Copyright 2017-2018 DERO Project. All rights reserved. 2 // Use of this source code in any form is governed by RESEARCH license. 3 // license can be found in the LICENSE file. 4 // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 5 // 6 // 7 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 8 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 9 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 10 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 11 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 12 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 13 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 14 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 15 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 16 17 package rpcserver 18 19 import "io" 20 import "fmt" 21 import "net" 22 import "time" 23 import "context" 24 import "sync" 25 import "sync/atomic" 26 27 //import "context" 28 import "net/http" 29 import "net/http/pprof" 30 31 //import "github.com/intel-go/fastjson" 32 import "github.com/osamingo/jsonrpc" 33 import log "github.com/sirupsen/logrus" 34 import "github.com/prometheus/client_golang/prometheus" 35 import "github.com/prometheus/client_golang/prometheus/promhttp" 36 37 import "github.com/deroproject/derosuite/config" 38 import "github.com/deroproject/derosuite/globals" 39 import "github.com/deroproject/derosuite/blockchain" 40 import "github.com/deroproject/derosuite/structures" 41 import "github.com/deroproject/derosuite/metrics" 42 43 var DEBUG_MODE bool 44 45 /* this file implements the rpcserver api, so as wallet and block explorer tools can work without migration */ 46 47 // all components requiring access to blockchain must use , this struct to communicate 48 // this structure must be update while mutex 49 type RPCServer struct { 50 srv *http.Server 51 mux *http.ServeMux 52 Exit_Event chan bool // blockchain is shutting down and we must quit ASAP 53 sync.RWMutex 54 } 55 56 var Exit_In_Progress bool 57 var chain *blockchain.Blockchain 58 var logger *log.Entry 59 60 func RPCServer_Start(params map[string]interface{}) (*RPCServer, error) { 61 62 var err error 63 var r RPCServer 64 65 _ = err 66 67 r.Exit_Event = make(chan bool) 68 69 logger = globals.Logger.WithFields(log.Fields{"com": "RPC"}) // all components must use this logger 70 chain = params["chain"].(*blockchain.Blockchain) 71 72 /* 73 // test whether chain is okay 74 if chain.Get_Height() == 0 { 75 return nil, fmt.Errorf("Chain DOES NOT have genesis block") 76 } 77 */ 78 79 go r.Run() 80 logger.Infof("RPC server started") 81 atomic.AddUint32(&globals.Subsystem_Active, 1) // increment subsystem 82 83 return &r, nil 84 } 85 86 // shutdown the rpc server component 87 func (r *RPCServer) RPCServer_Stop() { 88 r.Lock() 89 defer r.Unlock() 90 Exit_In_Progress = true 91 close(r.Exit_Event) // send signal to all connections to exit 92 93 if r.srv != nil { 94 r.srv.Shutdown(context.Background()) // shutdown the server 95 } 96 // TODO we must wait for connections to kill themselves 97 time.Sleep(1 * time.Second) 98 logger.Infof("RPC Shutdown") 99 atomic.AddUint32(&globals.Subsystem_Active, ^uint32(0)) // this decrement 1 fom subsystem 100 } 101 102 // setup handlers 103 func (r *RPCServer) Run() { 104 105 mr := jsonrpc.NewMethodRepository() 106 107 if err := mr.RegisterMethod("Main.Echo", EchoHandler{}, EchoParams{}, EchoResult{}); err != nil { 108 log.Fatalln(err) 109 } 110 111 // install getblockcount handler 112 if err := mr.RegisterMethod("getblockcount", GetBlockCount_Handler{}, structures.GetBlockCount_Params{}, structures.GetBlockCount_Result{}); err != nil { 113 log.Fatalln(err) 114 } 115 116 // install on_getblockhash 117 if err := mr.RegisterMethod("on_getblockhash", On_GetBlockHash_Handler{}, structures.On_GetBlockHash_Params{}, structures.On_GetBlockHash_Result{}); err != nil { 118 log.Fatalln(err) 119 } 120 121 // install getblocktemplate handler 122 if err := mr.RegisterMethod("getblocktemplate", GetBlockTemplate_Handler{}, structures.GetBlockTemplate_Params{}, structures.GetBlockTemplate_Result{}); err != nil { 123 log.Fatalln(err) 124 } 125 126 // submitblock handler 127 if err := mr.RegisterMethod("submitblock", SubmitBlock_Handler{}, structures.SubmitBlock_Params{}, structures.SubmitBlock_Result{}); err != nil { 128 log.Fatalln(err) 129 } 130 131 if err := mr.RegisterMethod("getlastblockheader", GetLastBlockHeader_Handler{}, structures.GetLastBlockHeader_Params{}, structures.GetLastBlockHeader_Result{}); err != nil { 132 log.Fatalln(err) 133 } 134 135 if err := mr.RegisterMethod("getblockheaderbyhash", GetBlockHeaderByHash_Handler{}, structures.GetBlockHeaderByHash_Params{}, structures.GetBlockHeaderByHash_Result{}); err != nil { 136 log.Fatalln(err) 137 } 138 139 if err := mr.RegisterMethod("getblockheaderbyheight", GetBlockHeaderByHeight_Handler{}, structures.GetBlockHeaderByHeight_Params{}, structures.GetBlockHeaderByHeight_Result{}); err != nil { 140 log.Fatalln(err) 141 } 142 143 if err := mr.RegisterMethod("getblockheaderbytopoheight", GetBlockHeaderByTopoHeight_Handler{}, structures.GetBlockHeaderByTopoHeight_Params{}, structures.GetBlockHeaderByHeight_Result{}); err != nil { 144 log.Fatalln(err) 145 } 146 147 if err := mr.RegisterMethod("getblock", GetBlock_Handler{}, structures.GetBlock_Params{}, structures.GetBlock_Result{}); err != nil { 148 log.Fatalln(err) 149 } 150 151 if err := mr.RegisterMethod("get_info", GetInfo_Handler{}, structures.GetInfo_Params{}, structures.GetInfo_Result{}); err != nil { 152 log.Fatalln(err) 153 } 154 155 if err := mr.RegisterMethod("gettxpool", GetTxPool_Handler{}, structures.GetTxPool_Params{}, structures.GetTxPool_Result{}); err != nil { 156 log.Fatalln(err) 157 } 158 159 // create a new mux 160 r.mux = http.NewServeMux() 161 162 default_address := "127.0.0.1:" + fmt.Sprintf("%d", config.Mainnet.RPC_Default_Port) 163 if !globals.IsMainnet() { 164 default_address = "127.0.0.1:" + fmt.Sprintf("%d", config.Testnet.RPC_Default_Port) 165 } 166 167 if _, ok := globals.Arguments["--rpc-bind"]; ok && globals.Arguments["--rpc-bind"] != nil { 168 addr, err := net.ResolveTCPAddr("tcp", globals.Arguments["--rpc-bind"].(string)) 169 if err != nil { 170 logger.Warnf("--rpc-bind address is invalid, err = %s", err) 171 } else { 172 if addr.Port == 0 { 173 logger.Infof("RPC server is disabled, No ports will be opened for RPC") 174 return 175 } else { 176 default_address = addr.String() 177 } 178 } 179 } 180 181 logger.Infof("RPC will listen on %s", default_address) 182 r.Lock() 183 r.srv = &http.Server{Addr: default_address, Handler: r.mux} 184 r.Unlock() 185 186 r.mux.HandleFunc("/", hello) 187 r.mux.Handle("/json_rpc", mr) 188 189 // handle nasty http requests 190 r.mux.HandleFunc("/getheight", getheight) 191 r.mux.HandleFunc("/getoutputs.bin", getoutputs) // stream any outputs to server, can make wallet work offline 192 r.mux.HandleFunc("/gettransactions", gettransactions) 193 r.mux.HandleFunc("/sendrawtransaction", SendRawTransaction_Handler) 194 r.mux.HandleFunc("/is_key_image_spent", iskeyimagespent) 195 196 if DEBUG_MODE { 197 // r.mux.HandleFunc("/debug/pprof/", pprof.Index) 198 199 // Register pprof handlers individually if required 200 r.mux.HandleFunc("/debug/pprof/", pprof.Index) 201 r.mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) 202 r.mux.HandleFunc("/debug/pprof/profile", pprof.Profile) 203 r.mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) 204 r.mux.HandleFunc("/debug/pprof/trace", pprof.Trace) 205 206 /* 207 // Register pprof handlers individually if required 208 r.mux.HandleFunc("/cdebug/pprof/", pprof.Index) 209 r.mux.HandleFunc("/cdebug/pprof/cmdline", pprof.Cmdline) 210 r.mux.HandleFunc("/cdebug/pprof/profile", pprof.Profile) 211 r.mux.HandleFunc("/cdebug/pprof/symbol", pprof.Symbol) 212 r.mux.HandleFunc("/cdebug/pprof/trace", pprof.Trace) 213 */ 214 215 // register metrics handler 216 r.mux.HandleFunc("/metrics", prometheus.InstrumentHandler("dero", promhttp.HandlerFor(metrics.Registry, promhttp.HandlerOpts{}))) 217 218 } 219 220 //r.mux.HandleFunc("/json_rpc/debug", mr.ServeDebug) 221 222 if err := r.srv.ListenAndServe(); err != http.ErrServerClosed { 223 logger.Warnf("ERR listening to address err %s", err) 224 } 225 226 } 227 228 func hello(w http.ResponseWriter, r *http.Request) { 229 io.WriteString(w, "Hello world!") 230 }