import os from twisted.internet import defer from torba.constants import COIN from torba.manager import WalletManager as BaseWalletManager class BackwardsCompatibleNetwork: def __init__(self, manager): self.manager = manager def get_local_height(self): return len(self.manager.ledgers.values()[0].headers) def get_server_height(self): return self.get_local_height() class LbryWalletManager(BaseWalletManager): @property def wallet(self): return self @property def network(self): return BackwardsCompatibleNetwork(self) @property def use_encryption(self): # TODO: implement this return False @property def is_first_run(self): return True def check_locked(self): return defer.succeed(False) @classmethod def from_old_config(cls, settings): coin_id = 'lbc_{}'.format(settings['blockchain_name'][-7:]) wallet_manager = cls.from_config({ 'ledgers': {coin_id: {'default_servers': settings['lbryum_servers']}} }) ledger = wallet_manager.ledgers.values()[0] wallet_manager.create_wallet( os.path.join(settings['lbryum_wallet_dir'], 'default_torba_wallet'), ledger.coin_class ) return wallet_manager def start(self): return self.start_ledgers() def stop(self): return self.stop_ledgers() def get_balance(self): return self.default_account.get_balance() def get_best_blockhash(self): return defer.succeed('') def get_unused_address(self): return defer.succeed(self.default_account.get_least_used_receiving_address()) def reserve_points(self, address, amount): # TODO: check if we have enough to cover amount return ReservedPoints(address, amount) def send_points_to_address(self, reserved, amount): account = self.default_account coin = account.coin ledger = coin.ledger tx_class = ledger.transaction_class in_class, out_class = tx_class.input_class, tx_class.output_class destination_address = reserved.identifier.encode('latin1') outputs = [ out_class.pay_pubkey_hash(amount*COIN, coin.address_to_hash160(destination_address)) ] amount += 0.001 amount = amount*COIN # TODO: use CoinSelector utxos = account.get_unspent_utxos() total = account.get_balance() if amount < total and total-amount > 0.00001*COIN: change_destination = account.get_least_used_change_address() outputs.append( out_class.pay_pubkey_hash(total-amount, coin.address_to_hash160(change_destination)) ) tx = tx_class() \ .add_inputs([in_class.spend(utxo) for utxo in utxos]) \ .add_outputs(outputs)\ .sign(account) return ledger.broadcast(tx) def get_wallet_info_query_handler_factory(self): return LBRYcrdAddressQueryHandlerFactory(self) def get_info_exchanger(self): return LBRYcrdAddressRequester(self) class ReservedPoints: def __init__(self, identifier, amount): self.identifier = identifier self.amount = amount class ClientRequest: def __init__(self, request_dict, response_identifier=None): self.request_dict = request_dict self.response_identifier = response_identifier class LBRYcrdAddressRequester: def __init__(self, wallet): self.wallet = wallet self._protocols = [] def send_next_request(self, peer, protocol): if not protocol in self._protocols: r = ClientRequest({'lbrycrd_address': True}, 'lbrycrd_address') d = protocol.add_request(r) d.addCallback(self._handle_address_response, peer, r, protocol) d.addErrback(self._request_failed, peer) self._protocols.append(protocol) return defer.succeed(True) else: return defer.succeed(False) def _handle_address_response(self, response_dict, peer, request, protocol): if request.response_identifier not in response_dict: raise ValueError( "Expected {} in response but did not get it".format(request.response_identifier)) assert protocol in self._protocols, "Responding protocol is not in our list of protocols" address = response_dict[request.response_identifier] self.wallet.update_peer_address(peer, address) def _request_failed(self, error, peer): raise Exception("A peer failed to send a valid public key response. Error: %s, peer: %s", error.getErrorMessage(), str(peer)) class LBRYcrdAddressQueryHandlerFactory: def __init__(self, wallet): self.wallet = wallet def build_query_handler(self): q_h = LBRYcrdAddressQueryHandler(self.wallet) return q_h def get_primary_query_identifier(self): return 'lbrycrd_address' def get_description(self): return "LBRYcrd Address - an address for receiving payments via LBRYcrd" class LBRYcrdAddressQueryHandler: def __init__(self, wallet): self.wallet = wallet self.query_identifiers = ['lbrycrd_address'] self.address = None self.peer = None def register_with_request_handler(self, request_handler, peer): self.peer = peer request_handler.register_query_handler(self, self.query_identifiers) def handle_queries(self, queries): def create_response(address): self.address = address fields = {'lbrycrd_address': address} return fields if self.query_identifiers[0] in queries: d = self.wallet.get_unused_address_for_peer(self.peer) d.addCallback(create_response) return d if self.address is None: raise Exception("Expected a request for an address, but did not receive one") else: return defer.succeed({})