Properly handle account labels

This commit is contained in:
Michał Sałaban 2019-04-02 22:13:51 +02:00
parent 5f340482d0
commit 864829b858
8 changed files with 105 additions and 19 deletions

View File

@ -13,12 +13,15 @@ class Account(object):
:param backend: a wallet backend
:param index: the account's index within the wallet
:param label: optional account label as `str`
"""
index = None
wallet = None
label = None
def __init__(self, backend, index):
def __init__(self, backend, index, label=None):
self.index = index
self.label = label
self._backend = backend
self.incoming = PaymentManager(index, backend, 'in')
self.outgoing = PaymentManager(index, backend, 'out')
@ -60,6 +63,7 @@ class Account(object):
"""
Creates a new address.
:param label: address label as `str`
:rtype: :class:`SubAddress <monero.address.SubAddress>`
"""
return self._backend.new_address(account=self.index, label=label)

View File

@ -2,7 +2,6 @@ from datetime import datetime
import operator
import json
import logging
import pprint
import requests
from .. import exceptions
@ -61,14 +60,14 @@ class JSONRPCDaemon(object):
hdr = {'Content-Type': 'application/json'}
_log.debug(u"Request: {path}\nData: {data}".format(
path=path,
data=pprint.pformat(data)))
data=json.dumps(data, indent=2, sort_keys=True)))
rsp = requests.post(self.url + path, headers=hdr, data=json.dumps(data))
if rsp.status_code != 200:
raise RPCError("Invalid HTTP status {code} for path {path}.".format(
code=rsp.status_code,
path=path))
result = rsp.json()
_ppresult = pprint.pformat(result)
_ppresult = json.dumps(result, indent=2, sort_keys=True)
_log.debug(u"Result:\n{result}".format(result=_ppresult))
return result
@ -78,7 +77,7 @@ class JSONRPCDaemon(object):
data = {'jsonrpc': '2.0', 'id': 0, 'method': method, 'params': params or {}}
_log.debug(u"Method: {method}\nParams:\n{params}".format(
method=method,
params=pprint.pformat(params)))
params=json.dumps(params, indent=2, sort_keys=True)))
auth = requests.auth.HTTPDigestAuth(self.user, self.password)
rsp = requests.post(self.url + '/json_rpc', headers=hdr, data=json.dumps(data), auth=auth)
if rsp.status_code == 401:
@ -88,7 +87,7 @@ class JSONRPCDaemon(object):
code=rsp.status_code,
method=method))
result = rsp.json()
_ppresult = pprint.pformat(result)
_ppresult = json.dumps(result, indent=2, sort_keys=True)
_log.debug(u"Result:\n{result}".format(result=_ppresult))
if 'error' in result:
@ -142,24 +141,20 @@ class JSONRPCWallet(object):
def accounts(self):
accounts = []
try:
_accounts = self.raw_request('get_accounts', squelch_error_logging=True)
except MethodNotFound:
# monero <= 0.11 : there's only one account and one address
_log.debug('Monero <= 0.11 found, no accounts')
self._master_address = self.addresses()[0]
return [Account(self, 0)]
_accounts = self.raw_request('get_accounts')
idx = 0
self._master_address = Address(_accounts['subaddress_accounts'][0]['base_address'])
for _acc in _accounts['subaddress_accounts']:
assert idx == _acc['account_index']
accounts.append(Account(self, _acc['account_index']))
accounts.append(Account(self, _acc['account_index'], label=_acc.get('label')))
idx += 1
return accounts
def new_account(self, label=None):
_account = self.raw_request('create_account', {'label': label})
return Account(self, _account['account_index']), SubAddress(_account['address'])
# NOTE: the following should re-read label by _account.get('label') but the RPC
# doesn't return that detail here
return Account(self, _account['account_index'], label=label), SubAddress(_account['address'])
def addresses(self, account=0):
_addresses = self.raw_request('getaddress', {'account_index': account})
@ -318,7 +313,7 @@ class JSONRPCWallet(object):
data = {'jsonrpc': '2.0', 'id': 0, 'method': method, 'params': params or {}}
_log.debug(u"Method: {method}\nParams:\n{params}".format(
method=method,
params=pprint.pformat(params)))
params=json.dumps(params, indent=2, sort_keys=True)))
auth = requests.auth.HTTPDigestAuth(self.user, self.password)
rsp = requests.post(self.url, headers=hdr, data=json.dumps(data), auth=auth)
if rsp.status_code == 401:
@ -328,13 +323,12 @@ class JSONRPCWallet(object):
code=rsp.status_code,
method=method))
result = rsp.json()
_ppresult = pprint.pformat(result)
_ppresult = json.dumps(result, indent=2, sort_keys=True)
_log.debug(u"Result:\n{result}".format(result=_ppresult))
if 'error' in result:
err = result['error']
if not squelch_error_logging:
_log.error(u"JSON RPC error:\n{result}".format(result=_ppresult))
_log.error(u"JSON RPC error:\n{result}".format(result=_ppresult))
# XXX: workaround for 0.11 bug throwing a wrong error code
if err['code'] == -4 and 'not enough money' in err['message']:
raise exceptions.NotEnoughMoney(err['message'])

View File

@ -91,6 +91,7 @@ class Wallet(object):
"""
Creates new account, appends it to the :class:`Wallet`'s account list and returns it.
:param label: account label as `str`
:rtype: :class:`Account`
"""
acc, addr = self._backend.new_account(label=label)

View File

@ -0,0 +1,18 @@
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"subaddress_accounts": [
{
"account_index": 0,
"balance": 0,
"base_address": "53NTw2x2eJH3KCrcgWAMErZb7mqN57wkVTEjRkkUUXoWCrAd513JErRFT1AC9RvEddgpxoZTVXYJG9Jez4w9x6qd5s76wdu",
"label": "Primary account",
"tag": "",
"unlocked_balance": 0
}
],
"total_balance": 0,
"total_unlocked_balance": 0
}
}

View File

@ -0,0 +1,8 @@
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"account_index": 1,
"address": "75oMNpEDZNZhe9zBuKP4i6RpknDzAzM7t64Kq6nToUsJZms13tUucewKfZpdaQ9sNVYiMhiDyZbZR7MxbTCjq7D8N9CCo5k"
}
}

View File

@ -0,0 +1,9 @@
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"balance": 0,
"multisig_import_needed": false,
"unlocked_balance": 0
}
}

View File

@ -0,0 +1,26 @@
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"subaddress_accounts": [
{
"account_index": 0,
"balance": 0,
"base_address": "53NTw2x2eJH3KCrcgWAMErZb7mqN57wkVTEjRkkUUXoWCrAd513JErRFT1AC9RvEddgpxoZTVXYJG9Jez4w9x6qd5s76wdu",
"label": "Primary account",
"tag": "",
"unlocked_balance": 0
},
{
"account_index": 1,
"balance": 0,
"base_address": "75oMNpEDZNZhe9zBuKP4i6RpknDzAzM7t64Kq6nToUsJZms13tUucewKfZpdaQ9sNVYiMhiDyZbZR7MxbTCjq7D8N9CCo5k",
"label": "account 1",
"tag": "",
"unlocked_balance": 0
}
],
"total_balance": 0,
"total_unlocked_balance": 0
}
}

View File

@ -139,6 +139,32 @@ class JSONRPCWalletTestCase(JSONTestCase):
self.assertEqual(a0addr.label, 'Primary account')
self.assertEqual(len(self.wallet.accounts[0].addresses()), 8)
@responses.activate
def test_account_creation(self):
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_account_creation-00-get_accounts.json'),
status=200)
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_account_creation-10-create_account.json'),
status=200)
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_account_creation-20-getbalance.json'),
status=200)
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_account_creation-30-get_accounts.json'),
status=200)
w = Wallet(JSONRPCWallet())
self.assertEqual(1, len(w.accounts))
w.new_account('account 1')
self.assertEqual(2, len(w.accounts))
self.assertEqual('account 1', w.accounts[1].label)
self.assertEqual(0, w.accounts[1].balance())
acc0, acc1 = w.accounts
w.refresh()
self.assertEqual(2, len(w.accounts))
self.assertEqual('account 1', w.accounts[1].label)
self.assertEqual([acc0, acc1], w.accounts)
@patch('monero.backends.jsonrpc.requests.post')
def test_incoming_confirmed(self, mock_post):
mock_post.return_value.status_code = 200