- fix and improvements related to the two balance command account_balance and wallet_balance

- working CommonWorkflowTests integration test
- pylint, unit and integration test fixes
- switch integration tests to use async/await
This commit is contained in:
Lex Berezhny 2018-07-16 23:32:37 -04:00 committed by Jack Robison
parent b2ab13187f
commit a28c9d09c8
No known key found for this signature in database
GPG key ID: DF25C68FE0239BB2
15 changed files with 109 additions and 113 deletions

View file

@ -354,7 +354,7 @@ def get_blob_hashsum(b):
iv = b['iv'] iv = b['iv']
blob_hashsum = get_lbry_hash_obj() blob_hashsum = get_lbry_hash_obj()
if length != 0: if length != 0:
blob_hashsum.update(blob_hash.encode()) blob_hashsum.update(blob_hash)
blob_hashsum.update(str(blob_num).encode()) blob_hashsum.update(str(blob_num).encode())
blob_hashsum.update(iv) blob_hashsum.update(iv)
blob_hashsum.update(str(length).encode()) blob_hashsum.update(str(length).encode())

View file

@ -43,6 +43,7 @@ from lbrynet.dht.error import TimeoutError
from lbrynet.core.Peer import Peer from lbrynet.core.Peer import Peer
from lbrynet.core.SinglePeerDownloader import SinglePeerDownloader from lbrynet.core.SinglePeerDownloader import SinglePeerDownloader
from lbrynet.core.client.StandaloneBlobDownloader import StandaloneBlobDownloader from lbrynet.core.client.StandaloneBlobDownloader import StandaloneBlobDownloader
from lbrynet.wallet.account import Account as LBRYAccount
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
requires = AuthJSONRPCServer.requires requires = AuthJSONRPCServer.requires
@ -980,34 +981,6 @@ class Daemon(AuthJSONRPCServer):
@requires(WALLET_COMPONENT) @requires(WALLET_COMPONENT)
@defer.inlineCallbacks @defer.inlineCallbacks
def jsonrpc_account_balance(self, account_name=None, confirmations=6):
"""
Return the balance of an individual account or all of the accounts.
Usage:
account_balance [<account_name> | --account=<account_name>] [--confirmations=<confirmations>]
Options:
--account=<account_name> : (str) If provided only the balance for this
account will be given
--confirmations=<confirmations> : (int) required confirmations (default: 6)
Returns:
(map) amount of lbry credits in wallet
"""
balances = yield self.wallet.get_balances(confirmations)
lbc_accounts = balances[self.ledger.get_id()]
if account_name is not None:
for account in lbc_accounts:
if account['account'] == account_name:
defer.returnValue(account)
raise Exception(
"No account found with name '{}', available accounts: {}."
.format(account_name, str([a['account'] for a in lbc_accounts]))
)
defer.returnValue(lbc_accounts)
@AuthJSONRPCServer.requires("wallet")
def jsonrpc_wallet_balance(self, address=None, include_unconfirmed=False): def jsonrpc_wallet_balance(self, address=None, include_unconfirmed=False):
""" """
Return the balance of the wallet Return the balance of the wallet
@ -1024,9 +997,10 @@ class Daemon(AuthJSONRPCServer):
(float) amount of lbry credits in wallet (float) amount of lbry credits in wallet
""" """
assert address is None, "Limiting by address needs to be re-implemented in new wallet." assert address is None, "Limiting by address needs to be re-implemented in new wallet."
return self.wallet.default_account.get_balance( dewies = yield self.wallet.default_account.get_balance(
0 if include_unconfirmed else 6 0 if include_unconfirmed else 6
) )
defer.returnValue(round(dewies / COIN, 3))
@requires(WALLET_COMPONENT) @requires(WALLET_COMPONENT)
@defer.inlineCallbacks @defer.inlineCallbacks
@ -3156,6 +3130,49 @@ class Daemon(AuthJSONRPCServer):
response = yield self._render_response(out) response = yield self._render_response(out)
defer.returnValue(response) defer.returnValue(response)
@AuthJSONRPCServer.requires("wallet")
def jsonrpc_account_balance(self, account_name=None, confirmations=6,
include_reserved=False, include_claims=False):
"""
Return the balance of an individual account or all of the accounts.
Usage:
account_balance [<account_name>] [--confirmations=<confirmations>]
[--include-reserved] [--include-claims]
Options:
--account=<account_name> : (str) If provided only the balance for this
account will be given
--confirmations=<confirmations> : (int) required confirmations (default: 6)
--include-reserved : (bool) include reserved UTXOs (default: false)
--include-claims : (bool) include claims, requires than a
LBC account is specified (default: false)
Returns:
(map) balance of account(s)
"""
if account_name:
for account in self.wallet.accounts:
if account.name == account_name:
if include_claims and not isinstance(account, LBRYAccount):
raise Exception(
"'--include-claims' requires specifying an LBC ledger account. "
"Found '{}', but it's an {} ledger account."
.format(account_name, account.ledger.symbol)
)
args = {
'confirmations': confirmations,
'include_reserved': include_reserved
}
if include_claims:
args['include_claims'] = True
return account.get_balance(**args)
raise Exception("Couldn't find an account named: '{}'.".format(account_name))
else:
if include_claims:
raise Exception("'--include-claims' requires specifying an LBC account.")
return self.wallet.get_balances(confirmations)
def loggly_time_string(dt): def loggly_time_string(dt):
formatted_dt = dt.strftime("%Y-%m-%dT%H:%M:%S") formatted_dt = dt.strftime("%Y-%m-%dT%H:%M:%S")

