Engine
Engine

Reputation: 141

bitcoin json rpc with python requests module?

I've been trying for hours, and I just don't know what I'm doing wrongly. It's just for planning/research (not performant) -- playing around with some code from github -- but I need to see it functional.

RPC_USER = username
RPC_PASS = pasword
rpc_id =  ID HERE
jsonrpc = "2.0"
payload = {"jsonrpc": jsonrpc, "id": rpc_id, "method": method, "params": params}
authstr = base64.encodestring(bytes('%s:%s' % (RPC_USER, RPC_PASS), 'utf-8')).strip() 
request_headers = {"Authorization": "Basic %s" % authstr, 'content-type': 'application/json'}
try:
    response = requests.get(RPC_URL, headers = request_headers, data = json.dumps(payload)).json()
    print(response['result'])      
except Exception as e: print(str(e))
if response['id'] != rpc_id:
        raise ValueError("invalid response id!")

I get an error as follows:

Here's the whole traceback:

Expecting value: line 1 column 1 (char 0) # prints the Exception

Traceback (most recent call last): 
  File "miner_2017.py", line 411, in <module>
    solo_miner(bin2hex("------coinbase message here -----"), "-----bitcoin address here-----")
  File "miner_2017.py", line 401, in solo_miner
    mined_block, hps = block_mine(rpc_getblocktemplate(), coinbase_message, 0, address, timeout=60)
  File "miner_2017.py", line 63, in rpc_getblocktemplate
    try: return rpc("getblocktemplate", [{}])
  File "miner_2017.py", line 52, in rpc
    if response['id'] != rpc_id:
UnboundLocalError: local variable 'response' referenced before assignment  

Which after doing some looking seems to be a problem with decoding the json object from a bytes object rather than a string object. I don't know how to fix this. It seems the "response" variable assignment was unsuccessful due to the json problem. How can I get the json object in string form from the request?

Would somebody help me out? Thanks

Upvotes: 2

Views: 7287

Answers (3)

Scalextrix
Scalextrix

Reputation: 531

#!/usr/bin/env python

import getpass
import json
import requests    

def instruct_wallet(method, params):
    url = "http://127.0.0.1:8332/"
    payload = json.dumps({"method": method, "params": params})
    headers = {'content-type': "application/json", 'cache-control': "no-cache"}
    try:
        response = requests.request("POST", url, data=payload, headers=headers, auth=(rpc_user, rpc_password))
        return json.loads(response.text)
    except requests.exceptions.RequestException as e:
        print e
    except:
        print 'No response from Wallet, check Bitcoin is running on this machine'

rpc_user='foo'
rpc_password='bar'
passphrase = getpass.getpass('Enter your wallet passphrase: ')
timeout = raw_input('Unlock for how many seconds: ')

answer = instruct_wallet('walletpassphrase', [passphrase, timeout])
if answer['error'] != None:
    print answer['error']
else:
    print answer['result']

I'm using something similar for Altcoins

Upvotes: 5

wyx
wyx

Reputation: 3534

import decimal
import itertools
import json

import requests

id_counter = itertools.count()


class BTCJsonRPC(object):

    def __init__(self, url, user, passwd, log, method=None, timeout=30):
        self.url = url
        self._user = user
        self._passwd = passwd
        self._method_name = method
        self._timeout = timeout
        self._log = log

    def __getattr__(self, method_name):
        return BTCJsonRPC(self.url, self._user, self._passwd, self._log, method_name, timeout=self._timeout)

    def __call__(self, *args):
        # rpc json call
        playload = json.dumps({'jsonrpc': '2.0', 'id': next(id_counter), "method": self._method_name, "params": args})
        headers = {'Content-type': 'application/json'}
        resp = None
        try:
            resp = requests.post(self.url, headers=headers, data=playload, timeout=self._timeout,
                                 auth=(self._user, self._passwd))
            resp = resp.json(parse_float=decimal.Decimal)
        except Exception as e:
            error_msg = resp.text if resp is not None else e
            msg = u"{} {}:[{}] \n {}".format('post', self._method_name, args, error_msg)
            self._log.error(msg)
            return

        if resp.get('error') is not None:
            e = resp['error']
            self._log.error('{}:[{}]\n {}:{}'.format(self._method_name, args, e['code'], e['message']))
            return None
        elif 'result' not in resp:
            self._log.error('[{}]:[{}]\n MISSING JSON-RPC RESULT'.format(self._method_name, args, ))
            return None

        return resp['result']

Upvotes: 3

C S
C S

Reputation: 1535

I'm pretty sure you just need to change from using a GET to a POST, i.e.:

change

response = requests.get(RPC_URL, headers = request_headers, data = json.dumps(payload)).json()

to

response = requests.post(RPC_URL, headers=request_headers, data=json.dumps(payload)).json()

In fact, when I tried this with GET (without dumping the response to json), I got a 405 response. You should always take a look at your response object before doing further debugging with it.

Upvotes: 1

Related Questions