This commit is contained in:
Alex Grintsvayg 2019-11-26 12:12:24 -05:00
parent 783f454f8e
commit e634397ecb
No known key found for this signature in database
GPG key ID: AEB3F089F86A22B5
5 changed files with 98 additions and 8 deletions

View file

@ -0,0 +1,51 @@
import asyncio
import logging
from torba.client.wallet import Wallet
from lbry.wallet.ledger import MainNetLedger
from lbry.wallet.dewies import lbc_to_dewies
from lbry.wallet.transaction import Output, Transaction
log = logging.getLogger(__name__)
class WalletServerPayer:
def __init__(self, ledger: MainNetLedger, wallet: Wallet):
self.ledger = ledger
self.wallet = wallet
self.running = False
self.task = None
async def pay(self):
while self.running:
await asyncio.sleep(24 * 60 * 60)
features = await self.ledger.network.get_server_features()
address = features['payment_address']
if not self.ledger.is_valid_address(address):
raise Exception(f"Invalid address: {address}")
if self.wallet.is_locked:
raise Exception("Cannot spend funds with locked wallet")
amount = lbc_to_dewies(features['daily_fee']) # check that this is in lbc and not dewies
# todo: check that amount is less than our max
tx = await Transaction.create([],
[Output.pay_pubkey_hash(amount, self.ledger.address_to_hash160(address))],
self.wallet.get_accounts_or_all(None),
self.wallet.get_account_or_default(None))
await self.ledger.broadcast(tx)
await self.analytics_manager.send_credits_sent()
async def start(self):
self.running = True
self.task = asyncio.ensure_future(self.pay())
self.task.add_done_callback(lambda _: log.info("Stopping wallet server payments."))
async def stop(self):
if self.running:
self.running = False
self.task.cancel()

View file

@ -4,6 +4,8 @@ import lbry.wallet
from lbry import __version__ as sdk_version
from torba.client.basenetwork import ClientSession
from torba.testcase import IntegrationTestCase
from torba.orchstr8.node import SPVNode
from lbry.testcase import CommandTestCase
class TestSessions(IntegrationTestCase):
@ -49,3 +51,40 @@ class TestSegwitServer(IntegrationTestCase):
async def test_at_least_it_starts(self):
await asyncio.wait_for(self.ledger.network.get_headers(0, 1), 1.0)
class TestUsagePayment(CommandTestCase):
async def test_single_server_payment(self):
# create wallet server
# set payment address and fee rate on server
# connect to server
# fast forward 24 hours
# check that payment was sent to server
address = (await self.account.receiving.get_addresses(limit=1, only_usable=True))[0]
node = SPVNode(self.conductor.spv_module, node_number=2)
await node.start(self.blockchain, extraconf={"PAYMENT_ADDRESS": address, "DAILY_FEE": "1"})
self.ledger.network.config['default_servers'] = [(node.hostname, node.port)]
await self.ledger.stop()
await self.ledger.start()
features = await self.ledger.network.get_server_features()
pass
# async def test_daily_payment(self):
# node2 = SPVNode(self.conductor.spv_module, node_number=2)
# self.ledger.network.config['default_servers'].append((node2.hostname, node2.port))
# await asyncio.wait_for(self.ledger.stop(), timeout=1)
# await asyncio.wait_for(self.ledger.start(), timeout=1)
# self.ledger.network.session_pool.new_connection_event.clear()
# await node2.start(self.blockchain)
# # this is only to speed up the test as retrying would take 4+ seconds
# for session in self.ledger.network.session_pool.sessions:
# session.trigger_urgent_reconnect.set()
# await asyncio.wait_for(self.ledger.network.session_pool.new_connection_event.wait(), timeout=1)

View file

@ -33,7 +33,7 @@ class NetworkTests(IntegrationTestCase):
address = (await self.account.get_addresses(limit=1))[0]
os.environ.update({
'DESCRIPTION': 'Fastest server in the west.',
'DONATION_ADDRESS': address,
'PAYMENT_ADDRESS': address,
'DAILY_FEE': '42'})
await self.conductor.spv_node.start(self.conductor.blockchain_node)
await self.ledger.network.on_connected.first

View file

@ -71,7 +71,7 @@ class Env:
self.tor_proxy_host = self.default('TOR_PROXY_HOST', 'localhost')
self.tor_proxy_port = self.integer('TOR_PROXY_PORT', None)
# The electrum client takes the empty string as unspecified
self.donation_address = self.default('DONATION_ADDRESS', '')
self.payment_address = self.default('PAYMENT_ADDRESS', '')
# Server limits to help prevent DoS
self.max_send = self.integer('MAX_SEND', 1000000)
self.max_subs = self.integer('MAX_SUBS', 250000)

View file

@ -751,7 +751,7 @@ class ElectrumX(SessionBase):
'protocol_max': max_str,
'genesis_hash': env.coin.GENESIS_HASH,
'description': env.description,
'payment_address': env.donation_address,
'payment_address': env.payment_address,
'daily_fee': env.daily_fee,
'hash_function': 'sha256',
}
@ -1073,14 +1073,14 @@ class ElectrumX(SessionBase):
('$SERVER_VERSION', self.version),
('$DAEMON_VERSION', daemon_version),
('$DAEMON_SUBVERSION', network_info['subversion']),
('$DONATION_ADDRESS', self.env.donation_address),
('$PAYMENT_ADDRESS', self.env.payment_address),
]:
banner = banner.replace(*pair)
return banner
async def donation_address(self):
"""Return the donation address as a string, empty if there is none."""
return self.env.donation_address
async def payment_address(self):
"""Return the payment address as a string, empty if there is none."""
return self.env.payment_address
async def banner(self):
"""Return the server banner text."""
@ -1265,7 +1265,7 @@ class ElectrumX(SessionBase):
'blockchain.transaction.get_merkle': self.transaction_merkle,
'server.add_peer': self.add_peer,
'server.banner': self.banner,
'server.donation_address': self.donation_address,
'server.payment_address': self.payment_address,
'server.features': self.server_features_async,
'server.peers.subscribe': self.peers_subscribe,
'server.version': self.server_version,