lbry-sdk/lbry/wallet/manager.py

148 lines
4.9 KiB
Python
Raw Normal View History

2018-05-26 05:26:07 +02:00
import os
2018-07-21 20:12:29 +02:00
import json
2020-01-03 04:50:27 +01:00
import typing
import logging
2020-01-03 04:18:49 +01:00
import asyncio
2019-05-29 07:21:54 +02:00
from binascii import unhexlify
from decimal import Decimal
2020-01-03 04:18:49 +01:00
from typing import List, Type, MutableSequence, MutableMapping, Optional
from lbry.error import KeyFeeAboveMaxAllowedError
2019-06-21 06:58:44 +02:00
from lbry.conf import Config
2018-06-14 21:18:36 +02:00
2020-01-03 04:18:49 +01:00
from .account import Account
2020-05-01 15:33:10 +02:00
from lbry.blockchain.dewies import dewies_to_lbc
from lbry.blockchain.ledger import Ledger
from lbry.db import Database
from lbry.blockchain.ledger import Ledger
from lbry.blockchain.transaction import Transaction, Output
2020-01-03 04:18:49 +01:00
2020-05-01 15:33:10 +02:00
from .wallet import Wallet, WalletStorage, ENCRYPT_ON_DISK
2020-01-03 04:50:27 +01:00
log = logging.getLogger(__name__)
2020-01-03 04:18:49 +01:00
class WalletManager:
2020-05-01 15:33:10 +02:00
def __init__(self, ledger: Ledger, db: Database,
wallets: MutableSequence[Wallet] = None,
2020-01-03 04:18:49 +01:00
ledgers: MutableMapping[Type[Ledger], Ledger] = None) -> None:
2020-05-01 15:33:10 +02:00
self.ledger = ledger
self.db = db
2020-01-03 04:18:49 +01:00
self.wallets = wallets or []
self.ledgers = ledgers or {}
self.running = False
self.config: Optional[Config] = None
2020-05-01 15:33:10 +02:00
async def open(self):
conf = self.ledger.conf
wallets_directory = os.path.join(conf.wallet_dir, 'wallets')
if not os.path.exists(wallets_directory):
os.mkdir(wallets_directory)
for wallet_file in conf.wallets:
wallet_path = os.path.join(wallets_directory, wallet_file)
2020-01-03 04:18:49 +01:00
wallet_storage = WalletStorage(wallet_path)
2020-05-01 15:33:10 +02:00
wallet = Wallet.from_storage(self.ledger, self.db, wallet_storage)
self.wallets.append(wallet)
2020-01-03 04:18:49 +01:00
2020-05-01 15:33:10 +02:00
self.ledger.coin_selection_strategy = self.ledger.conf.coin_selection_strategy
default_wallet = self.default_wallet
if default_wallet.default_account is None:
log.info('Wallet at %s is empty, generating a default account.', default_wallet.id)
default_wallet.generate_account()
default_wallet.save()
if default_wallet.is_locked and default_wallet.preferences.get(ENCRYPT_ON_DISK) is None:
default_wallet.preferences[ENCRYPT_ON_DISK] = True
default_wallet.save()
2020-01-03 04:18:49 +01:00
def import_wallet(self, path):
storage = WalletStorage(path)
2020-05-01 15:33:10 +02:00
wallet = Wallet.from_storage(self.ledger, self.db, storage)
2020-01-03 04:18:49 +01:00
self.wallets.append(wallet)
return wallet
2020-01-03 04:18:49 +01:00
@property
def default_wallet(self):
for wallet in self.wallets:
return wallet
2018-05-26 05:26:07 +02:00
2020-01-03 04:18:49 +01:00
@property
def default_account(self):
for wallet in self.wallets:
return wallet.default_account
@property
def accounts(self):
for wallet in self.wallets:
yield from wallet.accounts
async def start(self):
self.running = True
await asyncio.gather(*(
l.start() for l in self.ledgers.values()
))
async def stop(self):
await asyncio.gather(*(
l.stop() for l in self.ledgers.values()
))
self.running = False
def get_wallet_or_default(self, wallet_id: Optional[str]) -> Wallet:
if wallet_id is None:
return self.default_wallet
return self.get_wallet_or_error(wallet_id)
def get_wallet_or_error(self, wallet_id: str) -> Wallet:
for wallet in self.wallets:
if wallet.id == wallet_id:
return wallet
raise ValueError(f"Couldn't find wallet: {wallet_id}.")
@staticmethod
def get_balance(wallet):
accounts = wallet.accounts
if not accounts:
return 0
return accounts[0].ledger.db.get_balance(wallet=wallet, accounts=accounts)
2018-05-26 05:26:07 +02:00
def check_locked(self):
2019-10-14 05:43:06 +02:00
return self.default_wallet.is_locked
2018-05-26 05:26:07 +02:00
2019-12-05 21:34:24 +01:00
async def reset(self):
2019-12-11 00:32:50 +01:00
self.ledger.config = {
2019-12-05 21:34:24 +01:00
'auto_connect': True,
'default_servers': self.config.lbryum_servers,
'data_path': self.config.wallet_dir,
}
await self.ledger.stop()
await self.ledger.start()
2020-03-21 08:32:03 +01:00
async def get_best_blockhash(self):
if len(self.ledger.headers) <= 0:
return self.ledger.genesis_hash
2020-03-21 08:32:03 +01:00
return (await self.ledger.headers.hash(self.ledger.headers.height)).decode()
2018-05-26 05:26:07 +02:00
def get_unused_address(self):
2018-07-12 18:44:19 +02:00
return self.default_account.receiving.get_or_create_usable_address()
2018-05-26 05:26:07 +02:00
2020-04-11 23:27:41 +02:00
async def get_transaction(self, tx_hash: bytes):
tx = await self.db.get_transaction(tx_hash=tx_hash)
if tx:
return tx
try:
2020-04-11 23:27:41 +02:00
raw, merkle = await self.ledger.network.get_transaction_and_merkle(tx_hash)
except CodeMessageError as e:
if 'No such mempool or blockchain transaction.' in e.message:
return {'success': False, 'code': 404, 'message': 'transaction not found'}
return {'success': False, 'code': e.code, 'message': e.message}
height = merkle.get('block_height')
tx = Transaction(unhexlify(raw), height=height)
if height and height > 0:
await self.ledger.maybe_verify_transaction(tx, height, merkle)
2018-12-04 01:40:18 +01:00
return tx