def _save(claim_id, name, tx, n, encoded_meta): try: decoded = json.loads(base64.b64decode(encoded_meta)) verify_name_characters(name) meta = Metadata(decoded, process_now=False) ver = meta.get('ver', '0.0.1') log.debug("lbry://%s conforms to metadata version %s" % (name, ver)) self._claims.update({ tx: { 'name': name, 'claim_id': claim_id, 'nout': n, 'metadata': meta } }) sd_hash = meta['sources']['lbry_sd_hash'] self._check_name_at_height(self._chain_height, name) if claim_id in self.non_complying_claims: self.non_complying_claims.remove(claim_id) d = self._load_sd_attempts(sd_hash) d.addCallback(lambda _: self._load_stream_size(sd_hash)) return d except: if claim_id not in self.non_complying_claims: self.non_complying_claims.append(claim_id) self._claims.update( {txid: { 'name': name, 'claim_id': claim_id, 'nout': n }}) return self._notify_bad_metadata(name, txid)
def _get_stream_info_from_value(self, result, name): def _check_result_fields(r): for k in ['value', 'txid', 'n', 'height', 'amount']: assert k in r, "getvalueforname response missing field %s" % k def _log_success(claim_id): log.debug("lbry://%s complies with %s, claimid: %s", name, metadata.version, claim_id) return defer.succeed(None) if 'error' in result: log.warning("Got an error looking up a name: %s", result['error']) return Failure(UnknownNameError(name)) _check_result_fields(result) try: metadata = Metadata(json.loads(result['value'])) except (TypeError, ValueError, ValidationError): return Failure(InvalidStreamInfoError(name, result['value'])) sd_hash = metadata['sources']['lbry_sd_hash'] claim_outpoint = ClaimOutpoint(result['txid'], result['n']) d = self._save_name_metadata(name, claim_outpoint, sd_hash) d.addCallback( lambda _: self.get_claimid(name, result['txid'], result['n'])) d.addCallback(lambda cid: _log_success(cid)) d.addCallback(lambda _: metadata) return d
def _get_dict_for_return(self, name): meta = Metadata(self.updater.metadata[name], process_now=True) r = { 'name': name, 'value': meta, 'cost': self.updater.cost_and_availability[name]['cost'], 'available': self.updater.cost_and_availability[name]['available'], } return r
def _claim_name(self): log.debug('Claiming name') self._update_metadata() m = Metadata(self.metadata) def set_tx_hash(txid): log.debug('Name claimed using txid: %s', txid) self.txid = txid d = self.wallet.claim_name(self.publish_name, self.bid_amount, m) d.addCallback(set_tx_hash) return d
def _update_claim_database(self, block_hash, height, name, claim, txid): if 'supported claimId' in claim: log.info("Skipping claim support %s for lbry://%s, claimid: %s", txid, name, claim['supported claimId']) return defer.succeed(None) claim_value = base64.b64encode(claim['value']) nout = claim['nOut'] claim_id = claim['claimId'] try: claim_info = { 'name': name, 'claim_id': claim_id, 'nout': nout, 'metadata': Metadata(json.loads(claim['value']), process_now=False) } self._claims.update({txid: claim_info}) if claim_id in self.non_complying_claims: self.non_complying_claims.remove(claim_id) except ValueError: log.info("Claim %s has invalid metadata json", claim_id) if claim_id not in self.non_complying_claims: self.non_complying_claims.append(claim_id) self._claims.update( {txid: { 'name': name, 'claim_id': claim_id, 'nout': nout }}) except AssertionError: log.info("Claim %s has non conforming metadata", claim_id) if claim_id not in self.non_complying_claims: self.non_complying_claims.append(claim_id) self._claims.update( {txid: { 'name': name, 'claim_id': claim_id, 'nout': nout }}) log.info("Add claim for lbry://%s, id: %s, tx: %s", name, claim_id, txid) d = self.db.runQuery("insert into blocks values (?, ?, ?)", (height, block_hash, txid)) d.addCallback(lambda _: self.db.runQuery( "insert into claims values (?, ?, ?, ?)", (claim_id, name, txid, nout))) d.addCallback( lambda _: self.db.runQuery("insert into metadata values (?, ?, ?)", (claim_id, txid, claim_value))) return d
def claim_name(self, name, bid, metadata): """ Claim a name, or update if name already claimed by user @param name: str, name to claim @param bid: float, bid amount @param metadata: Metadata compliant dict @return: Deferred which returns a dict containing below items txid - txid of the resulting transaction nout - nout of the resulting claim fee - transaction fee paid to make claim claim_id - claim id of the claim """ _metadata = Metadata(metadata) my_claim = yield self.get_my_claim(name) if my_claim: log.info("Updating claim") if self.get_balance() < Decimal(bid) - Decimal(my_claim['amount']): raise InsufficientFundsError() new_metadata = yield self.update_metadata(_metadata, my_claim['value']) old_claim_outpoint = ClaimOutpoint(my_claim['txid'], my_claim['nout']) claim = yield self._send_name_claim_update(name, my_claim['claim_id'], old_claim_outpoint, new_metadata, bid) claim['claim_id'] = my_claim['claim_id'] else: log.info("Making a new claim") if self.get_balance() < bid: raise InsufficientFundsError() claim = yield self._send_name_claim(name, _metadata, bid) if not claim['success']: msg = 'Claim to name {} failed: {}'.format(name, claim['reason']) raise Exception(msg) claim = self._process_claim_out(claim) claim_outpoint = ClaimOutpoint(claim['txid'], claim['nout']) log.info("Saving metadata for claim %s %d", claim['txid'], claim['nout']) yield self._save_name_metadata(name, claim_outpoint, _metadata['sources']['lbry_sd_hash']) defer.returnValue(claim)
def _build_response(claim): try: metadata = Metadata(json.loads(claim['value'])) meta_ver = metadata.version sd_hash = metadata['sources']['lbry_sd_hash'] d = self._save_name_metadata(name, claim_outpoint, sd_hash) except (TypeError, ValueError, ValidationError): metadata = claim['value'] meta_ver = "Non-compliant" d = defer.succeed(None) d.addCallback(lambda _: self._format_claim_for_return( name, claim, metadata=metadata, meta_version=meta_ver)) log.info("get claim info lbry://%s metadata: %s, claimid: %s", name, meta_ver, claim['claimId']) return d
def _initialize_metadata(self): log.info("initializing metadata") nametrie = self.api.get_nametrie() for c in nametrie: name = c['name'] txid = c['txid'] claim = self._claims.get(txid, {}) if 'metadata' in claim: try: meta = Metadata(claim['metadata'], process_now=False) self.metadata[name] = meta except AssertionError: log.info("Bad metadata for lbry://%s", name) else: log.debug("Missing metadata for lbry://%s", name) if 'claim_id' in claim: self._handle_bad_new_claim(name, claim['claim_id'])
def _claim_name(self): log.debug('Claiming name') self._update_metadata() m = Metadata(self.metadata) def set_txid_nout(claim_out): if not claim_out['success']: msg = 'Failed to claim name:{}'.format(claim_out['reason']) defer.fail(Exception(msg)) txid = claim_out['txid'] nout = claim_out['nout'] log.debug('Name claimed using txid: %s, nout: %d', txid, nout) self.txid = txid self.nout = nout d = self.wallet.claim_name(self.publish_name, self.bid_amount, m) d.addCallback(set_txid_nout) return d
def _claim_name(self): log.debug('Claiming name') self._update_metadata() m = Metadata(self.metadata) def set_claim_out(claim_out): log.debug( 'Name claimed using txid: %s, nout: %d, claim_id: %s, fee :%f', claim_out['txid'], claim_out['nout'], claim_out['claim_id'], claim_out['fee']) self.txid = claim_out['txid'] self.nout = claim_out['nout'] self.claim_id = claim_out['claim_id'] self.fee = claim_out['fee'] d = self.wallet.claim_name(self.publish_name, self.bid_amount, m) d.addCallback(set_claim_out) return d
def claim_name(self, name, bid, m): def _save_metadata(claim_out, metadata): if not claim_out['success']: msg = 'Claim to name {} failed: {}'.format( name, claim_out['reason']) raise Exception(msg) claim_out = self._process_claim_out(claim_out) claim_outpoint = ClaimOutpoint(claim_out['txid'], claim_out['nout']) log.info("Saving metadata for claim %s %d", claim_outpoint['txid'], claim_outpoint['nout']) d = self._save_name_metadata(name, claim_outpoint, metadata['sources']['lbry_sd_hash']) d.addCallback(lambda _: claim_out) return d def _claim_or_update(claim, metadata, _bid): if not claim: log.debug("No own claim yet, making a new one") if self.get_balance() < _bid: raise InsufficientFundsError() return self._send_name_claim(name, metadata, _bid) else: log.debug("Updating over own claim") if self.get_balance() < _bid - claim['amount']: raise InsufficientFundsError() d = self.update_metadata(metadata, claim['value']) claim_outpoint = ClaimOutpoint(claim['txid'], claim['nOut']) d.addCallback( lambda new_metadata: self._send_name_claim_update( name, claim['claim_id'], claim_outpoint, new_metadata, _bid)) d.addCallback(lambda claim_out: claim_out.update( {'claim_id': claim['claim_id']})) return d meta = Metadata(m) d = self.get_my_claim(name) d.addCallback(lambda claim: _claim_or_update(claim, meta, bid)) d.addCallback(lambda claim_out: _save_metadata(claim_out, meta)) return d
def update_metadata(self, new_metadata, old_metadata): meta_for_return = old_metadata if isinstance(old_metadata, dict) else {} for k in new_metadata: meta_for_return[k] = new_metadata[k] return defer.succeed(Metadata(meta_for_return))
def make_claim(self, name, bid, metadata): validated_metadata = Metadata(metadata) claim_out = yield self.wallet.claim_name(name, bid, validated_metadata) defer.returnValue(claim_out)