Merge pull request #2728 from lbryio/check-server-version-from-client

check minimum server version from wallet client
This commit is contained in:
Jack Robison 2020-01-15 16:53:10 -05:00 committed by GitHub
commit f2545b98ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 21 additions and 3 deletions

View file

@ -55,6 +55,7 @@ Code | Name | Message
409 | ResolveTimeout | Failed to resolve '{url}' within the timeout. 409 | ResolveTimeout | Failed to resolve '{url}' within the timeout.
410 | KeyFeeAboveMaxAllowed | {message} 410 | KeyFeeAboveMaxAllowed | {message}
411 | InvalidPassword | Password is invalid. 411 | InvalidPassword | Password is invalid.
412 | IncompatibleWalletServer | '{server}:{port}' has an incompatibly old version.
**5xx** | Blob | **Blobs** **5xx** | Blob | **Blobs**
500 | BlobNotFound | Blob not found. 500 | BlobNotFound | Blob not found.
501 | BlobPermissionDenied | Permission denied to read blob. 501 | BlobPermissionDenied | Permission denied to read blob.

View file

@ -209,6 +209,12 @@ class InvalidPasswordError(WalletError):
super().__init__("Password is invalid.") super().__init__("Password is invalid.")
class IncompatibleWalletServerError(WalletError):
def __init__(self, server, port):
super().__init__(f"'{server}:{port}' has an incompatibly old version.")
class BlobError(BaseError): class BlobError(BaseError):
""" """
**Blobs** **Blobs**

View file

@ -5,6 +5,7 @@ from operator import itemgetter
from typing import Dict, Optional, Tuple from typing import Dict, Optional, Tuple
from lbry import __version__ from lbry import __version__
from lbry.error import IncompatibleWalletServerError
from lbry.wallet.rpc import RPCSession as BaseClientSession, Connector, RPCError, ProtocolError from lbry.wallet.rpc import RPCSession as BaseClientSession, Connector, RPCError, ProtocolError
from lbry.wallet.stream import StreamController from lbry.wallet.stream import StreamController
@ -97,8 +98,12 @@ class ClientSession(BaseClientSession):
await self.ensure_server_version() await self.ensure_server_version()
retry_delay = default_delay retry_delay = default_delay
except RPCError as e: except RPCError as e:
log.warning("Server error, ignoring for 1h: %s:%d -- %s", *self.server, e.message) log.debug("Server error, ignoring for 1h: %s:%d -- %s", *self.server, e.message)
retry_delay = 60 * 60 retry_delay = 60 * 60
except IncompatibleWalletServerError:
await self.close()
retry_delay = 60 * 60
log.debug("Wallet server has an incompatible version, retrying in 1h: %s:%d", *self.server)
except (asyncio.TimeoutError, OSError): except (asyncio.TimeoutError, OSError):
await self.close() await self.close()
retry_delay = min(60, retry_delay * 2) retry_delay = min(60, retry_delay * 2)
@ -112,9 +117,12 @@ class ClientSession(BaseClientSession):
async def ensure_server_version(self, required=None, timeout=3): async def ensure_server_version(self, required=None, timeout=3):
required = required or self.network.PROTOCOL_VERSION required = required or self.network.PROTOCOL_VERSION
return await asyncio.wait_for( response = await asyncio.wait_for(
self.send_request('server.version', [__version__, required]), timeout=timeout self.send_request('server.version', [__version__, required]), timeout=timeout
) )
if tuple(int(piece) for piece in response[0].split(".")) < self.network.MINIMUM_REQUIRED:
raise IncompatibleWalletServerError(*self.server)
return response
async def create_connection(self, timeout=6): async def create_connection(self, timeout=6):
connector = Connector(lambda: self, *self.server) connector = Connector(lambda: self, *self.server)
@ -139,6 +147,7 @@ class ClientSession(BaseClientSession):
class Network: class Network:
PROTOCOL_VERSION = __version__ PROTOCOL_VERSION = __version__
MINIMUM_REQUIRED = (0, 53, 2)
def __init__(self, ledger): def __init__(self, ledger):
self.ledger = ledger self.ledger = ledger

View file

@ -145,7 +145,9 @@ class ServerPickingTestCase(AsyncioTestCase):
class FakeSession(RPCSession): class FakeSession(RPCSession):
async def handle_request(self, request): async def handle_request(self, request):
await asyncio.sleep(latency) await asyncio.sleep(latency)
return {"height": 1} if request.method == 'server.version':
return tuple(request.args)
return {'height': 1}
server = await self.loop.create_server(lambda: FakeSession(), host='127.0.0.1', port=port) server = await self.loop.create_server(lambda: FakeSession(), host='127.0.0.1', port=port)
self.addCleanup(server.close) self.addCleanup(server.close)
return '127.0.0.1', port return '127.0.0.1', port