better handling for claims in abandoned channels

This commit is contained in:
Lex Berezhny 2019-06-04 14:16:11 -04:00
parent f96c46e84a
commit f23aea9951
5 changed files with 42 additions and 27 deletions

View file

@ -51,7 +51,6 @@ if typing.TYPE_CHECKING:
from lbrynet.wallet.manager import LbryWalletManager from lbrynet.wallet.manager import LbryWalletManager
from lbrynet.wallet.ledger import MainNetLedger from lbrynet.wallet.ledger import MainNetLedger
from lbrynet.stream.stream_manager import StreamManager from lbrynet.stream.stream_manager import StreamManager
from lbrynet.stream.managed_stream import ManagedStream
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -1808,9 +1807,9 @@ class Daemon(metaclass=JSONRPCServerType):
Returns: {Paginated[Output]} Returns: {Paginated[Output]}
""" """
if kwargs.pop('valid_channel_signatures', False): if kwargs.pop('valid_channel_signatures', False):
kwargs['is_channel_signature_valid'] = 1 kwargs['signature_valid'] = 1
if kwargs.pop('invalid_channel_signatures', False): if kwargs.pop('invalid_channel_signatures', False):
kwargs['is_channel_signature_valid'] = 0 kwargs['signature_valid'] = 0
page_num, page_size = abs(kwargs.pop('page', 1)), min(abs(kwargs.pop('page_size', 10)), 50) 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}) kwargs.update({'offset': page_size * (page_num-1), 'limit': page_size})
txos, offset, total = await self.ledger.claim_search(**kwargs) txos, offset, total = await self.ledger.claim_search(**kwargs)

View file

@ -184,12 +184,13 @@ class JSONResponseEncoder(JSONEncoder):
output['value_type'] = txo.claim.claim_type output['value_type'] = txo.claim.claim_type
if self.include_protobuf: if self.include_protobuf:
output['protobuf'] = hexlify(txo.claim.to_bytes()) output['protobuf'] = hexlify(txo.claim.to_bytes())
if check_signature and txo.claim.is_signed:
if txo.channel is not None: if txo.channel is not None:
output['signing_channel'] = self.encode_output(txo.channel) output['signing_channel'] = self.encode_output(txo.channel)
if check_signature and txo.claim.is_signed:
output['is_channel_signature_valid'] = False
if txo.channel:
output['is_channel_signature_valid'] = txo.is_signed_by(txo.channel, self.ledger) output['is_channel_signature_valid'] = txo.is_signed_by(txo.channel, self.ledger)
else:
output['signing_channel'] = {'channel_id': txo.claim.signing_channel_id}
output['is_channel_signature_valid'] = False
except DecodeError: except DecodeError:
pass pass
return output return output

View file

@ -195,14 +195,13 @@ class Stream(BaseClaim):
claim['source']['hash'] = self.source.file_hash claim['source']['hash'] = self.source.file_hash
if 'sd_hash' in claim['source']: if 'sd_hash' in claim['source']:
claim['source']['sd_hash'] = self.source.sd_hash claim['source']['sd_hash'] = self.source.sd_hash
if 'media_type' in claim['source']:
claim['stream_type'] = guess_stream_type(claim['source']['media_type'])
fee = claim.get('fee', {}) fee = claim.get('fee', {})
if 'address' in fee: if 'address' in fee:
fee['address'] = self.fee.address fee['address'] = self.fee.address
if 'amount' in fee: if 'amount' in fee:
fee['amount'] = str(self.fee.amount) fee['amount'] = str(self.fee.amount)
stream_type = self.message.WhichOneof('type')
if stream_type:
claim['stream_type'] = stream_type
return claim return claim
def update(self, file_path=None, height=None, width=None, duration=None, **kwargs): def update(self, file_path=None, height=None, width=None, duration=None, **kwargs):

View file

