Merge pull request #620 from lbryio/claim-caching

Add claim caching to wallet storage
This commit is contained in:
Alex Grin 2017-05-04 11:36:03 -04:00 committed by GitHub
commit 89ecd2c571
4 changed files with 385 additions and 127 deletions

View file

@ -16,6 +16,12 @@ at anytime.
* *
* *
* Added optional `address` and `include_unconfirmed` params to `jsonrpc_wallet_balance` method
* Wait for subscriptions before announcing wallet has finished starting
* Cache claims in wallet storage for use looking claims up by id or outpoint
* Try to use cached claim info for `file_list`
* Convert wallet storage to inlinecallbacks
### Fixed ### Fixed
* *
* *

View file

@ -1,6 +1,8 @@
import datetime import datetime
import logging import logging
import os import os
import json
import time
from twisted.internet import threads, reactor, defer, task from twisted.internet import threads, reactor, defer, task
from twisted.python.failure import Failure from twisted.python.failure import Failure
@ -23,10 +25,11 @@ from lbrynet.core.sqlite_helpers import rerun_if_locked
from lbrynet.interfaces import IRequestCreator, IQueryHandlerFactory, IQueryHandler, IWallet from lbrynet.interfaces import IRequestCreator, IQueryHandlerFactory, IQueryHandler, IWallet
from lbrynet.core.client.ClientRequest import ClientRequest from lbrynet.core.client.ClientRequest import ClientRequest
from lbrynet.core.Error import RequestCanceledError, InsufficientFundsError, UnknownNameError from lbrynet.core.Error import RequestCanceledError, InsufficientFundsError, UnknownNameError
from lbrynet.db_migrator.migrate1to2 import UNSET_NOUT
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
CLAIM_CACHE_TIME = 600
class ReservedPoints(object): class ReservedPoints(object):
def __init__(self, identifier, amount): def __init__(self, identifier, amount):
@ -60,6 +63,50 @@ class ClaimOutpoint(dict):
return not self.__eq__(compare) return not self.__eq__(compare)
class CachedClaim(object):
def __init__(self, claim_id, claim, claim_sequence, address, height, amount, supports,
channal_name, signature_is_valid, cache_timestamp, name, txid, nout):
self.claim_id = claim_id
self.claim = claim
self.claim_sequence = claim_sequence
self.address = address
self.height = height
self.amount = amount
self.supports = [] if not supports else json.loads(supports)
self.effective_amount = self.amount + sum([x['amount'] for x in self.supports])
self.channel_name = channal_name
self.signature_is_valid = signature_is_valid
self.cache_timestamp = cache_timestamp
self.name = name
self.txid = txid
self.nout = nout
def response_dict(self, check_expires=True):
if check_expires and (time.time() - int(self.cache_timestamp)) > CLAIM_CACHE_TIME:
return
claim = {
"height": self.height,
"address": self.address,
"claim_id": self.claim_id,
"claim_sequence": self.claim_sequence,
"effective_amount": self.effective_amount,
"has_signature": self.claim.has_signature,
"name": self.name,
"hex": self.claim.serialized.encode('hex'),
"value": self.claim.claim_dict,
"txid": self.txid,
"amount": self.amount,
"decoded_claim": True,
"supports": self.supports,
"nout": self.nout
}
if self.channel_name is not None:
claim['channel_name'] = self.channel_name
if self.signature_is_valid is not None:
claim['signature_is_valid'] = bool(self.signature_is_valid)
return claim
class MetaDataStorage(object): class MetaDataStorage(object):
def load(self): def load(self):
return defer.succeed(True) return defer.succeed(True)
@ -76,14 +123,38 @@ class MetaDataStorage(object):
def update_claimid(self, claim_id, name, claim_outpoint): def update_claimid(self, claim_id, name, claim_outpoint):
return defer.succeed(True) return defer.succeed(True)
def get_claimid_for_tx(self, name, claim_outpoint): def get_claimid_for_tx(self, claim_outpoint):
return defer.succeed(True) return defer.succeed(True)
@defer.inlineCallbacks
def get_cached_claim(self, claim_id, check_expire=True):
cache_info = yield self._get_cached_claim(claim_id)
response = None
if cache_info:
cached_claim = CachedClaim(claim_id, *cache_info)
response = cached_claim.response_dict(check_expires=check_expire)
defer.returnValue(response)
def _get_cached_claim(self, claim_id):
return defer.succeed(None)
def save_claim_to_cache(self, claim_id, claim_sequence, claim, claim_address, height, amount,
supports, channel_name, signature_is_valid):
return defer.succeed(True)
def save_claim_to_uri_cache(self, uri, claim_id, certificate_id=None):
return defer.succeed(None)
def get_cached_claim_for_uri(self, uri, check_expire=True):
return defer.succeed(None)
class InMemoryStorage(MetaDataStorage): class InMemoryStorage(MetaDataStorage):
def __init__(self): def __init__(self):
self.metadata = {} self.metadata = {}
self.claimids = {} self.claimids = {}
self.claim_dicts = {}
self.uri_cache = {}
MetaDataStorage.__init__(self) MetaDataStorage.__init__(self)
def save_name_metadata(self, name, claim_outpoint, sd_hash): def save_name_metadata(self, name, claim_outpoint, sd_hash):
@ -101,24 +172,59 @@ class InMemoryStorage(MetaDataStorage):
self.claimids[(name, claim_outpoint['txid'], claim_outpoint['nout'])] = claim_id self.claimids[(name, claim_outpoint['txid'], claim_outpoint['nout'])] = claim_id
return defer.succeed(True) return defer.succeed(True)
def get_claimid_for_tx(self, name, claim_outpoint): def get_claimid_for_tx(self, claim_outpoint):
try: result = None
return defer.succeed( for k, claim_id in self.claimids.iteritems():
self.claimids[(name, claim_outpoint['txid'], claim_outpoint['nout'])]) if k[1] == claim_outpoint['txid'] and k[2] == claim_outpoint['nout']:
except KeyError: result = claim_id
return defer.succeed(None) break
return defer.succeed(result)
def _get_cached_claim(self, claim_id):
claim_cache = self.claim_dicts.get(claim_id, None)
claim_tx_cache = None
for k, v in self.claimids.iteritems():
if v == claim_id:
claim_tx_cache = k
break
if claim_cache and claim_tx_cache:
cached_claim_args = tuple(claim_cache) + tuple(claim_tx_cache)
return defer.succeed(cached_claim_args)
return defer.succeed(None)
def save_claim_to_cache(self, claim_id, claim_sequence, claim, claim_address, height, amount,
supports, channel_name, signature_is_valid):
self.claim_dicts[claim_id] = (claim, claim_sequence, claim_address, height, amount,
supports, channel_name, signature_is_valid, int(time.time()))
return defer.succeed(True)
def save_claim_to_uri_cache(self, uri, claim_id, certificate_id=None):
self.uri_cache[uri] = (claim_id, certificate_id)
return defer.succeed(None)
@defer.inlineCallbacks
def get_cached_claim_for_uri(self, uri, check_expire=True):
result = self.uri_cache.get(uri, None)
response = None
if result:
claim_id, certificate_id = result
response = yield self.get_cached_claim(claim_id, check_expire)
if response and certificate_id:
certificate = yield self.get_cached_claim(certificate_id, check_expire)
response['certificate'] = certificate['claim']
defer.returnValue(response)
class SqliteStorage(MetaDataStorage): class SqliteStorage(MetaDataStorage):
def __init__(self, db_dir): def __init__(self, db_dir):
self.db_dir = db_dir self.db_dir = db_dir
self.db = None self.db = adbapi.ConnectionPool('sqlite3', os.path.join(self.db_dir, "blockchainname.db"),
check_same_thread=False)
MetaDataStorage.__init__(self) MetaDataStorage.__init__(self)
def load(self): def load(self):
self.db = adbapi.ConnectionPool('sqlite3', os.path.join(self.db_dir, "blockchainname.db"),
check_same_thread=False)
def create_tables(transaction): def create_tables(transaction):
transaction.execute("create table if not exists name_metadata (" + transaction.execute("create table if not exists name_metadata (" +
" name text, " + " name text, " +
@ -130,54 +236,162 @@ class SqliteStorage(MetaDataStorage):
" name text, " + " name text, " +
" txid text, " + " txid text, " +
" n integer)") " n integer)")
transaction.execute("CREATE TABLE IF NOT EXISTS claim_cache (" +
" row_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
" claim_id TEXT UNIQUE NOT NULL, " +
" claim_sequence INTEGER, " +
" claim_address TEXT NOT NULL, " +
" height INTEGER NOT NULL, " +
" amount INTEGER NOT NULL, " +
" supports TEXT, " +
" claim_pb TEXT, " +
" channel_name TEXT, " +
" signature_is_valid BOOL, " +
" last_modified TEXT)")
transaction.execute("CREATE TABLE IF NOT EXISTS uri_cache (" +
" row_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
" uri TEXT UNIQUE NOT NULL, " +
" cache_row INTEGER, " +
" certificate_row INTEGER, " +
" last_modified TEXT)")
return self.db.runInteraction(create_tables) return self.db.runInteraction(create_tables)
@rerun_if_locked
@defer.inlineCallbacks
def clean_bad_records(self): def clean_bad_records(self):
d = self.db.runQuery("delete from name_metadata where length(txid) > 64 or txid is null") yield self.db.runQuery("DELETE FROM name_metadata WHERE LENGTH(txid) > 64 OR txid IS NULL")
return d defer.returnValue(None)
def save_name_metadata(self, name, claim_outpoint, sd_hash):
d = self.db.runQuery(
"delete from name_metadata where name=? and txid=? and n=? and sd_hash=?",
(name, claim_outpoint['txid'], claim_outpoint['nout'], sd_hash))
d.addCallback(
lambda _: self.db.runQuery(
"delete from name_metadata where name=? and txid=? and n=? and sd_hash=?",
(name, claim_outpoint['txid'], UNSET_NOUT, sd_hash)))
d.addCallback(
lambda _: self.db.runQuery(
"insert into name_metadata values (?, ?, ?, ?)",
(name, claim_outpoint['txid'], claim_outpoint['nout'], sd_hash)))
return d
@rerun_if_locked @rerun_if_locked
@defer.inlineCallbacks
def save_name_metadata(self, name, claim_outpoint, sd_hash):
# TODO: refactor the 'name_metadata' and 'claim_ids' tables to not be terrible
txid, nout = claim_outpoint['txid'], claim_outpoint['nout']
record_exists = yield self.db.runQuery("SELECT COUNT(*) FROM name_metadata "
"WHERE name=? AND txid=? AND n=?",
(name, txid, nout))
if not record_exists:
yield self.db.runOperation("INSERT INTO name_metadata VALUES (?, ?, ?, ?)",
(name, txid, nout, sd_hash))
defer.returnValue(None)
@rerun_if_locked
@defer.inlineCallbacks
def get_claim_metadata_for_sd_hash(self, sd_hash): def get_claim_metadata_for_sd_hash(self, sd_hash):
d = self.db.runQuery("select name, txid, n from name_metadata where sd_hash=?", (sd_hash,)) result = yield self.db.runQuery("SELECT name, txid, n FROM name_metadata WHERE sd_hash=?",
d.addCallback(lambda r: r[0] if r else None) (sd_hash, ))
return d response = None
if result:
response = result[0]
defer.returnValue(response)
@rerun_if_locked
@defer.inlineCallbacks
def update_claimid(self, claim_id, name, claim_outpoint): def update_claimid(self, claim_id, name, claim_outpoint):
d = self.db.runQuery( txid, nout = claim_outpoint['txid'], claim_outpoint['nout']
"delete from claim_ids where claimId=? and name=? and txid=? and n=?", yield self.db.runOperation("INSERT OR IGNORE INTO claim_ids VALUES (?, ?, ?, ?)",
(claim_id, name, claim_outpoint['txid'], claim_outpoint['nout'])) (claim_id, name, txid, nout))
d.addCallback( defer.returnValue(claim_id)
lambda _: self.db.runQuery(
"delete from claim_ids where claimId=? and name=? and txid=? and n=?",
(claim_id, name, claim_outpoint['txid'], UNSET_NOUT)))
d.addCallback(
lambda r: self.db.runQuery(
"insert into claim_ids values (?, ?, ?, ?)",
(claim_id, name, claim_outpoint['txid'], claim_outpoint['nout'])))
d.addCallback(lambda _: claim_id)
return d
def get_claimid_for_tx(self, name, claim_outpoint): @rerun_if_locked
d = self.db.runQuery( @defer.inlineCallbacks
"select claimId from claim_ids where name=? and txid=? and n=?", def get_claimid_for_tx(self, claim_outpoint):
(name, claim_outpoint['txid'], claim_outpoint['nout'])) result = yield self.db.runQuery("SELECT claimId FROM claim_ids "
d.addCallback(lambda r: r[0][0] if r else None) "WHERE txid=? AND n=?",
return d (claim_outpoint['txid'], claim_outpoint['nout']))
response = None
if result:
response = result[0][0]
defer.returnValue(response)
@rerun_if_locked
@defer.inlineCallbacks
def _get_cached_claim(self, claim_id, check_expire=True):
r = yield self.db.runQuery("SELECT * FROM claim_cache WHERE claim_id=?", (claim_id, ))
claim_tx_info = yield self.db.runQuery("SELECT name, txid, n FROM claim_ids "
"WHERE claimId=?", (claim_id, ))
response = None
if r and claim_tx_info:
_, _, seq, claim_address, height, amount, supports, raw, chan_name, valid, ts = r[0]
last_modified = int(ts)
name, txid, nout = claim_tx_info[0]
claim = ClaimDict.deserialize(raw.decode('hex'))
response = (claim, seq, claim_address, height, amount, supports,
chan_name, valid, last_modified, name, txid, nout)
defer.returnValue(response)
@rerun_if_locked
@defer.inlineCallbacks
def save_claim_to_cache(self, claim_id, claim_sequence, claim, claim_address, height, amount,
supports, channel_name, signature_is_valid):
serialized = claim.serialized.encode("hex")
supports = json.dumps([] or supports)
now = str(int(time.time()))
yield self.db.runOperation("INSERT OR REPLACE INTO claim_cache(claim_sequence, "
" claim_id, claim_address, height, "
" amount, supports, claim_pb, "
" channel_name, signature_is_valid, "
" last_modified)"
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
(claim_sequence, claim_id, claim_address, height, amount,
supports, serialized, channel_name, signature_is_valid, now))
defer.returnValue(None)
@rerun_if_locked
@defer.inlineCallbacks
def save_claim_to_uri_cache(self, uri, claim_id, certificate_id=None):
result = yield self.db.runQuery("SELECT row_id, last_modified FROM claim_cache "
"WHERE claim_id=?", (claim_id, ))
certificate_result = None
certificate_row = None
if certificate_id:
certificate_result = yield self.db.runQuery("SELECT row_id FROM claim_cache "
"WHERE claim_id=?", (certificate_id, ))
if certificate_id is not None and certificate_result is None:
log.warning("Certificate is not in cache")
elif certificate_result:
certificate_row = certificate_result[0][0]
if result:
cache_row, ts = result[0]
yield self.db.runOperation("INSERT OR REPLACE INTO uri_cache(uri, cache_row, "
" certificate_row, last_modified) "
"VALUES (?, ?, ?, ?)",
(uri, cache_row, certificate_row,
str(int(time.time()))))
else:
log.warning("Claim is not in cache")
defer.returnValue(None)
@rerun_if_locked
@defer.inlineCallbacks
def get_cached_claim_for_uri(self, uri, check_expire=True):
result = yield self.db.runQuery("SELECT "
"claim.claim_id, cert.claim_id, uri_cache.last_modified "
"FROM uri_cache "
"INNER JOIN claim_cache as claim "
"ON uri_cache.cache_row=claim.row_id "
"LEFT OUTER JOIN claim_cache as cert "
"ON uri_cache.certificate_row=cert.row_id "
"WHERE uri_cache.uri=?", (uri, ))
response = None
if result:
claim_id, certificate_id, last_modified = result[0]
last_modified = int(last_modified)
if check_expire and time.time() - last_modified > CLAIM_CACHE_TIME:
defer.returnValue(None)
claim = yield self.get_cached_claim(claim_id)
if claim:
response = {
"claim": claim
}
if response and certificate_id is not None:
certificate = yield self.get_cached_claim(certificate_id)
response['certificate'] = certificate
defer.returnValue(response)
class Wallet(object): class Wallet(object):
@ -230,9 +444,6 @@ class Wallet(object):
def _update_claimid(self, claim_id, name, claim_outpoint): def _update_claimid(self, claim_id, name, claim_outpoint):
return self._storage.update_claimid(claim_id, name, claim_outpoint) return self._storage.update_claimid(claim_id, name, claim_outpoint)
def _get_claimid_for_tx(self, name, claim_outpoint):
return self._storage.get_claimid_for_tx(name, claim_outpoint)
@staticmethod @staticmethod
def log_stop_error(err): def log_stop_error(err):
log.error("An error occurred stopping the wallet: %s", err.getTraceback()) log.error("An error occurred stopping the wallet: %s", err.getTraceback())
@ -452,42 +663,30 @@ class Wallet(object):
###### ######
@defer.inlineCallbacks @defer.inlineCallbacks
def get_claim(self, claim_id): def get_cached_claim(self, claim_id, check_expire=True):
claim = yield self._get_claim_by_claimid(claim_id) results = yield self._storage.get_cached_claim(claim_id, check_expire)
if not claim: defer.returnValue(results)
log.warning("Claim does not exist: %s", claim_id)
defer.returnValue(None)
try:
decoded = smart_decode(claim['value'])
claim['value'] = decoded.claim_dict
claim['hex'] = decoded.serialized.encode('hex')
except DecodeError:
claim['hex'] = claim['value']
claim['value'] = None
claim['error'] = "Failed to decode"
log.warning("Failed to decode claim value for lbry://%s#%s", claim['name'],
claim['claim_id'])
defer.returnValue(claim)
def get_claimid(self, name, txid, nout): @defer.inlineCallbacks
def _get_id_for_return(claim_id): def get_claim(self, claim_id, check_expire=True):
if claim_id: cached_claim = yield self.get_cached_claim(claim_id, check_expire)
return defer.succeed(claim_id) if cached_claim:
result = cached_claim
else:
log.debug("Refreshing cached claim: %s", claim_id)
claim = yield self._get_claim_by_claimid(claim_id)
result = None
if claim:
result = yield self._handle_claim_result(claim)
else: else:
d = self.get_claims_from_tx(txid) log.warning("Claim does not exist: %s", claim_id)
d.addCallback( defer.returnValue(result)
lambda claims: next(
c for c in claims if c['name'] == name and
c['nout'] == claim_outpoint['nout']))
d.addCallback(
lambda claim: self._update_claimid(
claim['claim_id'], name, ClaimOutpoint(txid, claim['nout'])))
return d
@defer.inlineCallbacks
def get_claimid(self, txid, nout):
claim_outpoint = ClaimOutpoint(txid, nout) claim_outpoint = ClaimOutpoint(txid, nout)
d = self._get_claimid_for_tx(name, claim_outpoint) claim_id = yield self._storage.get_claimid_for_tx(claim_outpoint)
d.addCallback(_get_id_for_return) defer.returnValue(claim_id)
return d
@defer.inlineCallbacks @defer.inlineCallbacks
def get_my_claim(self, name): def get_my_claim(self, name):
@ -501,19 +700,19 @@ class Wallet(object):
defer.returnValue(my_claim) defer.returnValue(my_claim)
@defer.inlineCallbacks @defer.inlineCallbacks
def get_claim_info(self, name, txid=None, nout=None, claim_id=None): def get_claim_info(self, name, txid=None, nout=None, claim_id=None, check_expire=True):
if claim_id is not None: if claim_id is not None:
results = yield self.get_claim(claim_id) results = yield self.get_claim(claim_id, check_expire)
if results['name'] != name: if results['name'] != name:
raise Exception("Name does not match claim referenced by id") raise Exception("Name does not match claim referenced by id")
elif txid is None or nout is None: elif txid is None or nout is None:
results = yield self.get_claim_by_name(name) results = yield self.get_claim_by_name(name)
else: else:
results = yield self.get_claim_by_outpoint(ClaimOutpoint(txid, nout)) results = yield self.get_claim_by_outpoint(ClaimOutpoint(txid, nout), check_expire)
defer.returnValue(results) defer.returnValue(results)
@defer.inlineCallbacks @defer.inlineCallbacks
def _handle_claim_result(self, results): def _handle_claim_result(self, results, update_caches=True):
if not results: if not results:
raise UnknownNameError("No results to return") raise UnknownNameError("No results to return")
@ -523,16 +722,35 @@ class Wallet(object):
else: else:
raise Exception(results['error']) raise Exception(results['error'])
if 'certificate' in results:
try:
decoded = smart_decode(results['certificate']['value'])
claim_dict = decoded.claim_dict
outpoint = ClaimOutpoint(results['certificate']['txid'],
results['certificate']['nout'])
name = results['certificate']['name']
results['certificate']['value'] = claim_dict
results['certificate']['hex'] = decoded.serialized.encode('hex')
if update_caches:
yield self._save_name_metadata(name, outpoint, decoded.source_hash)
yield self._update_claimid(results['certificate']['claim_id'], name, outpoint)
yield self._storage.save_claim_to_cache(results['certificate']['claim_id'],
results['certificate']['claim_sequence'],
decoded, results['certificate']['address'],
results['certificate']['height'],
results['certificate']['amount'],
results['certificate']['supports'],
None,
None)
except DecodeError:
pass
if 'claim' in results: if 'claim' in results:
claim = results['claim'] claim = results['claim']
if 'has_signature' in claim and claim['has_signature']: if 'has_signature' in claim and claim['has_signature']:
if not claim['signature_is_valid']: if not claim['signature_is_valid']:
log.warning("lbry://%s#%s has an invalid signature", log.warning("lbry://%s#%s has an invalid signature",
claim['name'], claim['claim_id']) claim['name'], claim['claim_id'])
decoded = ClaimDict.load_dict(claim['value'])
claim_dict = decoded.claim_dict
claim['value'] = claim_dict
defer.returnValue(claim)
try: try:
decoded = smart_decode(claim['value']) decoded = smart_decode(claim['value'])
claim_dict = decoded.claim_dict claim_dict = decoded.claim_dict
@ -540,24 +758,28 @@ class Wallet(object):
name = claim['name'] name = claim['name']
claim['value'] = claim_dict claim['value'] = claim_dict
claim['hex'] = decoded.serialized.encode('hex') claim['hex'] = decoded.serialized.encode('hex')
yield self._save_name_metadata(name, outpoint, decoded.source_hash) if update_caches:
yield self._update_claimid(claim['claim_id'], name, outpoint) yield self._save_name_metadata(name, outpoint, decoded.source_hash)
yield self._update_claimid(claim['claim_id'], name, outpoint)
yield self._storage.save_claim_to_cache(claim['claim_id'],
claim['claim_sequence'],
decoded, claim['address'],
claim['height'],
claim['amount'], claim['supports'],
claim.get('channel_name', None),
claim.get('signature_is_valid', None))
except DecodeError: except DecodeError:
claim['hex'] = claim['value'] claim['hex'] = claim['value']
claim['value'] = None claim['value'] = None
claim['error'] = "Failed to decode value" claim['error'] = "Failed to decode value"
results = claim results['claim'] = claim
elif 'value' in results: elif 'value' in results:
if 'has_signature' in results and results['has_signature']: if 'has_signature' in results and results['has_signature']:
if not results['signature_is_valid']: if not results['signature_is_valid']:
log.warning("lbry://%s#%s has an invalid signature", log.warning("lbry://%s#%s has an invalid signature",
results['name'], results['claim_id']) results['name'], results['claim_id'])
decoded = ClaimDict.load_dict(results['value'])
claim_dict = decoded.claim_dict
results['value'] = claim_dict
defer.returnValue(results)
try: try:
decoded = ClaimDict.load_dict(results['value']) decoded = ClaimDict.load_dict(results['value'])
claim_dict = decoded.claim_dict claim_dict = decoded.claim_dict
@ -565,8 +787,18 @@ class Wallet(object):
claim_err = None claim_err = None
outpoint = ClaimOutpoint(results['txid'], results['nout']) outpoint = ClaimOutpoint(results['txid'], results['nout'])
name = results['name'] name = results['name']
yield self._save_name_metadata(name, outpoint, decoded.source_hash) if update_caches:
yield self._update_claimid(results['claim_id'], name, outpoint) yield self._save_name_metadata(name, outpoint, decoded.source_hash)
yield self._update_claimid(results['claim_id'], name, outpoint)
yield self._storage.save_claim_to_cache(results['claim_id'],
results.get('claim_sequence', None),
decoded, results['address'],
results['height'], results['amount'],
results.get('supports', '[]'),
results.get('channel_name', None),
results.get('signature_is_valid',
None))
except DecodeError: except DecodeError:
claim_dict = None claim_dict = None
claim_hex = results['value'] claim_hex = results['value']
@ -576,33 +808,46 @@ class Wallet(object):
results['hex'] = claim_hex results['hex'] = claim_hex
results['value'] = claim_dict results['value'] = claim_dict
log.info("get claim info lbry://%s#%s", results['name'], results['claim_id'])
defer.returnValue(results) defer.returnValue(results)
@defer.inlineCallbacks @defer.inlineCallbacks
def resolve_uri(self, uri): def resolve_uri(self, uri, check_cache=True):
resolve_results = yield self._get_value_for_uri(uri) cached_claim = None
if 'claim' in resolve_results: if check_cache:
formatted = yield self._handle_claim_result(resolve_results) cached_claim = yield self._storage.get_cached_claim_for_uri(uri, check_cache)
resolve_results['claim'] = formatted if cached_claim:
result = resolve_results log.debug("Using cached results for %s", uri)
elif 'claims_in_channel' in resolve_results: resolve_results = cached_claim
claims_for_return = []
for claim in resolve_results['claims_in_channel']:
formatted = yield self._handle_claim_result(claim)
claims_for_return.append(formatted)
resolve_results['claims_in_channel'] = claims_for_return
result = resolve_results
elif 'error' in resolve_results:
raise Exception(resolve_results['error'])
else: else:
result = None log.info("Resolving %s", uri)
resolve_results = yield self._get_value_for_uri(uri)
claim_id = None
if resolve_results and 'claim' in resolve_results:
claim_id = resolve_results['claim']['claim_id']
certificate_id = None
if resolve_results and 'certificate' in resolve_results:
certificate_id = resolve_results['certificate']['claim_id']
result = yield self._handle_claim_result(resolve_results, cached_claim is None)
if claim_id:
yield self._storage.save_claim_to_uri_cache(uri, claim_id, certificate_id)
defer.returnValue(result) defer.returnValue(result)
@defer.inlineCallbacks @defer.inlineCallbacks
def get_claim_by_outpoint(self, claim_outpoint): def get_claim_by_outpoint(self, claim_outpoint, check_expire=True):
claim = yield self._get_claim_by_outpoint(claim_outpoint['txid'], claim_outpoint['nout']) claim_id = yield self._storage.get_claimid_for_tx(claim_outpoint)
result = yield self._handle_claim_result(claim) txid, nout = claim_outpoint['txid'], claim_outpoint['nout']
if claim_id:
cached_claim = yield self._storage.get_cached_claim(claim_id, check_expire)
else:
cached_claim = None
if not cached_claim:
claim = yield self._get_claim_by_outpoint(txid, nout)
result = yield self._handle_claim_result(claim)
else:
result = cached_claim
defer.returnValue(result) defer.returnValue(result)
@defer.inlineCallbacks @defer.inlineCallbacks
@ -1124,7 +1369,7 @@ class LBRYumWallet(Wallet):
def _do_send_many(self, payments_to_send): def _do_send_many(self, payments_to_send):
def broadcast_send_many(paytomany_out): def broadcast_send_many(paytomany_out):
if 'hex' not in paytomany_out: if 'hex' not in paytomany_out:
raise Exception('Unepxected paytomany output:{}'.format(paytomany_out)) raise Exception('Unexpected paytomany output:{}'.format(paytomany_out))
return self._broadcast_transaction(paytomany_out['hex']) return self._broadcast_transaction(paytomany_out['hex'])
log.debug("Doing send many. payments to send: %s", str(payments_to_send)) log.debug("Doing send many. payments to send: %s", str(payments_to_send))

