package rpc import ( "fmt" "net" "strings" "time" "github.com/ethereum/go-ethereum/rpc" "github.com/harmony-one/harmony/hmy" nodeconfig "github.com/harmony-one/harmony/internal/configs/node" "github.com/harmony-one/harmony/internal/utils" v1 "github.com/harmony-one/harmony/rpc/v1" v2 "github.com/harmony-one/harmony/rpc/v2" ) // Version enum const ( V1 Version = iota V2 ) const ( // APIVersion used for DApp's, bumped after RPC refactor (7/2020) APIVersion = "1.1" // CallTimeout is the timeout given to all contract calls CallTimeout = 5 * time.Second // LogTag is the tag found in the log for all RPC logs LogTag = "[RPC]" // HTTPPortOffset .. HTTPPortOffset = 500 // WSPortOffset .. WSPortOffset = 800 netV1Namespace = "net" netV2Namespace = "netv2" ) var ( // HTTPModules .. HTTPModules = []string{"hmy", "hmyv2", netV1Namespace, netV2Namespace, "explorer"} // WSModules .. WSModules = []string{"hmy", "hmyv2", netV1Namespace, netV2Namespace, "web3"} httpListener net.Listener httpHandler *rpc.Server wsListener net.Listener wsHandler *rpc.Server httpEndpoint = "" wsEndpoint = "" httpVirtualHosts = []string{"*"} httpTimeouts = rpc.DefaultHTTPTimeouts httpOrigins = []string{"*"} wsOrigins = []string{"*"} ) // Version of the RPC type Version int // Namespace of the RPC version func (n Version) Namespace() string { return HTTPModules[n] } // StartServers starts the http & ws servers func StartServers(hmy *hmy.Harmony, port int, apis []rpc.API) error { ip := "" if !nodeconfig.GetPublicRPC() { ip = "127.0.0.1" } apis = append(apis, getAPIs(hmy)...) httpEndpoint = fmt.Sprintf("%v:%v", ip, port+HTTPPortOffset) if err := startHTTP(apis); err != nil { return err } wsEndpoint = fmt.Sprintf("%v:%v", ip, port+WSPortOffset) if err := startWS(apis); err != nil { return err } return nil } // StopServers stops the http & ws servers func StopServers() error { if httpListener != nil { if err := httpListener.Close(); err != nil { return err } httpListener = nil utils.Logger().Info(). Str("url", fmt.Sprintf("http://%s", httpEndpoint)). Msg("HTTP endpoint closed") } if httpHandler != nil { httpHandler.Stop() httpHandler = nil } if wsListener != nil { if err := wsListener.Close(); err != nil { return err } wsListener = nil utils.Logger().Info(). Str("url", fmt.Sprintf("http://%s", wsEndpoint)). Msg("WS endpoint closed") } if wsHandler != nil { wsHandler.Stop() wsHandler = nil } return nil } // getAPIs returns all the API methods for the RPC interface func getAPIs(hmy *hmy.Harmony) []rpc.API { return []rpc.API{ // Public methods NewPublicHarmonyAPI(hmy, V1), NewPublicHarmonyAPI(hmy, V2), NewPublicBlockchainAPI(hmy, V1), NewPublicBlockchainAPI(hmy, V2), NewPublicContractAPI(hmy, V1), NewPublicContractAPI(hmy, V2), NewPublicTransactionAPI(hmy, V1), NewPublicTransactionAPI(hmy, V2), NewPublicPoolAPI(hmy, V1), NewPublicPoolAPI(hmy, V2), NewPublicStakingAPI(hmy, V1), NewPublicStakingAPI(hmy, V2), // Private methods NewPrivateDebugAPI(hmy, V1), NewPrivateDebugAPI(hmy, V2), // Legacy methods (subject to removal) v1.NewPublicLegacyAPI(hmy), v2.NewPublicLegacyAPI(hmy), } } func startHTTP(apis []rpc.API) (err error) { httpListener, httpHandler, err = rpc.StartHTTPEndpoint( httpEndpoint, apis, HTTPModules, httpOrigins, httpVirtualHosts, httpTimeouts, ) if err != nil { return err } utils.Logger().Info(). Str("url", fmt.Sprintf("http://%s", httpEndpoint)). Str("cors", strings.Join(httpOrigins, ",")). Str("vhosts", strings.Join(httpVirtualHosts, ",")). Msg("HTTP endpoint opened") return nil } func startWS(apis []rpc.API) (err error) { wsListener, wsHandler, err = rpc.StartWSEndpoint(wsEndpoint, apis, WSModules, wsOrigins, true) if err != nil { return err } utils.Logger().Info(). Str("url", fmt.Sprintf("ws://%s", wsListener.Addr())). Msg("WebSocket endpoint opened") return nil }