@ -116,7 +116,7 @@ class SQLDB:
channel_join integer, -- height at which claim got valid signature / joined channel channel_join integer, -- height at which claim got valid signature / joined channel
signature bytes, signature bytes,
signature_digest bytes, signature_digest bytes,
is_channel_signature_valid bool not null default false, signature_valid bool,
effective_amount integer not null default 0, effective_amount integer not null default 0,
support_amount integer not null default 0, support_amount integer not null default 0,
@ -141,6 +141,8 @@ class SQLDB:
create index if not exists claim_stream_type_idx on claim (stream_type); create index if not exists claim_stream_type_idx on claim (stream_type);
create index if not exists claim_media_type_idx on claim (media_type); create index if not exists claim_media_type_idx on claim (media_type);
create index if not exists claim_signature_valid_idx on claim (signature_valid);
create index if not exists claim_effective_amount_idx on claim (effective_amount); create index if not exists claim_effective_amount_idx on claim (effective_amount);
create index if not exists claim_trending_group_idx on claim (trending_group); create index if not exists claim_trending_group_idx on claim (trending_group);
create index if not exists claim_trending_mixed_idx on claim (trending_mixed); create index if not exists claim_trending_mixed_idx on claim (trending_mixed);
@ -431,13 +433,14 @@ class SQLDB:
'channel_hash': None, 'channel_hash': None,
'signature': None, 'signature': None,
'signature_digest': None, 'signature_digest': None,
'is_channel_signature_valid': False 'signature_valid': None
} }
if claim.is_signed: if claim.is_signed:
update.update({ update.update({
'channel_hash': sqlite3.Binary(claim.signing_channel_hash), 'channel_hash': sqlite3.Binary(claim.signing_channel_hash),
'signature': sqlite3.Binary(txo.get_encoded_signature()), 'signature': sqlite3.Binary(txo.get_encoded_signature()),
'signature_digest': sqlite3.Binary(txo.get_signature_digest(self.ledger)) 'signature_digest': sqlite3.Binary(txo.get_signature_digest(self.ledger)),
'signature_valid': 0
}) })
claim_updates.append(update) claim_updates.append(update)
@ -454,13 +457,13 @@ class SQLDB:
'channel_hash': sqlite3.Binary(affected_claim['channel_hash']), 'channel_hash': sqlite3.Binary(affected_claim['channel_hash']),
'signature': sqlite3.Binary(affected_claim['signature']), 'signature': sqlite3.Binary(affected_claim['signature']),
'signature_digest': sqlite3.Binary(affected_claim['signature_digest']), 'signature_digest': sqlite3.Binary(affected_claim['signature_digest']),
'is_channel_signature_valid': False 'signature_valid': 0
}) })
for update in claim_updates: for update in claim_updates:
channel_pub_key = all_channel_keys.get(update['channel_hash']) channel_pub_key = all_channel_keys.get(update['channel_hash'])
if channel_pub_key and update['signature']: if channel_pub_key and update['signature']:
update['is_channel_signature_valid'] = Output.is_signature_valid( update['signature_valid'] = Output.is_signature_valid(
bytes(update['signature']), bytes(update['signature_digest']), channel_pub_key bytes(update['signature']), bytes(update['signature_digest']), channel_pub_key
) )
@ -468,20 +471,20 @@ class SQLDB:
self.db.executemany(f""" self.db.executemany(f"""
UPDATE claim SET UPDATE claim SET
channel_hash=:channel_hash, signature=:signature, signature_digest=:signature_digest, channel_hash=:channel_hash, signature=:signature, signature_digest=:signature_digest,
is_channel_signature_valid=:is_channel_signature_valid, signature_valid=:signature_valid,
channel_join=CASE channel_join=CASE
WHEN is_channel_signature_valid AND :is_channel_signature_valid THEN channel_join WHEN signature_valid=1 AND :signature_valid=1 THEN channel_join
WHEN :is_channel_signature_valid THEN {height} WHEN :signature_valid=1 THEN {height}
END, END,
canonical_url=CASE canonical_url=CASE
WHEN is_channel_signature_valid AND :is_channel_signature_valid THEN canonical_url WHEN signature_valid=1 AND :signature_valid=1 THEN canonical_url
WHEN :is_channel_signature_valid THEN WHEN :signature_valid=1 THEN
(SELECT short_url FROM claim WHERE claim_hash=:channel_hash)||'/'|| (SELECT short_url FROM claim WHERE claim_hash=:channel_hash)||'/'||
claim_name||COALESCE( claim_name||COALESCE(
(SELECT shortest_id(other_claim.claim_id, claim.claim_id) FROM claim AS other_claim (SELECT shortest_id(other_claim.claim_id, claim.claim_id) FROM claim AS other_claim
WHERE other_claim.normalized = claim.normalized AND WHERE other_claim.normalized = claim.normalized AND
other_claim.channel_hash = :channel_hash AND other_claim.channel_hash = :channel_hash AND
other_claim.is_channel_signature_valid = 1), other_claim.signature_valid = 1),
'#'||substr(claim_id, 1, 1) '#'||substr(claim_id, 1, 1)
) )
END END
@ -491,7 +494,9 @@ class SQLDB:
if spent_claims: if spent_claims:
self.execute( self.execute(
f""" f"""
UPDATE claim SET is_channel_signature_valid=0, channel_join=NULL, canonical_url=NULL UPDATE claim SET
signature_valid=CASE WHEN signature IS NOT NULL THEN 0 END,
channel_join=NULL, canonical_url=NULL
WHERE channel_hash IN ({','.join('?' for _ in spent_claims)}) WHERE channel_hash IN ({','.join('?' for _ in spent_claims)})
""", [sqlite3.Binary(cid) for cid in spent_claims] """, [sqlite3.Binary(cid) for cid in spent_claims]
) )
@ -517,7 +522,7 @@ class SQLDB:
claims_in_channel=( claims_in_channel=(
SELECT COUNT(*) FROM claim AS claim_in_channel SELECT COUNT(*) FROM claim AS claim_in_channel
WHERE claim_in_channel.channel_hash=claim.claim_hash AND WHERE claim_in_channel.channel_hash=claim.claim_hash AND
claim_in_channel.is_channel_signature_valid claim_in_channel.signature_valid=1
) )
WHERE claim_hash = ? WHERE claim_hash = ?
""", [(sqlite3.Binary(channel_hash),) for channel_hash in all_channel_keys.keys()]) """, [(sqlite3.Binary(channel_hash),) for channel_hash in all_channel_keys.keys()])
@ -800,14 +805,14 @@ class SQLDB:
claim.trending_local, claim.trending_global, claim.trending_local, claim.trending_global,
claim.short_url, claim.canonical_url, claim.short_url, claim.canonical_url,
claim.channel_hash, channel.txo_hash AS channel_txo_hash, claim.channel_hash, channel.txo_hash AS channel_txo_hash,
channel.height AS channel_height, claim.is_channel_signature_valid channel.height AS channel_height, claim.signature_valid
""", **constraints """, **constraints
) )
INTEGER_PARAMS = { INTEGER_PARAMS = {
'height', 'creation_height', 'activation_height', 'expiration_height', 'height', 'creation_height', 'activation_height', 'expiration_height',
'timestamp', 'creation_timestamp', 'release_time', 'timestamp', 'creation_timestamp', 'release_time',
'tx_position', 'channel_join', 'is_channel_signature_valid', 'tx_position', 'channel_join', 'signature_valid',
'amount', 'effective_amount', 'support_amount', 'amount', 'effective_amount', 'support_amount',
'trending_group', 'trending_mixed', 'trending_group', 'trending_mixed',
'trending_local', 'trending_global', 'trending_local', 'trending_global',
@ -870,7 +875,7 @@ class SQLDB:
else: else:
query['order_by'] = ['^channel_join'] query['order_by'] = ['^channel_join']
query['channel_hash'] = channel['claim_hash'] query['channel_hash'] = channel['claim_hash']
query['is_channel_signature_valid'] = 1 query['signature_valid'] = 1
elif set(query) == {'name'}: elif set(query) == {'name'}:
query['is_controlling'] = 1 query['is_controlling'] = 1
matches = self._search(**query, limit=1) matches = self._search(**query, limit=1)

View file

@ -144,6 +144,17 @@ class ClaimSearchCommand(ClaimTestCase):
# pass `invalid_channel_signatures=False` to catch a bug in argument processing # pass `invalid_channel_signatures=False` to catch a bug in argument processing
await self.assertFindsClaims([signed2], channel_ids=[channel_id2, self.channel_id], await self.assertFindsClaims([signed2], channel_ids=[channel_id2, self.channel_id],
valid_channel_signatures=True, invalid_channel_signatures=False) valid_channel_signatures=True, invalid_channel_signatures=False)
# invalid signature still returns channel_id
self.ledger._tx_cache.clear()
invalid_claims = await self.claim_search(invalid_channel_signatures=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)
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'])
# abandoned stream won't show up for streams in channel search # abandoned stream won't show up for streams in channel search
await self.stream_abandon(txid=signed2['txid'], nout=0) await self.stream_abandon(txid=signed2['txid'], nout=0)