def get_mutable_data_route_hash(route): """ Given an unserialized route, get its hash. Return the hash on success Return None on error """ route_json = json_stable_serialize(route) if route_json is None: return None return get_data_hash(route_json)
def get_mutable_data_route_hash( route ): """ Given an unserialized route, get its hash. Return the hash on success Return None on error """ route_json = json_stable_serialize( route ) if route_json is None: return None return get_data_hash( route_json )
def put_mutable_data(data, privatekey): """ Given the unserialized data, store it into our mutable data stores. Do so in a best-effor way. This method only fails if all storage providers fail. If the data is not signed, then it will be signed with the given private key. Return True on success Return False on error """ data_id = data['id'] data_text = data['data'] ver = data['ver'] sig = data.get('sig', None) if sig is None: sig = sign_mutable_data(data, privatekey) data['sig'] = sig data_json = json_stable_serialize(data) successes = 0 for handler in storage_handlers: if not hasattr(handler, "put_mutable_handler"): continue rc = False try: rc = handler.put_mutable_handler(data_id, ver, sig, data_json) except Exception, e: log.exception(e) continue if not rc: log.error("Failed to replicate with '%s'" % handler.__name__) else: successes += 1
def put_mutable_data( data, privatekey ): """ Given the unserialized data, store it into our mutable data stores. Do so in a best-effor way. This method only fails if all storage providers fail. If the data is not signed, then it will be signed with the given private key. Return True on success Return False on error """ data_id = data['id'] data_text = data['data'] ver = data['ver'] sig = data.get('sig', None) if sig is None: sig = sign_mutable_data( data, privatekey ) data['sig'] = sig data_json = json_stable_serialize( data ) successes = 0 for handler in storage_handlers: if not hasattr( handler, "put_mutable_handler" ): continue rc = False try: rc = handler.put_mutable_handler( data_id, ver, sig, data_json ) except Exception, e: log.exception( e ) continue if not rc: log.error("Failed to replicate with '%s'" % handler.__name__) else: successes += 1
rc = put_immutable_handler(hash_data(d), d, "unused") if not rc: raise Exception("put_immutable_handler('%s') failed" % d) # put_mutable_handler print "put_mutable_handler" for i in xrange(0, len(test_data)): d_id, d, n, s, url = test_data[i] data_url = make_mutable_url(d_id) data = mutable_data(d_id, d, n, sig=s) data_json = json_stable_serialize(data) rc = put_mutable_handler(d_id, n, "unused", data_json) if not rc: raise Exception("put_mutable_handler('%s', '%s') failed" % (d_id, d)) test_data[i][4] = data_url # get_immutable_handler print "get_immutable_handler" for i in xrange(0, len(test_data)): d_id, d, n, s, url = test_data[i] rd = get_immutable_handler(hash_data(d))
def put_mutable(name, data_id, data_text, privatekey, proxy=None, create=True, txid=None, ver=None, make_ver=None, conf=None ): """ put_mutable ** Consistency ** ver, if given, is the version to include in the data. make_ver, if given, is a callback that takes the data_id, data_text, and current version as arguments, and generates the version to be included in the data record uploaded. If ver is not given, but make_ver is, then make_ver will be used to generate the version. If neither ver nor make_ver are given, the mutable data (if it already exists) is fetched, and the version is calculated as the larget known version + 1. ** Durability ** Replication is best-effort. If one storage provider driver succeeds, the put_mutable succeeds. If they all fail, then put_mutable fails. More complex behavior can be had by creating a "meta-driver" that calls existing drivers' methods in the desired manner. """ if proxy is None: proxy = get_default_proxy() result = {} user = get_name_record(name, create_if_absent=create) if 'error' in user: return {'error': "Unable to load user record: %s" % user['error']} route = None exists = user_db.has_mutable_data_route(user, data_id) old_hash = None cur_hash = None new_ver = ver if ver is None: if exists: # mutable record already exists. # generate one automatically. # use the existing locally-stored version, # and fall back to using the last-known version # from the existing mutable data record. new_ver = load_mutable_data_version( config.get_config(), name, data_id, try_remote=True ) if new_ver is None: # data exists, but we couldn't figure out the version return {'error': "Unable to determine version"} if make_ver is not None: # generate version new_ver = make_ver( data_id, data_text, new_ver ) else: # no version known, and no way to generate it. # by default, start at 1. we'll manage it ourselves. if new_ver is None: new_ver = 1 else: new_ver += 1 # do we have a route for this data yet? if not exists: if not create: # won't create; expect it to exist return {'error': 'No such route'} # need to put one urls = storage.make_mutable_urls(data_id) if len(urls) == 0: return {"error": "No routes constructed"} writer_pubkey = pybitcointools.privkey_to_pubkey(privatekey) route = storage.mutable_data_route(data_id, urls, writer_pubkey=writer_pubkey) user_db.add_mutable_data_route(user, route) user_json = user_db.serialize_user(user) # update the user record with the new route 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'] cur_hash = update_result['value_hash'] else: route = user_db.get_mutable_data_route(user, data_id) if route is None: return {"error": "No such route"} # generate the data data = storage.mutable_data(data_id, data_text, new_ver, privkey=privatekey) if data is None: return {"error": "Failed to generate data record"} # serialize... data_json = parsing.json_stable_serialize(data) # replicate... store_rc = storage.put_mutable_data( data, privatekey ) if not store_rc: result['error'] = "Failed to store mutable data" else: result['status'] = True result['transaction_hash'] = txid if cur_hash: # propagate result['value_hash'] = cur_hash # cache new version store_mutable_data_version( conf, data_id, new_ver ) return result
def put_mutable(name, data_id, data_text, privatekey, proxy=None, create=True, txid=None, ver=None, make_ver=None, conf=None): """ put_mutable ** Consistency ** ver, if given, is the version to include in the data. make_ver, if given, is a callback that takes the data_id, data_text, and current version as arguments, and generates the version to be included in the data record uploaded. If ver is not given, but make_ver is, then make_ver will be used to generate the version. If neither ver nor make_ver are given, the mutable data (if it already exists) is fetched, and the version is calculated as the larget known version + 1. ** Durability ** Replication is best-effort. If one storage provider driver succeeds, the put_mutable succeeds. If they all fail, then put_mutable fails. More complex behavior can be had by creating a "meta-driver" that calls existing drivers' methods in the desired manner. """ if proxy is None: proxy = get_default_proxy() result = {} user = get_name_record(name, create_if_absent=create) if 'error' in user: return {'error': "Unable to load user record: %s" % user['error']} route = None exists = user_db.has_mutable_data_route(user, data_id) old_hash = None cur_hash = None new_ver = ver if ver is None: if exists: # mutable record already exists. # generate one automatically. # use the existing locally-stored version, # and fall back to using the last-known version # from the existing mutable data record. new_ver = load_mutable_data_version(config.get_config(), name, data_id, try_remote=True) if new_ver is None: # data exists, but we couldn't figure out the version return {'error': "Unable to determine version"} if make_ver is not None: # generate version new_ver = make_ver(data_id, data_text, new_ver) else: # no version known, and no way to generate it. # by default, start at 1. we'll manage it ourselves. if new_ver is None: new_ver = 1 else: new_ver += 1 # do we have a route for this data yet? if not exists: if not create: # won't create; expect it to exist return {'error': 'No such route'} # need to put one urls = storage.make_mutable_urls(data_id) if len(urls) == 0: return {"error": "No routes constructed"} writer_pubkey = pybitcointools.privkey_to_pubkey(privatekey) route = storage.mutable_data_route(data_id, urls, writer_pubkey=writer_pubkey) user_db.add_mutable_data_route(user, route) user_json = user_db.serialize_user(user) # update the user record with the new route 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'] cur_hash = update_result['value_hash'] else: route = user_db.get_mutable_data_route(user, data_id) if route is None: return {"error": "No such route"} # generate the data data = storage.mutable_data(data_id, data_text, new_ver, privkey=privatekey) if data is None: return {"error": "Failed to generate data record"} # serialize... data_json = parsing.json_stable_serialize(data) # replicate... store_rc = storage.put_mutable_data(data, privatekey) if not store_rc: result['error'] = "Failed to store mutable data" else: result['status'] = True result['transaction_hash'] = txid if cur_hash: # propagate result['value_hash'] = cur_hash # cache new version store_mutable_data_version(conf, data_id, new_ver) return result