Beispiel #1
0
 def get_rate():
     if current_work.value['best_share_hash'] is not None:
         height, last = tracker.get_height_and_last(current_work.value['best_share_hash'])
         att_s = p2pool_data.get_pool_attempts_per_second(tracker, current_work.value['best_share_hash'], min(height - 1, 720))
         fracs = [share.stale_frac for share in tracker.get_chain(current_work.value['best_share_hash'], min(120, height)) if share.stale_frac is not None]
         return json.dumps(int(att_s / (1. - (math.median(fracs) if fracs else 0))))
     return json.dumps(None)
Beispiel #2
0
        def status_thread():
            last_str = None
            last_time = 0
            while True:
                yield deferral.sleep(3)
                try:
                    height = node.tracker.get_height(node.best_share_var.value)
                    this_str = 'P2Pool: %i shares in chain (%i verified/%i total) Peers: %i (%i incoming)' % (
                        height,
                        len(node.tracker.verified.items),
                        len(node.tracker.items),
                        len(node.p2p_node.peers),
                        sum(1 for peer in node.p2p_node.peers.itervalues() if peer.incoming),
                    ) + (' FDs: %i R/%i W' % (len(reactor.getReaders()), len(reactor.getWriters())) if p2pool.DEBUG else '')
                    
                    datums, dt = wb.local_rate_monitor.get_datums_in_last()
                    my_att_s = sum(datum['work']/dt for datum in datums)
                    my_shares_per_s = sum(datum['work']/dt/bitcoin_data.target_to_average_attempts(datum['share_target']) for datum in datums)
                    this_str += '\n Local: %sH/s in last %s Local dead on arrival: %s Expected time to share: %s' % (
                        math.format(int(my_att_s)),
                        math.format_dt(dt),
                        math.format_binomial_conf(sum(1 for datum in datums if datum['dead']), len(datums), 0.95),
                        math.format_dt(1/my_shares_per_s) if my_shares_per_s else '???',
                    )
                    
                    if height > 2:
                        (stale_orphan_shares, stale_doa_shares), shares, _ = wb.get_stale_counts()
                        stale_prop = p2pool_data.get_average_stale_prop(node.tracker, node.best_share_var.value, min(60*60//net.SHARE_PERIOD, height))
                        real_att_s = p2pool_data.get_pool_attempts_per_second(node.tracker, node.best_share_var.value, min(height - 1, 60*60//net.SHARE_PERIOD)) / (1 - stale_prop)
                        
                        this_str += '\n Shares: %i (%i orphan, %i dead) Stale rate: %s Efficiency: %s Current payout: %.4f %s' % (
                            shares, stale_orphan_shares, stale_doa_shares,
                            math.format_binomial_conf(stale_orphan_shares + stale_doa_shares, shares, 0.95),
                            math.format_binomial_conf(stale_orphan_shares + stale_doa_shares, shares, 0.95, lambda x: (1 - x)/(1 - stale_prop)),
                            node.get_current_txouts().get(bitcoin_data.pubkey_hash_to_script2(my_pubkey_hash), 0)*1e-8, net.PARENT.SYMBOL,
                        )
			print(node.bitcoind_work.value['bits'])
			print(real_att_s)
                        this_str += '\n Pool: %sH/s Stale rate: %.1f%% Expected time to block: %s' % (
                            math.format(int(real_att_s)),
                            100*stale_prop,
                            math.format_dt(2**256 / node.bitcoind_work.value['bits'].target / real_att_s),
                        )
                        
                        for warning in p2pool_data.get_warnings(node.tracker, node.best_share_var.value, net, bitcoind_getinfo_var.value, node.bitcoind_work.value):
                            print >>sys.stderr, '#'*40
                            print >>sys.stderr, '>>> Warning: ' + warning
                            print >>sys.stderr, '#'*40
                        
                        if gc.garbage:
                            print '%i pieces of uncollectable cyclic garbage! Types: %r' % (len(gc.garbage), map(type, gc.garbage))
                    
                    if this_str != last_str or time.time() > last_time + 15:
                        print this_str
                        last_str = this_str
                        last_time = time.time()
                except:
                    log.err()
Beispiel #3
0
 def status_thread():
     last_str = None
     last_time = 0
     while True:
         yield deferral.sleep(3)
         try:
             height = node.tracker.get_height(node.best_share_var.value)
             this_str = 'P2Pool: %i shares in chain (%i verified/%i total) Peers: %i (%i incoming)' % (
                 height,
                 len(node.tracker.verified.items),
                 len(node.tracker.items),
                 len(node.p2p_node.peers),
                 sum(1 for peer in node.p2p_node.peers.itervalues() if peer.incoming),
             ) + (' FDs: %i R/%i W' % (len(reactor.getReaders()), len(reactor.getWriters())) if p2pool.DEBUG else '')
             
             datums, dt = wb.local_rate_monitor.get_datums_in_last()
             my_att_s = sum(datum['work']/dt for datum in datums)
             my_shares_per_s = sum(datum['work']/dt/bitcoin_data.target_to_average_attempts(datum['share_target']) for datum in datums)
             this_str += '\n Local: %sH/s in last %s Local dead on arrival: %s Expected time to share: %s' % (
                 math.format(int(my_att_s)),
                 math.format_dt(dt),
                 math.format_binomial_conf(sum(1 for datum in datums if datum['dead']), len(datums), 0.95),
                 math.format_dt(1/my_shares_per_s) if my_shares_per_s else '???',
             )
             
             if height > 2:
                 (stale_orphan_shares, stale_doa_shares), shares, _ = wb.get_stale_counts()
                 stale_prop = p2pool_data.get_average_stale_prop(node.tracker, node.best_share_var.value, min(60*60//net.SHARE_PERIOD, height))
                 real_att_s = p2pool_data.get_pool_attempts_per_second(node.tracker, node.best_share_var.value, min(height - 1, 60*60//net.SHARE_PERIOD)) / (1 - stale_prop)
                 
                 this_str += '\n Shares: %i (%i orphan, %i dead) Stale rate: %s Efficiency: %s Current payout: %.4f %s' % (
                     shares, stale_orphan_shares, stale_doa_shares,
                     math.format_binomial_conf(stale_orphan_shares + stale_doa_shares, shares, 0.95),
                     math.format_binomial_conf(stale_orphan_shares + stale_doa_shares, shares, 0.95, lambda x: (1 - x)/(1 - stale_prop)),
                     ### CJWinty: dimecoin has only 5 digits
                     node.get_current_txouts().get(bitcoin_data.pubkey_hash_to_script2(my_pubkey_hash), 0)*1e-5, net.PARENT.SYMBOL,
                 )
                 this_str += '\n Pool: %sH/s Stale rate: %.1f%% Expected time to block: %s' % (
                     math.format(int(real_att_s)),
                     100*stale_prop,
                     math.format_dt(2**256 / node.dimecoind_work.value['bits'].target / real_att_s),
                 )
                 
                 for warning in p2pool_data.get_warnings(node.tracker, node.best_share_var.value, net, dimecoind_warning_var.value, node.dimecoind_work.value):
                     print >>sys.stderr, '#'*40
                     print >>sys.stderr, '>>> Warning: ' + warning
                     print >>sys.stderr, '#'*40
                 
                 if gc.garbage:
                     print '%i pieces of uncollectable cyclic garbage! Types: %r' % (len(gc.garbage), map(type, gc.garbage))
             
             if this_str != last_str or time.time() > last_time + 15:
                 print this_str
                 last_str = this_str
                 last_time = time.time()
         except:
             log.err()
Beispiel #4
0
 def get_rate():
     if current_work.value['best_share_hash'] is not None:
         height, last = tracker.get_height_and_last(
             current_work.value['best_share_hash'])
         att_s = p2pool_data.get_pool_attempts_per_second(
             tracker, current_work.value['best_share_hash'],
             min(height - 1, 720))
         fracs = [
             share.stale_frac for share in tracker.get_chain(
                 current_work.value['best_share_hash'], min(
                     120, height)) if share.stale_frac is not None
         ]
         return json.dumps(
             int(att_s / (1. - (math.median(fracs) if fracs else 0))))
     return json.dumps(None)
Beispiel #5
0
 def status_thread():
     last_str = None
     last_time = 0
     while True:
         yield deferral.sleep(3)
         try:
             if time.time() > current_work2.value['last_update'] + 60:
                 print '''---> LOST CONTACT WITH BITCOIND for 60 seconds, check that it isn't frozen or dead <---'''
             if current_work.value['best_share_hash'] is not None:
                 height, last = tracker.get_height_and_last(current_work.value['best_share_hash'])
                 if height > 2:
                     att_s = p2pool_data.get_pool_attempts_per_second(tracker, current_work.value['best_share_hash'], min(height - 1, 720))
                     weights, total_weight, donation_weight = tracker.get_cumulative_weights(current_work.value['best_share_hash'], min(height, 720), 65535*2**256)
                     shares, stale_doa_shares, stale_not_doa_shares = get_share_counts(True)
                     stale_shares = stale_doa_shares + stale_not_doa_shares
                     fracs = [share.stale_frac for share in tracker.get_chain(current_work.value['best_share_hash'], min(120, height)) if share.stale_frac is not None]
                     this_str = 'Pool: %sH/s in %i shares (%i/%i verified) Recent: %.02f%% >%sH/s Shares: %i (%i orphan, %i dead) Peers: %i' % (
                         math.format(int(att_s / (1. - (math.median(fracs) if fracs else 0)))),
                         height,
                         len(tracker.verified.shares),
                         len(tracker.shares),
                         weights.get(my_script, 0)/total_weight*100,
                         math.format(int(weights.get(my_script, 0)*att_s//total_weight / (1. - (math.median(fracs) if fracs else 0)))),
                         shares,
                         stale_not_doa_shares,
                         stale_doa_shares,
                         len(p2p_node.peers),
                     ) + (' FDs: %i R/%i W' % (len(reactor.getReaders()), len(reactor.getWriters())) if p2pool.DEBUG else '')
                     if fracs:
                         med = math.median(fracs)
                         this_str += '\nPool stales: %i%%' % (int(100*med+.5),)
                         conf = 0.95
                         if shares:
                             this_str += u' Own: %i±%i%%' % tuple(int(100*x+.5) for x in math.interval_to_center_radius(math.binomial_conf_interval(stale_shares, shares, conf)))
                             if med < .99:
                                 this_str += u' Own efficiency: %i±%i%%' % tuple(int(100*x+.5) for x in math.interval_to_center_radius((1 - y)/(1 - med) for y in math.binomial_conf_interval(stale_shares, shares, conf)[::-1]))
                     if this_str != last_str or time.time() > last_time + 15:
                         print this_str
                         last_str = this_str
                         last_time = time.time()
         except:
             log.err()
Beispiel #6
0
    def get_work(self, pubkey_hash, desired_share_target, desired_pseudoshare_target):
        if self.node.best_share_var.value is None and self.node.net.PERSIST:
            raise jsonrpc.Error_for_code(-12345)(u'p2pool is downloading shares')
        
        if self.merged_work.value:
            tree, size = bitcoin_data.make_auxpow_tree(self.merged_work.value)
            mm_hashes = [self.merged_work.value.get(tree.get(i), dict(hash=0))['hash'] for i in xrange(size)]
            mm_data = '\xfa\xbemm' + bitcoin_data.aux_pow_coinbase_type.pack(dict(
                merkle_root=bitcoin_data.merkle_hash(mm_hashes),
                size=size,
                nonce=0,
            ))
            mm_later = [(aux_work, mm_hashes.index(aux_work['hash']), mm_hashes) for chain_id, aux_work in self.merged_work.value.iteritems()]
        else:
            mm_data = ''
            mm_later = []
        
        tx_hashes = [bitcoin_data.hash256(bitcoin_data.tx_type.pack(tx)) for tx in self.current_work.value['transactions']]
        tx_map = dict(zip(tx_hashes, self.current_work.value['transactions']))
        
        previous_share = self.node.tracker.items[self.node.best_share_var.value] if self.node.best_share_var.value is not None else None
        if previous_share is None:
            share_type = p2pool_data.Share
        else:
            previous_share_type = type(previous_share)
            
            if previous_share_type.SUCCESSOR is None or self.node.tracker.get_height(previous_share.hash) < self.node.net.CHAIN_LENGTH:
                share_type = previous_share_type
            else:
                successor_type = previous_share_type.SUCCESSOR
                
                counts = p2pool_data.get_desired_version_counts(self.node.tracker,
                    self.node.tracker.get_nth_parent_hash(previous_share.hash, self.node.net.CHAIN_LENGTH*9//10), self.node.net.CHAIN_LENGTH//10)
                upgraded = counts.get(successor_type.VERSION, 0)/sum(counts.itervalues())
                if upgraded > .65:
                    print 'Switchover imminent. Upgraded: %.3f%% Threshold: %.3f%%' % (upgraded*100, 95)
                print 
                # Share -> NewShare only valid if 95% of hashes in [net.CHAIN_LENGTH*9//10, net.CHAIN_LENGTH] for new version
                if counts.get(successor_type.VERSION, 0) > sum(counts.itervalues())*95//100:
                    share_type = successor_type
                else:
                    share_type = previous_share_type
        
        if desired_share_target is None:
            desired_share_target = 2**256-1  # will be reduced to SANE_TARGET_RANGE later
            local_hash_rate = self._estimate_local_hash_rate()
            if local_hash_rate is not None:
                desired_share_target = min(desired_share_target,
                    bitcoin_data.average_attempts_to_target(local_hash_rate * self.node.net.SHARE_PERIOD / 0.0167)) # limit to 1.67% of pool shares by modulating share difficulty
           
            local_addr_rates = self.get_local_addr_rates()
            lookbehind = 3600//self.node.net.SHARE_PERIOD
            block_subsidy = self.node.bitcoind_work.value['subsidy']
            if previous_share is not None and self.node.tracker.get_height(previous_share.hash) > lookbehind:
                expected_payout_per_block = local_addr_rates.get(pubkey_hash, 0)/p2pool_data.get_pool_attempts_per_second(self.node.tracker, self.node.best_share_var.value, lookbehind) \
                    * block_subsidy*(1-self.donation_percentage/100) # XXX doesn't use global stale rate to compute pool hash
                if expected_payout_per_block < self.node.net.PARENT.DUST_THRESHOLD:
                    desired_share_target = min(desired_share_target,
                        bitcoin_data.average_attempts_to_target((bitcoin_data.target_to_average_attempts(self.node.bitcoind_work.value['bits'].target)*self.node.net.SPREAD)*self.node.net.PARENT.DUST_THRESHOLD/block_subsidy)
                    )
	
        
        if True:
            share_info, gentx, other_transaction_hashes, get_share = share_type.generate_transaction(
                tracker=self.node.tracker,
                share_data=dict(
                    previous_share_hash=self.node.best_share_var.value,
                    coinbase=(script.create_push_script([
                        self.current_work.value['height'],
                        ] + ([mm_data] if mm_data else []) + [
                    ]) + self.current_work.value['coinbaseflags'])[:100],
                    nonce=random.randrange(2**32),
                    pubkey_hash=pubkey_hash,
                    subsidy=self.current_work.value['subsidy'],
                    donation=math.perfect_round(65535*self.donation_percentage/100),
                    stale_info=(lambda (orphans, doas), total, (orphans_recorded_in_chain, doas_recorded_in_chain):
                        'orphan' if orphans > orphans_recorded_in_chain else
                        'doa' if doas > doas_recorded_in_chain else
                        None
                    )(*self.get_stale_counts()),
                    desired_version=(share_type.SUCCESSOR if share_type.SUCCESSOR is not None else share_type).VOTING_VERSION,
                ),
                block_target=self.current_work.value['bits'].target,
                desired_timestamp=int(time.time() + 0.5),
                desired_target=desired_share_target,
                ref_merkle_link=dict(branch=[], index=0),
                desired_other_transaction_hashes_and_fees=zip(tx_hashes, self.current_work.value['transaction_fees']),
                net=self.node.net,
                known_txs=tx_map,
                base_subsidy=self.node.net.PARENT.SUBSIDY_FUNC(self.current_work.value['height']),
            )
		    
		    
       
        
        
        packed_gentx = bitcoin_data.tx_type.pack(gentx)
        other_transactions = [tx_map[tx_hash] for tx_hash in other_transaction_hashes]
        
        mm_later = [(dict(aux_work, target=aux_work['target'] if aux_work['target'] == 'p2pool' else share_info['bits'].target), index, hashes) for aux_work, index, hashes in mm_later]
        
        if desired_pseudoshare_target is None:
            target = 2**256-1
            local_hash_rate = self._estimate_local_hash_rate()
            if local_hash_rate is not None:
                target = min(target,
                    bitcoin_data.average_attempts_to_target(local_hash_rate * 1)) # limit to 1 share response every second by modulating pseudoshare difficulty
        else:
            target = desired_pseudoshare_target
           
       # target = max(target, share_info['bits'].target)
        
        for aux_work, index, hashes in mm_later:
            target = max(target, aux_work['target'])
         
        target = math.clip(target, self.node.net.PARENT.SANE_TARGET_RANGE)
      
        
        getwork_time = time.time()
        lp_count = self.new_work_event.times
        merkle_link = bitcoin_data.calculate_merkle_link([None] + other_transaction_hashes, 0)
        
        print 'New work for worker! Difficulty: %.06f Share difficulty: %.08f Total block value: %.6f %s including %i transactions' % (
            bitcoin_data.target_to_difficulty(target),
            bitcoin_data.target_to_difficulty(share_info['bits'].target),
            self.current_work.value['subsidy']*1e-8, self.node.net.PARENT.SYMBOL,
            len(self.current_work.value['transactions']),
        )
        
        ba = dict(
            version=min(self.current_work.value['version'], 2),
            previous_block=self.current_work.value['previous_block'],
            merkle_link=merkle_link,
            coinb1=packed_gentx[:-self.COINBASE_NONCE_LENGTH-4],
            coinb2=packed_gentx[-4:],
            timestamp=self.current_work.value['time'],
            bits=self.current_work.value['bits'],
            share_target=target,
        )
        
        received_header_hashes = set()
        
        def got_response(header, user, coinbase_nonce):
            assert len(coinbase_nonce) == self.COINBASE_NONCE_LENGTH
            new_packed_gentx = packed_gentx[:-self.COINBASE_NONCE_LENGTH-4] + coinbase_nonce + packed_gentx[-4:] if coinbase_nonce != '\0'*self.COINBASE_NONCE_LENGTH else packed_gentx
            new_gentx = bitcoin_data.tx_type.unpack(new_packed_gentx) if coinbase_nonce != '\0'*self.COINBASE_NONCE_LENGTH else gentx
            
           
            header_hash = bitcoin_data.hash256(bitcoin_data.block_header_type.pack(header))
            pow_hash = self.node.net.PARENT.POW_FUNC(bitcoin_data.block_header_type.pack(header))
            try:
                if pow_hash <= header['bits'].target or p2pool.DEBUG:
                    helper.submit_block(dict(header=header, txs=[new_gentx] + other_transactions), False, self.node.factory, self.node.bitcoind, self.node.bitcoind_work, self.node.net)
                    if pow_hash <= header['bits'].target:
                        print
                        print 'GOT BLOCK FROM MINER! Passing to bitcoind! %s%064x' % (self.node.net.PARENT.BLOCK_EXPLORER_URL_PREFIX, header_hash)
                        print
            except:
                log.err(None, 'Error while processing potential block:')
            
            user, _, _, _ = self.get_user_details(user)
            assert header['previous_block'] == ba['previous_block']
            assert header['merkle_root'] == bitcoin_data.check_merkle_link(bitcoin_data.hash256(new_packed_gentx), merkle_link)
            assert header['bits'] == ba['bits']
            
            on_time = self.new_work_event.times == lp_count
            
            for aux_work, index, hashes in mm_later:
                try:
                    if pow_hash <= aux_work['target'] or p2pool.DEBUG:
                        df = deferral.retry('Error submitting merged block: (will retry)', 10, 10)(aux_work['merged_proxy'].rpc_getauxblock)(
                            pack.IntType(256, 'big').pack(aux_work['hash']).encode('hex'),
                           # neoscrypt uses little endian only
                           # pack.IntType(256, 'little').pack(aux_work['hash']).encode('hex'),
                            bitcoin_data.aux_pow_type.pack(dict(
                                merkle_tx=dict(
                                    tx=new_gentx,
                                    block_hash=header_hash,
                                    merkle_link=merkle_link,
                                ),
                                merkle_link=bitcoin_data.calculate_merkle_link(hashes, index),
                                parent_block_header=header,
                            )).encode('hex'),
                        )
                        @df.addCallback
                        def _(result, aux_work=aux_work):
                            if result != (pow_hash <= aux_work['target']):
                                print >>sys.stderr, 'Merged block submittal result: %s Expected: %s' % (result, pow_hash <= aux_work['target'])
                            else:
                                print 'Merged block submittal result: %s' % (result,)
                        @df.addErrback
                        def _(err):
                            log.err(err, 'Error submitting merged block:')
                except:
                    log.err(None, 'Error while processing merged mining POW:')
            
            if pow_hash <= share_info['bits'].target and header_hash not in received_header_hashes:
                last_txout_nonce = pack.IntType(8*self.COINBASE_NONCE_LENGTH).unpack(coinbase_nonce)
                share = get_share(header, last_txout_nonce)
                
                print 'GOT SHARE! %s %s prev %s age %.2fs%s' % (
                    user,
                    p2pool_data.format_hash(share.hash),
                    p2pool_data.format_hash(share.previous_hash),
                    time.time() - getwork_time,
                    ' DEAD ON ARRIVAL' if not on_time else '',
                )
                self.my_share_hashes.add(share.hash)
                if not on_time:
                    self.my_doa_share_hashes.add(share.hash)
                
                self.node.tracker.add(share)
                self.node.set_best_share()
                
                try:
                    if (pow_hash <= header['bits'].target or p2pool.DEBUG) and self.node.p2p_node is not None:
                        self.node.p2p_node.broadcast_share(share.hash)
                except:
                    log.err(None, 'Error forwarding block solution:')
                
                self.share_received.happened(bitcoin_data.target_to_average_attempts(share.target), not on_time, share.hash)
	    if p2pool.DEBUG:
		print 'Hash:   %X' % (pow_hash)
		print 'Target: %X' % (target)
            if pow_hash > target:
                print 'Worker %s submitted share with hash > target:' % (user,)
            elif header_hash in received_header_hashes:
                print >>sys.stderr, 'Worker %s submitted share more than once!' % (user,)
            else:
                received_header_hashes.add(header_hash)
                
                self.pseudoshare_received.happened(bitcoin_data.target_to_average_attempts(target), not on_time, user)
                self.recent_shares_ts_work.append((time.time(), bitcoin_data.target_to_average_attempts(target)))
                while len(self.recent_shares_ts_work) > 50:
                    self.recent_shares_ts_work.pop(0)
                self.local_rate_monitor.add_datum(dict(work=bitcoin_data.target_to_average_attempts(target), dead=not on_time, user=user, share_target=share_info['bits'].target))
                self.local_addr_rate_monitor.add_datum(dict(work=bitcoin_data.target_to_average_attempts(target), pubkey_hash=pubkey_hash))
            
            return on_time
        
        return ba, got_response
Beispiel #7
0
    def get_user_details(self, username):
        contents = re.split('([+/])', username)
        assert len(contents) % 2 == 1
        
        user, contents2 = contents[0], contents[1:]
        
        desired_pseudoshare_target = None
        desired_share_target = None
        for symbol, parameter in zip(contents2[::2], contents2[1::2]):
            if symbol == '+':
                try:
                    desired_pseudoshare_target = bitcoin_data.difficulty_to_target(float(parameter))
                except:
                    if p2pool.DEBUG:
                        log.err()
            elif symbol == '/':
                try:
                    desired_share_target = bitcoin_data.difficulty_to_target(float(parameter))
                except:
                    if p2pool.DEBUG:
                        log.err()

	
        set_adaptive_target = (self.diff_policy == 'F') or ((self.diff_policy == 'A') and (desired_share_target is None))
        set_adaptive_pseudo = (self.diff_policy == 'F') or ((self.diff_policy == 'A') and (desired_pseudoshare_target is None))
        user_rate = None
        pool_rate = None
        
        if set_adaptive_target: # calculate pool hashrate
            height = self.node.tracker.get_height(self.node.best_share_var.value)
            if height > 5: # we want at least 6 shares in chain
                stale_prop = p2pool_data.get_average_stale_prop(self.node.tracker, self.node.best_share_var.value, min(60*60//self.node.net.SHARE_PERIOD, height))
                pool_rate = p2pool_data.get_pool_attempts_per_second(self.node.tracker, self.node.best_share_var.value, min(height - 1, 60*60//self.node.net.SHARE_PERIOD)) / (1 - stale_prop)
	
        if set_adaptive_pseudo or set_adaptive_target: # calculate user's hashrate
            datums, dt = self.local_rate_monitor.get_datums_in_last()
            npoints = sum(datum['user'] == user for datum in datums)
            if npoints > 5: # at least 6 hashrate datums for the user
                user_rate = 0
                for datum in datums:
                    if datum['user'] == user:
                        user_rate += datum['work']/dt
	
        if set_adaptive_target:
            desired_share_target = None
            if user_rate is not None and pool_rate is not None:
                if user_rate and pool_rate:
                    # min 20 shares per block AND min 20 shares per chain
                    desired_share_target = 20 * (max(self.node.bitcoind_work.value['bits'].target * pool_rate, 2**256 // (self.node.net.CHAIN_LENGTH * self.node.net.SHARE_PERIOD)) // user_rate)
	
        if set_adaptive_pseudo:
            desired_pseudoshare_target = None
            if user_rate is not None:
                if user_rate:
                    # min 20 pseudoshares per 10 minutes
                    desired_pseudoshare_target = 20 * (2**256 // user_rate // (10*60))
	
        if random.uniform(0, 100) < self.worker_fee:
            pubkey_hash = self.my_pubkey_hash
        else:
            try:
                pubkey_hash = bitcoin_data.address_to_pubkey_hash(user, self.node.net.PARENT)
            except: # XXX blah
                pubkey_hash = self.my_pubkey_hash
        
        return user, pubkey_hash, desired_share_target, desired_pseudoshare_target
Beispiel #8
0
    def get_work(self, pubkey_hash, desired_share_target,
                 desired_pseudoshare_target):
        global print_throttle
        if (self.node.p2p_node is None or len(self.node.p2p_node.peers)
                == 0) and self.node.net.PERSIST:
            raise jsonrpc.Error_for_code(-12345)(
                u'p2pool is not connected to any peers')
        if self.node.best_share_var.value is None and self.node.net.PERSIST:
            raise jsonrpc.Error_for_code(-12345)(
                u'p2pool is downloading shares')

        if self.merged_work.value:
            tree, size = dash_data.make_auxpow_tree(self.merged_work.value)
            mm_hashes = [
                self.merged_work.value.get(tree.get(i), dict(hash=0))['hash']
                for i in xrange(size)
            ]
            mm_data = '\xfa\xbemm' + dash_data.aux_pow_coinbase_type.pack(
                dict(
                    merkle_root=dash_data.merkle_hash(mm_hashes),
                    size=size,
                    nonce=0,
                ))
            mm_later = [
                (aux_work, mm_hashes.index(aux_work['hash']), mm_hashes)
                for chain_id, aux_work in self.merged_work.value.iteritems()
            ]
        else:
            mm_data = ''
            mm_later = []

        tx_hashes = [
            dash_data.hash256(dash_data.tx_type.pack(tx))
            for tx in self.current_work.value['transactions']
        ]
        tx_map = dict(zip(tx_hashes, self.current_work.value['transactions']))

        previous_share = self.node.tracker.items[
            self.node.best_share_var.
            value] if self.node.best_share_var.value is not None else None
        if previous_share is None:
            share_type = p2pool_data.Share
        else:
            previous_share_type = type(previous_share)

            if previous_share_type.SUCCESSOR is None or self.node.tracker.get_height(
                    previous_share.hash) < self.node.net.CHAIN_LENGTH:
                share_type = previous_share_type
            else:
                successor_type = previous_share_type.SUCCESSOR

                counts = p2pool_data.get_desired_version_counts(
                    self.node.tracker,
                    self.node.tracker.get_nth_parent_hash(
                        previous_share.hash,
                        self.node.net.CHAIN_LENGTH * 9 // 10),
                    self.node.net.CHAIN_LENGTH // 10)
                upgraded = counts.get(successor_type.VERSION, 0) / sum(
                    counts.itervalues())
                if upgraded > .65:
                    print 'Switchover imminent. Upgraded: %.3f%% Threshold: %.3f%%' % (
                        upgraded * 100, 95)
                # Share -> NewShare only valid if 95% of hashes in [net.CHAIN_LENGTH*9//10, net.CHAIN_LENGTH] for new version
                if counts.get(successor_type.VERSION,
                              0) > sum(counts.itervalues()) * 95 // 100:
                    share_type = successor_type
                else:
                    share_type = previous_share_type

        if desired_share_target is None:
            desired_share_target = 2**256 - 1
            local_hash_rate = self._estimate_local_hash_rate()
            if local_hash_rate is not None:
                desired_share_target = min(
                    desired_share_target,
                    dash_data.average_attempts_to_target(
                        local_hash_rate * self.node.net.SHARE_PERIOD / 0.0167)
                )  # limit to 1.67% of pool shares by modulating share difficulty

            local_addr_rates = self.get_local_addr_rates()
            lookbehind = 3600 // self.node.net.SHARE_PERIOD
            block_subsidy = self.node.dashd_work.value['subsidy']
            if previous_share is not None and self.node.tracker.get_height(
                    previous_share.hash) > lookbehind:
                expected_payout_per_block = local_addr_rates.get(pubkey_hash, 0)/p2pool_data.get_pool_attempts_per_second(self.node.tracker, self.node.best_share_var.value, lookbehind) \
                    * block_subsidy*(1-self.donation_percentage/100) # XXX doesn't use global stale rate to compute pool hash
                if expected_payout_per_block < self.node.net.PARENT.DUST_THRESHOLD:
                    desired_share_target = min(
                        desired_share_target,
                        dash_data.average_attempts_to_target(
                            (dash_data.target_to_average_attempts(
                                self.node.dashd_work.value['bits'].target) *
                             self.node.net.SPREAD) *
                            self.node.net.PARENT.DUST_THRESHOLD /
                            block_subsidy))

        if True:
            share_info, gentx, other_transaction_hashes, get_share = share_type.generate_transaction(
                tracker=self.node.tracker,
                share_data=dict(
                    previous_share_hash=self.node.best_share_var.value,
                    coinbase=(script.create_push_script([
                        self.current_work.value['height'],
                    ] + ([mm_data] if mm_data else []) + []) +
                              self.current_work.value['coinbaseflags'] +
                              self.node.net.COINBASEEXT)[:100],
                    nonce=random.randrange(2**32),
                    pubkey_hash=pubkey_hash,
                    subsidy=self.current_work.value['subsidy'],
                    donation=math.perfect_round(
                        65535 * self.donation_percentage / 100),
                    stale_info=(
                        lambda (orphans, doas), total,
                        (orphans_recorded_in_chain, doas_recorded_in_chain
                         ): 'orphan'
                        if orphans > orphans_recorded_in_chain else 'doa'
                        if doas > doas_recorded_in_chain else None)(
                            *self.get_stale_counts()),
                    desired_version=(share_type.SUCCESSOR
                                     if share_type.SUCCESSOR is not None else
                                     share_type).VOTING_VERSION,
                    payment_amount=self.current_work.value['payment_amount'],
                    packed_payments=self.current_work.value['packed_payments'],
                ),
                block_target=self.current_work.value['bits'].target,
                desired_timestamp=int(time.time() + 0.5),
                desired_target=desired_share_target,
                ref_merkle_link=dict(branch=[], index=0),
                desired_other_transaction_hashes_and_fees=zip(
                    tx_hashes, self.current_work.value['transaction_fees']),
                net=self.node.net,
                known_txs=tx_map,
                base_subsidy=self.current_work.value['subsidy'],
            )

        packed_gentx = dash_data.tx_type.pack(gentx)
        other_transactions = [
            tx_map[tx_hash] for tx_hash in other_transaction_hashes
        ]

        mm_later = [
            (dict(aux_work,
                  target=aux_work['target'] if aux_work['target'] != 'p2pool'
                  else share_info['bits'].target), index, hashes)
            for aux_work, index, hashes in mm_later
        ]

        if desired_pseudoshare_target is None:
            target = 2**256 - 1
            local_hash_rate = self._estimate_local_hash_rate()
            if local_hash_rate is not None:
                target = min(
                    target,
                    dash_data.average_attempts_to_target(local_hash_rate * 1)
                )  # limit to 1 share response every second by modulating pseudoshare difficulty
        else:
            target = desired_pseudoshare_target
        target = max(target, share_info['bits'].target)
        for aux_work, index, hashes in mm_later:
            target = max(target, aux_work['target'])
        target = math.clip(target, self.node.net.PARENT.SANE_TARGET_RANGE)

        getwork_time = time.time()
        lp_count = self.new_work_event.times
        merkle_link = dash_data.calculate_merkle_link(
            [None] + other_transaction_hashes, 0)

        if print_throttle is 0.0:
            print_throttle = time.time()
        else:
            current_time = time.time()
            if (current_time - print_throttle) > 5.0:
                print 'New work for worker %s! Difficulty: %.06f Share difficulty: %.06f Block %s Total value: %.6f %s including %i transactions' % (
                    dash_data.pubkey_hash_to_address(pubkey_hash,
                                                     self.node.net.PARENT),
                    dash_data.target_to_difficulty(target),
                    dash_data.target_to_difficulty(share_info['bits'].target),
                    self.current_work.value['height'],
                    self.current_work.value['subsidy'] * 1e-8,
                    self.node.net.PARENT.SYMBOL,
                    len(self.current_work.value['transactions']),
                )
                print_throttle = time.time()

        #need this for stats
        self.last_work_shares.value[dash_data.pubkey_hash_to_address(
            pubkey_hash, self.node.net.PARENT)] = share_info['bits']

        ba = dict(
            version=self.current_work.value['version'],
            previous_block=self.current_work.value['previous_block'],
            merkle_link=merkle_link,
            coinb1=packed_gentx[:-self.COINBASE_NONCE_LENGTH - 4],
            coinb2=packed_gentx[-4:],
            timestamp=self.current_work.value['time'],
            bits=self.current_work.value['bits'],
            share_target=target,
        )

        received_header_hashes = set()

        def got_response(header, user, coinbase_nonce):
            assert len(coinbase_nonce) == self.COINBASE_NONCE_LENGTH
            new_packed_gentx = packed_gentx[:-self.COINBASE_NONCE_LENGTH - 4] + coinbase_nonce + packed_gentx[
                -4:] if coinbase_nonce != '\0' * self.COINBASE_NONCE_LENGTH else packed_gentx
            new_gentx = dash_data.tx_type.unpack(
                new_packed_gentx
            ) if coinbase_nonce != '\0' * self.COINBASE_NONCE_LENGTH else gentx

            header_hash = self.node.net.PARENT.BLOCKHASH_FUNC(
                dash_data.block_header_type.pack(header))
            pow_hash = self.node.net.PARENT.POW_FUNC(
                dash_data.block_header_type.pack(header))
            try:
                if pow_hash <= header['bits'].target or p2pool.DEBUG:
                    helper.submit_block(
                        dict(header=header,
                             txs=[new_gentx] + other_transactions), False,
                        self.node.factory, self.node.dashd,
                        self.node.dashd_work, self.node.net)
                    if pow_hash <= header['bits'].target:
                        print
                        print 'GOT BLOCK FROM MINER! Passing to dashd! %s%064x' % (
                            self.node.net.PARENT.BLOCK_EXPLORER_URL_PREFIX,
                            header_hash)
                        print
                        # New block found
                        self.node.factory.new_block.happened(header_hash)
            except:
                log.err(None, 'Error while processing potential block:')

            user, _, _, _ = self.get_user_details(user)
            assert header['previous_block'] == ba['previous_block']
            assert header['merkle_root'] == dash_data.check_merkle_link(
                dash_data.hash256(new_packed_gentx), merkle_link)
            assert header['bits'] == ba['bits']

            on_time = self.new_work_event.times == lp_count

            for aux_work, index, hashes in mm_later:
                try:
                    if pow_hash <= aux_work['target'] or p2pool.DEBUG:
                        df = deferral.retry(
                            'Error submitting merged block: (will retry)', 10,
                            10)(aux_work['merged_proxy'].rpc_getauxblock)(
                                pack.IntType(256, 'big').pack(
                                    aux_work['hash']).encode('hex'),
                                dash_data.aux_pow_type.pack(
                                    dict(
                                        merkle_tx=dict(
                                            tx=new_gentx,
                                            block_hash=header_hash,
                                            merkle_link=merkle_link,
                                        ),
                                        merkle_link=dash_data.
                                        calculate_merkle_link(hashes, index),
                                        parent_block_header=header,
                                    )).encode('hex'),
                            )

                        @df.addCallback
                        def _(result, aux_work=aux_work):
                            if result != (pow_hash <= aux_work['target']):
                                print >> sys.stderr, 'Merged block submittal result: %s Expected: %s' % (
                                    result, pow_hash <= aux_work['target'])
                            else:
                                print 'Merged block submittal result: %s' % (
                                    result, )

                        @df.addErrback
                        def _(err):
                            log.err(err, 'Error submitting merged block:')
                except:
                    log.err(None, 'Error while processing merged mining POW:')

            if pow_hash <= share_info[
                    'bits'].target and header_hash not in received_header_hashes:
                last_txout_nonce = pack.IntType(
                    8 * self.COINBASE_NONCE_LENGTH).unpack(coinbase_nonce)
                share = get_share(header, last_txout_nonce)

                print 'GOT SHARE! %s %s prev %s age %.2fs%s' % (
                    user,
                    p2pool_data.format_hash(share.hash),
                    p2pool_data.format_hash(share.previous_hash),
                    time.time() - getwork_time,
                    ' DEAD ON ARRIVAL' if not on_time else '',
                )
                self.my_share_hashes.add(share.hash)
                if not on_time:
                    self.my_doa_share_hashes.add(share.hash)

                self.node.tracker.add(share)
                self.node.set_best_share()

                try:
                    if (pow_hash <= header['bits'].target or
                            p2pool.DEBUG) and self.node.p2p_node is not None:
                        self.node.p2p_node.broadcast_share(share.hash)
                except:
                    log.err(None, 'Error forwarding block solution:')

                self.share_received.happened(
                    dash_data.target_to_average_attempts(share.target),
                    not on_time, share.hash)

            if pow_hash > target:
                print 'Worker %s submitted share with hash > target:' % (
                    user, )
                print '    Hash:   %56x' % (pow_hash, )
                print '    Target: %56x' % (target, )
            elif header_hash in received_header_hashes:
                print >> sys.stderr, 'Worker %s submitted share more than once!' % (
                    user, )
            else:
                received_header_hashes.add(header_hash)

                self.pseudoshare_received.happened(
                    dash_data.target_to_average_attempts(target), not on_time,
                    user)
                self.recent_shares_ts_work.append(
                    (time.time(),
                     dash_data.target_to_average_attempts(target)))
                while len(self.recent_shares_ts_work) > 50:
                    self.recent_shares_ts_work.pop(0)
                self.local_rate_monitor.add_datum(
                    dict(work=dash_data.target_to_average_attempts(target),
                         dead=not on_time,
                         user=user,
                         share_target=share_info['bits'].target))
                self.local_addr_rate_monitor.add_datum(
                    dict(work=dash_data.target_to_average_attempts(target),
                         pubkey_hash=pubkey_hash))

            return on_time

        return ba, got_response
Beispiel #9
0
    def get_work(self,
                 pubkey_hash,
                 desired_share_target,
                 desired_pseudoshare_target,
                 worker_ip=None):
        global print_throttle
        t0 = time.time()
        if (self.node.p2p_node is None or len(self.node.p2p_node.peers)
                == 0) and self.node.net.PERSIST:
            raise jsonrpc.Error_for_code(-12345)(
                u'p2pool is not connected to any peers')
        if self.node.best_share_var.value is None and self.node.net.PERSIST:
            raise jsonrpc.Error_for_code(-12345)(
                u'p2pool is downloading shares')
        unknown_rules = set(
            r[1:] if r.startswith('!') else r
            for r in self.node.bitcoind_work.value['rules']) - set(
                getattr(self.node.net, 'SOFTFORKS_REQUIRED', []))
        if unknown_rules:
            print "Unknown softforks found: ", unknown_rules
            raise jsonrpc.Error_for_code(-12345)(u'unknown rule activated')

        if self.merged_work.value:
            tree, size = bitcoin_data.make_auxpow_tree(self.merged_work.value)
            mm_hashes = [
                self.merged_work.value.get(tree.get(i), dict(hash=0))['hash']
                for i in xrange(size)
            ]
            mm_data = '\xfa\xbemm' + bitcoin_data.aux_pow_coinbase_type.pack(
                dict(
                    merkle_root=bitcoin_data.merkle_hash(mm_hashes),
                    size=size,
                    nonce=0,
                ))
            mm_later = [
                (aux_work, mm_hashes.index(aux_work['hash']), mm_hashes)
                for chain_id, aux_work in self.merged_work.value.iteritems()
            ]
        else:
            mm_data = ''
            mm_later = []

        tx_hashes = [
            bitcoin_data.hash256(bitcoin_data.tx_type.pack(tx))
            for tx in self.current_work.value['transactions']
        ]
        tx_map = dict(zip(tx_hashes, self.current_work.value['transactions']))

        self.node.mining2_txs_var.set(
            tx_map)  # let node.py know not to evict these transactions

        previous_share = self.node.tracker.items[
            self.node.best_share_var.
            value] if self.node.best_share_var.value is not None else None
        if previous_share is None:
            share_type = p2pool_data.Share
        else:
            previous_share_type = type(previous_share)

            if previous_share_type.SUCCESSOR is None or self.node.tracker.get_height(
                    previous_share.hash) < self.node.net.CHAIN_LENGTH:
                share_type = previous_share_type
            else:
                successor_type = previous_share_type.SUCCESSOR

                counts = p2pool_data.get_desired_version_counts(
                    self.node.tracker,
                    self.node.tracker.get_nth_parent_hash(
                        previous_share.hash,
                        self.node.net.CHAIN_LENGTH * 9 // 10),
                    self.node.net.CHAIN_LENGTH // 10)
                upgraded = counts.get(successor_type.VERSION, 0) / sum(
                    counts.itervalues())
                if upgraded > .65:
                    print 'Switchover imminent. Upgraded: %.3f%% Threshold: %.3f%%' % (
                        upgraded * 100, 95)
                # Share -> NewShare only valid if 95% of hashes in [net.CHAIN_LENGTH*9//10, net.CHAIN_LENGTH] for new version
                if counts.get(successor_type.VERSION,
                              0) > sum(counts.itervalues()) * 95 // 100:
                    share_type = successor_type
                else:
                    share_type = previous_share_type

        local_addr_rates = self.get_local_addr_rates()

        if desired_share_target is None:
            desired_share_target = bitcoin_data.difficulty_to_target(
                float(1.0 / self.node.net.PARENT.DUMB_SCRYPT_DIFF))
            local_hash_rate = local_addr_rates.get(pubkey_hash, 0)
            if local_hash_rate > 0.0:
                desired_share_target = min(
                    desired_share_target,
                    bitcoin_data.average_attempts_to_target(
                        local_hash_rate * self.node.net.SHARE_PERIOD / 0.0167)
                )  # limit to 1.67% of pool shares by modulating share difficulty

            lookbehind = 3600 // self.node.net.SHARE_PERIOD
            block_subsidy = self.node.bitcoind_work.value['subsidy']
            if previous_share is not None and self.node.tracker.get_height(
                    previous_share.hash) > lookbehind:
                expected_payout_per_block = local_addr_rates.get(pubkey_hash, 0)/p2pool_data.get_pool_attempts_per_second(self.node.tracker, self.node.best_share_var.value, lookbehind) \
                    * block_subsidy*(1-self.donation_percentage/100) # XXX doesn't use global stale rate to compute pool hash
                if expected_payout_per_block < self.node.net.PARENT.DUST_THRESHOLD:
                    desired_share_target = min(
                        desired_share_target,
                        bitcoin_data.average_attempts_to_target(
                            (bitcoin_data.target_to_average_attempts(
                                self.node.bitcoind_work.value['bits'].target) *
                             self.node.net.SPREAD) *
                            self.node.net.PARENT.DUST_THRESHOLD /
                            block_subsidy))

        if True:
            share_info, gentx, other_transaction_hashes, get_share = share_type.generate_transaction(
                tracker=self.node.tracker,
                share_data=dict(
                    previous_share_hash=self.node.best_share_var.value,
                    coinbase=(script.create_push_script([
                        self.current_work.value['height'],
                    ] + ([mm_data] if mm_data else []) + self.args.coinb_texts)
                              +
                              self.current_work.value['coinbaseflags'])[:100],
                    nonce=random.randrange(2**32),
                    pubkey_hash=pubkey_hash,
                    subsidy=self.current_work.value['subsidy'],
                    donation=math.perfect_round(
                        65535 * self.donation_percentage / 100),
                    stale_info=(
                        lambda (orphans, doas), total,
                        (orphans_recorded_in_chain, doas_recorded_in_chain
                         ): 'orphan'
                        if orphans > orphans_recorded_in_chain else 'doa'
                        if doas > doas_recorded_in_chain else None)(
                            *self.get_stale_counts()),
                    desired_version=(share_type.SUCCESSOR
                                     if share_type.SUCCESSOR is not None else
                                     share_type).VOTING_VERSION,
                ),
                block_target=self.current_work.value['bits'].target,
                desired_timestamp=int(time.time() + 0.5),
                desired_target=desired_share_target,
                ref_merkle_link=dict(branch=[], index=0),
                desired_other_transaction_hashes_and_fees=zip(
                    tx_hashes, self.current_work.value['transaction_fees']),
                net=self.node.net,
                known_txs=tx_map,
                base_subsidy=self.node.net.PARENT.SUBSIDY_FUNC(
                    self.current_work.value['height']),
            )

        packed_gentx = bitcoin_data.tx_id_type.pack(
            gentx)  # stratum miners work with stripped transactions
        other_transactions = [
            tx_map[tx_hash] for tx_hash in other_transaction_hashes
        ]

        mm_later = [
            (dict(aux_work,
                  target=aux_work['target'] if aux_work['target'] != 'p2pool'
                  else share_info['bits'].target), index, hashes)
            for aux_work, index, hashes in mm_later
        ]

        if desired_pseudoshare_target is None:
            target = bitcoin_data.difficulty_to_target(
                float(1.0 / self.node.net.PARENT.DUMB_SCRYPT_DIFF))
            local_hash_rate = self._estimate_local_hash_rate()
            if local_hash_rate is not None:
                target = bitcoin_data.average_attempts_to_target(
                    local_hash_rate * 1
                )  # target 10 share responses every second by modulating pseudoshare difficulty
            else:
                # If we don't yet have an estimated node hashrate, then we still need to not undershoot the difficulty.
                # Otherwise, we might get 1 PH/s of hashrate on difficulty settings appropriate for 1 GH/s.
                # 1/3000th the difficulty of a full share should be a reasonable upper bound. That way, if
                # one node has the whole p2pool hashrate, it will still only need to process one pseudoshare
                # every ~0.01 seconds.
                target = min(
                    target, 3000 * bitcoin_data.average_attempts_to_target(
                        (bitcoin_data.target_to_average_attempts(
                            self.node.bitcoind_work.value['bits'].target) *
                         self.node.net.SPREAD) *
                        self.node.net.PARENT.DUST_THRESHOLD / block_subsidy))
        else:
            target = desired_pseudoshare_target
        target = max(target, share_info['bits'].target)
        for aux_work, index, hashes in mm_later:
            target = max(target, aux_work['target'])
        target = math.clip(target, self.node.net.PARENT.SANE_TARGET_RANGE)

        getwork_time = time.time()
        lp_count = self.new_work_event.times
        merkle_link = bitcoin_data.calculate_merkle_link(
            [None] + other_transaction_hashes, 0) if share_info.get(
                'segwit_data', None
            ) is None else share_info['segwit_data']['txid_merkle_link']

        if print_throttle is 0.0:
            print_throttle = time.time()
        else:
            current_time = time.time()
            if (current_time - print_throttle) > 5.0:
                print 'New work for %s! Diff: %.02f Share diff: %.02f Block value: %.2f %s (%i tx, %.0f kB)' % (
                    bitcoin_data.pubkey_hash_to_address(
                        pubkey_hash, self.node.net.PARENT),
                    bitcoin_data.target_to_difficulty(target),
                    bitcoin_data.target_to_difficulty(
                        share_info['bits'].target),
                    self.current_work.value['subsidy'] * 1e-8,
                    self.node.net.PARENT.SYMBOL,
                    len(self.current_work.value['transactions']),
                    sum(
                        map(bitcoin_data.tx_type.packed_size,
                            self.current_work.value['transactions'])) / 1000.,
                )
                print_throttle = time.time()

        #need this for stats
        self.last_work_shares.value[bitcoin_data.pubkey_hash_to_address(
            pubkey_hash, self.node.net.PARENT)] = share_info['bits']

        ba = dict(
            version=max(self.current_work.value['version'], 0x20000000),
            previous_block=self.current_work.value['previous_block'],
            merkle_link=merkle_link,
            coinb1=packed_gentx[:-self.COINBASE_NONCE_LENGTH - 4],
            coinb2=packed_gentx[-4:],
            timestamp=self.current_work.value['time'],
            bits=self.current_work.value['bits'],
            share_target=target,
        )

        received_header_hashes = set()

        def got_response(header, user, coinbase_nonce):
            t0 = time.time()
            assert len(coinbase_nonce) == self.COINBASE_NONCE_LENGTH
            new_packed_gentx = packed_gentx[:-self.COINBASE_NONCE_LENGTH - 4] + coinbase_nonce + packed_gentx[
                -4:] if coinbase_nonce != '\0' * self.COINBASE_NONCE_LENGTH else packed_gentx
            new_gentx = bitcoin_data.tx_type.unpack(
                new_packed_gentx
            ) if coinbase_nonce != '\0' * self.COINBASE_NONCE_LENGTH else gentx
            if bitcoin_data.is_segwit_tx(
                    gentx
            ):  # reintroduce witness data to the gentx produced by stratum miners
                new_gentx['marker'] = 0
                new_gentx['flag'] = gentx['flag']
                new_gentx['witness'] = gentx['witness']

            header_hash = bitcoin_data.hash256(
                bitcoin_data.block_header_type.pack(header))
            pow_hash = self.node.net.PARENT.POW_FUNC(
                bitcoin_data.block_header_type.pack(header))
            try:
                if pow_hash <= header['bits'].target or p2pool.DEBUG:
                    helper.submit_block(
                        dict(header=header,
                             txs=[new_gentx] + other_transactions), False,
                        self.node.factory, self.node.bitcoind,
                        self.node.bitcoind_work, self.node.net)
                    if pow_hash <= header['bits'].target:
                        print
                        print 'GOT BLOCK FROM MINER! Passing to bitcoind! %s%064x' % (
                            self.node.net.PARENT.BLOCK_EXPLORER_URL_PREFIX,
                            header_hash)
                        print
            except:
                log.err(None, 'Error while processing potential block:')

            user, _, _, _ = self.get_user_details(user)
            assert header['previous_block'] == ba['previous_block']
            assert header['merkle_root'] == bitcoin_data.check_merkle_link(
                bitcoin_data.hash256(new_packed_gentx), merkle_link)
            assert header['bits'] == ba['bits']

            on_time = self.new_work_event.times == lp_count

            for aux_work, index, hashes in mm_later:
                try:
                    if pow_hash <= aux_work['target'] or p2pool.DEBUG:
                        df = deferral.retry(
                            'Error submitting merged block: (will retry)', 10,
                            10)(aux_work['merged_proxy'].rpc_getauxblock)(
                                pack.IntType(256, 'big').pack(
                                    aux_work['hash']).encode('hex'),
                                bitcoin_data.aux_pow_type.pack(
                                    dict(
                                        merkle_tx=dict(
                                            tx=new_gentx,
                                            block_hash=header_hash,
                                            merkle_link=merkle_link,
                                        ),
                                        merkle_link=bitcoin_data.
                                        calculate_merkle_link(hashes, index),
                                        parent_block_header=header,
                                    )).encode('hex'),
                            )

                        @df.addCallback
                        def _(result, aux_work=aux_work):
                            if result != (pow_hash <= aux_work['target']):
                                print >> sys.stderr, 'Merged block submittal result: %s Expected: %s' % (
                                    result, pow_hash <= aux_work['target'])
                            else:
                                print 'Merged block submittal result: %s' % (
                                    result, )

                        @df.addErrback
                        def _(err):
                            log.err(err, 'Error submitting merged block:')
                except:
                    log.err(None, 'Error while processing merged mining POW:')

            if pow_hash <= share_info[
                    'bits'].target and header_hash not in received_header_hashes:
                last_txout_nonce = pack.IntType(
                    8 * self.COINBASE_NONCE_LENGTH).unpack(coinbase_nonce)
                share = get_share(header, last_txout_nonce)

                print 'GOT SHARE! %s %s prev %s age %.2fs%s' % (
                    user,
                    p2pool_data.format_hash(share.hash),
                    p2pool_data.format_hash(share.previous_hash),
                    time.time() - getwork_time,
                    ' DEAD ON ARRIVAL' if not on_time else '',
                )

                # node.py will sometimes forget transactions if bitcoind's work has changed since this stratum
                # job was assigned. Fortunately, the tx_map is still in in our scope from this job, so we can use that
                # to refill it if needed.

                known_txs = self.node.known_txs_var.value
                missing = {
                    hsh: val
                    for (hsh, val) in tx_map.iteritems()
                    if not hsh in known_txs
                }
                if missing:
                    print "Warning: %i transactions were erroneously evicted from known_txs_var. Refilling now." % len(
                        missing)
                    self.node.known_txs_var.add(missing)

                self.my_share_hashes.add(share.hash)
                if not on_time:
                    self.my_doa_share_hashes.add(share.hash)

                self.node.tracker.add(share)
                self.node.set_best_share()

                try:
                    if (pow_hash <= header['bits'].target or
                            p2pool.DEBUG) and self.node.p2p_node is not None:
                        self.node.p2p_node.broadcast_share(share.hash)
                except:
                    log.err(None, 'Error forwarding block solution:')

                self.share_received.happened(
                    bitcoin_data.target_to_average_attempts(share.target),
                    not on_time, share.hash)

            if pow_hash > target:
                print 'Worker %s submitted share with hash > target:' % (
                    user, )
                print '    Hash:   %56x' % (pow_hash, )
                print '    Target: %56x' % (target, )
            elif header_hash in received_header_hashes:
                print >> sys.stderr, 'Worker %s submitted share more than once!' % (
                    user, )
            else:
                received_header_hashes.add(header_hash)

                self.pseudoshare_received.happened(
                    bitcoin_data.target_to_average_attempts(target),
                    not on_time, user)
                self.recent_shares_ts_work.append(
                    (time.time(),
                     bitcoin_data.target_to_average_attempts(target)))
                while len(self.recent_shares_ts_work) > 50:
                    self.recent_shares_ts_work.pop(0)
                self.local_rate_monitor.add_datum(
                    dict(work=bitcoin_data.target_to_average_attempts(target),
                         dead=not on_time,
                         user=user,
                         share_target=share_info['bits'].target))
                self.local_addr_rate_monitor.add_datum(
                    dict(work=bitcoin_data.target_to_average_attempts(target),
                         pubkey_hash=pubkey_hash))
            t1 = time.time()
            if p2pool.BENCH and (t1 - t1) > .01:
                print "%8.3f ms for work.py:got_response()" % (
                    (t1 - t0) * 1000.)

            return on_time

        t1 = time.time()
        if p2pool.BENCH:
            print "%8.3f ms for work.py:get_work()" % ((t1 - t0) * 1000.)
        return ba, got_response
Beispiel #10
0
    def get_work(self, pubkey_hash, desired_share_target, desired_pseudoshare_target):
        if self.node.best_share_var.value is None and self.node.net.PERSIST:
            raise jsonrpc.Error_for_code(-12345)(u"p2pool is downloading shares")

        if self.merged_work.value:
            tree, size = bitcoin_data.make_auxpow_tree(self.merged_work.value)
            mm_hashes = [self.merged_work.value.get(tree.get(i), dict(hash=0))["hash"] for i in xrange(size)]
            mm_data = "\xfa\xbemm" + bitcoin_data.aux_pow_coinbase_type.pack(
                dict(merkle_root=bitcoin_data.merkle_hash(mm_hashes), size=size, nonce=0)
            )
            mm_later = [
                (aux_work, mm_hashes.index(aux_work["hash"]), mm_hashes)
                for chain_id, aux_work in self.merged_work.value.iteritems()
            ]
        else:
            mm_data = ""
            mm_later = []

        tx_hashes = [
            bitcoin_data.hash256(bitcoin_data.tx_type.pack(tx)) for tx in self.current_work.value["transactions"]
        ]
        tx_map = dict(zip(tx_hashes, self.current_work.value["transactions"]))

        previous_share = (
            self.node.tracker.items[self.node.best_share_var.value]
            if self.node.best_share_var.value is not None
            else None
        )
        if previous_share is None:
            share_type = p2pool_data.Share
        else:
            previous_share_type = type(previous_share)

            if (
                previous_share_type.SUCCESSOR is None
                or self.node.tracker.get_height(previous_share.hash) < self.node.net.CHAIN_LENGTH
            ):
                share_type = previous_share_type
            else:
                successor_type = previous_share_type.SUCCESSOR

                counts = p2pool_data.get_desired_version_counts(
                    self.node.tracker,
                    self.node.tracker.get_nth_parent_hash(previous_share.hash, self.node.net.CHAIN_LENGTH * 9 // 10),
                    self.node.net.CHAIN_LENGTH // 10,
                )
                upgraded = counts.get(successor_type.VERSION, 0) / sum(counts.itervalues())
                if upgraded > 0.65:
                    print "Switchover imminent. Upgraded: %.3f%% Threshold: %.3f%%" % (upgraded * 100, 95)
                print
                # Share -> NewShare only valid if 95% of hashes in [net.CHAIN_LENGTH*9//10, net.CHAIN_LENGTH] for new version
                if counts.get(successor_type.VERSION, 0) > sum(counts.itervalues()) * 95 // 100:
                    share_type = successor_type
                else:
                    share_type = previous_share_type

        if desired_share_target is None:
            desired_share_target = 2 ** 256 - 1
            local_hash_rate = self._estimate_local_hash_rate()
            if local_hash_rate is not None:
                desired_share_target = min(
                    desired_share_target,
                    bitcoin_data.average_attempts_to_target(local_hash_rate * self.node.net.SHARE_PERIOD / 0.0167),
                )  # limit to 1.67% of pool shares by modulating share difficulty

            local_addr_rates = self.get_local_addr_rates()
            lookbehind = 3600 // self.node.net.SHARE_PERIOD
            block_subsidy = self.node.bitcoind_work.value["subsidy"]
            if previous_share is not None and self.node.tracker.get_height(previous_share.hash) > lookbehind:
                expected_payout_per_block = (
                    local_addr_rates.get(pubkey_hash, 0)
                    / p2pool_data.get_pool_attempts_per_second(
                        self.node.tracker, self.node.best_share_var.value, lookbehind
                    )
                    * block_subsidy
                    * (1 - self.donation_percentage / 100)
                )  # XXX doesn't use global stale rate to compute pool hash
                if expected_payout_per_block < self.node.net.PARENT.DUST_THRESHOLD:
                    desired_share_target = min(
                        desired_share_target,
                        bitcoin_data.average_attempts_to_target(
                            (
                                bitcoin_data.target_to_average_attempts(self.node.bitcoind_work.value["bits"].target)
                                * self.node.net.SPREAD
                            )
                            * self.node.net.PARENT.DUST_THRESHOLD
                            / block_subsidy
                        ),
                    )

        if True:
            share_info, gentx, other_transaction_hashes, get_share = share_type.generate_transaction(
                tracker=self.node.tracker,
                share_data=dict(
                    previous_share_hash=self.node.best_share_var.value,
                    coinbase=(
                        script.create_push_script(
                            [self.current_work.value["height"]] + ([mm_data] if mm_data else []) + []
                        )
                        + self.current_work.value["coinbaseflags"]
                    )[:100],
                    nonce=random.randrange(2 ** 32),
                    pubkey_hash=pubkey_hash,
                    subsidy=self.current_work.value["subsidy"],
                    donation=math.perfect_round(65535 * self.donation_percentage / 100),
                    stale_info=(
                        lambda (orphans, doas), total, (orphans_recorded_in_chain, doas_recorded_in_chain): "orphan"
                        if orphans > orphans_recorded_in_chain
                        else "doa"
                        if doas > doas_recorded_in_chain
                        else None
                    )(*self.get_stale_counts()),
                    desired_version=(
                        share_type.SUCCESSOR if share_type.SUCCESSOR is not None else share_type
                    ).VOTING_VERSION,
                ),
                block_target=self.current_work.value["bits"].target,
                desired_timestamp=int(time.time() + 0.5),
                desired_target=desired_share_target,
                ref_merkle_link=dict(branch=[], index=0),
                desired_other_transaction_hashes_and_fees=zip(tx_hashes, self.current_work.value["transaction_fees"]),
                net=self.node.net,
                known_txs=tx_map,
                base_subsidy=self.node.net.PARENT.SUBSIDY_FUNC(self.current_work.value["height"]),
            )

        packed_gentx = bitcoin_data.tx_type.pack(gentx)
        other_transactions = [tx_map[tx_hash] for tx_hash in other_transaction_hashes]

        mm_later = [
            (
                dict(
                    aux_work, target=aux_work["target"] if aux_work["target"] != "p2pool" else share_info["bits"].target
                ),
                index,
                hashes,
            )
            for aux_work, index, hashes in mm_later
        ]

        if desired_pseudoshare_target is None:
            target = 2 ** 256 - 1
            local_hash_rate = self._estimate_local_hash_rate()
            if local_hash_rate is not None:
                target = min(
                    target, bitcoin_data.average_attempts_to_target(local_hash_rate * 3)
                )  # limit to 1 share response every 3 seconds by modulating pseudoshare difficulty
        else:
            target = desired_pseudoshare_target
        target = max(target, share_info["bits"].target)
        for aux_work, index, hashes in mm_later:
            target = max(target, aux_work["target"])
        target = math.clip(target, self.node.net.PARENT.SANE_TARGET_RANGE)

        getwork_time = time.time()
        lp_count = self.new_work_event.times
        merkle_link = bitcoin_data.calculate_merkle_link([None] + other_transaction_hashes, 0)

        print "New work for worker! Difficulty: %.09f Share difficulty: %.09f Total block value: %.6f %s including %i transactions" % (
            bitcoin_data.target_to_difficulty(target),
            bitcoin_data.target_to_difficulty(share_info["bits"].target),
            self.current_work.value["subsidy"] * 1e-8,
            self.node.net.PARENT.SYMBOL,
            len(self.current_work.value["transactions"]),
        )

        ba = dict(
            version=min(self.current_work.value["version"], 2),
            previous_block=self.current_work.value["previous_block"],
            merkle_link=merkle_link,
            coinb1=packed_gentx[: -self.COINBASE_NONCE_LENGTH - 4],
            coinb2=packed_gentx[-4:],
            timestamp=self.current_work.value["time"],
            bits=self.current_work.value["bits"],
            share_target=target,
        )

        received_header_hashes = set()

        def got_response(header, user, coinbase_nonce):
            assert len(coinbase_nonce) == self.COINBASE_NONCE_LENGTH
            new_packed_gentx = (
                packed_gentx[: -self.COINBASE_NONCE_LENGTH - 4] + coinbase_nonce + packed_gentx[-4:]
                if coinbase_nonce != "\0" * self.COINBASE_NONCE_LENGTH
                else packed_gentx
            )
            new_gentx = (
                bitcoin_data.tx_type.unpack(new_packed_gentx)
                if coinbase_nonce != "\0" * self.COINBASE_NONCE_LENGTH
                else gentx
            )

            header_hash = bitcoin_data.hash256(bitcoin_data.block_header_type.pack(header))
            pow_hash = self.node.net.PARENT.POW_FUNC(bitcoin_data.block_header_type.pack(header))
            try:
                if pow_hash <= header["bits"].target or p2pool.DEBUG:
                    helper.submit_block(
                        dict(header=header, txs=[new_gentx] + other_transactions),
                        False,
                        self.node.factory,
                        self.node.bitcoind,
                        self.node.bitcoind_work,
                        self.node.net,
                    )
                    if pow_hash <= header["bits"].target:
                        print
                        print "GOT BLOCK FROM MINER! Passing to bitcoind! %s%064x" % (
                            self.node.net.PARENT.BLOCK_EXPLORER_URL_PREFIX,
                            header_hash,
                        )
                        print
            except:
                log.err(None, "Error while processing potential block:")

            user, _, _, _ = self.get_user_details(user)
            assert header["previous_block"] == ba["previous_block"]
            assert header["merkle_root"] == bitcoin_data.check_merkle_link(
                bitcoin_data.hash256(new_packed_gentx), merkle_link
            )
            assert header["bits"] == ba["bits"]
            # Check momentum using midhash (who knows why it is called that) and birthday values
            midhash = hashlib.sha256(hashlib.sha256(bitcoin_data.block_header_type.pack(header)[:80]).digest()).digest()
            # print 'MIDHASH: {0}'.format(midhash.encode('hex'))
            # print 'A: {0}'.format(header['birthdayA'])
            # print 'B: {0}'.format(header['birthdayB'])
            momentumc = rewardcoin_momentum.checkMomentum(midhash, header["birthdayA"], header["birthdayB"])
            # print momentumc
            if momentumc == False:
                print "Invalid Momentum from Client!"
                return False

            on_time = self.new_work_event.times == lp_count

            for aux_work, index, hashes in mm_later:
                try:
                    if pow_hash <= aux_work["target"] or p2pool.DEBUG:
                        df = deferral.retry("Error submitting merged block: (will retry)", 10, 10)(
                            aux_work["merged_proxy"].rpc_getauxblock
                        )(
                            pack.IntType(256, "big").pack(aux_work["hash"]).encode("hex"),
                            bitcoin_data.aux_pow_type.pack(
                                dict(
                                    merkle_tx=dict(tx=new_gentx, block_hash=header_hash, merkle_link=merkle_link),
                                    merkle_link=bitcoin_data.calculate_merkle_link(hashes, index),
                                    parent_block_header=header,
                                )
                            ).encode("hex"),
                        )

                        @df.addCallback
                        def _(result, aux_work=aux_work):
                            if result != (pow_hash <= aux_work["target"]):
                                print >> sys.stderr, "Merged block submittal result: %s Expected: %s" % (
                                    result,
                                    pow_hash <= aux_work["target"],
                                )
                            else:
                                print "Merged block submittal result: %s" % (result,)

                        @df.addErrback
                        def _(err):
                            log.err(err, "Error submitting merged block:")

                except:
                    log.err(None, "Error while processing merged mining POW:")

            if pow_hash <= share_info["bits"].target and header_hash not in received_header_hashes:
                last_txout_nonce = pack.IntType(8 * self.COINBASE_NONCE_LENGTH).unpack(coinbase_nonce)
                share = get_share(header, last_txout_nonce)

                print "GOT SHARE! %s %s prev %s age %.2fs%s" % (
                    user,
                    p2pool_data.format_hash(share.hash),
                    p2pool_data.format_hash(share.previous_hash),
                    time.time() - getwork_time,
                    " DEAD ON ARRIVAL" if not on_time else "",
                )
                self.my_share_hashes.add(share.hash)
                if not on_time:
                    self.my_doa_share_hashes.add(share.hash)

                self.node.tracker.add(share)
                self.node.set_best_share()

                try:
                    if (pow_hash <= header["bits"].target or p2pool.DEBUG) and self.node.p2p_node is not None:
                        self.node.p2p_node.broadcast_share(share.hash)
                except:
                    log.err(None, "Error forwarding block solution:")

                self.share_received.happened(
                    bitcoin_data.target_to_average_attempts(share.target), not on_time, share.hash
                )

            if pow_hash > target:
                print "Worker %s submitted share with hash > target:" % (user,)
                print "    Hash:   %56x" % (pow_hash,)
                print "    Target: %56x" % (target,)
            elif header_hash in received_header_hashes:
                print >> sys.stderr, "Worker %s submitted share more than once!" % (user,)
            else:
                received_header_hashes.add(header_hash)

                self.pseudoshare_received.happened(bitcoin_data.target_to_average_attempts(target), not on_time, user)
                self.recent_shares_ts_work.append((time.time(), bitcoin_data.target_to_average_attempts(target)))
                while len(self.recent_shares_ts_work) > 50:
                    self.recent_shares_ts_work.pop(0)
                self.local_rate_monitor.add_datum(
                    dict(
                        work=bitcoin_data.target_to_average_attempts(target),
                        dead=not on_time,
                        user=user,
                        share_target=share_info["bits"].target,
                    )
                )
                self.local_addr_rate_monitor.add_datum(
                    dict(work=bitcoin_data.target_to_average_attempts(target), pubkey_hash=pubkey_hash)
                )

            return on_time

        return ba, got_response
Beispiel #11
0
 def status_thread():
     last_str = None
     last_time = 0
     while True:
         yield deferral.sleep(3)
         try:
             if time.time() > current_work2.value['last_update'] + 60:
                 print '''---> LOST CONTACT WITH BITCOIND for 60 seconds, check that it isn't frozen or dead <---'''
             if current_work.value['best_share_hash'] is not None:
                 height, last = tracker.get_height_and_last(
                     current_work.value['best_share_hash'])
                 if height > 2:
                     att_s = p2pool_data.get_pool_attempts_per_second(
                         tracker, current_work.value['best_share_hash'],
                         min(height - 1, 720))
                     weights, total_weight, donation_weight = tracker.get_cumulative_weights(
                         current_work.value['best_share_hash'],
                         min(height, 720), 65535 * 2**256)
                     shares, stale_doa_shares, stale_not_doa_shares = get_share_counts(
                         True)
                     stale_shares = stale_doa_shares + stale_not_doa_shares
                     fracs = [
                         share.stale_frac
                         for share in tracker.get_chain(
                             current_work.value['best_share_hash'],
                             min(120, height))
                         if share.stale_frac is not None
                     ]
                     this_str = 'Pool: %sH/s in %i shares (%i/%i verified) Recent: %.02f%% >%sH/s Shares: %i (%i orphan, %i dead) Peers: %i' % (
                         math.format(
                             int(att_s /
                                 (1. -
                                  (math.median(fracs) if fracs else 0)))
                         ),
                         height,
                         len(tracker.verified.shares),
                         len(tracker.shares),
                         weights.get(my_script, 0) / total_weight * 100,
                         math.format(
                             int(
                                 weights.get(my_script, 0) * att_s //
                                 total_weight /
                                 (1. -
                                  (math.median(fracs) if fracs else 0)))
                         ),
                         shares,
                         stale_not_doa_shares,
                         stale_doa_shares,
                         len(p2p_node.peers),
                     ) + (' FDs: %i R/%i W' %
                          (len(reactor.getReaders()),
                           len(reactor.getWriters()))
                          if p2pool.DEBUG else '')
                     if fracs:
                         med = math.median(fracs)
                         this_str += '\nPool stales: %i%%' % (
                             int(100 * med + .5), )
                         conf = 0.95
                         if shares:
                             this_str += u' Own: %i±%i%%' % tuple(
                                 int(100 * x + .5) for x in
                                 math.interval_to_center_radius(
                                     math.binomial_conf_interval(
                                         stale_shares, shares, conf)))
                             if med < .99:
                                 this_str += u' Own efficiency: %i±%i%%' % tuple(
                                     int(100 * x + .5) for x in
                                     math.interval_to_center_radius(
                                         (1 - y) / (1 - med) for y in
                                         math.binomial_conf_interval(
                                             stale_shares, shares,
                                             conf)[::-1]))
                     if this_str != last_str or time.time(
                     ) > last_time + 15:
                         print this_str
                         last_str = this_str
                         last_time = time.time()
         except:
             log.err()
Beispiel #12
0
    def get_user_details(self, username):
        contents = re.split('([+/])', username)
        assert len(contents) % 2 == 1

        user, contents2 = contents[0], contents[1:]

        desired_pseudoshare_target = None
        desired_share_target = None
        for symbol, parameter in zip(contents2[::2], contents2[1::2]):
            if symbol == '+':
                try:
                    desired_pseudoshare_target = bitcoin_data.difficulty_to_target(
                        float(parameter))
                except:
                    if p2pool.DEBUG:
                        log.err()
            elif symbol == '/':
                try:
                    desired_share_target = bitcoin_data.difficulty_to_target(
                        float(parameter))
                except:
                    if p2pool.DEBUG:
                        log.err()

        set_adaptive_target = (self.diff_policy
                               == 'F') or ((self.diff_policy == 'A') and
                                           (desired_share_target is None))
        set_adaptive_pseudo = (self.diff_policy == 'F') or (
            (self.diff_policy == 'A') and (desired_pseudoshare_target is None))
        user_rate = None
        pool_rate = None

        if set_adaptive_target:  # calculate pool hashrate
            height = self.node.tracker.get_height(
                self.node.best_share_var.value)
            if height > 5:  # we want at least 6 shares in chain
                stale_prop = p2pool_data.get_average_stale_prop(
                    self.node.tracker, self.node.best_share_var.value,
                    min(60 * 60 // self.node.net.SHARE_PERIOD, height))
                pool_rate = p2pool_data.get_pool_attempts_per_second(
                    self.node.tracker, self.node.best_share_var.value,
                    min(height - 1, 60 * 60 //
                        self.node.net.SHARE_PERIOD)) / (1 - stale_prop)

        if set_adaptive_pseudo or set_adaptive_target:  # calculate user's hashrate
            datums, dt = self.local_rate_monitor.get_datums_in_last()
            npoints = sum(datum['user'] == user for datum in datums)
            if npoints > 5:  # at least 6 hashrate datums for the user
                user_rate = 0
                for datum in datums:
                    if datum['user'] == user:
                        user_rate += datum['work'] / dt

        if set_adaptive_target:
            desired_share_target = None
            if user_rate is not None and pool_rate is not None:
                if user_rate and pool_rate:
                    # min 20 shares per block AND min 20 shares per chain
                    desired_share_target = 20 * (max(
                        self.node.bitcoind_work.value['bits'].target *
                        pool_rate, 2**256 //
                        (self.node.net.CHAIN_LENGTH *
                         self.node.net.SHARE_PERIOD)) // user_rate)

        if set_adaptive_pseudo:
            desired_pseudoshare_target = None
            if user_rate is not None:
                if user_rate:
                    # min 20 pseudoshares per 10 minutes
                    desired_pseudoshare_target = 20 * (2**256 // user_rate //
                                                       (10 * 60))

        if random.uniform(0, 100) < self.worker_fee:
            pubkey_hash = self.my_pubkey_hash
        else:
            try:
                pubkey_hash = bitcoin_data.address_to_pubkey_hash(
                    user, self.node.net.PARENT)
            except:  # XXX blah
                pubkey_hash = self.my_pubkey_hash

        return user, pubkey_hash, desired_share_target, desired_pseudoshare_target
Beispiel #13
0
    def get_user_details(self, user):
        desired_pseudoshare_target = None
        if '+' in user:
            user, desired_pseudoshare_difficulty_str = user.rsplit('+', 1)
            try:
                desired_pseudoshare_target = bitcoin_data.difficulty_to_target(
                    float(desired_pseudoshare_difficulty_str))
            except:
                pass

        desired_share_target = None
        if '/' in user:
            user, min_diff_str = user.rsplit('/', 1)
            try:
                desired_share_target = bitcoin_data.difficulty_to_target(
                    float(min_diff_str))
            except:
                pass

        set_adaptive_target = (self.diff_policy
                               == 'F') or ((self.diff_policy == 'D') and
                                           (desired_share_target is None))
        set_adaptive_pseudo = (self.diff_policy == 'F') or (
            (self.diff_policy == 'D') and (desired_pseudoshare_target is None))
        user_rate = None
        pool_rate = None

        if set_adaptive_target:  # calculate pool hashrate
            height = self.node.tracker.get_height(
                self.node.best_share_var.value)
            if height > 5:  # we want at least 6 shares in chain
                stale_prop = p2pool_data.get_average_stale_prop(
                    self.node.tracker, self.node.best_share_var.value,
                    min(60 * 60 // self.node.net.SHARE_PERIOD, height))
                pool_rate = p2pool_data.get_pool_attempts_per_second(
                    self.node.tracker, self.node.best_share_var.value,
                    min(height - 1, 60 * 60 //
                        self.node.net.SHARE_PERIOD)) / (1 - stale_prop)

        if set_adaptive_pseudo or set_adaptive_target:  # calculate user's hashrate
            datums, dt = self.local_rate_monitor.get_datums_in_last()
            npoints = sum(datum['user'] == user for datum in datums)
            if npoints > 5:  # at least 6 hashrate datums for the user
                user_rate = 0
                for datum in datums:
                    if datum['user'] == user:
                        user_rate += datum['work'] / dt

        if set_adaptive_target:
            desired_share_target = None
            if user_rate is not None and pool_rate is not None:
                if user_rate and pool_rate:
                    desired_share_target = 20 * (
                        max(
                            self.node.bitcoind_work.value['bits'].target *
                            pool_rate, 2**256 //
                            (self.node.net.CHAIN_LENGTH *
                             self.node.net.SHARE_PERIOD)) // user_rate
                    )  # min 20 shares per block AND min 20 shares per chain

        if set_adaptive_pseudo:
            desired_pseudoshare_target = None
            if user_rate is not None:
                if user_rate:
                    desired_pseudoshare_target = 20 * (
                        2**256 // user_rate //
                        (10 * 60))  # min 20 pseudoshares per 10 minutes

        if desired_share_target is None:
            desired_share_target = 2**265 - 1

        if random.uniform(0, 100) < self.worker_fee:
            pubkey_hash = self.my_pubkey_hash
        else:
            try:
                pubkey_hash = bitcoin_data.address_to_pubkey_hash(
                    user, self.node.net.PARENT)
            except:  # XXX blah
                pubkey_hash = self.my_pubkey_hash

        return user, pubkey_hash, desired_share_target, desired_pseudoshare_target
Beispiel #14
0
    def get_user_details(self, user):
        desired_pseudoshare_target = None
        if "+" in user:
            user, desired_pseudoshare_difficulty_str = user.rsplit("+", 1)
            try:
                desired_pseudoshare_target = bitcoin_data.difficulty_to_target(
                    float(desired_pseudoshare_difficulty_str)
                )
            except:
                pass

        desired_share_target = None
        if "/" in user:
            user, min_diff_str = user.rsplit("/", 1)
            try:
                desired_share_target = bitcoin_data.difficulty_to_target(float(min_diff_str))
            except:
                pass

        set_adaptive_target = (self.diff_policy == "F") or (
            (self.diff_policy == "D") and (desired_share_target is None)
        )
        set_adaptive_pseudo = (self.diff_policy == "F") or (
            (self.diff_policy == "D") and (desired_pseudoshare_target is None)
        )
        user_rate = None
        pool_rate = None

        if set_adaptive_target:  # calculate pool hashrate
            height = self.node.tracker.get_height(self.node.best_share_var.value)
            if height > 5:  # we want at least 6 shares in chain
                stale_prop = p2pool_data.get_average_stale_prop(
                    self.node.tracker,
                    self.node.best_share_var.value,
                    min(60 * 60 // self.node.net.SHARE_PERIOD, height),
                )
                pool_rate = p2pool_data.get_pool_attempts_per_second(
                    self.node.tracker,
                    self.node.best_share_var.value,
                    min(height - 1, 60 * 60 // self.node.net.SHARE_PERIOD),
                ) / (1 - stale_prop)

        if set_adaptive_pseudo or set_adaptive_target:  # calculate user's hashrate
            datums, dt = self.local_rate_monitor.get_datums_in_last()
            npoints = sum(datum["user"] == user for datum in datums)
            if npoints > 5:  # at least 6 hashrate datums for the user
                user_rate = 0
                for datum in datums:
                    if datum["user"] == user:
                        user_rate += datum["work"] / dt

        if set_adaptive_target:
            desired_share_target = None
            if user_rate is not None and pool_rate is not None:
                if user_rate and pool_rate:
                    desired_share_target = 20 * (
                        max(
                            self.node.bitcoind_work.value["bits"].target * pool_rate,
                            2 ** 256 // (self.node.net.CHAIN_LENGTH * self.node.net.SHARE_PERIOD),
                        )
                        // user_rate
                    )  # min 20 shares per block AND min 20 shares per chain

        if set_adaptive_pseudo:
            desired_pseudoshare_target = None
            if user_rate is not None:
                if user_rate:
                    desired_pseudoshare_target = 20 * (
                        2 ** 256 // user_rate // (10 * 60)
                    )  # min 20 pseudoshares per 10 minutes

        if desired_share_target is None:
            desired_share_target = 2 ** 265 - 1

        if random.uniform(0, 100) < self.worker_fee:
            pubkey_hash = self.my_pubkey_hash
        else:
            try:
                pubkey_hash = bitcoin_data.address_to_pubkey_hash(user, self.node.net.PARENT)
            except:  # XXX blah
                pubkey_hash = self.my_pubkey_hash

        return user, pubkey_hash, desired_share_target, desired_pseudoshare_target
Beispiel #15
0
def main(args):
    try:
        if args.charts:
            from . import draw
        
        print 'p2pool (version %s)' % (p2pool_init.__version__,)
        print
        
        # connect to bitcoind over JSON-RPC and do initial getwork
        url = 'http://%s:%i/' % (args.bitcoind_address, args.bitcoind_rpc_port)
        print '''Testing bitcoind RPC connection to '%s' with username '%s'...''' % (url, args.bitcoind_rpc_username)
        bitcoind = jsonrpc.Proxy(url, (args.bitcoind_rpc_username, args.bitcoind_rpc_password))
        temp_work, temp_height = yield getwork(bitcoind)
        print '    ...success!'
        print '    Current block hash: %x height: %i' % (temp_work.previous_block, temp_height)
        print
        
        # connect to bitcoind over bitcoin-p2p and do checkorder to get pubkey to send payouts to
        print '''Testing bitcoind P2P connection to '%s:%s'...''' % (args.bitcoind_address, args.bitcoind_p2p_port)
        factory = bitcoin.p2p.ClientFactory(args.net)
        reactor.connectTCP(args.bitcoind_address, args.bitcoind_p2p_port, factory)
        my_script = yield get_payout_script(factory)
        if args.pubkey_hash is None:
            if my_script is None:
                print '    IP transaction denied ... falling back to sending to address.'
                my_script = yield get_payout_script2(bitcoind, args.net)
        else:
            my_script = bitcoin.data.pubkey_hash_to_script2(args.pubkey_hash)
        print '    ...success!'
        print '    Payout script:', my_script.encode('hex')
        print
        
        ht = bitcoin.p2p.HeightTracker(factory)
        
        tracker = p2pool.OkayTracker(args.net)
        chains = expiring_dict.ExpiringDict(300)
        def get_chain(chain_id_data):
            return chains.setdefault(chain_id_data, Chain(chain_id_data))
        
        peer_heads = expiring_dict.ExpiringDict(300) # hash -> peers that know of it
        
        # information affecting work that should trigger a long-polling update
        current_work = variable.Variable(None)
        # information affecting work that should not trigger a long-polling update
        current_work2 = variable.Variable(None)
        
        work_updated = variable.Event()
        
        requested = expiring_dict.ExpiringDict(300)
        
        @defer.inlineCallbacks
        def set_real_work1():
            work, height = yield getwork(bitcoind)
            changed = work.previous_block != current_work.value['previous_block'] if current_work.value is not None else True
            current_work.set(dict(
                version=work.version,
                previous_block=work.previous_block,
                target=work.target,
                height=height,
                best_share_hash=current_work.value['best_share_hash'] if current_work.value is not None else None,
            ))
            current_work2.set(dict(
                clock_offset=time.time() - work.timestamp,
            ))
            if changed:
                set_real_work2()
        
        def set_real_work2():
            best, desired = tracker.think(ht, current_work.value['previous_block'], time.time() - current_work2.value['clock_offset'])
            
            t = dict(current_work.value)
            t['best_share_hash'] = best
            current_work.set(t)
            
            t = time.time()
            for peer2, share_hash in desired:
                if share_hash not in tracker.tails: # was received in the time tracker.think was running
                    continue
                last_request_time, count = requested.get(share_hash, (None, 0))
                if last_request_time is not None and last_request_time - 5 < t < last_request_time + 10 * 1.5**count:
                    continue
                potential_peers = set()
                for head in tracker.tails[share_hash]:
                    potential_peers.update(peer_heads.get(head, set()))
                potential_peers = [peer for peer in potential_peers if peer.connected2]
                if count == 0 and peer2 is not None and peer2.connected2:
                    peer = peer2
                else:
                    peer = random.choice(potential_peers) if potential_peers and random.random() > .2 else peer2
                    if peer is None:
                        continue
                
                print 'Requesting parent share %s from %s' % (p2pool.format_hash(share_hash), '%s:%i' % peer.addr)
                peer.send_getshares(
                    hashes=[share_hash],
                    parents=2000,
                    stops=list(set(tracker.heads) | set(
                        tracker.get_nth_parent_hash(head, min(max(0, tracker.get_height_and_last(head)[0] - 1), 10)) for head in tracker.heads
                    ))[:100],
                )
                requested[share_hash] = t, count + 1
        
        print 'Initializing work...'
        yield set_real_work1()
        set_real_work2()
        print '    ...success!'
        
        start_time = time.time() - current_work2.value['clock_offset']
        
        # setup p2p logic and join p2pool network
        
        def share_share(share, ignore_peer=None):
            for peer in p2p_node.peers.itervalues():
                if peer is ignore_peer:
                    continue
                #if p2pool_init.DEBUG:
                #    print "Sending share %s to %r" % (p2pool.format_hash(share.hash), peer.addr)
                peer.send_shares([share])
            share.flag_shared()
        
        def p2p_shares(shares, peer=None):
            if len(shares) > 5:
                print 'Processing %i shares...' % (len(shares),)
            
            some_new = False
            for share in shares:
                if share.hash in tracker.shares:
                    #print 'Got duplicate share, ignoring. Hash: %s' % (p2pool.format_hash(share.hash),)
                    continue
                some_new = True
                
                #print 'Received share %s from %r' % (p2pool.format_hash(share.hash), share.peer.addr if share.peer is not None else None)
                
                tracker.add(share)
                #for peer2, share_hash in desired:
                #    print 'Requesting parent share %x' % (share_hash,)
                #    peer2.send_getshares(hashes=[share_hash], parents=2000)
                
                if share.bitcoin_hash <= share.header['target']:
                    print
                    print 'GOT BLOCK! Passing to bitcoind! %s bitcoin: %x' % (p2pool.format_hash(share.hash), share.bitcoin_hash,)
                    print
                    if factory.conn.value is not None:
                        factory.conn.value.send_block(block=share.as_block(tracker, args.net))
                    else:
                        print 'No bitcoind connection! Erp!'
            
            if shares and peer is not None:
                peer_heads.setdefault(shares[0].hash, set()).add(peer)
            
            if some_new:
                set_real_work2()
            
            if len(shares) > 5:
                print '... done processing %i shares. Have: %i/~%i' % (len(shares), len(tracker.shares), 2*args.net.CHAIN_LENGTH)
        
        def p2p_share_hashes(share_hashes, peer):
            t = time.time()
            get_hashes = []
            for share_hash in share_hashes:
                if share_hash in tracker.shares:
                    continue
                last_request_time, count = requested.get(share_hash, (None, 0))
                if last_request_time is not None and last_request_time - 5 < t < last_request_time + 10 * 1.5**count:
                    continue
                print 'Got share hash, requesting! Hash: %s' % (p2pool.format_hash(share_hash),)
                get_hashes.append(share_hash)
                requested[share_hash] = t, count + 1
            
            if share_hashes and peer is not None:
                peer_heads.setdefault(share_hashes[0], set()).add(peer)
            if get_hashes:
                peer.send_getshares(hashes=get_hashes, parents=0, stops=[])
        
        def p2p_get_shares(share_hashes, parents, stops, peer):
            parents = min(parents, 1000//len(share_hashes))
            stops = set(stops)
            shares = []
            for share_hash in share_hashes:
                for share in itertools.islice(tracker.get_chain_known(share_hash), parents + 1):
                    if share.hash in stops:
                        break
                    shares.append(share)
            peer.send_shares(shares, full=True)
        
        print 'Joining p2pool network using TCP port %i...' % (args.p2pool_port,)
        
        def parse(x):
            if ':' in x:
                ip, port = x.split(':')
                return ip, int(port)
            else:
                return x, args.net.P2P_PORT
        
        nodes = set([
            ('72.14.191.28', args.net.P2P_PORT),
            ('62.204.197.159', args.net.P2P_PORT),
            ('142.58.248.28', args.net.P2P_PORT),
            ('94.23.34.145', args.net.P2P_PORT),
        ])
        for host in [
            'p2pool.forre.st',
            'dabuttonfactory.com',
        ]:
            try:
                nodes.add(((yield reactor.resolve(host)), args.net.P2P_PORT))
            except:
                log.err(None, 'Error resolving bootstrap node IP:')
        
        p2p_node = p2p.Node(
            current_work=current_work,
            port=args.p2pool_port,
            net=args.net,
            addr_store=db.SQLiteDict(sqlite3.connect(os.path.join(os.path.dirname(sys.argv[0]), 'addrs.dat'), isolation_level=None), args.net.ADDRS_TABLE),
            mode=0 if args.low_bandwidth else 1,
            preferred_addrs=set(map(parse, args.p2pool_nodes)) | nodes,
        )
        p2p_node.handle_shares = p2p_shares
        p2p_node.handle_share_hashes = p2p_share_hashes
        p2p_node.handle_get_shares = p2p_get_shares
        
        p2p_node.start()
        
        # send share when the chain changes to their chain
        def work_changed(new_work):
            #print 'Work changed:', new_work
            for share in tracker.get_chain_known(new_work['best_share_hash']):
                if share.shared:
                    break
                share_share(share, share.peer)
        current_work.changed.watch(work_changed)
        
        print '    ...success!'
        print
        
        @defer.inlineCallbacks
        def upnp_thread():
            while True:
                try:
                    is_lan, lan_ip = yield ipdiscover.get_local_ip()
                    if not is_lan:
                        continue
                    pm = yield portmapper.get_port_mapper()
                    yield pm._upnp.add_port_mapping(lan_ip, args.net.P2P_PORT, args.net.P2P_PORT, 'p2pool', 'TCP')
                except:
                    if p2pool_init.DEBUG:
                        log.err()
                yield deferral.sleep(random.expovariate(1/120))
        
        if args.upnp:
            upnp_thread()
         
        # start listening for workers with a JSON-RPC server
        
        print 'Listening for workers on port %i...' % (args.worker_port,)
        
        # setup worker logic
        
        merkle_root_to_transactions = expiring_dict.ExpiringDict(300)
        run_identifier = struct.pack('<Q', random.randrange(2**64))
        
        def compute(state, payout_script):
            if payout_script is None:
                payout_script = my_script
            if state['best_share_hash'] is None and args.net.PERSIST:
                raise jsonrpc.Error(-12345, u'p2pool is downloading shares')
            pre_extra_txs = [tx for tx in tx_pool.itervalues() if tx.is_good()]
            pre_extra_txs = pre_extra_txs[:2**16 - 1] # merkle_branch limit
            extra_txs = []
            size = 0
            for tx in pre_extra_txs:
                this_size = len(bitcoin.data.tx_type.pack(tx.tx))
                if size + this_size > 500000:
                    break
                extra_txs.append(tx)
                size += this_size
            # XXX check sigops!
            # XXX assuming generate_tx is smallish here..
            generate_tx = p2pool.generate_transaction(
                tracker=tracker,
                previous_share_hash=state['best_share_hash'],
                new_script=payout_script,
                subsidy=(50*100000000 >> (state['height'] + 1)//210000) + sum(tx.value_in - tx.value_out for tx in extra_txs),
                nonce=run_identifier + struct.pack('<Q', random.randrange(2**64)),
                block_target=state['target'],
                net=args.net,
            )
            print 'Generating! Difficulty: %.06f Payout if block: %.6f BTC' % (0xffff*2**208/p2pool.coinbase_type.unpack(generate_tx['tx_ins'][0]['script'])['share_data']['target'], generate_tx['tx_outs'][-1]['value']*1e-8)
            #print 'Target: %x' % (p2pool.coinbase_type.unpack(generate_tx['tx_ins'][0]['script'])['share_data']['target'],)
            #, have', shares.count(my_script) - 2, 'share(s) in the current chain. Fee:', sum(tx.value_in - tx.value_out for tx in extra_txs)/100000000
            transactions = [generate_tx] + [tx.tx for tx in extra_txs]
            merkle_root = bitcoin.data.merkle_hash(transactions)
            merkle_root_to_transactions[merkle_root] = transactions # will stay for 1000 seconds
            
            timestamp = int(time.time() - current_work2.value['clock_offset'])
            if state['best_share_hash'] is not None:
                timestamp2 = math.median((s.timestamp for s in itertools.islice(tracker.get_chain_to_root(state['best_share_hash']), 11)), use_float=False) + 1
                if timestamp2 > timestamp:
                    print 'Toff', timestamp2 - timestamp
                    timestamp = timestamp2
            target2 = p2pool.coinbase_type.unpack(generate_tx['tx_ins'][0]['script'])['share_data']['target']
            times[p2pool.coinbase_type.unpack(generate_tx['tx_ins'][0]['script'])['share_data']['nonce']] = time.time()
            #print 'SENT', 2**256//p2pool.coinbase_type.unpack(generate_tx['tx_ins'][0]['script'])['share_data']['target']
            return bitcoin.getwork.BlockAttempt(state['version'], state['previous_block'], merkle_root, timestamp, state['target'], target2)
        
        my_shares = set()
        times = {}
        
        def got_response(data):
            try:
                # match up with transactions
                header = bitcoin.getwork.decode_data(data)
                transactions = merkle_root_to_transactions.get(header['merkle_root'], None)
                if transactions is None:
                    print '''Couldn't link returned work's merkle root with its transactions - should only happen if you recently restarted p2pool'''
                    return False
                block = dict(header=header, txs=transactions)
                hash_ = bitcoin.data.block_header_type.hash256(block['header'])
                if hash_ <= block['header']['target'] or p2pool_init.DEBUG:
                    print
                    print 'GOT BLOCK! Passing to bitcoind! bitcoin: %x' % (hash_,)
                    print
                    if factory.conn.value is not None:
                        factory.conn.value.send_block(block=block)
                    else:
                        print 'No bitcoind connection! Erp!'
                target = p2pool.coinbase_type.unpack(transactions[0]['tx_ins'][0]['script'])['share_data']['target']
                if hash_ > target:
                    print 'Worker submitted share with hash (%x) > target (%x)' % (hash_, target)
                    return False
                share = p2pool.Share.from_block(block)
                my_shares.add(share.hash)
                print 'GOT SHARE! %s prev %s age %.2fs' % (p2pool.format_hash(share.hash), p2pool.format_hash(share.previous_hash), time.time() - times[share.nonce]) + (' DEAD ON ARRIVAL' if share.previous_hash != current_work.value['best_share_hash'] else '')
                good = share.previous_hash == current_work.value['best_share_hash']
                # maybe revert back to tracker being non-blocking so 'good' can be more accurate?
                p2p_shares([share])
                # eg. good = share.hash == current_work.value['best_share_hash'] here
                return good
            except:
                log.err(None, 'Error processing data received from worker:')
                return False
        
        web_root = worker_interface.WorkerInterface(current_work, compute, got_response, args.net)
        
        def get_rate():
            if current_work.value['best_share_hash'] is not None:
                height, last = tracker.get_height_and_last(current_work.value['best_share_hash'])
                att_s = p2pool.get_pool_attempts_per_second(tracker, current_work.value['best_share_hash'], args.net, min(height, 720))
                return json.dumps(att_s)
            return json.dumps(None)
        
        def get_users():
            height, last = tracker.get_height_and_last(current_work.value['best_share_hash'])
            weights, total_weight = tracker.get_cumulative_weights(current_work.value['best_share_hash'], min(height, 720), 2**256)
            res = {}
            for script in sorted(weights, key=lambda s: weights[s]):
                res[script.encode('hex')] = weights[script]/total_weight
            return json.dumps(res)
        
        class WebInterface(resource.Resource):
            def __init__(self, func, mime_type):
                self.func, self.mime_type = func, mime_type
            
            def render_GET(self, request):
                request.setHeader('Content-Type', self.mime_type)
                return self.func()
        
        web_root.putChild('rate', WebInterface(get_rate, 'application/json'))
        web_root.putChild('users', WebInterface(get_users, 'application/json'))
        if args.charts:
            web_root.putChild('chain_img', WebInterface(lambda: draw.get(tracker, current_work.value['best_share_hash']), 'image/png'))
        
        reactor.listenTCP(args.worker_port, server.Site(web_root))
        
        print '    ...success!'
        print
        
        # done!
        
        tx_pool = expiring_dict.ExpiringDict(600, get_touches=False) # hash -> tx
        get_raw_transaction = deferral.DeferredCacher(lambda tx_hash: bitcoind.rpc_getrawtransaction('%x' % tx_hash), expiring_dict.ExpiringDict(100))
        
        class Tx(object):
            def __init__(self, tx, seen_at_block):
                self.hash = bitcoin.data.tx_type.hash256(tx)
                self.tx = tx
                self.seen_at_block = seen_at_block
                self.mentions = set([bitcoin.data.tx_type.hash256(tx)] + [tx_in['previous_output']['hash'] for tx_in in tx['tx_ins']])
                #print
                #print '%x %r' % (seen_at_block, tx)
                #for mention in self.mentions:
                #    print '%x' % mention
                #print
                self.parents_all_in_blocks = False
                self.value_in = 0
                #print self.tx
                self.value_out = sum(txout['value'] for txout in self.tx['tx_outs'])
                self._find_parents_in_blocks()
            
            @defer.inlineCallbacks
            def _find_parents_in_blocks(self):
                for tx_in in self.tx['tx_ins']:
                    try:
                        raw_transaction = yield get_raw_transaction(tx_in['previous_output']['hash'])
                    except Exception:
                        return
                    self.value_in += raw_transaction['tx']['txouts'][tx_in['previous_output']['index']]['value']
                    #print raw_transaction
                    if not raw_transaction['parent_blocks']:
                        return
                self.parents_all_in_blocks = True
            
            def is_good(self):
                if not self.parents_all_in_blocks:
                    return False
                x = self.is_good2()
                #print 'is_good:', x
                return x
        
        @defer.inlineCallbacks
        def new_tx(tx_hash):
            try:
                assert isinstance(tx_hash, (int, long))
                #print 'REQUESTING', tx_hash
                tx = yield (yield factory.getProtocol()).get_tx(tx_hash)
                #print 'GOT', tx
                tx_pool[bitcoin.data.tx_type.hash256(tx)] = Tx(tx, current_work.value['previous_block'])
            except:
                log.err(None, 'Error handling tx:')
        # disable for now, for testing impact on stales
        #factory.new_tx.watch(new_tx)
        
        def new_block(block_hash):
            work_updated.happened()
        factory.new_block.watch(new_block)
        
        print 'Started successfully!'
        print
        
        ht.updated.watch(lambda x: set_real_work2())
        
        @defer.inlineCallbacks
        def work1_thread():
            while True:
                flag = work_updated.get_deferred()
                try:
                    yield set_real_work1()
                except:
                    log.err()
                yield defer.DeferredList([flag, deferral.sleep(random.expovariate(1/20))], fireOnOneCallback=True)
        
        @defer.inlineCallbacks
        def work2_thread():
            while True:
                try:
                    set_real_work2()
                except:
                    log.err()
                yield deferral.sleep(random.expovariate(1/20))
        
        work1_thread()
        work2_thread()
        
        counter = skiplists.CountsSkipList(tracker, run_identifier)
        
        while True:
            yield deferral.sleep(3)
            try:
                if current_work.value['best_share_hash'] is not None:
                    height, last = tracker.get_height_and_last(current_work.value['best_share_hash'])
                    if height > 5:
                        att_s = p2pool.get_pool_attempts_per_second(tracker, current_work.value['best_share_hash'], args.net)
                        weights, total_weight = tracker.get_cumulative_weights(current_work.value['best_share_hash'], min(height, 120), 2**100)
                        matching_in_chain = counter(current_work.value['best_share_hash'], height)
                        shares_in_chain = my_shares & matching_in_chain
                        stale_shares = my_shares - matching_in_chain
                        print 'Pool: %sH/s in %i shares Recent: %.02f%% >%sH/s Shares: %i (%i stale) Peers: %i' % (
                            math.format(att_s),
                            height,
                            weights.get(my_script, 0)/total_weight*100,
                            math.format(weights.get(my_script, 0)/total_weight*att_s),
                            len(shares_in_chain) + len(stale_shares),
                            len(stale_shares),
                            len(p2p_node.peers),
                        )
                        #weights, total_weight = tracker.get_cumulative_weights(current_work.value['best_share_hash'], min(height, 100), 2**100)
                        #for k, v in weights.iteritems():
                        #    print k.encode('hex'), v/total_weight
            except:
                log.err()
    except:
        log.err(None, 'Fatal error:')
        reactor.stop()
Beispiel #16
0
 def get_rate():
     if current_work.value['best_share_hash'] is not None:
         height, last = tracker.get_height_and_last(current_work.value['best_share_hash'])
         att_s = p2pool.get_pool_attempts_per_second(tracker, current_work.value['best_share_hash'], args.net, min(height, 720))
         return json.dumps(att_s)
     return json.dumps(None)