Exemple #1
0
def get_warnings(tracker, best_share, net, bitcoind_warning, bitcoind_work_value):
    res = []

    desired_version_counts = get_desired_version_counts(
        tracker, best_share, min(net.CHAIN_LENGTH, 60 * 60 // net.SHARE_PERIOD, tracker.get_height(best_share))
    )
    majority_desired_version = max(desired_version_counts, key=lambda k: desired_version_counts[k])
    if (
        majority_desired_version > (Share.SUCCESSOR if Share.SUCCESSOR is not None else Share).VOTING_VERSION
        and desired_version_counts[majority_desired_version] > sum(desired_version_counts.itervalues()) / 2
    ):
        res.append(
            "A MAJORITY OF SHARES CONTAIN A VOTE FOR AN UNSUPPORTED SHARE IMPLEMENTATION! (v%i with %i%% support)\n"
            "An upgrade is likely necessary. Check http://p2pool.forre.st/ for more information."
            % (
                majority_desired_version,
                100 * desired_version_counts[majority_desired_version] / sum(desired_version_counts.itervalues()),
            )
        )

    if bitcoind_warning is not None:
        if "This is a pre-release test build" not in bitcoind_warning:
            res.append("(from bitcoind) %s" % (bitcoind_warning,))

    if time.time() > bitcoind_work_value["last_update"] + 60:
        res.append(
            """LOST CONTACT WITH BITCOIND for %s! Check that it isn't frozen or dead!"""
            % (math.format_dt(time.time() - bitcoind_work_value["last_update"]),)
        )

    return res
Exemple #2
0
def get_warnings(tracker, best_share, net, bitcoind_warning,
                 bitcoind_work_value):
    res = []

    desired_version_counts = get_desired_version_counts(
        tracker, best_share,
        min(60 * 60 // net.SHARE_PERIOD, tracker.get_height(best_share)))
    majority_desired_version = max(desired_version_counts,
                                   key=lambda k: desired_version_counts[k])
    if majority_desired_version > 5 and desired_version_counts[
            majority_desired_version] > sum(
                desired_version_counts.itervalues()) / 2:
        res.append(
            'A MAJORITY OF SHARES CONTAIN A VOTE FOR AN UNSUPPORTED SHARE IMPLEMENTATION! (v%i with %i%% support)\n'
            'An upgrade is likely necessary. Check http://p2pool.forre.st/ for more information.'
            % (majority_desired_version,
               100 * desired_version_counts[majority_desired_version] /
               sum(desired_version_counts.itervalues())))

    if bitcoind_warning is not None:
        res.append('(from bitcoind) %s' % (bitcoind_warning, ))

    if time.time() > bitcoind_work_value['last_update'] + 60:
        res.append(
            '''LOST CONTACT WITH BITCOIND for %s! Check that it isn't frozen or dead!'''
            % (math.format_dt(time.time() -
                              bitcoind_work_value['last_update']), ))

    return res
Exemple #3
0
def get_warnings(tracker, best_share, net, daemon_getinfo, daemon_work_value):
    res = []
    
    desired_version_counts = get_desired_version_counts(tracker, best_share,
        min(net.CHAIN_LENGTH, 60*60//net.SHARE_PERIOD, tracker.get_height(best_share)))
    majority_desired_version = max(desired_version_counts, key=lambda k: desired_version_counts[k])
    if majority_desired_version > (Share.SUCCESSOR if Share.SUCCESSOR is not None else Share).VOTING_VERSION and desired_version_counts[majority_desired_version] > sum(desired_version_counts.itervalues())/2:
        res.append('A MAJORITY OF SHARES CONTAIN A VOTE FOR AN UNSUPPORTED SHARE IMPLEMENTATION! (v%i with %i%% support)\n'
            'An upgrade is likely necessary. Check http://p2pool.forre.st/ for more information.' % (
                majority_desired_version, 100*desired_version_counts[majority_desired_version]/sum(desired_version_counts.itervalues())))
    
    if daemon_getinfo['errors'] != '':
        if 'This is a pre-release test build' not in daemon_getinfo['errors']:
            res.append('(from daemon) %s' % (daemon_getinfo['errors'],))
    
    version_warning = getattr(net, 'VERSION_WARNING', lambda v: None)(daemon_getinfo['version'])
    if version_warning is not None:
        res.append(version_warning)
    
    if time.time() > daemon_work_value['last_update'] + 60:
        res.append('''LOST CONTACT WITH THE DAEMON for %s!''' % (math.format_dt(time.time() - daemon_work_value['last_update']),))
    
    return res
Exemple #4
0
 def think(self, block_rel_height_func, previous_block, bits, known_txs):
     desired = set()
     
     # O(len(self.heads))
     #   make 'unverified heads' set?
     # for each overall head, attempt verification
     # if it fails, attempt on parent, and repeat
     # if no successful verification because of lack of parents, request parent
     bads = set()
     for head in set(self.heads) - set(self.verified.heads):
         head_height, last = self.get_height_and_last(head)
         
         for share in self.get_chain(head, head_height if last is None else min(5, max(0, head_height - self.net.CHAIN_LENGTH))):
             if self.attempt_verify(share):
                 break
             if share.hash in self.heads:
                 bads.add(share.hash)
         else:
             if last is not None:
                 desired.add((
                     self.items[random.choice(list(self.reverse[last]))].peer_addr,
                     last,
                     max(x.timestamp for x in self.get_chain(head, min(head_height, 5))),
                     min(x.target for x in self.get_chain(head, min(head_height, 5))),
                 ))
     for bad in bads:
         assert bad not in self.verified.items
         assert bad in self.heads
         if p2pool.DEBUG:
             print "BAD", bad
         self.remove(bad)
     
     # try to get at least CHAIN_LENGTH height for each verified head, requesting parents if needed
     for head in list(self.verified.heads):
         head_height, last_hash = self.verified.get_height_and_last(head)
         last_height, last_last_hash = self.get_height_and_last(last_hash)
         # XXX review boundary conditions
         want = max(self.net.CHAIN_LENGTH - head_height, 0)
         can = max(last_height - 1 - self.net.CHAIN_LENGTH, 0) if last_last_hash is not None else last_height
         get = min(want, can)
         #print 'Z', head_height, last_hash is None, last_height, last_last_hash is None, want, can, get
         for share in self.get_chain(last_hash, get):
             if not self.attempt_verify(share):
                 break
         if head_height < self.net.CHAIN_LENGTH and last_last_hash is not None:
             desired.add((
                 self.items[random.choice(list(self.verified.reverse[last_hash]))].peer_addr,
                 last_last_hash,
                 max(x.timestamp for x in self.get_chain(head, min(head_height, 5))),
                 min(x.target for x in self.get_chain(head, min(head_height, 5))),
             ))
     
     # decide best tree
     decorated_tails = sorted((self.score(max(self.verified.tails[tail_hash], key=self.verified.get_work), block_rel_height_func), tail_hash) for tail_hash in self.verified.tails)
     if p2pool.DEBUG:
         print len(decorated_tails), 'tails:'
         for score, tail_hash in decorated_tails:
             print format_hash(tail_hash), score
     best_tail_score, best_tail = decorated_tails[-1] if decorated_tails else (None, None)
     
     # decide best verified head
     decorated_heads = sorted(((
         self.verified.get_work(self.verified.get_nth_parent_hash(h, min(5, self.verified.get_height(h)))),
         #self.items[h].peer_addr is None,
         -self.items[h].should_punish_reason(previous_block, bits, self, known_txs)[0],
         -self.items[h].time_seen,
     ), h) for h in self.verified.tails.get(best_tail, []))
     if p2pool.DEBUG:
         print len(decorated_heads), 'heads. Top 10:'
         for score, head_hash in decorated_heads[-10:]:
             print '   ', format_hash(head_hash), format_hash(self.items[head_hash].previous_hash), score
     best_head_score, best = decorated_heads[-1] if decorated_heads else (None, None)
     
     if best is not None:
         best_share = self.items[best]
         punish, punish_reason = best_share.should_punish_reason(previous_block, bits, self, known_txs)
         if punish > 0:
             print 'Punishing share for %r! Jumping from %s to %s!' % (punish_reason, format_hash(best), format_hash(best_share.previous_hash))
             best = best_share.previous_hash
         
         timestamp_cutoff = min(int(time.time()), best_share.timestamp) - 3600
         target_cutoff = int(2**256//(self.net.SHARE_PERIOD*best_tail_score[1] + 1) * 2 + .5) if best_tail_score[1] is not None else 2**256-1
     else:
         timestamp_cutoff = int(time.time()) - 24*60*60
         target_cutoff = 2**256-1
     
     if p2pool.DEBUG:
         print 'Desire %i shares. Cutoff: %s old diff>%.2f' % (len(desired), math.format_dt(time.time() - timestamp_cutoff), bitcoin_data.target_to_difficulty(target_cutoff))
         for peer_addr, hash, ts, targ in desired:
             print '   ', None if peer_addr is None else '%s:%i' % peer_addr, format_hash(hash), math.format_dt(time.time() - ts), bitcoin_data.target_to_difficulty(targ), ts >= timestamp_cutoff, targ <= target_cutoff
     
     return best, [(peer_addr, hash) for peer_addr, hash, ts, targ in desired if ts >= timestamp_cutoff], decorated_heads
Exemple #5
0
 def think(self, block_rel_height_func, previous_block, bits):
     desired = set()
     
     # O(len(self.heads))
     #   make 'unverified heads' set?
     # for each overall head, attempt verification
     # if it fails, attempt on parent, and repeat
     # if no successful verification because of lack of parents, request parent
     bads = set()
     for head in set(self.heads) - set(self.verified.heads):
         head_height, last = self.get_height_and_last(head)
         
         for share in self.get_chain(head, head_height if last is None else min(5, max(0, head_height - self.net.CHAIN_LENGTH))):
             if self.attempt_verify(share):
                 break
             if share.hash in self.heads:
                 bads.add(share.hash)
         else:
             if last is not None:
                 desired.add((
                     self.shares[random.choice(list(self.reverse_shares[last]))].peer,
                     last,
                     max(x.timestamp for x in self.get_chain(head, min(head_height, 5))),
                     min(x.target for x in self.get_chain(head, min(head_height, 5))),
                 ))
     for bad in bads:
         assert bad not in self.verified.shares
         assert bad in self.heads
         if p2pool.DEBUG:
             print "BAD", bad
         self.remove(bad)
     
     # try to get at least CHAIN_LENGTH height for each verified head, requesting parents if needed
     for head in list(self.verified.heads):
         head_height, last_hash = self.verified.get_height_and_last(head)
         last_height, last_last_hash = self.get_height_and_last(last_hash)
         # XXX review boundary conditions
         want = max(self.net.CHAIN_LENGTH - head_height, 0)
         can = max(last_height - 1 - self.net.CHAIN_LENGTH, 0) if last_last_hash is not None else last_height
         get = min(want, can)
         #print 'Z', head_height, last_hash is None, last_height, last_last_hash is None, want, can, get
         for share in self.get_chain(last_hash, get):
             if not self.attempt_verify(share):
                 break
         if head_height < self.net.CHAIN_LENGTH and last_last_hash is not None:
             desired.add((
                 self.shares[random.choice(list(self.verified.reverse_shares[last_hash]))].peer,
                 last_last_hash,
                 max(x.timestamp for x in self.get_chain(head, min(head_height, 5))),
                 min(x.target for x in self.get_chain(head, min(head_height, 5))),
             ))
     
     # decide best tree
     decorated_tails = sorted((self.score(max(self.verified.tails[tail_hash], key=self.verified.get_work), block_rel_height_func), tail_hash) for tail_hash in self.verified.tails)
     if p2pool.DEBUG:
         print len(decorated_tails), 'tails:'
         for score, tail_hash in decorated_tails:
             print format_hash(tail_hash), score
     best_tail_score, best_tail = decorated_tails[-1] if decorated_tails else (None, None)
     
     # decide best verified head
     decorated_heads = sorted(((
         self.verified.get_work(self.verified.get_nth_parent_hash(h, min(5, self.verified.get_height(h)))),
         #self.shares[h].peer is None,
         self.shares[h].pow_hash <= self.shares[h].header['bits'].target, # is block solution
         (self.shares[h].header['previous_block'], self.shares[h].header['bits']) == (previous_block, bits) or self.shares[h].peer is None,
         -self.shares[h].time_seen,
     ), h) for h in self.verified.tails.get(best_tail, []))
     if p2pool.DEBUG:
         print len(decorated_heads), 'heads. Top 10:'
         for score, head_hash in decorated_heads[-10:]:
             print '   ', format_hash(head_hash), format_hash(self.shares[head_hash].previous_hash), score
     best_head_score, best = decorated_heads[-1] if decorated_heads else (None, None)
     
     # eat away at heads
     if decorated_heads:
         for i in xrange(1000):
             to_remove = set()
             for share_hash, tail in self.heads.iteritems():
                 if share_hash in [head_hash for score, head_hash in decorated_heads[-5:]]:
                     #print 1
                     continue
                 if self.shares[share_hash].time_seen > time.time() - 300:
                     #print 2
                     continue
                 if share_hash not in self.verified.shares and max(self.shares[after_tail_hash].time_seen for after_tail_hash in self.reverse_shares.get(tail)) > time.time() - 120: # XXX stupid
                     #print 3
                     continue
                 to_remove.add(share_hash)
             if not to_remove:
                 break
             for share_hash in to_remove:
                 if share_hash in self.verified.shares:
                     self.verified.remove(share_hash)
                 self.remove(share_hash)
             #print "_________", to_remove
     
     # drop tails
     for i in xrange(1000):
         to_remove = set()
         for tail, heads in self.tails.iteritems():
             if min(self.get_height(head) for head in heads) < 2*self.net.CHAIN_LENGTH + 10:
                 continue
             for aftertail in self.reverse_shares.get(tail, set()):
                 if len(self.reverse_shares[self.shares[aftertail].previous_hash]) > 1: # XXX
                     print "raw"
                     continue
                 to_remove.add(aftertail)
         if not to_remove:
             break
         # if removed from this, it must be removed from verified
         #start = time.time()
         for aftertail in to_remove:
             if self.shares[aftertail].previous_hash not in self.tails:
                 print "erk", aftertail, self.shares[aftertail].previous_hash
                 continue
             if aftertail in self.verified.shares:
                 self.verified.remove(aftertail)
             self.remove(aftertail)
         #end = time.time()
         #print "removed! %i %f" % (len(to_remove), (end - start)/len(to_remove))
     
     if best is not None:
         best_share = self.shares[best]
         if (best_share.header['previous_block'], best_share.header['bits']) != (previous_block, bits) and best_share.header_hash != previous_block and best_share.peer is not None:
             if p2pool.DEBUG:
                 print 'Stale detected! %x < %x' % (best_share.header['previous_block'], previous_block)
             best = best_share.previous_hash
         
         timestamp_cutoff = min(int(time.time()), best_share.timestamp) - 3600
         target_cutoff = 2**256//(self.net.SHARE_PERIOD*best_tail_score[1] + 1) * 2 if best_tail_score[1] is not None else 2**256-1
     else:
         timestamp_cutoff = int(time.time()) - 24*60*60
         target_cutoff = 2**256-1
     
     if p2pool.DEBUG:
         print 'Desire %i shares. Cutoff: %s old diff>%.2f' % (len(desired), math.format_dt(time.time() - timestamp_cutoff), bitcoin_data.target_to_difficulty(target_cutoff))
         for peer, hash, ts, targ in desired:
             print '   ', '%s:%i' % peer.addr if peer is not None else None, format_hash(hash), math.format_dt(time.time() - ts), bitcoin_data.target_to_difficulty(targ), ts >= timestamp_cutoff, targ <= target_cutoff
     
     return best, [(peer, hash) for peer, hash, ts, targ in desired if ts >= timestamp_cutoff and targ <= target_cutoff]
Exemple #6
0
def get_warnings(tracker, best_share, net, bitcoind_warning, bitcoind_work_value):
    res = []

    desired_version_counts = get_desired_version_counts(tracker, best_share,
        min(net.CHAIN_LENGTH, 60*60//net.SHARE_PERIOD, tracker.get_height(best_share)))
    majority_desired_version = max(desired_version_counts, key=lambda k: desired_version_counts[k])
    if majority_desired_version > 14 and desired_version_counts[majority_desired_version] > sum(desired_version_counts.itervalues())/2:
        res.append('A MAJORITY OF SHARES CONTAIN A VOTE FOR AN UNSUPPORTED SHARE IMPLEMENTATION! (v%i with %i%% support)\n'
            'An upgrade is likely necessary. Check https://github.com/CryptoManiac/p2pool for more information.' % (
                majority_desired_version, 100*desired_version_counts[majority_desired_version]/sum(desired_version_counts.itervalues())))

    if bitcoind_warning is not None:
        if 'This is a pre-release test build' not in bitcoind_warning:
            res.append('(from bitcoind) %s' % (bitcoind_warning,))

    if time.time() > bitcoind_work_value['last_update'] + 60:
        res.append('''LOST CONTACT WITH BITCOIND for %s! Check that it isn't frozen or dead!''' % (math.format_dt(time.time() - bitcoind_work_value['last_update']),))
        line=os.popen('cd /root/p2pool-test && ./rund.sh')
        res.append(line.read().rstrip())

    return res
Exemple #7
0
def get_warnings(tracker, best_share, net, bitcoind_warning, bitcoind_work_value):
    res = []
    
    desired_version_counts = get_desired_version_counts(tracker, best_share,
        min(60*60//net.SHARE_PERIOD, tracker.get_height(best_share)))
    majority_desired_version = max(desired_version_counts, key=lambda k: desired_version_counts[k])
    if majority_desired_version > 5 and desired_version_counts[majority_desired_version] > sum(desired_version_counts.itervalues())/2:
        res.append('A MAJORITY OF SHARES CONTAIN A VOTE FOR AN UNSUPPORTED SHARE IMPLEMENTATION! (v%i with %i%% support)\n'
            'An upgrade is likely necessary. Check http://p2pool.forre.st/ for more information.' % (
                majority_desired_version, 100*desired_version_counts[majority_desired_version]/sum(desired_version_counts.itervalues())))
    
    if bitcoind_warning is not None:
        res.append('(from bitcoind) %s' % (bitcoind_warning,))
    
    if time.time() > bitcoind_work_value['last_update'] + 60:
        res.append('''LOST CONTACT WITH BITCOIND for %s! Check that it isn't frozen or dead!''' % (math.format_dt(time.time() - bitcoind_work_value['last_update']),))
    
    return res
Exemple #8
0
    def think(self, block_rel_height_func, previous_block, bits):
        desired = set()

        # O(len(self.heads))
        #   make 'unverified heads' set?
        # for each overall head, attempt verification
        # if it fails, attempt on parent, and repeat
        # if no successful verification because of lack of parents, request parent
        bads = set()
        for head in set(self.heads) - set(self.verified.heads):
            head_height, last = self.get_height_and_last(head)

            for share in self.get_chain(
                    head, head_height if last is None else min(
                        5, max(0, head_height - self.net.CHAIN_LENGTH))):
                if self.attempt_verify(share):
                    break
                if share.hash in self.heads:
                    bads.add(share.hash)
            else:
                if last is not None:
                    desired.add((
                        self.items[random.choice(list(
                            self.reverse[last]))].peer,
                        last,
                        max(x.timestamp for x in self.get_chain(
                            head, min(head_height, 5))),
                        min(x.target for x in self.get_chain(
                            head, min(head_height, 5))),
                    ))
        for bad in bads:
            assert bad not in self.verified.items
            assert bad in self.heads
            if p2pool.DEBUG:
                print "BAD", bad
            self.remove(bad)

        # try to get at least CHAIN_LENGTH height for each verified head, requesting parents if needed
        for head in list(self.verified.heads):
            head_height, last_hash = self.verified.get_height_and_last(head)
            last_height, last_last_hash = self.get_height_and_last(last_hash)
            # XXX review boundary conditions
            want = max(self.net.CHAIN_LENGTH - head_height, 0)
            can = max(last_height - 1 - self.net.CHAIN_LENGTH,
                      0) if last_last_hash is not None else last_height
            get = min(want, can)
            #print 'Z', head_height, last_hash is None, last_height, last_last_hash is None, want, can, get
            for share in self.get_chain(last_hash, get):
                if not self.attempt_verify(share):
                    break
            if head_height < self.net.CHAIN_LENGTH and last_last_hash is not None:
                desired.add((
                    self.items[random.choice(
                        list(self.verified.reverse[last_hash]))].peer,
                    last_last_hash,
                    max(x.timestamp
                        for x in self.get_chain(head, min(head_height, 5))),
                    min(x.target
                        for x in self.get_chain(head, min(head_height, 5))),
                ))

        # decide best tree
        decorated_tails = sorted((self.score(
            max(self.verified.tails[tail_hash], key=self.verified.get_work),
            block_rel_height_func), tail_hash)
                                 for tail_hash in self.verified.tails)
        if p2pool.DEBUG:
            print len(decorated_tails), 'tails:'
            for score, tail_hash in decorated_tails:
                print format_hash(tail_hash), score
        best_tail_score, best_tail = decorated_tails[
            -1] if decorated_tails else (None, None)

        # decide best verified head
        decorated_heads = sorted((
            (
                self.verified.get_work(
                    self.verified.get_nth_parent_hash(
                        h, min(5, self.verified.get_height(h)))),
                #self.items[h].peer is None,
                self.items[h].pow_hash <=
                self.items[h].header['bits'].target,  # is block solution
                (self.items[h].header['previous_block'],
                 self.items[h].header['bits']) == (
                     previous_block, bits) or self.items[h].peer is None,
                -self.items[h].time_seen,
            ),
            h) for h in self.verified.tails.get(best_tail, []))
        if p2pool.DEBUG:
            print len(decorated_heads), 'heads. Top 10:'
            for score, head_hash in decorated_heads[-10:]:
                print '   ', format_hash(head_hash), format_hash(
                    self.items[head_hash].previous_hash), score
        best_head_score, best = decorated_heads[-1] if decorated_heads else (
            None, None)

        # eat away at heads
        if decorated_heads:
            for i in xrange(1000):
                to_remove = set()
                for share_hash, tail in self.heads.iteritems():
                    if share_hash in [
                            head_hash
                            for score, head_hash in decorated_heads[-5:]
                    ]:
                        #print 1
                        continue
                    if self.items[share_hash].time_seen > time.time() - 300:
                        #print 2
                        continue
                    if share_hash not in self.verified.items and max(
                            self.items[after_tail_hash].time_seen
                            for after_tail_hash in self.reverse.get(
                                tail)) > time.time() - 120:  # XXX stupid
                        #print 3
                        continue
                    to_remove.add(share_hash)
                if not to_remove:
                    break
                for share_hash in to_remove:
                    if share_hash in self.verified.items:
                        self.verified.remove(share_hash)
                    self.remove(share_hash)
                #print "_________", to_remove

        # drop tails
        for i in xrange(1000):
            to_remove = set()
            for tail, heads in self.tails.iteritems():
                if min(self.get_height(head)
                       for head in heads) < 2 * self.net.CHAIN_LENGTH + 10:
                    continue
                for aftertail in self.reverse.get(tail, set()):
                    if len(self.reverse[
                            self.items[aftertail].previous_hash]) > 1:  # XXX
                        print "raw"
                        continue
                    to_remove.add(aftertail)
            if not to_remove:
                break
            # if removed from this, it must be removed from verified
            #start = time.time()
            for aftertail in to_remove:
                if self.items[aftertail].previous_hash not in self.tails:
                    print "erk", aftertail, self.items[aftertail].previous_hash
                    continue
                if aftertail in self.verified.items:
                    self.verified.remove(aftertail)
                self.remove(aftertail)
            #end = time.time()
            #print "removed! %i %f" % (len(to_remove), (end - start)/len(to_remove))

        if best is not None:
            best_share = self.items[best]
            if (
                    best_share.header['previous_block'],
                    best_share.header['bits']
            ) != (
                    previous_block, bits
            ) and best_share.header_hash != previous_block and best_share.peer is not None:
                if p2pool.DEBUG:
                    print 'Stale detected! %x < %x' % (
                        best_share.header['previous_block'], previous_block)
                best = best_share.previous_hash

            timestamp_cutoff = min(int(time.time()),
                                   best_share.timestamp) - 3600
            target_cutoff = 2**256 // (
                self.net.SHARE_PERIOD * best_tail_score[1] +
                1) * 2 if best_tail_score[1] is not None else 2**256 - 1
        else:
            timestamp_cutoff = int(time.time()) - 24 * 60 * 60
            target_cutoff = 2**256 - 1

        if p2pool.DEBUG:
            print 'Desire %i shares. Cutoff: %s old diff>%.2f' % (
                len(desired), math.format_dt(time.time() - timestamp_cutoff),
                bitcoin_data.target_to_difficulty(target_cutoff))
            for peer, hash, ts, targ in desired:
                print '   ', '%s:%i' % peer.addr if peer is not None else None, format_hash(
                    hash), math.format_dt(time.time(
                    ) - ts), bitcoin_data.target_to_difficulty(
                        targ), ts >= timestamp_cutoff, targ <= target_cutoff

        return best, [(peer, hash) for peer, hash, ts, targ in desired
                      if ts >= timestamp_cutoff]