View file

@ -123,7 +123,7 @@ class ManagedEncryptedFileDownloader(EncryptedFileSaver):
self.outpoint = ClaimOutpoint(self.txid, self.nout) self.outpoint = ClaimOutpoint(self.txid, self.nout)
else: else:
raise NoSuchSDHash(self.sd_hash) raise NoSuchSDHash(self.sd_hash)
self.claim_id = yield self.wallet.get_claimid(self.name, self.txid, self.nout) self.claim_id = yield self.wallet.get_claimid(self.txid, self.nout)
defer.returnValue(None) defer.returnValue(None)
@defer.inlineCallbacks @defer.inlineCallbacks

View file

@ -878,7 +878,7 @@ class Daemon(AuthJSONRPCServer):
size = None size = None
message = None message = None
claim = yield self.session.wallet.get_claim(lbry_file.claim_id) claim = yield self.session.wallet.get_claim(lbry_file.claim_id, check_expire=False)
if claim and 'value' in claim: if claim and 'value' in claim:
metadata = claim['value'] metadata = claim['value']
@ -915,7 +915,6 @@ class Daemon(AuthJSONRPCServer):
'suggested_file_name': lbry_file.suggested_file_name, 'suggested_file_name': lbry_file.suggested_file_name,
'sd_hash': lbry_file.sd_hash, 'sd_hash': lbry_file.sd_hash,
'name': lbry_file.name, 'name': lbry_file.name,
'channel_name': channel_name,
'outpoint': outpoint, 'outpoint': outpoint,
'claim_id': lbry_file.claim_id, 'claim_id': lbry_file.claim_id,
'download_path': full_path, 'download_path': full_path,
@ -926,6 +925,8 @@ class Daemon(AuthJSONRPCServer):
'message': message, 'message': message,
'metadata': metadata 'metadata': metadata
} }
if channel_name is not None:
result['channel_name'] = channel_name
if has_signature is not None: if has_signature is not None:
result['has_signature'] = has_signature result['has_signature'] = has_signature
if signature_is_valid is not None: if signature_is_valid is not None:
@ -1394,7 +1395,13 @@ class Daemon(AuthJSONRPCServer):
} }
""" """
try: try:
claim_results = yield self.session.wallet.get_claim_info(name, txid, nout, claim_id) if claim_id:
claim_results = yield self.session.wallet.get_claim(claim_id)
elif txid and nout is not None:
outpoint = ClaimOutpoint(txid, nout)
claim_results = yield self.session.wallet.get_claim_by_outpoint(outpoint)
else:
claim_results = yield self.session.wallet.get_claim_by_name(name)
result = format_json_out_amount_as_float(claim_results) result = format_json_out_amount_as_float(claim_results)
except (TypeError, UnknownNameError): except (TypeError, UnknownNameError):
result = False result = False