|
|
|
"""
|
|
|
|
RPC wrapper around requests library
|
|
|
|
"""
|
|
|
|
import json
|
|
|
|
|
|
|
|
import requests
|
|
|
|
|
|
|
|
from .exceptions import RequestsError, RequestsTimeoutError, RPCError
|
|
|
|
|
|
|
|
from ..constants import DEFAULT_ENDPOINT, DEFAULT_TIMEOUT
|
|
|
|
|
|
|
|
|
|
|
|
def base_request(
|
|
|
|
method, params=None, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
|
|
|
|
) -> str:
|
|
|
|
"""Basic RPC request.
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
---------
|
|
|
|
method: str
|
|
|
|
RPC Method to call
|
|
|
|
params: :obj:`list`, optional
|
|
|
|
Parameters for the RPC method
|
|
|
|
endpoint: :obj:`str`, optional
|
|
|
|
Endpoint to send request to
|
|
|
|
timeout: :obj:`int`, optional
|
|
|
|
Timeout in seconds
|
|
|
|
|
|
|
|
Returns
|
|
|
|
-------
|
|
|
|
str
|
|
|
|
Raw output from the request
|
|
|
|
|
|
|
|
Raises
|
|
|
|
------
|
|
|
|
TypeError
|
|
|
|
If params is not a list or None
|
|
|
|
RequestsTimeoutError
|
|
|
|
If request timed out
|
|
|
|
RequestsError
|
|
|
|
If other request error occured
|
|
|
|
"""
|
|
|
|
if params is None:
|
|
|
|
params = []
|
|
|
|
elif not isinstance(params, list):
|
|
|
|
raise TypeError(f"invalid type {params.__class__}")
|
|
|
|
|
|
|
|
try:
|
|
|
|
payload = {"id": "1", "jsonrpc": "2.0", "method": method, "params": params}
|
|
|
|
headers = {"Content-Type": "application/json"}
|
|
|
|
|
|
|
|
resp = requests.request(
|
|
|
|
"POST",
|
|
|
|
endpoint,
|
|
|
|
headers=headers,
|
|
|
|
data=json.dumps(payload),
|
|
|
|
timeout=timeout,
|
|
|
|
allow_redirects=True,
|
|
|
|
)
|
|
|
|
return resp.content
|
|
|
|
except requests.exceptions.Timeout as err:
|
|
|
|
raise RequestsTimeoutError(endpoint) from err
|
|
|
|
except requests.exceptions.RequestException as err:
|
|
|
|
raise RequestsError(endpoint) from err
|
|
|
|
|
|
|
|
|
|
|
|
def rpc_request(
|
|
|
|
method, params=None, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
|
|
|
|
) -> dict:
|
|
|
|
"""RPC request.
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
---------
|
|
|
|
method: str
|
|
|
|
RPC Method to call
|
|
|
|
params: :obj:`list`, optional
|
|
|
|
Parameters for the RPC method
|
|
|
|
endpoint: :obj:`str`, optional
|
|
|
|
Endpoint to send request to
|
|
|
|
timeout: :obj:`int`, optional
|
|
|
|
Timeout in seconds
|
|
|
|
|
|
|
|
Returns
|
|
|
|
-------
|
|
|
|
dict
|
|
|
|
Returns dictionary representation of RPC response
|
|
|
|
Example format:
|
|
|
|
{
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"id": 1,
|
|
|
|
"result": ...
|
|
|
|
}
|
|
|
|
|
|
|
|
Raises
|
|
|
|
------
|
|
|
|
RPCError
|
|
|
|
If RPC response returned a blockchain error
|
|
|
|
|
|
|
|
See Also
|
|
|
|
--------
|
|
|
|
base_request
|
|
|
|
"""
|
|
|
|
raw_resp = base_request(method, params, endpoint, timeout)
|
|
|
|
|
|
|
|
try:
|
|
|
|
resp = json.loads(raw_resp)
|
|
|
|
if "error" in resp:
|
|
|
|
raise RPCError(method, endpoint, str(resp["error"]))
|
|
|
|
return resp
|
|
|
|
except json.decoder.JSONDecodeError as err:
|
|
|
|
raise RPCError(method, endpoint, raw_resp) from err
|