added --not_channel_ids and --has_channel_signature

This commit is contained in:
Lex Berezhny 2019-06-23 19:58:41 -04:00
parent d0e1468acd
commit 9ce93a1da6
8 changed files with 137 additions and 53 deletions

View file

@ -1707,8 +1707,8 @@ class Daemon(metaclass=JSONRPCServerType):
Usage:
claim_search [<name> | --name=<name>] [--claim_id=<claim_id>] [--txid=<txid>] [--nout=<nout>]
[--channel=<channel> | --channel_ids=<channel_ids>...]
[--valid_channel_signatures] [--invalid_channel_signatures]
[--channel=<channel> | --channel_ids=<channel_ids>... --not_channel_ids=<not_channel_ids>...]
[--has_channel_signature] [--valid_channel_signature | --invalid_channel_signature]
[--is_controlling] [--release_time=<release_time>] [--public_key_id=<public_key_id>]
[--timestamp=<timestamp>] [--creation_timestamp=<creation_timestamp>]
[--height=<height>] [--creation_height=<creation_height>]
@ -1736,14 +1736,22 @@ class Daemon(metaclass=JSONRPCServerType):
see --channel_ids if you need to filter by
multiple channels at the same time,
includes claims with invalid signatures,
use in conjunction with --valid_channel_signatures
use in conjunction with --valid_channel_signature
--channel_ids=<channel_ids> : (str) claims signed by any of these channels
(arguments must be claim ids of the channels),
includes claims with invalid signatures,
use in conjunction with --valid_channel_signatures
--valid_channel_signatures : (bool) only return claims with valid channel signatures
--invalid_channel_signatures : (bool) only return claims with invalid channel signatures
--is_controlling : (bool) only return winning claims of their respective name
implies --has_channel_signature,
use in conjunction with --valid_channel_signature
--not_channel_ids=<not_channel_ids>: (str) exclude claims signed by any of these channels
(arguments must be claim ids of the channels)
--has_channel_signature : (bool) claims with a channel signature (valid or invalid)
--valid_channel_signature : (bool) claims with a valid channel signature or no signature,
use in conjunction with --has_channel_signature to
only get claims with valid signatures
--invalid_channel_signature : (bool) claims with invalid channel signature or no signature,
use in conjunction with --has_channel_signature to
only get claims with invalid signatures
--is_controlling : (bool) winning claims of their respective name
--public_key_id=<public_key_id> : (str) only return channels having this public key id, this is
the same key as used in the wallet file to map
channel certificate private keys: {'public_key_id': 'private key'}
@ -1811,9 +1819,9 @@ class Daemon(metaclass=JSONRPCServerType):
Returns: {Paginated[Output]}
"""
if kwargs.pop('valid_channel_signatures', False):
if kwargs.pop('valid_channel_signature', False):
kwargs['signature_valid'] = 1
if kwargs.pop('invalid_channel_signatures', False):
if kwargs.pop('invalid_channel_signature', False):
kwargs['signature_valid'] = 0
page_num, page_size = abs(kwargs.pop('page', 1)), min(abs(kwargs.pop('page_size', 10)), 50)
kwargs.update({'offset': page_size * (page_num-1), 'limit': page_size})

View file

@ -303,3 +303,7 @@ class CommandTestCase(IntegrationTestCase):
async def claim_search(self, **kwargs):
return (await self.out(self.daemon.jsonrpc_claim_search(**kwargs)))['items']
@staticmethod
def get_claim_id(tx):
return tx['outputs'][0]['claim_id']

View file

@ -813,6 +813,30 @@ class SQLDB:
constraints['claim.channel_hash__in'] = [
sqlite3.Binary(unhexlify(cid)[::-1]) for cid in channel_ids
]
if 'not_channel_ids' in constraints:
not_channel_ids = constraints.pop('not_channel_ids')
if not_channel_ids:
not_channel_ids_binary = [
sqlite3.Binary(unhexlify(ncid)[::-1]) for ncid in not_channel_ids
]
if constraints.get('has_channel_signature', False):
constraints['claim.channel_hash__not_in'] = not_channel_ids_binary
else:
constraints['null_or_not_channel__or'] = {
'claim.signature_valid__is_null': True,
'claim.channel_hash__not_in': not_channel_ids_binary
}
if 'signature_valid' in constraints:
has_channel_signature = constraints.pop('has_channel_signature', False)
if has_channel_signature:
constraints['claim.signature_valid'] = constraints.pop('signature_valid')
else:
constraints['null_or_signature__or'] = {
'claim.signature_valid__is_null': True,
'claim.signature_valid': constraints.pop('signature_valid')
}
elif 'has_channel_signature' in constraints:
constraints['claim.signature_valid__is_not_null'] = constraints.pop('has_channel_signature')
if 'txid' in constraints:
tx_hash = unhexlify(constraints.pop('txid'))[::-1]
@ -883,15 +907,16 @@ class SQLDB:
INTEGER_PARAMS = {
'height', 'creation_height', 'activation_height', 'expiration_height',
'timestamp', 'creation_timestamp', 'release_time', 'fee_amount',
'tx_position', 'channel_join', 'signature_valid',
'tx_position', 'channel_join',
'amount', 'effective_amount', 'support_amount',
'trending_group', 'trending_mixed',
'trending_local', 'trending_global',
}
SEARCH_PARAMS = {
'name', 'claim_id', 'txid', 'nout', 'channel', 'channel_ids', 'public_key_id',
'claim_type', 'stream_types', 'media_types', 'fee_currency',
'name', 'claim_id', 'txid', 'nout', 'channel', 'channel_ids', 'not_channel_ids',
'public_key_id', 'claim_type', 'stream_types', 'media_types', 'fee_currency',
'has_channel_signature', 'signature_valid',
'any_tags', 'all_tags', 'not_tags',
'any_locations', 'all_locations', 'not_locations',
'any_languages', 'all_languages', 'not_languages',

View file

@ -178,7 +178,7 @@ class Examples(CommandTestCase):
'Create a channel claim without metadata',
'channel', 'create', '@channel', '1.0'
)
channel_id = channel['outputs'][0]['claim_id']
channel_id = self.get_claim_id(channel)
await self.on_transaction_dict(channel)
await self.generate(1)
await self.on_transaction_dict(channel)
@ -195,7 +195,7 @@ class Examples(CommandTestCase):
channel = await r(
'Update a channel claim',
'channel', 'update', channel['outputs'][0]['claim_id'], '--title="New Channel"'
'channel', 'update', self.get_claim_id(channel), '--title="New Channel"'
)
await self.on_transaction_dict(channel)
@ -214,7 +214,7 @@ class Examples(CommandTestCase):
await self.on_transaction_dict(big_channel)
await self.generate(1)
await self.on_transaction_dict(big_channel)
await self.daemon.jsonrpc_channel_abandon(big_channel['outputs'][0]['claim_id'])
await self.daemon.jsonrpc_channel_abandon(self.get_claim_id(big_channel))
await self.generate(1)
# stream claims
@ -229,7 +229,7 @@ class Examples(CommandTestCase):
await self.on_transaction_dict(stream)
await self.generate(1)
await self.on_transaction_dict(stream)
stream_id = stream['outputs'][0]['claim_id']
stream_id = self.get_claim_id(stream)
stream_name = stream['outputs'][0]['name']
stream = await r(
'Update a stream claim to add channel',
@ -291,7 +291,7 @@ class Examples(CommandTestCase):
await self.on_transaction_dict(big_stream)
await self.generate(1)
await self.on_transaction_dict(big_stream)
await self.daemon.jsonrpc_channel_abandon(big_stream['outputs'][0]['claim_id'])
await self.daemon.jsonrpc_channel_abandon(self.get_claim_id(big_stream))
await self.generate(1)
# files

View file

@ -19,7 +19,7 @@ class EpicAdventuresOfChris45(CommandTestCase):
# registered the @spam channel yet? "I should do that!" he
# exclaims and goes back to his computer to do just that!
tx = await self.channel_create('@spam', '1.0')
channel_id = tx['outputs'][0]['claim_id']
channel_id = self.get_claim_id(tx)
# Do we have it locally?
channels = await self.out(self.daemon.jsonrpc_channel_list())
@ -54,7 +54,7 @@ class EpicAdventuresOfChris45(CommandTestCase):
data=b'[insert long story about eels driving hovercraft]',
channel_id=channel_id
)
claim_id = tx['outputs'][0]['claim_id']
claim_id = self.get_claim_id(tx)
# He quickly checks the unconfirmed balance to make sure everything looks
# correct.
@ -120,7 +120,7 @@ class EpicAdventuresOfChris45(CommandTestCase):
tx = await self.stream_create(
'fresh-start', '1.0', data=b'Amazingly Original First Line', channel_id=channel_id
)
claim_id2 = tx['outputs'][0]['claim_id']
claim_id2 = self.get_claim_id(tx)
await self.generate(5)

View file

@ -66,7 +66,7 @@ class ClaimSearchCommand(ClaimTestCase):
async def create_channel(self):
self.channel = await self.channel_create('@abc', '1.0')
self.channel_id = self.channel['outputs'][0]['claim_id']
self.channel_id = self.get_claim_id(self.channel)
async def create_lots_of_streams(self):
tx = await self.daemon.jsonrpc_account_fund(None, None, '0.001', outputs=100, broadcast=True)
@ -93,7 +93,7 @@ class ClaimSearchCommand(ClaimTestCase):
self.assertEqual(len(claims), len(results))
for claim, result in zip(claims, results):
self.assertEqual(
(claim['txid'], claim['outputs'][0]['claim_id']),
(claim['txid'], self.get_claim_id(claim)),
(result['txid'], result['claim_id'])
)
@ -128,7 +128,7 @@ class ClaimSearchCommand(ClaimTestCase):
await self.assertFindsClaim(signed2, name='on-channel-claim', channel_ids=[channel_id2])
await self.assertFindsClaim(unsigned, name='unsigned')
await self.assertFindsClaim(unsigned, txid=unsigned['txid'], nout=0)
await self.assertFindsClaim(unsigned, claim_id=unsigned['outputs'][0]['claim_id'])
await self.assertFindsClaim(unsigned, claim_id=self.get_claim_id(unsigned))
two = await self.stream_create('on-channel-claim-2', '0.0001', channel_id=self.channel_id)
three = await self.stream_create('on-channel-claim-3', '0.0001', channel_id=self.channel_id)
@ -139,20 +139,20 @@ class ClaimSearchCommand(ClaimTestCase):
await self.assertFindsClaims(claims, channel=f"@abc#{self.channel_id}")
await self.assertFindsClaims([three, two, signed2, signed], channel_ids=[channel_id2, self.channel_id])
await self.channel_abandon(claim_id=self.channel_id)
await self.assertFindsClaims([], channel=f"@abc#{self.channel_id}", valid_channel_signatures=True)
await self.assertFindsClaims([], channel_ids=[self.channel_id], valid_channel_signatures=True)
await self.assertFindsClaims([signed2], channel_ids=[channel_id2], valid_channel_signatures=True)
# pass `invalid_channel_signatures=False` to catch a bug in argument processing
await self.assertFindsClaims([], channel=f"@abc#{self.channel_id}", valid_channel_signature=True)
await self.assertFindsClaims([], channel_ids=[self.channel_id], valid_channel_signature=True)
await self.assertFindsClaims([signed2], channel_ids=[channel_id2], valid_channel_signature=True)
# pass `invalid_channel_signature=False` to catch a bug in argument processing
await self.assertFindsClaims([signed2], channel_ids=[channel_id2, self.channel_id],
valid_channel_signatures=True, invalid_channel_signatures=False)
valid_channel_signature=True, invalid_channel_signature=False)
# invalid signature still returns channel_id
self.ledger._tx_cache.clear()
invalid_claims = await self.claim_search(invalid_channel_signatures=True)
invalid_claims = await self.claim_search(invalid_channel_signature=True, has_channel_signature=True)
self.assertEqual(3, len(invalid_claims))
self.assertTrue(all([not c['is_channel_signature_valid'] for c in invalid_claims]))
self.assertEqual({'channel_id': self.channel_id}, invalid_claims[0]['signing_channel'])
valid_claims = await self.claim_search(valid_channel_signatures=True)
valid_claims = await self.claim_search(valid_channel_signature=True, has_channel_signature=True)
self.assertEqual(1, len(valid_claims))
self.assertTrue(all([c['is_channel_signature_valid'] for c in valid_claims]))
self.assertEqual('@abc', valid_claims[0]['signing_channel']['name'])
@ -247,6 +247,59 @@ class ClaimSearchCommand(ClaimTestCase):
await self.assertFindsClaims([claim5], fee_currency='usd')
await self.assertFindsClaims([], fee_currency='foo')
async def test_search_by_channel(self):
match = self.assertFindsClaims
chan1_id = self.get_claim_id(await self.channel_create('@chan1'))
chan2_id = self.get_claim_id(await self.channel_create('@chan2'))
chan3_id = self.get_claim_id(await self.channel_create('@chan3'))
claim1 = await self.stream_create('claim1')
claim2 = await self.stream_create('claim2', channel_id=chan1_id)
claim3 = await self.stream_create('claim3', channel_id=chan1_id)
claim4 = await self.stream_create('claim4', channel_id=chan2_id)
claim5 = await self.stream_create('claim5', channel_id=chan2_id)
claim6 = await self.stream_create('claim6', channel_id=chan3_id)
await self.channel_abandon(chan3_id)
# {has/valid/invalid}_channel_signature
await match([claim6, claim5, claim4, claim3, claim2], has_channel_signature=True)
await match([claim5, claim4, claim3, claim2, claim1], valid_channel_signature=True, claim_type='stream')
await match([claim6, claim1], invalid_channel_signature=True, claim_type='stream')
await match([claim5, claim4, claim3, claim2], has_channel_signature=True, valid_channel_signature=True)
await match([claim6], has_channel_signature=True, invalid_channel_signature=True)
# not_channel_ids
await match([claim6, claim5, claim4, claim3, claim2, claim1], not_channel_ids=['abc123'], claim_type='stream')
await match([claim5, claim4, claim3, claim2, claim1], not_channel_ids=[chan3_id], claim_type='stream')
await match([claim6, claim5, claim4, claim1], not_channel_ids=[chan1_id], claim_type='stream')
await match([claim6, claim3, claim2, claim1], not_channel_ids=[chan2_id], claim_type='stream')
await match([claim6, claim1], not_channel_ids=[chan1_id, chan2_id], claim_type='stream')
# not_channel_ids + valid_channel_signature
await match([claim5, claim4, claim3, claim2, claim1],
not_channel_ids=['abc123'], valid_channel_signature=True, claim_type='stream')
await match([claim5, claim4, claim1],
not_channel_ids=[chan1_id], valid_channel_signature=True, claim_type='stream')
await match([claim3, claim2, claim1],
not_channel_ids=[chan2_id], valid_channel_signature=True, claim_type='stream')
await match([claim1], not_channel_ids=[chan1_id, chan2_id], valid_channel_signature=True, claim_type='stream')
# not_channel_ids + has_channel_signature
await match([claim6, claim5, claim4, claim3, claim2], not_channel_ids=['abc123'], has_channel_signature=True)
await match([claim6, claim5, claim4], not_channel_ids=[chan1_id], has_channel_signature=True)
await match([claim6, claim3, claim2], not_channel_ids=[chan2_id], has_channel_signature=True)
await match([claim6], not_channel_ids=[chan1_id, chan2_id], has_channel_signature=True)
# not_channel_ids + has_channel_signature + valid_channel_signature
await match([claim5, claim4, claim3, claim2],
not_channel_ids=['abc123'], has_channel_signature=True, valid_channel_signature=True)
await match([claim5, claim4],
not_channel_ids=[chan1_id], has_channel_signature=True, valid_channel_signature=True)
await match([claim3, claim2],
not_channel_ids=[chan2_id], has_channel_signature=True, valid_channel_signature=True)
await match([], not_channel_ids=[chan1_id, chan2_id], has_channel_signature=True, valid_channel_signature=True)
async def test_claim_type_and_media_type_search(self):
# create an invalid/unknown claim
address = await self.account.receiving.get_or_create_usable_address()
@ -307,7 +360,7 @@ class ChannelCommands(CommandTestCase):
async def test_channel_bids(self):
# enough funds
tx = await self.channel_create('@foo', '5.0')
claim_id = tx['outputs'][0]['claim_id']
claim_id = self.get_claim_id(tx)
self.assertEqual(len(await self.daemon.jsonrpc_channel_list()), 1)
await self.assertBalance(self.account, '4.991893')
@ -433,7 +486,7 @@ class ChannelCommands(CommandTestCase):
async def test_channel_export_import_into_new_account(self):
tx = await self.channel_create('@foo', '1.0')
claim_id = tx['outputs'][0]['claim_id']
claim_id = self.get_claim_id(tx)
channel_private_key = (await self.account.get_channels())[0].private_key
exported_data = await self.out(self.daemon.jsonrpc_channel_export(claim_id))
@ -455,7 +508,7 @@ class ChannelCommands(CommandTestCase):
async def test_channel_export_import_into_existing_account(self):
tx = await self.channel_create('@foo', '1.0')
claim_id = tx['outputs'][0]['claim_id']
claim_id = self.get_claim_id(tx)
channel_private_key = (await self.account.get_channels())[0].private_key
exported_data = await self.out(self.daemon.jsonrpc_channel_export(claim_id))
@ -507,7 +560,7 @@ class StreamCommands(ClaimTestCase):
async def test_stream_bids(self):
# enough funds
tx = await self.stream_create('foo', '2.0')
claim_id = tx['outputs'][0]['claim_id']
claim_id = self.get_claim_id(tx)
self.assertEqual(len(await self.daemon.jsonrpc_claim_list()), 1)
await self.assertBalance(self.account, '7.993893')
@ -551,7 +604,7 @@ class StreamCommands(ClaimTestCase):
self.assertEqual('5.0', await self.daemon.jsonrpc_account_balance(account2_id))
baz_tx = await self.out(self.channel_create('@baz', '1.0', account_id=account2_id))
baz_id = baz_tx['outputs'][0]['claim_id']
baz_id = self.get_claim_id(baz_tx)
channels = await self.out(self.daemon.jsonrpc_channel_list(account1_id))
self.assertEqual(len(channels), 1)
@ -731,7 +784,7 @@ class StreamCommands(ClaimTestCase):
self.assertEqual(tx['outputs'][0]['value'], fixed_values)
# stream_update re-signs with the same channel
channel_id = (await self.channel_create('@chan'))['outputs'][0]['claim_id']
channel_id = self.get_claim_id(await self.channel_create('@chan'))
tx = await self.stream_update(claim_id, channel_id=channel_id)
self.assertEqual(tx['outputs'][0]['signing_channel']['name'], '@chan')
tx = await self.stream_update(claim_id, title='channel re-signs')
@ -919,7 +972,7 @@ class StreamCommands(ClaimTestCase):
tx = await self.out(self.daemon.jsonrpc_stream_create(
'chrome', '1.0', file_path=self.video_file_name,
tags='blah', languages='uk', locations='UA::Kyiv',
channel_id=channel['outputs'][0]['claim_id']
channel_id=self.get_claim_id(channel)
))
await self.on_transaction_dict(tx)
txo = tx['outputs'][0]
@ -941,7 +994,7 @@ class StreamCommands(ClaimTestCase):
await self.assertBalance(self.account, '10.0')
tx = await self.stream_create(bid='2.5') # creates new claim
claim_id = tx['outputs'][0]['claim_id']
claim_id = self.get_claim_id(tx)
txs = await self.out(self.daemon.jsonrpc_transaction_list())
self.assertEqual(len(txs[0]['claim_info']), 1)
self.assertEqual(txs[0]['confirmations'], 1)
@ -977,7 +1030,7 @@ class StreamCommands(ClaimTestCase):
await self.assertBalance(self.account, '10.0')
tx = await self.stream_create(bid='0.0001')
await self.assertBalance(self.account, '9.979793')
await self.stream_abandon(tx['outputs'][0]['claim_id'])
await self.stream_abandon(self.get_claim_id(tx))
await self.assertBalance(self.account, '9.97968399')
async def test_publish(self):
@ -1001,10 +1054,7 @@ class StreamCommands(ClaimTestCase):
tx2 = await self.publish('foo', tags='updated')
self.assertEqual(1, len(self.daemon.jsonrpc_file_list()))
self.assertEqual(
tx1['outputs'][0]['claim_id'],
tx2['outputs'][0]['claim_id']
)
self.assertEqual(self.get_claim_id(tx1), self.get_claim_id(tx2))
# update conflict with two claims of the same name
tx3 = await self.stream_create('foo', allow_duplicate_name=True)
@ -1013,7 +1063,7 @@ class StreamCommands(ClaimTestCase):
self.assertEqual(2, len(self.daemon.jsonrpc_file_list()))
# abandon duplicate stream
await self.stream_abandon(tx3['outputs'][0]['claim_id'])
await self.stream_abandon(self.get_claim_id(tx3))
# publish to a channel
await self.channel_create('@abc')
@ -1022,7 +1072,7 @@ class StreamCommands(ClaimTestCase):
r = await self.resolve('lbry://@abc/foo')
self.assertEqual(
r['lbry://@abc/foo']['claim_id'],
tx3['outputs'][0]['claim_id']
self.get_claim_id(tx3)
)
# publishing again clears channel
@ -1054,7 +1104,7 @@ class SupportCommands(CommandTestCase):
# create the claim we'll be tipping and supporting
tx = await self.stream_create()
claim_id = tx['outputs'][0]['claim_id']
claim_id = self.get_claim_id(tx)
# account1 and account2 balances:
await self.assertBalance(self.account, '3.979769')

View file

@ -279,7 +279,7 @@ class FileCommands(CommandTestCase):
async def __raw_value_update_no_fee_address(self, tx, claim_address, **kwargs):
tx = await self.daemon.jsonrpc_stream_update(
tx['outputs'][0]['claim_id'], preview=True, claim_address=claim_address, **kwargs
self.get_claim_id(tx), preview=True, claim_address=claim_address, **kwargs
)
tx.outputs[0].claim.stream.fee.address_bytes = b''
tx.outputs[0].script.generate()

View file

@ -11,9 +11,6 @@ from torba.client.hash import sha256, Base58
class BaseResolveTestCase(CommandTestCase):
def get_claim_id(self, tx):
return tx['outputs'][0]['claim_id']
async def assertResolvesToClaimId(self, name, claim_id):
other = (await self.resolve(name))[name]
if claim_id is None:
@ -173,7 +170,7 @@ class ResolveCommand(BaseResolveTestCase):
abandoned_channel_id = channel['claim_id']
await self.channel_abandon(txid=channel['txid'], nout=0)
channel = (await self.channel_create('@abc', '1.0'))['outputs'][0]
orphan_claim_id = orphan_claim['outputs'][0]['claim_id']
orphan_claim_id = self.get_claim_id(orphan_claim)
# Original channel doesnt exists anymore, so the signature is invalid. For invalid signatures, resolution is
# only possible outside a channel
@ -220,7 +217,7 @@ class ResolveCommand(BaseResolveTestCase):
_ = await self.stream_create(one, '0.1')
c = await self.stream_create(two, '0.2')
winner_id = c['outputs'][0]['claim_id']
winner_id = self.get_claim_id(c)
r1 = await self.resolve(f'lbry://{one}')
r2 = await self.resolve(f'lbry://{two}')
@ -286,7 +283,7 @@ class ResolveCommand(BaseResolveTestCase):
return await fut
tx = await self.channel_create('@abc', '0.01')
channel_id = tx['outputs'][0]['claim_id']
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