View file

@ -1,5 +1,5 @@
import logging import logging
from binascii import hexlify, unhexlify from binascii import unhexlify
from twisted.internet import defer from twisted.internet import defer
@ -70,21 +70,15 @@ class Account(BaseAccount):
failed += 1 failed += 1
log.info('Checked: %s, Converted: %s, Failed: %s', total, succeded, failed) log.info('Checked: %s, Converted: %s, Failed: %s', total, succeded, failed)
def get_balance(self, confirmations=6, include_claims=False): def get_balance(self, confirmations=6, include_claims=False, **constraints):
if include_claims: if not include_claims:
return super(Account, self).get_balance(confirmations) constraints.update({'is_claim': 0, 'is_update': 0, 'is_support': 0})
else: return super(Account, self).get_balance(confirmations, **constraints)
return super(Account, self).get_balance(
confirmations, is_claim=0, is_update=0, is_support=0
)
def get_unspent_outputs(self, include_claims=False): def get_unspent_outputs(self, include_claims=False, **constraints):
if include_claims: if not include_claims:
return super(Account, self).get_unspent_outputs() constraints.update({'is_claim': 0, 'is_update': 0, 'is_support': 0})
else: return super(Account, self).get_unspent_outputs(**constraints)
return super(Account, self).get_unspent_outputs(
is_claim=0, is_update=0, is_support=0
)
@classmethod @classmethod
def from_dict(cls, ledger, d): # type: (torba.baseledger.BaseLedger, Dict) -> BaseAccount def from_dict(cls, ledger, d): # type: (torba.baseledger.BaseLedger, Dict) -> BaseAccount

View file

@ -39,7 +39,7 @@ class WalletDatabase(BaseDatabase):
'is_support': txo.script.is_support_claim, 'is_support': txo.script.is_support_claim,
}) })
if txo.script.is_claim_involved: if txo.script.is_claim_involved:
row['claim_name'] = txo.script.values['claim_name'] row['claim_name'] = txo.script.values['claim_name'].decode()
if txo.script.is_update_claim or txo.script.is_support_claim: if txo.script.is_update_claim or txo.script.is_support_claim:
row['claim_id'] = hexlify(txo.script.values['claim_id'][::-1]) row['claim_id'] = hexlify(txo.script.values['claim_id'][::-1])
elif txo.script.is_claim_name: elif txo.script.is_claim_name:

