From bb8a2bfff7648a04328fae505883700d29570d76 Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Wed, 23 Oct 2019 10:54:05 -0400 Subject: [PATCH] fix bug with resolve and conflicting claim_id segments --- lbry/lbry/wallet/server/db/reader.py | 2 +- .../tests/integration/test_resolve_command.py | 52 ------------------- lbry/tests/unit/wallet/server/test_sqldb.py | 11 ++++ 3 files changed, 12 insertions(+), 53 deletions(-) diff --git a/lbry/lbry/wallet/server/db/reader.py b/lbry/lbry/wallet/server/db/reader.py index 89b444b2b..c24697aab 100644 --- a/lbry/lbry/wallet/server/db/reader.py +++ b/lbry/lbry/wallet/server/db/reader.py @@ -397,7 +397,7 @@ def resolve_url(raw_url): if set(query) == {'name'}: query['is_controlling'] = True else: - query['order_by'] = ['^height'] + query['order_by'] = ['^creation_height'] matches = _search(**query, limit=1) if matches: channel = matches[0] diff --git a/lbry/tests/integration/test_resolve_command.py b/lbry/tests/integration/test_resolve_command.py index 8e2424f6b..c9e52219e 100644 --- a/lbry/tests/integration/test_resolve_command.py +++ b/lbry/tests/integration/test_resolve_command.py @@ -259,58 +259,6 @@ class ResolveCommand(BaseResolveTestCase): '@olds/bad_example': {'error': '@olds/bad_example did not resolve to a claim'} }) - async def _test_resolve_abc_foo(self): - response = await self.resolve('lbry://@abc/foo') - claim = response['lbry://@abc/foo'] - self.assertIn('signing_channel', claim) - self.assertEqual(claim['name'], 'foo') - self.assertEqual(claim['signing_channel']['name'], '@abc') - self.assertEqual(claim['meta']['claims_in_channel'], 0) - self.assertEqual( - claim['timestamp'], - self.ledger.headers[claim['height']]['timestamp'] - ) - self.assertEqual( - claim['signing_channel']['timestamp'], - self.ledger.headers[claim['signing_channel']['height']]['timestamp'] - ) - - @skip('this test does not work with new resolve') - async def test_resolve_lru_cache_doesnt_persist_errors(self): - original_get_transaction = self.daemon.wallet_manager.ledger.network.get_transaction - - async def timeout_get_transaction(txid): - fut = self.loop.create_future() - - def delayed_raise_cancelled_error(): - fut.set_exception(asyncio.CancelledError()) - - self.loop.call_soon(delayed_raise_cancelled_error) - return await fut - - tx = await self.channel_create('@abc', '0.01') - channel_id = self.get_claim_id(tx) - await self.stream_create('foo', '0.01', channel_id=channel_id) - - # raise a cancelled error from get_transaction - self.daemon.wallet_manager.ledger.network.get_transaction = timeout_get_transaction - with self.assertRaises(KeyError): - await self._test_resolve_abc_foo() - - # restore the real get_transaction that doesn't cancel, it should be called and the result cached - self.daemon.wallet_manager.ledger.network.get_transaction = original_get_transaction - await self._test_resolve_abc_foo() - called_again = asyncio.Event(loop=self.loop) - - def check_result_cached(txid): - called_again.set() - return original_get_transaction(txid) - - # check that the result was cached - self.daemon.wallet_manager.ledger.network.get_transaction = check_result_cached - await self._test_resolve_abc_foo() - self.assertFalse(called_again.is_set()) - class ResolveAfterReorg(BaseResolveTestCase): diff --git a/lbry/tests/unit/wallet/server/test_sqldb.py b/lbry/tests/unit/wallet/server/test_sqldb.py index 574d13c59..ca886a63a 100644 --- a/lbry/tests/unit/wallet/server/test_sqldb.py +++ b/lbry/tests/unit/wallet/server/test_sqldb.py @@ -343,6 +343,7 @@ class TestClaimtrie(TestSQLDB): tx_chan_a = self.get_channel_with_claim_id_prefix('a', 1, key=b'c') tx_chan_ab = self.get_channel_with_claim_id_prefix('ab', 72, key=b'c') txo_chan_a = tx_chan_a[0].tx.outputs[0] + txo_chan_ab = tx_chan_ab[0].tx.outputs[0] advance(1, [tx_chan_a]) advance(2, [tx_chan_ab]) r_ab, r_a = reader._search(order_by=['creation_height'], limit=2) @@ -379,6 +380,12 @@ class TestClaimtrie(TestSQLDB): self.assertEqual("@foo#a/foo#ab", r_ab2['canonical_url']) self.assertEqual(2, reader._search(claim_id=txo_chan_a.claim_id, limit=1)[0]['claims_in_channel']) + # pick correct claim in case of claims with conflicting claim id segments + # make sure that activation_height is used instead of height (issue #2448) + # after updating chan "a" check this again + self.assertEqual(reader.resolve_url("@foo#a")['claim_hash'], txo_chan_a.claim_hash) + self.assertEqual(reader.resolve_url("@foo#ab")['claim_hash'], txo_chan_ab.claim_hash) + # change channel public key, invaliding stream claim signatures advance(8, [self.get_channel_update(txo_chan_a, COIN, key=b'a')]) r_ab2, r_a2 = reader._search(order_by=['creation_height'], limit=2) @@ -398,6 +405,10 @@ class TestClaimtrie(TestSQLDB): self.assertEqual("@foo#a/foo#ab", r_ab2['canonical_url']) self.assertEqual(2, reader._search(claim_id=txo_chan_a.claim_id, limit=1)[0]['claims_in_channel']) + # check chan "a" is still resolved (issue #2448) + self.assertEqual(reader.resolve_url("@foo#a")['claim_hash'], txo_chan_a.claim_hash) + self.assertEqual(reader.resolve_url("@foo#ab")['claim_hash'], txo_chan_ab.claim_hash) + # claim abandon updates claims_in_channel advance(10, [self.get_abandon(tx_ab2)]) self.assertEqual(1, reader._search(claim_id=txo_chan_a.claim_id, limit=1)[0]['claims_in_channel'])