wallet_id related test fixes

This commit is contained in:
Lex Berezhny 2019-09-20 09:25:50 -04:00
parent 84587ac232
commit ea434e3469
5 changed files with 65 additions and 44 deletions

View file

@ -1014,7 +1014,7 @@ class Daemon(metaclass=JSONRPCServerType):
Get preference value for key or all values if not key is passed in. Get preference value for key or all values if not key is passed in.
Usage: Usage:
preference_get [<key>] preference_get [<key>] [--wallet_id=<wallet_id>]
Options: Options:
--key=<key> : (str) key associated with value --key=<key> : (str) key associated with value
@ -1024,7 +1024,8 @@ class Daemon(metaclass=JSONRPCServerType):
Returns: Returns:
(dict) Dictionary of preference(s) (dict) Dictionary of preference(s)
""" """
account = self.get_account_or_default(account_id) wallet = self.wallet_manager.get_wallet_or_default(wallet_id)
account = wallet.get_account_or_default(account_id)
if key: if key:
if key in account.preferences: if key in account.preferences:
return {key: account.preferences[key]} return {key: account.preferences[key]}
@ -1036,7 +1037,7 @@ class Daemon(metaclass=JSONRPCServerType):
Set preferences Set preferences
Usage: Usage:
preference_set (<key>) (<value>) preference_set (<key>) (<value>) [--wallet_id=<wallet_id>]
Options: Options:
--key=<key> : (str) key associated with value --key=<key> : (str) key associated with value
@ -1047,7 +1048,8 @@ class Daemon(metaclass=JSONRPCServerType):
Returns: Returns:
(dict) Dictionary with key/value of new preference (dict) Dictionary with key/value of new preference
""" """
account = self.get_account_or_default(account_id) wallet = self.wallet_manager.get_wallet_or_default(wallet_id)
account = wallet.get_account_or_default(account_id)
if value and isinstance(value, str) and value[0] in ('[', '{'): if value and isinstance(value, str) and value[0] in ('[', '{'):
value = json.loads(value) value = json.loads(value)
account.preferences[key] = value account.preferences[key] = value
@ -1199,7 +1201,8 @@ class Daemon(metaclass=JSONRPCServerType):
@requires("wallet") @requires("wallet")
async def jsonrpc_account_add( async def jsonrpc_account_add(
self, account_name, single_key=False, seed=None, private_key=None, public_key=None): self, account_name, wallet_id=None, single_key=False,
seed=None, private_key=None, public_key=None):
""" """
Add a previously created account from a seed, private key or public key (read-only). Add a previously created account from a seed, private key or public key (read-only).
Specify --single_key for single address or vanity address accounts. Specify --single_key for single address or vanity address accounts.
@ -1207,7 +1210,7 @@ class Daemon(metaclass=JSONRPCServerType):
Usage: Usage:
account_add (<account_name> | --account_name=<account_name>) account_add (<account_name> | --account_name=<account_name>)
(--seed=<seed> | --private_key=<private_key> | --public_key=<public_key>) (--seed=<seed> | --private_key=<private_key> | --public_key=<public_key>)
[--single_key] [--single_key] [--wallet_id=<wallet_id>]
Options: Options:
--account_name=<account_name> : (str) name of the account to add --account_name=<account_name> : (str) name of the account to add
@ -1215,11 +1218,13 @@ class Daemon(metaclass=JSONRPCServerType):
--private_key=<private_key> : (str) private key for new account --private_key=<private_key> : (str) private key for new account
--public_key=<public_key> : (str) public key for new account --public_key=<public_key> : (str) public key for new account
--single_key : (bool) create single key account, default is multi-key --single_key : (bool) create single key account, default is multi-key
--wallet_id=<wallet_id> : (str) restrict operation to specific wallet
Returns: {Account} Returns: {Account}
""" """
wallet = self.wallet_manager.get_wallet_or_default(wallet_id)
account = LBCAccount.from_dict( account = LBCAccount.from_dict(
self.ledger, self.default_wallet, { self.ledger, wallet, {
'name': account_name, 'name': account_name,
'seed': seed, 'seed': seed,
'private_key': private_key, 'private_key': private_key,
@ -1229,40 +1234,37 @@ class Daemon(metaclass=JSONRPCServerType):
} }
} }
) )
wallet.save()
if self.ledger.network.is_connected: if self.ledger.network.is_connected:
await self.ledger.subscribe_account(account) await self.ledger.subscribe_account(account)
self.default_wallet.save()
return account return account
@requires("wallet") @requires("wallet")
async def jsonrpc_account_create(self, account_name, single_key=False): async def jsonrpc_account_create(self, account_name, single_key=False, wallet_id=None):
""" """
Create a new account. Specify --single_key if you want to use Create a new account. Specify --single_key if you want to use
the same address for all transactions (not recommended). the same address for all transactions (not recommended).
Usage: Usage:
account_create (<account_name> | --account_name=<account_name>) [--single_key] account_create (<account_name> | --account_name=<account_name>)
[--single_key] [--wallet_id=<wallet_id>]
Options: Options:
--account_name=<account_name> : (str) name of the account to create --account_name=<account_name> : (str) name of the account to create
--single_key : (bool) create single key account, default is multi-key --single_key : (bool) create single key account, default is multi-key
--wallet_id=<wallet_id> : (str) restrict operation to specific wallet
Returns: {Account} Returns: {Account}
""" """
wallet = self.wallet_manager.get_wallet_or_default(wallet_id)
account = LBCAccount.generate( account = LBCAccount.generate(
self.ledger, self.default_wallet, account_name, { self.ledger, wallet, account_name, {
'name': SingleKey.name if single_key else HierarchicalDeterministic.name 'name': SingleKey.name if single_key else HierarchicalDeterministic.name
} }
) )
wallet.save()
if self.ledger.network.is_connected: if self.ledger.network.is_connected:
await self.ledger.subscribe_account(account) await self.ledger.subscribe_account(account)
self.default_wallet.save()
return account return account
@requires("wallet") @requires("wallet")
@ -1538,60 +1540,65 @@ class Daemon(metaclass=JSONRPCServerType):
""" """
@requires("wallet") @requires("wallet")
def jsonrpc_sync_hash(self): def jsonrpc_sync_hash(self, wallet_id=None):
""" """
Deterministic hash of the wallet. Deterministic hash of the wallet.
Usage: Usage:
sync_hash sync_hash [<wallet_id> | --wallet_id=<wallet_id>]
Options: Options:
--wallet_id=<wallet_id> : (str) wallet for which to generate hash
Returns: Returns:
(str) sha256 hash of wallet (str) sha256 hash of wallet
""" """
return hexlify(self.default_wallet.hash).decode() wallet = self.wallet_manager.get_wallet_or_default(wallet_id)
return hexlify(wallet.hash).decode()
@requires("wallet") @requires("wallet")
def jsonrpc_sync_apply(self, password, data=None, encrypt_password=None): def jsonrpc_sync_apply(self, password, data=None, encrypt_password=None, wallet_id=None):
""" """
Apply incoming synchronization data, if provided, and then produce a sync hash and Apply incoming synchronization data, if provided, and then produce a sync hash and
an encrypted wallet. an encrypted wallet.
Usage: Usage:
sync_apply <password> [--data=<data>] [--encrypt-password=<encrypt_password>] sync_apply <password> [--data=<data>] [--encrypt-password=<encrypt_password>]
[--wallet_id=<wallet_id>]
Options: Options:
--password=<password> : (str) password to decrypt incoming and encrypt outgoing data --password=<password> : (str) password to decrypt incoming and encrypt outgoing data
--data=<data> : (str) incoming sync data, if any --data=<data> : (str) incoming sync data, if any
--encrypt-password=<encrypt_password> : (str) password to encrypt outgoing data if different --encrypt-password=<encrypt_password> : (str) password to encrypt outgoing data if different
from the decrypt password, used during password changes from the decrypt password, used during password changes
--wallet_id=<wallet_id> : (str) wallet being sync'ed
Returns: Returns:
(map) sync hash and data (map) sync hash and data
""" """
wallet = self.wallet_manager.get_wallet_or_default(wallet_id)
if data is not None: if data is not None:
decrypted_data = Wallet.unpack(password, data) decrypted_data = Wallet.unpack(password, data)
for account_data in decrypted_data['accounts']: for account_data in decrypted_data['accounts']:
_, _, pubkey = LBCAccount.keys_from_dict(self.ledger, account_data) _, _, pubkey = LBCAccount.keys_from_dict(self.ledger, account_data)
account_id = pubkey.address account_id = pubkey.address
local_match = None local_match = None
for local_account in self.default_wallet.accounts: for local_account in wallet.accounts:
if account_id == local_account.id: if account_id == local_account.id:
local_match = local_account local_match = local_account
break break
if local_match is not None: if local_match is not None:
local_match.apply(account_data) local_match.apply(account_data)
else: else:
new_account = LBCAccount.from_dict(self.ledger, self.default_wallet, account_data) new_account = LBCAccount.from_dict(self.ledger, wallet, account_data)
if self.ledger.network.is_connected: if self.ledger.network.is_connected:
asyncio.create_task(self.ledger.subscribe_account(new_account)) asyncio.create_task(self.ledger.subscribe_account(new_account))
self.default_wallet.save() wallet.save()
encrypted = self.default_wallet.pack(encrypt_password or password) encrypted = wallet.pack(encrypt_password or password)
return { return {
'hash': self.jsonrpc_sync_hash(), 'hash': self.jsonrpc_sync_hash(wallet_id),
'data': encrypted.decode() 'data': encrypted.decode()
} }
@ -1616,7 +1623,8 @@ class Daemon(metaclass=JSONRPCServerType):
Returns: Returns:
(bool) true, if address is associated with current wallet (bool) true, if address is associated with current wallet
""" """
account = self.get_account_or_default(account_id) wallet = self.wallet_manager.get_wallet_or_default(wallet_id)
account = wallet.get_account_or_default(account_id)
match = await self.ledger.db.get_address(address=address, accounts=[account]) match = await self.ledger.db.get_address(address=address, accounts=[account])
if match is not None: if match is not None:
return True return True
@ -1640,13 +1648,16 @@ class Daemon(metaclass=JSONRPCServerType):
Returns: {Paginated[Address]} Returns: {Paginated[Address]}
""" """
wallet = self.wallet_manager.get_wallet_or_default(wallet_id)
constraints = { constraints = {
'cols': ('address', 'account', 'used_times') 'cols': ('address', 'account', 'used_times', 'pubkey', 'chain_code', 'n', 'depth')
} }
if address: if address:
constraints['address'] = address constraints['address'] = address
if account_id: if account_id:
constraints['accounts'] = [self.get_account_or_error(account_id)] constraints['accounts'] = [wallet.get_account_or_error(account_id)]
else:
constraints['accounts'] = wallet.accounts
return maybe_paginate( return maybe_paginate(
self.ledger.get_addresses, self.ledger.get_addresses,
self.ledger.get_address_count, self.ledger.get_address_count,
@ -3312,7 +3323,8 @@ class Daemon(metaclass=JSONRPCServerType):
Returns: Returns:
None None
""" """
return self.get_account_or_default(account_id).release_all_outputs() wallet = self.wallet_manager.get_wallet_or_default(wallet_id)
return wallet.get_account_or_default(account_id).release_all_outputs()
BLOB_DOC = """ BLOB_DOC = """
Blob management. Blob management.
@ -3736,7 +3748,7 @@ class Daemon(metaclass=JSONRPCServerType):
@requires(WALLET_COMPONENT) @requires(WALLET_COMPONENT)
async def jsonrpc_comment_create(self, claim_id, comment, parent_id=None, channel_account_id=None, async def jsonrpc_comment_create(self, claim_id, comment, parent_id=None, channel_account_id=None,
channel_name=None, channel_id=None): channel_name=None, channel_id=None, wallet_id=None):
""" """
Create and associate a comment with a claim using your channel identity. Create and associate a comment with a claim using your channel identity.
@ -3745,7 +3757,7 @@ class Daemon(metaclass=JSONRPCServerType):
(<claim_id> | --claim_id=<claim_id>) (<claim_id> | --claim_id=<claim_id>)
[--parent_id=<parent_id>] [--parent_id=<parent_id>]
[--channel_id=<channel_id>] [--channel_name=<channel_name>] [--channel_id=<channel_id>] [--channel_name=<channel_name>]
[--channel_account_id=<channel_account_id>...] [--channel_account_id=<channel_account_id>...] [--wallet_id=<wallet_id>]
Options: Options:
--comment=<comment> : (str) Comment to be made, should be at most 2000 characters. --comment=<comment> : (str) Comment to be made, should be at most 2000 characters.
@ -3755,6 +3767,7 @@ class Daemon(metaclass=JSONRPCServerType):
--channel_name=<channel_name> : (str) The channel you want to post as, prepend with a '@' --channel_name=<channel_name> : (str) The channel you want to post as, prepend with a '@'
--channel_account_id=<channel_account_id> : (str) one or more account ids for accounts to look in --channel_account_id=<channel_account_id> : (str) one or more account ids for accounts to look in
for channel certificates, defaults to all accounts. for channel certificates, defaults to all accounts.
--wallet_id=<wallet_id> : (str) restrict operation to specific wallet
Returns: Returns:
(dict) Comment object if successfully made, (None) otherwise (dict) Comment object if successfully made, (None) otherwise
@ -3769,12 +3782,15 @@ class Daemon(metaclass=JSONRPCServerType):
"timestamp": (int) The time at which comment was entered into the server at, in nanoseconds. "timestamp": (int) The time at which comment was entered into the server at, in nanoseconds.
} }
""" """
wallet = self.wallet_manager.get_wallet_or_default(wallet_id)
comment_body = { comment_body = {
'comment': comment.strip(), 'comment': comment.strip(),
'claim_id': claim_id, 'claim_id': claim_id,
'parent_id': parent_id, 'parent_id': parent_id,
} }
channel = await self.get_channel_or_none(channel_account_id, channel_id, channel_name, for_signing=True) channel = await self.get_channel_or_none(
wallet, channel_account_id, channel_id, channel_name, for_signing=True
)
if channel: if channel:
comment_body.update({ comment_body.update({
'channel_id': channel.claim_id, 'channel_id': channel.claim_id,
@ -3787,15 +3803,16 @@ class Daemon(metaclass=JSONRPCServerType):
return response return response
@requires(WALLET_COMPONENT) @requires(WALLET_COMPONENT)
async def jsonrpc_comment_abandon(self, comment_id): async def jsonrpc_comment_abandon(self, comment_id, wallet_id=None):
""" """
Abandon a comment published under your channel identity. Abandon a comment published under your channel identity.
Usage: Usage:
comment_abandon (<comment_id> | --comment_id=<comment_id>) comment_abandon (<comment_id> | --comment_id=<comment_id>) [--wallet_id=<wallet_id>]
Options: Options:
--comment_id=<comment_id> : (str) The ID of the comment to be abandoned. --comment_id=<comment_id> : (str) The ID of the comment to be abandoned.
--wallet_id=<wallet_id : (str) restrict operation to specific wallet
Returns: Returns:
(dict) Object with the `comment_id` passed in as the key, and a flag indicating if it was abandoned (dict) Object with the `comment_id` passed in as the key, and a flag indicating if it was abandoned
@ -3805,13 +3822,14 @@ class Daemon(metaclass=JSONRPCServerType):
} }
} }
""" """
wallet = self.wallet_manager.get_wallet_or_default(wallet_id)
abandon_comment_body = {'comment_id': comment_id} abandon_comment_body = {'comment_id': comment_id}
channel = await comment_client.jsonrpc_post( channel = await comment_client.jsonrpc_post(
self.conf.comment_server, 'get_channel_from_comment_id', comment_id=comment_id self.conf.comment_server, 'get_channel_from_comment_id', comment_id=comment_id
) )
if 'error' in channel: if 'error' in channel:
return {comment_id: {'abandoned': False}} return {comment_id: {'abandoned': False}}
channel = await self.get_channel_or_none(None, **channel) channel = await self.get_channel_or_none(wallet, None, **channel)
abandon_comment_body.update({ abandon_comment_body.update({
'channel_id': channel.claim_id, 'channel_id': channel.claim_id,
'channel_name': channel.claim_name, 'channel_name': channel.claim_name,

View file

@ -6,6 +6,7 @@ from json import JSONEncoder
from google.protobuf.message import DecodeError from google.protobuf.message import DecodeError
from torba.client.bip32 import PubKey
from lbry.schema.claim import Claim from lbry.schema.claim import Claim
from lbry.wallet.ledger import MainNetLedger, Account from lbry.wallet.ledger import MainNetLedger, Account
from lbry.wallet.transaction import Transaction, Output from lbry.wallet.transaction import Transaction, Output
@ -118,6 +119,8 @@ class JSONResponseEncoder(JSONEncoder):
return self.encode_output(obj) return self.encode_output(obj)
if isinstance(obj, Claim): if isinstance(obj, Claim):
return self.encode_claim(obj) return self.encode_claim(obj)
if isinstance(obj, PubKey):
return obj.extended_key_string()
if isinstance(obj, datetime): if isinstance(obj, datetime):
return obj.strftime("%Y%m%dT%H:%M:%S") return obj.strftime("%Y%m%dT%H:%M:%S")
if isinstance(obj, Decimal): if isinstance(obj, Decimal):

View file

@ -135,7 +135,7 @@ class WalletDatabase(BaseDatabase):
await self.db.execute_fetchall( await self.db.execute_fetchall(
"UPDATE txo SET is_reserved = 0 WHERE" "UPDATE txo SET is_reserved = 0 WHERE"
" is_reserved = 1 AND txo.address IN (" " is_reserved = 1 AND txo.address IN ("
" SELECT address from pubkey_address WHERE account = ?" " SELECT address from account_address WHERE account = ?"
" )", (account.public_key.address, ) " )", (account.public_key.address, )
) )
@ -143,9 +143,9 @@ class WalletDatabase(BaseDatabase):
return self.db.execute_fetchall(f""" return self.db.execute_fetchall(f"""
select txo.amount, exists(select * from txi where txi.txoid=txo.txoid) as spent, select txo.amount, exists(select * from txi where txi.txoid=txo.txoid) as spent,
(txo.txid in (txo.txid in
(select txi.txid from txi join pubkey_address a on txi.address = a.address (select txi.txid from txi join account_address a on txi.address = a.address
where a.account = ?)) as from_me, where a.account = ?)) as from_me,
(txo.address in (select address from pubkey_address where account=?)) as to_me, (txo.address in (select address from account_address where account=?)) as to_me,
tx.height tx.height
from txo join tx using (txid) where txo_type={TXO_TYPES['support']} from txo join tx using (txid) where txo_type={TXO_TYPES['support']}
""", (account_id, account_id)) """, (account_id, account_id))

View file

@ -4,9 +4,9 @@ from lbry.testcase import CommandTestCase
class AddressManagement(CommandTestCase): class AddressManagement(CommandTestCase):
async def test_address_list(self): async def test_address_list(self):
addresses = await self.daemon.jsonrpc_address_list() addresses = await self.out(self.daemon.jsonrpc_address_list())
self.assertEqual(27, len(addresses)) self.assertEqual(27, len(addresses))
single = await self.daemon.jsonrpc_address_list(addresses[11]['address']) single = await self.out(self.daemon.jsonrpc_address_list(addresses[11]['address']))
self.assertEqual(1, len(single)) self.assertEqual(1, len(single))
self.assertEqual(single[0], addresses[11]) self.assertEqual(single[0], addresses[11])

View file

@ -600,8 +600,8 @@ class BaseDatabase(SQLiteMixin):
**constraints **constraints
)) ))
async def get_addresses(self, **constraints): async def get_addresses(self, cols=None, **constraints):
cols = ( cols = cols or (
'address', 'account', 'chain', 'history', 'used_times', 'address', 'account', 'chain', 'history', 'used_times',
'pubkey', 'chain_code', 'n', 'depth' 'pubkey', 'chain_code', 'n', 'depth'
) )