def upgrade_timestamp(timestamp, args): """Attempt to upgrade an incomplete timestamp to make it verifiable Returns True if the timestamp has changed, False otherwise. Note that this means if the timestamp that is already complete, False will be returned as nothing has changed. """ def directly_verified(stamp): if stamp.attestations: yield stamp else: for result_stamp in stamp.ops.values(): yield from directly_verified(result_stamp) yield from () def get_attestations(stamp): return set(attest for msg, attest in stamp.all_attestations()) changed = False # First, check the cache for upgrades to this timestamp. Since the cache is # local, we do this very agressively, checking every single sub-timestamp # against the cache. def walk_stamp(stamp): yield stamp for sub_stamp in stamp.ops.values(): yield from walk_stamp(sub_stamp) existing_attestations = get_attestations(timestamp) for sub_stamp in walk_stamp(timestamp): try: cached_stamp = args.cache[sub_stamp.msg] except KeyError: continue sub_stamp.merge(cached_stamp) new_attestations_from_cache = get_attestations(timestamp).difference(existing_attestations) if len(new_attestations_from_cache): changed = True logging.info("Got %d attestation(s) from cache" % len(new_attestations_from_cache)) existing_attestations.update(new_attestations_from_cache) for new_att in new_attestations_from_cache: logging.debug(" %r" % new_att) while not is_timestamp_complete(timestamp, args): # Check remote calendars for upgrades. # # This time we only check PendingAttestations - we can't be as # agressive. found_new_attestations = False for sub_stamp in directly_verified(timestamp): for attestation in sub_stamp.attestations: if attestation.__class__ == PendingAttestation: calendar_urls = args.calendar_urls if calendar_urls: # FIXME: this message is incorrectly displayed, disabling for now. # # logging.debug("Attestation URI %s overridden by user-specified remote calendar(s)" % attestation.uri) pass else: if attestation.uri in args.whitelist: calendar_urls = [attestation.uri] else: logging.warning("Ignoring attestation from calendar %s: Calendar not in whitelist" % attestation.uri) continue commitment = sub_stamp.msg for calendar_url in calendar_urls: logging.debug("Checking calendar %s for %s" % (attestation.uri, b2x(commitment))) calendar = remote_calendar(calendar_url) try: upgraded_stamp = calendar.get_timestamp(commitment) except opentimestamps.calendar.CommitmentNotFoundError as exp: logging.warning("Calendar %s: %s" % (attestation.uri, exp.reason)) continue except urllib.error.URLError as exp: logging.warning("Calendar %s: %s" % (attestation.uri, exp.reason)) continue atts_from_remote = get_attestations(upgraded_stamp) if atts_from_remote: logging.info("Got %d attestation(s) from %s" % (len(atts_from_remote), calendar_url)) for att in get_attestations(upgraded_stamp): logging.debug(" %r" % att) new_attestations = get_attestations(upgraded_stamp).difference(existing_attestations) if new_attestations: changed = True found_new_attestations = True existing_attestations.update(new_attestations) # FIXME: need to think about DoS attacks here args.cache.merge(upgraded_stamp) sub_stamp.merge(upgraded_stamp) if not args.wait: break elif found_new_attestations: # We got something new, so loop around immediately to check if # we're now complete continue else: # Nothing new, so wait logging.info("Timestamp not complete; waiting %d sec before trying again" % args.wait_interval) time.sleep(args.wait_interval) return changed
def upgrade_timestamp(timestamp, args): """Attempt to upgrade an incomplete timestamp to make it verifiable Returns True if the timestamp has changed, False otherwise. Note that this means if the timestamp that is already complete, False will be returned as nothing has changed. """ def directly_verified(stamp): if stamp.attestations: yield stamp else: for result_stamp in stamp.ops.values(): yield from directly_verified(result_stamp) yield from () def get_attestations(stamp): return set(attest for msg, attest in stamp.all_attestations()) changed = False # First, check the cache for upgrades to this timestamp. Since the cache is # local, we do this very agressively, checking every single sub-timestamp # against the cache. def walk_stamp(stamp): yield stamp for sub_stamp in stamp.ops.values(): yield from walk_stamp(sub_stamp) existing_attestations = get_attestations(timestamp) for sub_stamp in walk_stamp(timestamp): try: cached_stamp = args.cache[sub_stamp.msg] except KeyError: continue sub_stamp.merge(cached_stamp) new_attestations_from_cache = get_attestations(timestamp).difference( existing_attestations) if len(new_attestations_from_cache): changed = True logging.info("Got %d attestation(s) from cache" % len(new_attestations_from_cache)) existing_attestations.update(new_attestations_from_cache) for new_att in new_attestations_from_cache: logging.debug(" %r" % new_att) while not is_timestamp_complete(timestamp, args): # Check remote calendars for upgrades. # # This time we only check PendingAttestations - we can't be as # agressive. found_new_attestations = False for sub_stamp in directly_verified(timestamp): for attestation in sub_stamp.attestations: if attestation.__class__ == PendingAttestation: calendar_urls = args.calendar_urls if calendar_urls: # FIXME: this message is incorrectly displayed, disabling for now. # # logging.debug("Attestation URI %s overridden by user-specified remote calendar(s)" % attestation.uri) pass else: if args.whitelist is None: logging.warning( "Ignoring attestation from calendar %s: Remote calendars disabled" % attestation.uri) continue elif attestation.uri in args.whitelist: calendar_urls = [attestation.uri] else: logging.warning( "Ignoring attestation from calendar %s: Calendar not in whitelist" % attestation.uri) continue commitment = sub_stamp.msg for calendar_url in calendar_urls: logging.debug("Checking calendar %s for %s" % (attestation.uri, b2x(commitment))) calendar = remote_calendar(calendar_url) try: upgraded_stamp = calendar.get_timestamp(commitment) except opentimestamps.calendar.CommitmentNotFoundError as exp: logging.warning("Calendar %s: %s" % (attestation.uri, exp.reason)) continue except urllib.error.URLError as exp: logging.warning("Calendar %s: %s" % (attestation.uri, exp.reason)) continue atts_from_remote = get_attestations(upgraded_stamp) if atts_from_remote: logging.info("Got %d attestation(s) from %s" % (len(atts_from_remote), calendar_url)) for att in get_attestations(upgraded_stamp): logging.debug(" %r" % att) new_attestations = get_attestations( upgraded_stamp).difference(existing_attestations) if new_attestations: changed = True found_new_attestations = True existing_attestations.update(new_attestations) # FIXME: need to think about DoS attacks here args.cache.merge(upgraded_stamp) sub_stamp.merge(upgraded_stamp) if not args.wait: break elif found_new_attestations: # We got something new, so loop around immediately to check if # we're now complete continue else: # Nothing new, so wait logging.info( "Timestamp not complete; waiting %d sec before trying again" % args.wait_interval) time.sleep(args.wait_interval) return changed
def upgrade_timestamp(timestamp): """Attempt to upgrade an incomplete timestamp to make it verifiable Returns True if the timestamp has changed, False otherwise. Note that this means if the timestamp that is already complete, False will be returned as nothing has changed. """ def directly_verified(stamp): if stamp.attestations: yield stamp else: for result_stamp in stamp.ops.values(): yield from directly_verified(result_stamp) yield from () def get_attestations(stamp): #return set(attest for msg, attest in stamp.all_attestations()) return set(attest for _, attest in stamp.all_attestations()) changed = False existing_atts = get_attestations(timestamp) if not is_timestamp_complete(timestamp): # Check remote calendars for upgrades. # # This time we only check PendingAttestations - we can't be as # agressive. for sub_stamp in directly_verified(timestamp): for attestation in sub_stamp.attestations: if attestation.__class__ == PendingAttestation: commitment = sub_stamp.msg #for calendar_url in calendar_urls: for calendar_url in [attestation.uri]: msg = "Checking calendar %s for %s" % (attestation.uri, b2x(commitment)) logging.debug(msg) calendar = remote_calendar(calendar_url) try: upgraded_stamp = calendar.get_timestamp(commitment) except opentimestamps.calendar.CommitmentNotFoundError as exp: msg = "Calendar %s: %s" % (attestation.uri, exp.reason) logging.warning(msg) continue except urllib.error.URLError as exp: msg = "Calendar %s: %s" % (attestation.uri, exp.reason) logging.warning(msg) continue atts_from_remote = get_attestations(upgraded_stamp) if atts_from_remote: msg = "Got %d attestation(s) from %s" % \ (len(atts_from_remote), calendar_url) logging.info(msg) for att in get_attestations(upgraded_stamp): msg = " %r" % att logging.debug(msg) new_atts = get_attestations(upgraded_stamp).difference(existing_atts) if new_atts: changed = True existing_atts.update(new_atts) # FIXME: need to think about DoS attacks here #args.cache.merge(upgraded_stamp) sub_stamp.merge(upgraded_stamp) return changed