def get_immutable(name, data_hash, data_id=None, proxy=None): """ get_immutable Fetch a piece of immutable data. Use @data_hash to look it up in the user's zonefile, and then fetch and verify the data itself from the configured storage providers. Return {'data': the data, 'hash': hash} on success Return {'error': ...} on failure """ if proxy is None: proxy = get_default_proxy() user_zonefile = get_name_zonefile(name, proxy=proxy) if user_zonefile is None: return {'error': 'No user zonefile defined'} if 'error' in user_zonefile: return user_zonefile if blockstack_profiles.is_profile_in_legacy_format( user_zonefile ) or not user_db.is_user_zonefile( user_zonefile ): # zonefile is really a legacy profile return {'error': 'Profile is in a legacy format that does not support immutable data.'} if data_id is not None: # look up hash by name h = user_db.get_immutable_data_hash( user_zonefile, data_id ) if h is None: return {'error': 'No such immutable datum'} if type(h) == list: # this tool doesn't allow this to happen (one ID matches one hash), # but that doesn't preclude the user from doing this with other tools. if data_hash is not None and data_hash not in h: return {'error': 'Data ID/hash mismatch'} else: return {'error': "Multiple matches for '%s': %s" % (data_id, ",".join(h))} if data_hash is not None: if h != data_hash: return {'error': 'Data ID/hash mismatch'} else: data_hash = h elif not user_db.has_immutable_data( user_zonefile, data_hash ): return {'error': 'No such immutable datum'} data_url_hint = user_db.get_immutable_data_url( user_zonefile, data_hash ) data = storage.get_immutable_data( data_hash, fqu=name, data_id=data_id, data_url=data_url_hint ) if data is None: return {'error': 'No immutable data returned'} return {'data': data, 'hash': data_hash}
def delete_immutable(name, data_key, privatekey, proxy=None, txid=None): """ delete_immutable """ if proxy is None: proxy = get_default_proxy() result = {} user = get_name_record(name) if 'error' in user: # no user data return {'error': "Unable to load user record: %s" % user['error']} # does the user record have this data? if not user_db.has_immutable_data(user, data_key): # already deleted return {'status': True} # remove hash from the user record and update it user_db.remove_immutable_data(user, data_key) user_json = user_db.serialize_user(user) update_result = update(name, user_json, privatekey, txid=txid, proxy=proxy) if 'error' in update_result: # update failed; caller should try again return update_result txid = update_result['transaction_hash'] # remove the data itself data delete_result = storage.delete_immutable_data(data_key, txid) if delete_result: result['status'] = True else: # be sure to give back the update transaction hash, so this call can be retried result['error'] = 'Failed to delete immutable data' result['transaction_hash'] = txid result['value_hash'] = update_result['value_hash'] return result
def get_immutable(name, data_key): """ get_immutable """ user = get_name_record(name) if 'error' in user: # no user data return {'error': "Unable to load user record: %s" % user['error']} if not user_db.has_immutable_data(user, data_key): # no data return {'error': 'Profile has no such immutable data'} data = storage.get_immutable_data(data_key) if data is None: # no data return {'error': 'No immutable data found'} return {'data': data}
def delete_immutable(name, data_key, data_id=None, proxy=None, txid=None, wallet_keys=None): """ delete_immutable Remove an immutable datum from a name's profile, given by @data_key. Return a dict with {'status': True} on success Return a dict with {'error': ...} on failure """ from backend.nameops import do_update if proxy is None: proxy = get_default_proxy() legacy = False user_zonefile = get_name_zonefile( name, proxy=proxy, include_name_record=True ) if user_zonefile is None or 'error' in user_zonefile: if user_zonefile is None: return {'error': 'No user zonefile'} else: return user_zonefile name_record = user_zonefile['name_record'] del user_zonefile['name_record'] if blockstack_profiles.is_profile_in_legacy_format( user_zonefile ) or not user_db.is_user_zonefile( user_zonefile ): # zonefile is a legacy profile. There is no immutable data log.info("Profile is in legacy format. No immutable data.") return {'status': True} if data_key is None: if data_id is not None: # look up the key (or list of keys) # shouldn't be a list--this tool prevents that--but deal with it nevertheless data_key = user_db.get_immutable_data_hash( user_zonefile, data_id ) if type(data_key) == list: return {'error': "Multiple hashes for '%s': %s" % (data_id, ",".join(data_key)) } if data_key is None: return {'error': "No hash for '%s'" % data_id} else: return {'error': 'No data hash or data ID given'} # already deleted? if not user_db.has_immutable_data( user_zonefile, data_key ): return {'status': True} # remove user_db.remove_immutable_data_zonefile( user_zonefile, data_key ) zonefile_hash = hash_zonefile( user_zonefile ) if txid is None: # actually send the transaction _, payment_privkey = get_payment_keypair(wallet_keys=wallet_keys, config_path=proxy.conf['path']) _, owner_privkey = get_owner_keypair(wallet_keys=wallet_keys, config_path=proxy.conf['path']) utxo_client = get_utxo_provider_client( config_path=proxy.conf['path'] ) broadcaster_client = get_tx_broadcaster( config_path=proxy.conf['path'] ) update_result = do_update( name, zonefile_hash, owner_privkey, payment_privkey, utxo_client, broadcaster_client, config_path=proxy.conf['path'], proxy=proxy ) if 'error' in update_result: # failed to remove from zonefile return update_result txid = update_result['transaction_hash'] result = { 'zonefile_hash': zonefile_hash, 'transaction_hash': txid } # put new zonefile rc = store_name_zonefile( name, user_zonefile, txid ) if not rc: result['error'] = 'Failed to put new zonefile' return result # delete immutable data data_privkey = get_data_or_owner_privkey( user_zonefile, name_record['address'], wallet_keys=wallet_keys, config_path=proxy.conf['path'] ) if 'error' in data_privkey: return {'error': data_privkey['error']} else: data_privkey = data_privkey['privatekey'] assert data_privkey is not None rc = storage.delete_immutable_data( data_key, txid, data_privkey ) if not rc: result['error'] = 'Failed to delete immutable data' return result else: result['status'] = True return result