View file

@ -100,7 +100,7 @@ class LbryWalletManager(BaseWalletManager):
'seed_version': json_dict['seed_version'], 'seed_version': json_dict['seed_version'],
'private_key': json_dict['master_private_keys']['x/'], 'private_key': json_dict['master_private_keys']['x/'],
'public_key': json_dict['master_public_keys']['x/'], 'public_key': json_dict['master_public_keys']['x/'],
'certificates': json_dict['claim_certificates'], 'certificates': json_dict.get('claim_certificates', []),
'receiving_gap': 20, 'receiving_gap': 20,
'change_gap': 6, 'change_gap': 6,
'receiving_maximum_uses_per_address': 2, 'receiving_maximum_uses_per_address': 2,
@ -179,8 +179,8 @@ class LbryWalletManager(BaseWalletManager):
"claim_id": hexlify(tx.get_claim_id(txo.position)).decode(), "claim_id": hexlify(tx.get_claim_id(txo.position)).decode(),
"name": name, "name": name,
"amount": bid, "amount": bid,
"address": address.decode(), "address": address,
"txid": tx.id.decode(), "txid": tx.id,
"nout": txo.position, "nout": txo.position,
"value": claim_dict, "value": claim_dict,
"height": -1, "height": -1,

View file

@ -353,7 +353,8 @@ def _verify_proof(name, claim_trie_root, result, height, depth, transaction_clas
claim_id = result['claim_id'] claim_id = result['claim_id']
claim_sequence = result['claim_sequence'] claim_sequence = result['claim_sequence']
claim_script = claim_output.script claim_script = claim_output.script
decoded_name, decoded_value = claim_script.values['claim_name'].decode(), claim_script.values['claim'] decoded_name = claim_script.values['claim_name'].decode()
decoded_value = claim_script.values['claim']
if decoded_name == name: if decoded_name == name:
return _build_response(name, decoded_value, claim_id, return _build_response(name, decoded_value, claim_id,
tx.id, nOut, claim_output.amount, tx.id, nOut, claim_output.amount,
@ -418,7 +419,7 @@ def _decode_claim_result(claim):
decoded = smart_decode(claim['value']) decoded = smart_decode(claim['value'])
claim_dict = decoded.claim_dict claim_dict = decoded.claim_dict
claim['value'] = claim_dict claim['value'] = claim_dict
claim['hex'] = decoded.serialized.encode('hex') claim['hex'] = hexlify(decoded.serialized)
except DecodeError: except DecodeError:
claim['hex'] = claim['value'] claim['hex'] = claim['value']
claim['value'] = None claim['value'] = None

View file

@ -1,5 +1,4 @@
import struct import struct
from binascii import hexlify
from typing import List # pylint: disable=unused-import from typing import List # pylint: disable=unused-import
from twisted.internet import defer # pylint: disable=unused-import from twisted.internet import defer # pylint: disable=unused-import

View file

@ -49,7 +49,7 @@ def package_files(directory):
yield os.path.join('..', path, filename) yield os.path.join('..', path, filename)
package_name = "lbrynet" package_name = "lbry"
base_dir = os.path.abspath(os.path.dirname(__file__)) base_dir = os.path.abspath(os.path.dirname(__file__))
# Get the long description from the README file # Get the long description from the README file
with open(os.path.join(base_dir, 'README.md'), 'rb') as f: with open(os.path.join(base_dir, 'README.md'), 'rb') as f:
@ -65,7 +65,7 @@ setup(
long_description=long_description, long_description=long_description,
keywords="lbry protocol media", keywords="lbry protocol media",
license='MIT', license='MIT',
packages=find_packages(base_dir), packages=find_packages(exclude=('tests',)),
install_requires=requires, install_requires=requires,
entry_points={'console_scripts': console_scripts}, entry_points={'console_scripts': console_scripts},
zip_safe=False, zip_safe=False,

View file

@ -1,4 +0,0 @@
# log_support setups the default Logger class
# and so we need to ensure that it is also
# setup for the tests
from lbrynet.core import log_support

View file

@ -128,37 +128,32 @@ class CommandTestCase(IntegrationTestCase):
self.daemon.component_manager.components.add(file_manager) self.daemon.component_manager.components.add(file_manager)
class ChannelNewCommandTests(CommandTestCase): class CommonWorkflowTests(CommandTestCase):
VERBOSE = True VERBOSE = False
@defer.inlineCallbacks async def test_user_creating_channel_and_publishing_file(self):
def test_new_channel(self):
result = yield self.daemon.jsonrpc_channel_new('@bar', 1*COIN)
self.assertTrue(result['success'])
yield self.ledger.on_transaction.deferred_where(
lambda e: e.tx.id == result['txid']
)
# User checks their balance.
result = await d2f(self.daemon.jsonrpc_wallet_balance(include_unconfirmed=True))
self.assertEqual(result, 10)
class WalletBalanceCommandTests(CommandTestCase): # Decides to get a cool new channel.
channel = await d2f(self.daemon.jsonrpc_channel_new('@spam', 1))
self.assertTrue(channel['success'])
await self.on_transaction_id(channel['txid'])
await self.blockchain.generate(1)
await self.on_transaction_id(channel['txid'])
VERBOSE = True # Check balance again.
result = await d2f(self.daemon.jsonrpc_wallet_balance(include_unconfirmed=True))
self.assertEqual(result, 8.99)
@defer.inlineCallbacks # Now lets publish a hello world file to the channel.
def test_wallet_balance(self):
result = yield self.daemon.jsonrpc_wallet_balance()
self.assertEqual(result, 10*COIN)
class PublishCommandTests(CommandTestCase):
VERBOSE = True
@defer.inlineCallbacks
def test_publish(self):
with tempfile.NamedTemporaryFile() as file: with tempfile.NamedTemporaryFile() as file:
file.write(b'hello world!') file.write(b'hello world!')
file.flush() file.flush()
result = yield self.daemon.jsonrpc_publish('foo', 1, file_path=file.name) result = await d2f(self.daemon.jsonrpc_publish(
'foo', 1, file_path=file.name, channel_name='@spam', channel_id=channel['claim_id']
))
print(result) print(result)

View file

@ -40,7 +40,7 @@ example_claim_dict = {
class BasicTransactionTest(IntegrationTestCase): class BasicTransactionTest(IntegrationTestCase):
VERBOSE = True VERBOSE = False
async def test_creating_updating_and_abandoning_claim_with_channel(self): async def test_creating_updating_and_abandoning_claim_with_channel(self):
@ -87,13 +87,6 @@ class BasicTransactionTest(IntegrationTestCase):
await self.blockchain.generate(1) await self.blockchain.generate(1)
await self.on_transaction(abandon_tx) await self.on_transaction(abandon_tx)
await self.blockchain.generate(1) # should not resolve, but does, why?
await self.blockchain.generate(1) # response = await d2f(self.ledger.resolve(0, 10, 'lbry://@bar/foo'))
await self.blockchain.generate(1) # self.assertNotIn('lbry://@bar/foo', response)
await self.blockchain.generate(1)
await self.blockchain.generate(1)
await asyncio.sleep(5)
response = await d2f(self.ledger.resolve(0, 10, 'lbry://@bar/foo'))
self.assertNotIn('lbry://@bar/foo', response)

View file

@ -1,4 +1,4 @@
from io import StringIO from io import BytesIO
import mock import mock
from twisted.internet import defer from twisted.internet import defer
@ -8,8 +8,7 @@ from twisted.trial import unittest
from lbrynet.core import Peer from lbrynet.core import Peer
from lbrynet.core.server import BlobRequestHandler from lbrynet.core.server import BlobRequestHandler
from lbrynet.core.PaymentRateManager import NegotiatedPaymentRateManager, BasePaymentRateManager from lbrynet.core.PaymentRateManager import NegotiatedPaymentRateManager, BasePaymentRateManager
from tests.mocks\ from unit.mocks import BlobAvailabilityTracker as DummyBlobAvailabilityTracker, mock_conf_settings
import BlobAvailabilityTracker as DummyBlobAvailabilityTracker, mock_conf_settings
class TestBlobRequestHandlerQueries(unittest.TestCase): class TestBlobRequestHandlerQueries(unittest.TestCase):
@ -119,7 +118,7 @@ class TestBlobRequestHandlerSender(unittest.TestCase):
def test_file_is_sent_to_consumer(self): def test_file_is_sent_to_consumer(self):
# TODO: also check that the expected payment values are set # TODO: also check that the expected payment values are set
consumer = proto_helpers.StringTransport() consumer = proto_helpers.StringTransport()
test_file = StringIO('test') test_file = BytesIO(b'test')
handler = BlobRequestHandler.BlobRequestHandler(None, None, None, None) handler = BlobRequestHandler.BlobRequestHandler(None, None, None, None)
handler.peer = mock.create_autospec(Peer.Peer) handler.peer = mock.create_autospec(Peer.Peer)
handler.currently_uploading = mock.Mock() handler.currently_uploading = mock.Mock()

View file

@ -1,14 +1,14 @@
from twisted.trial import unittest from twisted.trial import unittest
from twisted.internet import defer from twisted.internet import defer
from lbrynet.wallet.ledger import MainNetLedger from lbrynet.wallet.ledger import MainNetLedger, WalletDatabase
from lbrynet.wallet.account import Account from lbrynet.wallet.account import Account
class TestAccount(unittest.TestCase): class TestAccount(unittest.TestCase):
def setUp(self): def setUp(self):
self.ledger = MainNetLedger(db=MainNetLedger.database_class(':memory:')) self.ledger = MainNetLedger({'db': WalletDatabase(':memory:')})
return self.ledger.db.start() return self.ledger.db.start()
@defer.inlineCallbacks @defer.inlineCallbacks
@ -44,28 +44,29 @@ class TestAccount(unittest.TestCase):
) )
self.assertEqual( self.assertEqual(
account.private_key.extended_key_string(), account.private_key.extended_key_string(),
b'xprv9s21ZrQH143K42ovpZygnjfHdAqSd9jo7zceDfPRogM7bkkoNVv7DRNLEoB8' 'xprv9s21ZrQH143K42ovpZygnjfHdAqSd9jo7zceDfPRogM7bkkoNVv7DRNLEoB8'
b'HoirMgH969NrgL8jNzLEegqFzPRWM37GXd4uE8uuRkx4LAe' 'HoirMgH969NrgL8jNzLEegqFzPRWM37GXd4uE8uuRkx4LAe'
) )
self.assertEqual( self.assertEqual(
account.public_key.extended_key_string(), account.public_key.extended_key_string(),
b'xpub661MyMwAqRbcGWtPvbWh9sc2BCfw2cTeVDYF23o3N1t6UZ5wv3EMmDgp66FxH' 'xpub661MyMwAqRbcGWtPvbWh9sc2BCfw2cTeVDYF23o3N1t6UZ5wv3EMmDgp66FxH'
b'uDtWdft3B5eL5xQtyzAtkdmhhC95gjRjLzSTdkho95asu9' 'uDtWdft3B5eL5xQtyzAtkdmhhC95gjRjLzSTdkho95asu9'
) )
address = yield account.receiving.ensure_address_gap() address = yield account.receiving.ensure_address_gap()
self.assertEqual(address[0], b'bCqJrLHdoiRqEZ1whFZ3WHNb33bP34SuGx') self.assertEqual(address[0], 'bCqJrLHdoiRqEZ1whFZ3WHNb33bP34SuGx')
private_key = yield self.ledger.get_private_key_for_address(b'bCqJrLHdoiRqEZ1whFZ3WHNb33bP34SuGx') private_key = yield self.ledger.get_private_key_for_address('bCqJrLHdoiRqEZ1whFZ3WHNb33bP34SuGx')
self.assertEqual( self.assertEqual(
private_key.extended_key_string(), private_key.extended_key_string(),
b'xprv9vwXVierUTT4hmoe3dtTeBfbNv1ph2mm8RWXARU6HsZjBaAoFaS2FRQu4fptR' 'xprv9vwXVierUTT4hmoe3dtTeBfbNv1ph2mm8RWXARU6HsZjBaAoFaS2FRQu4fptR'
b'AyJWhJW42dmsEaC1nKnVKKTMhq3TVEHsNj1ca3ciZMKktT' 'AyJWhJW42dmsEaC1nKnVKKTMhq3TVEHsNj1ca3ciZMKktT'
) )
private_key = yield self.ledger.get_private_key_for_address(b'BcQjRlhDOIrQez1WHfz3whnB33Bp34sUgX') private_key = yield self.ledger.get_private_key_for_address('BcQjRlhDOIrQez1WHfz3whnB33Bp34sUgX')
self.assertIsNone(private_key) self.assertIsNone(private_key)
def test_load_and_save_account(self): def test_load_and_save_account(self):
account_data = { account_data = {
'name': 'Main Account',
'seed': 'seed':
"carbon smart garage balance margin twelve chest sword toast envelope bottom stomac" "carbon smart garage balance margin twelve chest sword toast envelope bottom stomac"
"h absent", "h absent",
@ -76,10 +77,12 @@ class TestAccount(unittest.TestCase):
'public_key': 'public_key':
'xpub661MyMwAqRbcGWtPvbWh9sc2BCfw2cTeVDYF23o3N1t6UZ5wv3EMmDgp66FxH' 'xpub661MyMwAqRbcGWtPvbWh9sc2BCfw2cTeVDYF23o3N1t6UZ5wv3EMmDgp66FxH'
'uDtWdft3B5eL5xQtyzAtkdmhhC95gjRjLzSTdkho95asu9', 'uDtWdft3B5eL5xQtyzAtkdmhhC95gjRjLzSTdkho95asu9',
'certificates': {},
'receiving_gap': 10, 'receiving_gap': 10,
'receiving_maximum_use_per_address': 2, 'receiving_maximum_uses_per_address': 2,
'change_gap': 10, 'change_gap': 10,
'change_maximum_use_per_address': 2, 'change_maximum_uses_per_address': 2,
'is_hd': True
} }
account = Account.from_dict(self.ledger, account_data) account = Account.from_dict(self.ledger, account_data)

View file

@ -17,9 +17,8 @@ setenv =
PYTHONHASHSEED=0 PYTHONHASHSEED=0
integration: LEDGER=lbrynet.wallet integration: LEDGER=lbrynet.wallet
commands = commands =
unit: pylint lbrynet unit: pylint --rcfile=../.pylintrc ../lbrynet
unit: coverage run -p --source={envsitepackagesdir}/lbrynet -m twisted.trial functional unit unit: coverage run -p --source={envsitepackagesdir}/lbrynet -m twisted.trial functional unit
integration: orchstr8 download integration: orchstr8 download
integration: coverage run -p --source={envsitepackagesdir}/lbrynet -m twisted.trial --reactor=asyncio integration.wallet.test_transactions.BasicTransactionTest integration: coverage run -p --source={envsitepackagesdir}/lbrynet -m twisted.trial --reactor=asyncio integration.wallet.test_transactions.BasicTransactionTest
integration: coverage run -p --source={envsitepackagesdir}/lbrynet -m twisted.trial --reactor=asyncio integration.wallet.test_commands.ChannelNewCommandTests integration: coverage run -p --source={envsitepackagesdir}/lbrynet -m twisted.trial --reactor=asyncio integration.wallet.test_commands.CommonWorkflowTests
#integration: coverage run -p --source={envsitepackagesdir}/lbrynet -m twisted.trial --reactor=asyncio integration.wallet.test_commands.PublishCommandTests